samples updating with AgentScope-Runtime 1.0.0 (#43)

This commit is contained in:
Zhiling (Bruce) Luo
2025-12-09 21:19:33 +08:00
committed by GitHub
parent 67469f1caa
commit 68450961bb
10 changed files with 353 additions and 271 deletions

View File

@@ -1,56 +1,41 @@
# -*- coding: utf-8 -*-
import functools
import os
import threading
from typing import List, Dict, AsyncGenerator
from openai import OpenAI
from agentscope.agent import ReActAgent
from agentscope.formatter import DashScopeChatFormatter
from agentscope.message import TextBlock
from agentscope.model import DashScopeChatModel
from agentscope_runtime.engine import Runner
from agentscope_runtime.engine.agents.agentscope_agent import AgentScopeAgent
from agentscope_runtime.engine.schemas.agent_schemas import (
AgentRequest,
RunStatus,
)
from agentscope_runtime.engine.services import SandboxService
from agentscope_runtime.engine.services.context_manager import ContextManager
from agentscope_runtime.engine.services.environment_manager import (
EnvironmentManager,
)
from agentscope_runtime.engine.services.memory_service import (
InMemoryMemoryService,
)
from agentscope_runtime.engine.services.session_history_service import (
InMemorySessionHistoryService,
)
from agentscope_runtime.sandbox.tools.browser import (
browser_click,
browser_close,
browser_console_messages,
browser_drag,
browser_file_upload,
browser_handle_dialog,
browser_hover,
browser_navigate,
browser_navigate_back,
browser_navigate_forward,
browser_network_requests,
browser_pdf_save,
browser_press_key,
browser_resize,
browser_select_option,
browser_snapshot,
browser_tab_close,
browser_tab_list,
browser_tab_new,
browser_tab_select,
browser_take_screenshot,
browser_type,
browser_wait_for,
run_ipython_cell,
run_shell_command,
)
from agentscope.pipeline import stream_printing_messages
from agentscope.tool import Toolkit, ToolResponse
from prompts import SYSTEM_PROMPT
from agentscope_runtime.adapters.agentscope.memory import (
AgentScopeSessionHistoryMemory,
)
from agentscope_runtime.engine import AgentApp
from agentscope_runtime.engine.schemas.agent_schemas import (
AgentRequest,
)
from agentscope_runtime.engine.services.agent_state.state_service import (
InMemoryStateService,
)
from agentscope_runtime.engine.services.sandbox.sandbox_service import (
SandboxService,
)
# flake8: noqa: E501
from agentscope_runtime.engine.services.session_history.session_history_service import ( # pylint: disable=line-too-long
InMemorySessionHistoryService, # pylint: disable=line-too-long
)
if os.path.exists(".env"):
from dotenv import load_dotenv
@@ -59,116 +44,162 @@ if os.path.exists(".env"):
USER_ID = "user_1"
SESSION_ID = "session_001" # Using a fixed ID for simplicity
PORT = 8090
class AgentscopeBrowseruseAgent:
def __init__(self) -> None:
self.tools = [
run_shell_command,
run_ipython_cell,
browser_close,
browser_resize,
browser_console_messages,
browser_handle_dialog,
browser_file_upload,
browser_press_key,
browser_navigate,
browser_navigate_back,
browser_navigate_forward,
browser_network_requests,
browser_pdf_save,
browser_take_screenshot,
browser_snapshot,
browser_click,
browser_drag,
browser_hover,
browser_type,
browser_select_option,
browser_tab_list,
browser_tab_new,
browser_tab_select,
browser_tab_close,
browser_wait_for,
def sandbox_tool_adapter(func):
"""
Sandbox Tool Adapter.
Wraps a sandbox tool function so that its output is always converted
into a ToolResponse object, which is required by the Toolkit.
This adapter preserves the original function signature and docstring
so that JSON schemas can be correctly generated by the Toolkit.
Args:
func: Original sandbox tool function (may return dict, string, etc.).
Returns:
A callable that produces ToolResponse instead of raw data.
"""
@functools.wraps(func)
def wrapper(*args, **kwargs):
res = func(*args, **kwargs)
if isinstance(res, ToolResponse):
return res
# TODO: fix this
return ToolResponse(content=[TextBlock(type="text", text=str(res))])
return wrapper
desktop_url = ""
def init():
agent_app = AgentApp(
app_name="Friday",
app_description="A helpful assistant",
)
@agent_app.init
async def init_func(self):
self.state_service = InMemoryStateService()
self.session_service = InMemorySessionHistoryService()
self.sandbox_service = SandboxService()
await self.state_service.start()
await self.session_service.start()
await self.sandbox_service.start()
@agent_app.shutdown
async def shutdown_func(self):
await self.state_service.stop()
await self.session_service.stop()
await self.sandbox_service.stop()
@agent_app.query(framework="agentscope")
async def query_func(
self,
msgs,
request: AgentRequest = None,
):
session_id = request.session_id
user_id = request.user_id
state = await self.state_service.export_state(
session_id=session_id,
user_id=user_id,
)
# Get sandbox
sandboxes = self.sandbox_service.connect(
session_id=session_id,
user_id=user_id,
sandbox_types=["browser"],
)
sandbox = sandboxes[0]
global desktop_url
desktop_url = sandbox.desktop_url
browser_tools = [
sandbox.browser_navigate,
sandbox.browser_take_screenshot,
sandbox.browser_snapshot,
sandbox.browser_click,
sandbox.browser_type,
]
self.agent = AgentScopeAgent(
toolkit = Toolkit()
for tool in browser_tools:
toolkit.register_tool_function(sandbox_tool_adapter(tool))
agent = ReActAgent(
name="Friday",
model=DashScopeChatModel(
"qwen-max",
api_key=os.getenv("DASHSCOPE_API_KEY"),
enable_thinking=True,
stream=True,
),
agent_config={
"sys_prompt": SYSTEM_PROMPT,
},
tools=self.tools,
agent_builder=ReActAgent,
sys_prompt=SYSTEM_PROMPT,
toolkit=toolkit,
memory=AgentScopeSessionHistoryMemory(
service=self.session_service,
session_id=session_id,
user_id=user_id,
),
formatter=DashScopeChatFormatter(),
)
async def connect(self) -> None:
session_history_service = InMemorySessionHistoryService()
if state:
agent.load_state_dict(state)
await session_history_service.create_session(
user_id=USER_ID,
session_id=SESSION_ID,
async for msg, last in stream_printing_messages(
agents=[agent],
coroutine_task=agent(msgs),
):
yield msg, last
state = agent.state_dict()
await self.state_service.save_state(
user_id=user_id,
session_id=session_id,
state=state,
)
self.mem_service = InMemoryMemoryService()
await self.mem_service.start()
self.sandbox_service = SandboxService()
await self.sandbox_service.start()
def run_agent_app():
agent_app.run(host="127.0.0.1", port=PORT)
self.context_manager = ContextManager(
memory_service=self.mem_service,
session_history_service=session_history_service,
)
self.environment_manager = EnvironmentManager(
sandbox_service=self.sandbox_service,
)
sandboxes = self.sandbox_service.connect(
session_id=SESSION_ID,
user_id=USER_ID,
tools=self.tools,
)
threading.Thread(target=run_agent_app, daemon=True).start()
return agent_app
if len(sandboxes) > 0:
sandbox = sandboxes[0]
self.desktop_url = sandbox.desktop_url
else:
self.desktop_url = ""
runner = Runner(
agent=self.agent,
context_manager=self.context_manager,
environment_manager=self.environment_manager,
)
self.runner = runner
class AgentscopeBrowseruseAgent:
def __init__(self) -> None:
self.agent = init()
self.desktop_url = ""
async def chat(
self,
chat_messages: List[Dict],
) -> AsyncGenerator[Dict, None]:
convert_messages = []
for chat_message in chat_messages:
convert_messages.append(
{
"role": chat_message["role"],
"content": [
{
"type": "text",
"text": chat_message["content"],
},
],
},
)
request = AgentRequest(input=convert_messages, session_id=SESSION_ID)
request.tools = []
async for message in self.runner.stream_query(
user_id=USER_ID,
request=request,
):
if (
message.object == "message"
and RunStatus.Completed == message.status
):
yield message.content
client = OpenAI(base_url=f"http://127.0.0.1:{PORT}/compatible-mode/v1")
stream = client.responses.create(
model="any_name",
input=chat_messages[-1]["content"],
stream=True,
)
global desktop_url
self.desktop_url = desktop_url
for chunk in stream:
if hasattr(chunk, "delta"):
yield chunk.delta
else:
yield {}
# if chunk.choices[0].delta.content is not None:
# yield chunk.choices[0].delta.content
async def close(self) -> None:
await self.sandbox_service.stop()

View File

@@ -1,17 +1,18 @@
# -*- coding: utf-8 -*-
import asyncio
import json
import logging
import os
import time
from quart import Quart, Response, jsonify, request
from quart_cors import cors
from agentscope_browseruse_agent import AgentscopeBrowseruseAgent
from agentscope_runtime.engine.schemas.agent_schemas import (
DataContent,
TextContent,
)
from quart import Quart, Response, jsonify, request
from quart_cors import cors
app = Quart(__name__)
app = cors(app, allow_origin="*")
@@ -35,9 +36,8 @@ if os.path.exists(".env"):
async def user_mode(input_data):
messages = input_data.get("messages", [])
last_name = ""
async for item_list in agent.chat(messages):
if item_list:
item = item_list[0]
async for item in agent.chat(messages):
if item:
res = ""
if isinstance(item, TextContent):
res = item.text
@@ -48,8 +48,9 @@ async def user_mode(input_data):
continue
res = "I will use the tool" + json.dumps(item.data["name"])
last_name = json.dumps(item.data["name"])
yield simple_yield(res + "\n")
elif isinstance(item, str):
res = item
yield simple_yield(res)
else:
yield simple_yield()
@@ -105,5 +106,5 @@ async def get_env_info():
if __name__ == "__main__":
asyncio.run(agent.connect())
agent.chat([{"role": "user", "content": "hello"}])
app.run(host="0.0.0.0", port=9000)

View File

@@ -1,5 +1,6 @@
pyyaml>=6.0.2
quart>=0.8.0
quart-cors>=0.8.0
agentscope-runtime==0.2.0
agentscope-runtime>=1.0.0
agentscope[full]>=1.0.5
openai>=2.8.1

View File

@@ -94,16 +94,19 @@ const App: React.FC = () => {
setMessages(newMessages);
setIsTyping(true);
await processMessageToChatGPT(newMessages);
await get_desktop_url();
};
async function processMessageToChatGPT(chatMessages: ChatMessage) {
let apiMessages = chatMessages
const apiMessages = chatMessages
.map((messageObject) => {
if (messageObject.message.trim() === "") {
return null;
}
let role = messageObject.sender === "assistant" ? "assistant" : "user";
const role =
messageObject.sender === "assistant" ? "assistant" : "user";
return { role, content: messageObject.message };
})
.filter(Boolean);
@@ -143,7 +146,9 @@ const App: React.FC = () => {
]);
while (true) {
const { done, value } = await reader.read();
if (done) break;
if (done) {
break;
}
const chunk = decoder.decode(value);
accumulatedMessage += chunk;
@@ -152,7 +157,9 @@ const App: React.FC = () => {
accumulatedMessage = lines.pop() || "";
for (const line of lines) {
if (line.trim() === "") continue;
if (line.trim() === "") {
continue;
}
try {
const parsed = JSON.parse(line.split("data: ")[1]);

View File

@@ -1,6 +1,5 @@
DASHSCOPE_API_KEY=
DASHSCOPE_BASE_URL=
DASHSCOPE_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
SERVER_PORT=8080
SERVER_ENDPOINT=agent
SERVER_HOST=localhost
USER_MANAGER_STORAGE=user.json

View File

@@ -1,70 +1,109 @@
# -*- coding: utf-8 -*-
import asyncio
# pylint:disable=redefined-outer-name, unused-argument
import os
from agentscope.formatter import DashScopeChatFormatter
from agentscope.tool import Toolkit, execute_python_code
from agentscope.pipeline import stream_printing_messages
from agentscope.agent import ReActAgent
from agentscope.model import DashScopeChatModel
from agentscope_runtime.engine import LocalDeployManager, Runner
from agentscope_runtime.engine.agents.agentscope_agent import AgentScopeAgent
from agentscope_runtime.engine.services.context_manager import ContextManager
from agentscope_runtime.engine import AgentApp
from agentscope_runtime.engine.schemas.agent_schemas import AgentRequest
from agentscope_runtime.adapters.agentscope.memory import (
AgentScopeSessionHistoryMemory,
)
from agentscope_runtime.engine.services.agent_state import (
InMemoryStateService,
)
from agentscope_runtime.engine.services.session_history import (
InMemorySessionHistoryService,
)
def local_deploy():
asyncio.run(_local_deploy())
async def _local_deploy():
from dotenv import load_dotenv
load_dotenv()
server_port = int(os.environ.get("SERVER_PORT", "8090"))
server_endpoint = os.environ.get("SERVER_ENDPOINT", "agent")
model = DashScopeChatModel(
model_name="qwen-turbo",
api_key=os.getenv("DASHSCOPE_API_KEY"),
)
agent = AgentScopeAgent(
name="Friday",
model=model,
agent_config={
"sys_prompt": "A simple LLM agent to generate a short response",
},
agent_builder=ReActAgent,
# server_endpoint = os.environ.get("SERVER_ENDPOINT", "process")
agent_app = AgentApp(
app_name="Friday",
app_description="A simple LLM agent to generate a short response",
)
context_manager = ContextManager()
@agent_app.init
async def init_func(self):
self.state_service = InMemoryStateService()
self.session_service = InMemorySessionHistoryService()
runner = Runner(
agent=agent,
context_manager=context_manager,
)
await self.state_service.start()
await self.session_service.start()
deploy_manager = LocalDeployManager(host="localhost", port=server_port)
try:
deployment_info = await runner.deploy(
deploy_manager,
endpoint_path=f"/{server_endpoint}",
@agent_app.shutdown
async def shutdown_func(self):
await self.state_service.stop()
await self.session_service.stop()
@agent_app.query(framework="agentscope")
async def query_func(
self,
msgs,
request: AgentRequest = None,
**kwargs,
):
session_id = request.session_id
user_id = request.user_id
state = await self.state_service.export_state(
session_id=session_id,
user_id=user_id,
)
print("✅ Service deployed successfully!")
print(f" URL: {deployment_info['url']}")
print(f" Endpoint: {deployment_info['url']}/{server_endpoint}")
print("\nAgent Service is running in the background.")
toolkit = Toolkit()
toolkit.register_tool_function(execute_python_code)
while True:
await asyncio.sleep(1)
agent = ReActAgent(
name="Friday",
model=DashScopeChatModel(
"qwen-turbo",
api_key=os.getenv("DASHSCOPE_API_KEY"),
enable_thinking=True,
stream=True,
),
sys_prompt="You're a helpful assistant named Friday.",
toolkit=toolkit,
memory=AgentScopeSessionHistoryMemory(
service=self.session_service,
session_id=session_id,
user_id=user_id,
),
formatter=DashScopeChatFormatter(),
)
except (KeyboardInterrupt, asyncio.CancelledError):
# This block will be executed when you press Ctrl+C.
print("\nShutdown signal received. Stopping the service...")
if deploy_manager.is_running:
await deploy_manager.stop()
print("✅ Service stopped.")
except Exception as e:
print(f"An error occurred: {e}")
if deploy_manager.is_running:
await deploy_manager.stop()
if state:
agent.load_state_dict(state)
async for msg, last in stream_printing_messages(
agents=[agent],
coroutine_task=agent(msgs),
):
yield msg, last
state = agent.state_dict()
await self.state_service.save_state(
user_id=user_id,
session_id=session_id,
state=state,
)
agent_app.run(host="127.0.0.1", port=server_port)
if __name__ == "__main__":

View File

@@ -1,5 +1,6 @@
flask>=3.1.2
flask_cors>=6.0.1
agentscope-runtime==0.2.0
agentscope-runtime>=1.0.0
agentscope-runtime[agentscope]
flask_sqlalchemy>=3.1.1
flask_sqlalchemy>=3.1.1
openai>=2.8.1

View File

@@ -5,6 +5,8 @@ import os
from datetime import datetime
import requests
from openai import OpenAI
from dotenv import load_dotenv
from flask import Flask, request, jsonify
from flask_cors import CORS
@@ -152,29 +154,25 @@ def sse_client(url, data=None):
pass
def call_runner(query, query_user_id, query_session_id):
def call_runner(query):
server_port = int(os.environ.get("SERVER_PORT", "8090"))
server_endpoint = os.environ.get("SERVER_ENDPOINT", "agent")
server_host = os.environ.get("SERVER_HOST", "localhost")
url = f"http://{server_host}:{server_port}/{server_endpoint}"
data_arg = {
"input": [
{
"role": "user",
"content": [
{
"type": "text",
"text": query,
},
],
},
],
"session_id": query_session_id,
"user_id": query_user_id,
}
for content in sse_client(url, data=data_arg):
yield content
client = OpenAI(
base_url=f"http://{server_host}:{server_port}/compatible-mode/v1",
)
stream = client.responses.create(
model="any_name",
input=query,
stream=True,
)
for chunk in stream:
if hasattr(chunk, "delta"):
yield chunk.delta
else:
yield ""
# API routes
@@ -359,11 +357,9 @@ def send_message(conversation_id):
ai_response_text = ""
question = text
conversation_id_str = str(conversation_id)
for item in call_runner(
question,
conversation_id_str,
conversation_id_str,
):
ai_response_text += item

View File

@@ -1,24 +1,24 @@
import React, { useState, useEffect, useRef } from 'react';
import { MessageCircle, User, Send, Plus, LogOut, Menu, X, Bot } from 'lucide-react';
import React, { useState, useEffect, useRef } from "react";
import { MessageCircle, User, Send, Plus, LogOut, Menu, X, Bot } from "lucide-react";
const App = () => {
const [isLoggedIn, setIsLoggedIn] = useState(false);
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [currentUser, setCurrentUser] = useState(null);
const [conversations, setConversations] = useState([]);
const [activeConversation, setActiveConversation] = useState(null);
const [message, setMessage] = useState('');
const [message, setMessage] = useState("");
const [isMenuOpen, setIsMenuOpen] = useState(false);
const [loading, setLoading] = useState(false);
const messagesEndRef = useRef(null);
// API base URL
const API_BASE = 'http://localhost:5100/api';
const API_BASE = "http://localhost:5100/api";
// Auto scroll to bottom of messages
useEffect(() => {
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
}, [activeConversation?.messages]);
// Fetch user conversations
@@ -34,7 +34,7 @@ const App = () => {
}
}
} catch (error) {
console.error('Error fetching conversations:', error);
console.error("Error fetching conversations:", error);
}
};
@@ -47,7 +47,7 @@ const App = () => {
setActiveConversation(data);
}
} catch (error) {
console.error('Error loading conversation:', error);
console.error("Error loading conversation:", error);
}
};
@@ -58,9 +58,9 @@ const App = () => {
try {
const response = await fetch(`${API_BASE}/login`, {
method: 'POST',
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify({ username, password }),
});
@@ -72,11 +72,11 @@ const App = () => {
await fetchConversations(userData.id);
} else {
const errorData = await response.json();
alert(errorData.error || 'Login failed');
alert(errorData.error || "Login failed");
}
} catch (error) {
console.error('Login error:', error);
alert('Network error. Please try again.');
console.error("Login error:", error);
alert("Network error. Please try again.");
} finally {
setLoading(false);
}
@@ -86,8 +86,8 @@ const App = () => {
const handleLogout = () => {
setIsLoggedIn(false);
setCurrentUser(null);
setUsername('');
setPassword('');
setUsername("");
setPassword("");
setConversations([]);
setActiveConversation(null);
setIsMenuOpen(false);
@@ -95,16 +95,18 @@ const App = () => {
// Create new conversation
const createNewConversation = async () => {
if (!currentUser) return;
if (!currentUser) {
return;
}
setLoading(true);
try {
const response = await fetch(`${API_BASE}/users/${currentUser.id}/conversations`, {
method: 'POST',
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify({ title: 'New Conversation' }),
body: JSON.stringify({ title: "New Conversation" }),
});
if (response.ok) {
@@ -113,7 +115,7 @@ const App = () => {
await loadConversation(newConversation.id);
}
} catch (error) {
console.error('Error creating conversation:', error);
console.error("Error creating conversation:", error);
} finally {
setLoading(false);
setIsMenuOpen(false);
@@ -122,17 +124,19 @@ const App = () => {
// Send message
const sendMessage = async () => {
if (!message.trim() || !activeConversation) return;
if (!message.trim() || !activeConversation) {
return;
}
setLoading(true);
try {
// Send user message
const userMessageResponse = await fetch(`${API_BASE}/conversations/${activeConversation.id}/messages`, {
method: 'POST',
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify({ text: message, sender: 'user' }),
body: JSON.stringify({ text: message, sender: "user" }),
});
if (userMessageResponse.ok) {
@@ -142,16 +146,16 @@ const App = () => {
const updatedConversation = {
...activeConversation,
messages: [...activeConversation.messages, userMessage],
title: activeConversation.messages.length === 1 ? message.slice(0, 20) + (message.length > 20 ? '...' : '') : activeConversation.title
title: activeConversation.messages.length === 1 ? message.slice(0, 20) + (message.length > 20 ? "..." : "") : activeConversation.title
};
setActiveConversation(updatedConversation);
setMessage('');
setMessage("");
// Fetch updated conversation to get AI response
await loadConversation(activeConversation.id);
}
} catch (error) {
console.error('Error sending message:', error);
console.error("Error sending message:", error);
} finally {
setLoading(false);
}
@@ -159,9 +163,9 @@ const App = () => {
// Format timestamp
const formatTime = (timestamp) => {
return new Date(timestamp).toLocaleTimeString('en-US', {
hour: '2-digit',
minute: '2-digit'
return new Date(timestamp).toLocaleTimeString("en-US", {
hour: "2-digit",
minute: "2-digit"
});
};
@@ -206,7 +210,7 @@ const App = () => {
disabled={loading}
className="w-full bg-indigo-600 text-white py-3 rounded-lg font-medium hover:bg-indigo-700 transition-colors focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 disabled:opacity-50"
>
{loading ? 'Logging in...' : 'Login'}
{loading ? "Logging in..." : "Login"}
</button>
</form>
@@ -283,7 +287,7 @@ const App = () => {
setIsMenuOpen(false);
}}
className={`p-4 border-b border-gray-100 cursor-pointer hover:bg-gray-50 transition-colors ${
activeConversation?.id === conversation.id ? 'bg-indigo-50 border-l-4 border-l-indigo-500' : ''
activeConversation?.id === conversation.id ? "bg-indigo-50 border-l-4 border-l-indigo-500" : ""
}`}
>
<div className="flex items-start space-x-3">
@@ -291,7 +295,7 @@ const App = () => {
<div className="flex-1 min-w-0">
<h3 className="font-medium text-gray-900 truncate">{conversation.title}</h3>
<p className="text-sm text-gray-500 truncate">
{conversation.preview || 'New conversation'}
{conversation.preview || "New conversation"}
</p>
</div>
</div>
@@ -328,17 +332,17 @@ const App = () => {
{activeConversation.messages.map((msg) => (
<div
key={msg.id}
className={`flex ${msg.sender === 'user' ? 'justify-end' : 'justify-start'}`}
className={`flex ${msg.sender === "user" ? "justify-end" : "justify-start"}`}
>
<div
className={`max-w-xs lg:max-w-md px-4 py-3 rounded-2xl ${
msg.sender === 'user'
? 'bg-indigo-600 text-white rounded-br-md'
: 'bg-white text-gray-800 border border-gray-200 rounded-bl-md shadow-sm'
msg.sender === "user"
? "bg-indigo-600 text-white rounded-br-md"
: "bg-white text-gray-800 border border-gray-200 rounded-bl-md shadow-sm"
}`}
>
<p className="text-sm">{msg.text}</p>
<p className={`text-xs mt-1 ${msg.sender === 'user' ? 'text-indigo-100' : 'text-gray-500'}`}>
<p className={`text-xs mt-1 ${msg.sender === "user" ? "text-indigo-100" : "text-gray-500"}`}>
{formatTime(msg.created_at)}
</p>
</div>
@@ -354,7 +358,7 @@ const App = () => {
type="text"
value={message}
onChange={(e) => setMessage(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && !loading && sendMessage()}
onKeyPress={(e) => e.key === "Enter" && !loading && sendMessage()}
disabled={loading}
className="flex-1 px-4 py-3 border border-gray-300 rounded-full focus:ring-2 focus:ring-indigo-500 focus:border-transparent transition-all disabled:opacity-50"
placeholder="Type a message..."

View File

@@ -12,10 +12,14 @@ from langchain_core.runnables import RunnableConfig
from langgraph.graph import START, END
from langgraph.graph import StateGraph
from langgraph.types import Send
from agentscope_runtime.engine.agents.langgraph_agent import LangGraphAgent
from agentscope_runtime.engine.helpers.helper import simple_call_agent_direct
from configuration import Configuration
from state import (
OverallState,
QueryGenerationState,
ReflectionState,
WebSearchState,
)
from llm_utils import call_dashscope, extract_json_from_qwen
from custom_search_tool import CustomSearchTool
from llm_prompts import (
query_writer_instructions,
@@ -23,13 +27,12 @@ from llm_prompts import (
reflection_instructions,
answer_instructions,
)
from llm_utils import call_dashscope, extract_json_from_qwen
from state import (
OverallState,
QueryGenerationState,
ReflectionState,
WebSearchState,
)
from configuration import Configuration
from agentscope_runtime.engine.agents.langgraph_agent import LangGraphAgent
from agentscope_runtime.engine.helpers.helper import simple_call_agent_direct
from .utils import (
get_research_topic,
insert_citation_markers,