Agent 接入案例:React
useAgent 适合多轮 Agent 对话、工具调用和状态管理场景。Agent 的 assistant 消息使用 message.parts 表示时序内容。
tsx
import { useEffect, useState } from 'react';
import { useAgent } from '@tencent/ssv-ai-sdk-react';
import { AGUIPlugin } from '@tencent/ssv-ai-sdk-plugin-agui';
const UI_ONLY_TOOLS = ['launchRocket'];
export function AgentChat() {
const [input, setInput] = useState('');
const [themeColor, setThemeColor] = useState('#1890ff');
const {
messages,
status,
assistantStatus,
agentState,
send,
stop,
setMessages,
setTools,
on,
off,
} = useAgent({
api: {
chatEndpoint: {
url: 'https://your-api.com/agent',
},
},
mode: 'stream',
plugins: [new AGUIPlugin()],
});
useEffect(() => {
setTools([
{
name: 'setThemeColor',
description: 'Set the page theme color. Use hex format like #1890ff.',
type: 'frontend',
parameters: {
type: 'object',
properties: {
color: { type: 'string', description: 'Hex color' },
},
required: ['color'],
},
handler: async ({ color }) => {
setThemeColor(color);
return { success: true, color };
},
},
]);
}, [setTools]);
useEffect(() => {
const handleToolExecuted = ({ toolCallId, toolCallName, result }) => {
if (UI_ONLY_TOOLS.includes(toolCallName)) return;
const toolMessage = {
id: `tool-${Date.now()}`,
role: 'tool',
content: typeof result === 'string' ? result : JSON.stringify(result),
toolCallId,
extraInfo: {},
};
setMessages([...messages, toolMessage]);
send({}, { type: 'tools' });
};
on('toolExecuted', handleToolExecuted);
return () => off('toolExecuted', handleToolExecuted);
}, [messages, on, off, send, setMessages]);
const handleSend = async () => {
if (!input.trim() || status === 'loading') return;
await send({ input });
setInput('');
};
return (
<div style={{ '--theme-color': themeColor }}>
<div className="messages">
{messages.map((message) => (
<div key={message.id} className={`message ${message.role}`}>
{message.role === 'user' && <div>{message.content}</div>}
{message.role === 'assistant' && message.parts?.map((part, index) => {
if (part.type === 'reasoning') {
return <div key={index} className="reasoning">{part.reason}</div>;
}
if (part.type === 'text') {
return <div key={index}>{part.text}</div>;
}
if (part.type === 'tool_call') {
return (
<div key={part.id} className="tool-call">
工具:{part.name},状态:{part.status}
{part.result && <pre>{JSON.stringify(part.result, null, 2)}</pre>}
{part.error && <div className="error">{part.error}</div>}
</div>
);
}
return null;
})}
</div>
))}
</div>
<div>助手状态:{assistantStatus}</div>
<div>Agent 状态:{JSON.stringify(agentState)}</div>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && handleSend()}
placeholder="输入消息..."
/>
{status === 'loading' ? (
<button onClick={stop}>停止</button>
) : (
<button onClick={handleSend}>发送</button>
)}
</div>
);
}
工具结果回传规则
Frontend 工具执行完成后会触发 toolExecuted。业务侧需要:
- 构造
role: 'tool'的消息 - 调用
setMessages([...messages, toolMessage]) - 调用
send({}, { type: 'tools' })继续 Agent Run
Backend 工具的结果由后端返回,不触发 toolExecuted,前端只负责渲染 part.result。
@ssv-lab