Files
qiming/qiming-rcoder/docs/sse-event-structure.md
2026-06-01 13:54:52 +08:00

304 lines
8.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SSE 进度事件结构文档
## 📖 概览
本文档说明如何在 OpenAPI Swagger 文档中查看和理解 SSE (Server-Sent Events) 进度流的事件结构。
## 🔍 在 OpenAPI 文档中查看
### 1. 访问 Swagger UI
启动服务后访问:
```
http://localhost:8087/api/docs
```
### 2. 查看 SSE 接口
在 Swagger UI 中找到以下接口:
- **Agent 进度流**: `GET /agent/progress/{session_id}`
- **Computer Agent 进度流**: `GET /computer/agent/progress/{session_id}`
### 3. 查看事件结构
在接口文档的 "Responses" 部分:
1. 点击 **200 响应** 展开详情
2.**description** 中查看:
- 📡 SSE 事件格式说明
- 🔄 各种事件类型示例
- 💡 JavaScript 使用示例
3.**Schemas** 部分查找 `ProgressEventDoc` 获取完整的字段定义
## 📊 事件结构说明
### ProgressEventDoc
通过 SSE 流推送的核心事件结构:
```typescript
interface ProgressEventDoc {
// 消息主类型
message_type: "SessionPromptStart" | "SessionPromptEnd" | "AgentSessionUpdate" | "Heartbeat";
// 消息子类型(作为 SSE 的 event 字段)
sub_type: string; // agent_message_chunk, tool_call, end_turn 等
// ACP 消息的完整 JSON 载荷(作为 SSE 的 data 字段)
payload: object;
// 可选的请求 ID
request_id?: string;
// 时间戳Unix 毫秒)
timestamp: number;
}
```
### 常见子类型 (sub_type)
| sub_type | 说明 | payload 示例 |
|----------|------|-------------|
| `agent_message_chunk` | AI 响应文本片段 | `{"content":{"type":"text","text":"Hello"},"index":0}` |
| `agent_thought_chunk` | AI 思考过程片段 | `{"thinking":"正在分析...","is_complete":false}` |
| `tool_call` | 工具调用事件 | `{"tool_name":"read_file","tool_input":{"path":"test.rs"},"status":"started"}` |
| `tool_result` | 工具执行结果 | `{"tool_name":"read_file","tool_output":"...","status":"success"}` |
| `plan` | 执行计划 | `{"steps":[...],"current_step":1}` |
| `end_turn` | 对话轮次结束 | `{"reason":"complete","final_message":"Done"}` |
| `cancelled` | 任务被取消 | `{"reason":"user_request"}` |
| `error` | 错误事件 | `{"code":"EXECUTION_ERROR","message":"..."}` |
## 📡 SSE 原始格式
实际通过网络传输的 SSE 消息格式:
```
event: agent_message_chunk
data: {"content":{"type":"text","text":"正在分析您的请求..."},"index":0}
event: tool_call
data: {"tool_name":"read_file","tool_input":{"path":"src/main.rs"},"status":"started"}
event: tool_result
data: {"tool_name":"read_file","tool_output":"fn main() {...}","status":"success"}
event: end_turn
data: {"reason":"complete","final_message":"任务已完成"}
```
## 💻 客户端使用示例
### JavaScript / TypeScript
```typescript
// 1. 建立 SSE 连接
const eventSource = new EventSource('/agent/progress/session_123');
// 2. 监听特定事件类型
eventSource.addEventListener('agent_message_chunk', (event) => {
const data = JSON.parse(event.data);
console.log('AI 响应:', data.content.text);
// 更新 UI 显示 AI 响应
});
eventSource.addEventListener('tool_call', (event) => {
const data = JSON.parse(event.data);
console.log(`工具调用: ${data.tool_name}`, data.tool_input);
// 显示工具调用状态
});
eventSource.addEventListener('tool_result', (event) => {
const data = JSON.parse(event.data);
console.log(`工具结果: ${data.tool_name}`, data.tool_output);
// 显示工具执行结果
});
eventSource.addEventListener('end_turn', (event) => {
const data = JSON.parse(event.data);
console.log('任务完成:', data.final_message);
eventSource.close(); // 关闭连接
});
// 3. 错误处理
eventSource.onerror = (error) => {
console.error('连接错误:', error);
eventSource.close();
};
// 4. 监听所有消息(可选)
eventSource.onmessage = (event) => {
console.log('收到消息:', event.data);
};
```
### Python
```python
import sseclient
import requests
import json
# 1. 建立 SSE 连接
response = requests.get(
'http://localhost:8087/agent/progress/session_123',
stream=True,
headers={'Accept': 'text/event-stream'}
)
client = sseclient.SSEClient(response)
# 2. 处理事件
for event in client.events():
if event.event == 'agent_message_chunk':
data = json.loads(event.data)
print(f"AI 响应: {data['content']['text']}")
elif event.event == 'tool_call':
data = json.loads(event.data)
print(f"工具调用: {data['tool_name']}")
elif event.event == 'end_turn':
data = json.loads(event.data)
print(f"任务完成: {data['final_message']}")
break
```
### Rust
```rust
use eventsource_stream::Eventsource;
use futures_util::StreamExt;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = reqwest::Client::new();
let mut stream = client
.get("http://localhost:8087/agent/progress/session_123")
.send()
.await?
.bytes_stream()
.eventsource();
while let Some(event) = stream.next().await {
match event {
Ok(event) => {
match event.event.as_str() {
"agent_message_chunk" => {
let data: serde_json::Value = serde_json::from_str(&event.data)?;
println!("AI 响应: {}", data["content"]["text"]);
}
"tool_call" => {
let data: serde_json::Value = serde_json::from_str(&event.data)?;
println!("工具调用: {}", data["tool_name"]);
}
"end_turn" => {
println!("任务完成");
break;
}
_ => {}
}
}
Err(e) => {
eprintln!("错误: {}", e);
break;
}
}
}
Ok(())
}
```
## 🎯 完整工作流程
```
1. 发起对话
POST /chat
返回 { session_id: "session_123" }
2. 建立 SSE 连接
GET /agent/progress/session_123
EventSource 连接建立
3. 接收进度事件
event: agent_message_chunk
data: {...}
event: tool_call
data: {...}
event: tool_result
data: {...}
event: end_turn
data: {...}
4. 关闭连接
eventSource.close()
```
## 🔧 在 Swagger UI 中测试
虽然 Swagger UI 本身不支持直接测试 SSE 流,但你可以:
1. 使用浏览器开发者工具的 Network 标签
2. 使用 `curl` 命令:
```bash
curl -N http://localhost:8087/agent/progress/session_123
```
3. 使用专门的 SSE 测试工具
## 📚 相关文档
- [OpenAPI 规范](http://localhost:8087/api/docs)
- [ACP (Agent Client Protocol) 协议文档](../specs/)
- [gRPC 架构文档](./grpc-architecture.md)
## ❓ FAQ
### Q: 为什么在 OpenAPI 中看不到具体的 data 字段?
A: 因为 SSE 是流式响应OpenAPI 无法像普通 JSON 响应那样定义结构。我们通过以下方式提供文档:
1. **ProgressEventDoc** schema定义了事件的完整结构
2. **接口 description**:提供详细的事件格式说明和示例
3. **本文档**:提供完整的使用指南
### Q: 如何知道有哪些可能的 sub_type
A: 查看:
1. Swagger UI 中的接口描述部分
2. `ProgressEventDoc` schema 的 `sub_type` 字段注释
3. 本文档的"常见子类型"表格
### Q: payload 的具体结构在哪里定义?
A: `payload` 是透传的 ACP (Agent Client Protocol) 消息,具体结构取决于 `sub_type`。每种 `sub_type` 的 payload 结构在接口文档的示例中都有说明。
### Q: 如何处理错误?
A: SSE 流可能会发送 `error` 事件,同时监听 `EventSource.onerror` 来处理连接错误:
```javascript
eventSource.addEventListener('error', (event) => {
const data = JSON.parse(event.data);
console.error('业务错误:', data.code, data.message);
});
eventSource.onerror = (error) => {
console.error('连接错误:', error);
};
```
## 📝 总结
- ✅ **在 Swagger UI 中查看**: `ProgressEventDoc` schema 和接口描述
- ✅ **事件格式**: SSE 标准格式event = sub_type, data = payload
- ✅ **客户端支持**: JavaScript, Python, Rust 等都有成熟的 SSE 客户端库
- ✅ **类型安全**: 可以根据 `ProgressEventDoc` 定义生成 TypeScript 类型