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]);