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,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..."