feat: 实现 AgentScope ReAct Runner 两阶段执行并重构事件处理

This commit is contained in:
zl-q
2026-03-16 09:01:01 +08:00
parent 072c09d99d
commit dcceb48d84
51 changed files with 5015 additions and 5663 deletions
+370
View File
@@ -0,0 +1,370 @@
# Agent SSE Events
本文档记录 Agent Runtime 产生的所有 Server-Sent Events (SSE) 事件,用于前端实时展示。
## 事件流转架构
```
pipeline.emit()
AgentScopeEventPipeline.emit()
├─→ store.persist() → 持久化到数据库
└─→ bus.publish() → 发布到 Redis Stream
前端通过 GET /runs/{thread_id}/events 读取
```
## 事件统一格式
所有事件在 Redis 中传输时都包含以下字段:
```typescript
{
type: string, // 事件类型
threadId: string, // 会话 ID
runId: string, // 运行 ID
data: object // 事件数据
}
```
---
## 1. Orchestrator 生命周期事件
### run.started
Agent 开始运行时触发。
```typescript
{
type: "run.started",
threadId: "xxx",
runId: "yyy",
data: {}
}
```
### run.finished
Agent 成功完成时触发。
```typescript
{
type: "run.finished",
threadId: "xxx",
runId: "yyy",
data: {}
}
```
### run.error
Agent 运行出错时触发。
```typescript
{
type: "run.error",
threadId: "xxx",
runId: "yyy",
data: {
message: "runtime execution failed"
}
}
```
---
## 2. Step 阶段事件
### step.start
阶段开始时触发。
```typescript
{
type: "step.start",
threadId: "xxx",
runId: "yyy",
data: {
stepName: "router" | "worker"
}
}
```
### step.finish
阶段结束时触发。
```typescript
{
type: "step.finish",
threadId: "xxx",
runId: "yyy",
data: {
stepName: "router" | "worker"
}
}
```
---
## 3. Worker 运行时事件
### 3.1 文本消息事件
#### text.start
文本消息开始时触发。
```typescript
{
type: "text.start",
threadId: "xxx",
runId: "yyy",
data: {
messageId: "msg-xxx",
role: "assistant",
stage: "worker"
}
}
```
#### text.delta
文本内容增量更新时触发。
```typescript
{
type: "text.delta",
threadId: "xxx",
runId: "yyy",
data: {
messageId: "msg-xxx",
delta: "这是新增的文本内容",
stage: "worker"
}
}
```
#### text.end
文本消息结束时触发,包含完整输出和使用统计。
```typescript
{
type: "text.end",
threadId: "xxx",
runId: "yyy",
data: {
messageId: "msg-xxx",
role: "assistant",
stage: "worker",
workerAgentOutput: {
status: "success" | "partial_success" | "failed",
answer: "主回复文本",
key_points: ["要点1", "要点2"],
result_type: "execution_report" | "clarification" | "error_report" | "unknown",
suggested_actions: ["建议操作1"],
error: null | { code: string, message: string },
ui_hints: { ... } | null // 仅在 ui_mode 非空时存在
},
model: "gpt-4o",
inputTokens: 1000,
outputTokens: 500,
cost: 0.025,
latencyMs: 1500
}
}
```
**workerAgentOutput 详细结构:**
```typescript
// WorkerAgentOutputLite
{
status: "success" | "partial_success" | "failed",
answer: string,
key_points: string[],
result_type: "execution_report" | "clarification" | "error_report" | "unknown",
suggested_actions: string[],
error: { code: string, message: string } | null
}
// WorkerAgentOutputRich (当 ui.ui_mode 非空时)
{
// ... WorkerAgentOutputLite 字段
ui_hints: {
ui_mode: string,
ui_state: object,
actions: UiHintAction[]
}
}
```
---
### 3.2 工具调用事件
#### tool.start
工具调用开始时触发。
```typescript
{
type: "tool.start",
threadId: "xxx",
runId: "yyy",
data: {
messageId: "msg-xxx",
toolCallId: "call-abc",
toolName: "calendar_read",
stage: "worker"
}
}
```
#### tool.args
工具调用参数时触发。
```typescript
{
type: "tool.args",
threadId: "xxx",
runId: "yyy",
data: {
messageId: "msg-xxx",
toolCallId: "call-abc",
toolName: "calendar_read",
args: { start_date: "2024-01-01", end_date: "2024-01-07" },
stage: "worker"
}
}
```
#### tool.end
工具调用结束时触发。
```typescript
{
type: "tool.end",
threadId: "xxx",
runId: "yyy",
data: {
messageId: "msg-xxx",
toolCallId: "call-abc",
toolName: "calendar_read",
stage: "worker"
}
}
```
#### tool.result
工具执行结果时触发。
```typescript
{
type: "tool.result",
threadId: "xxx",
runId: "yyy",
data: {
messageId: "msg-xxx",
toolCallId: "call-abc",
toolName: "calendar_read",
stage: "worker",
toolAgentOutput: {
tool_name: "calendar_read",
tool_call_id: "call-abc",
tool_call_args: { start_date: "2024-01-01", end_date: "2024-01-07" },
status: "success" | "failed",
result_summary: "找到3个事件...",
ui_hints: null,
attachments: null
}
}
}
```
**toolAgentOutput 详细结构:**
```typescript
{
tool_name: string,
tool_call_id: string,
tool_call_args: object | null,
status: "success" | "failed",
result_summary: string,
ui_hints: object | null,
attachments: Array<{
bucket: string,
path: string,
mime_type: string,
url: string
}> | null
}
```
---
## 使用统计字段
`text.end` 事件中包含使用统计:
| 字段 | 类型 | 说明 |
|------|------|------|
| `model` | string | 使用的模型名称 |
| `inputTokens` | number | 输入 token 数量 |
| `outputTokens` | number | 输出 token 数量 |
| `cost` | number | 花费(美元) |
| `latencyMs` | number | 延迟(毫秒) |
---
## 前端接收示例
```javascript
const eventSource = new EventSource(`/runs/${threadId}/events`);
eventSource.addEventListener('run.started', (e) => {
console.log('Agent started:', JSON.parse(e.data));
});
eventSource.addEventListener('step.start', (e) => {
console.log('Step started:', JSON.parse(e.data));
});
eventSource.addEventListener('text.delta', (e) => {
const data = JSON.parse(e.data);
console.log('Text delta:', data.data.delta);
});
eventSource.addEventListener('tool.start', (e) => {
const data = JSON.parse(e.data);
console.log('Tool called:', data.data.toolName);
});
eventSource.addEventListener('tool.result', (e) => {
const data = JSON.parse(e.data);
console.log('Tool result:', data.data.toolAgentOutput);
});
eventSource.addEventListener('text.end', (e) => {
const data = JSON.parse(e.data);
console.log('Worker output:', data.data.workerAgentOutput);
console.log('Usage:', {
inputTokens: data.data.inputTokens,
outputTokens: data.data.outputTokens,
cost: data.data.cost
});
});
eventSource.addEventListener('run.finished', (e) => {
console.log('Agent finished:', JSON.parse(e.data));
});
eventSource.addEventListener('run.error', (e) => {
console.log('Agent error:', JSON.parse(e.data));
});
```