Files
tmp/harness-chat.md
T
V-LiuShuang eee6640952 add
2026-09-18 10:23:50 +08:00

993 lines
30 KiB
Markdown
Raw 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.
# Harness Chat 接口文档
`POST /harness/chat`
## 1. 接口说明
- 路径:`/harness/chat`
- 方法:`POST`
- 内容类型:`application/json`
- 返回类型:`Flux<AgentEvent>`(**流式响应**,支持 SSE 与 JSON 数组两种方式)
- 功能:向智能体发送一条用户输入,返回一段**细粒度智能体事件流**。调用方按事件类型逐条解析即可渲染「思考中 / 正在调用工具 / 流式输出答案 / 需要人工确认」等 UI 状态。
> 源码位置:`mis-common/mis-common-harness/java/com/lcfc/harness/chat/HarnessChatGateway.java#L18-L23`
>
> ```java
> @PostMapping("/chat")
> public Flux<AgentEvent> chat(@RequestBody AgentChatRequest request) {
> ChatUiChannel channel = HarnessAgent.builder().build().channel(ChatUiChannel.create());
> SendOptions sendOptions = SendOptions.of(request.getUserId(), request.getSessionId());
> return channel.sendStream(sendOptions, request.getInput());
> }
> ```
## 2. 请求
### 2.1 请求头
| Header | 值 | 说明 |
| --- | --- | --- |
| `Content-Type` | `application/json` | 必填 |
| `Accept` | `text/event-stream``application/json` | 决定响应格式(见 §3 |
### 2.2 请求体(`AgentChatRequest`
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `sessionId` | String | ✅ | 会话 ID;同一用户不同会话相互隔离 |
| `userId` | String | ✅ | 用户 ID;用于智能体命名空间隔离 / 会话路由 |
| `input` | String | ✅ | 用户输入内容 |
| `chatModel` | Object | ❌ | 聊天模型配置(`name``stream``temperature` |
`chatModel` 结构:
| 字段 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `name` | String | - | 模型名称,如 `gpt-oss-120b` |
| `stream` | Boolean | `true` | 是否流式 |
| `temperature` | Double | `0.2` | 温度 |
### 2.3 请求示例
```json
POST /harness/chat
Host: localhost:8080
Content-Type: application/json
Accept: text/event-stream
{
"sessionId": "sess-20260918-001",
"userId": "user-10001",
"input": "帮我梳理今天的任务清单,生成一份 markdown 并保存到工作区",
"chatModel": {
"name": "gpt-oss-120b",
"stream": true,
"temperature": 0.2
}
}
```
> ⚠️ 注意:当前实现中 `chatModel` 并未被使用(`HarnessAgent.builder().build()` 未传入模型配置)。如需按请求指定模型,需要扩展 `HarnessChatGateway`。
## 3. 响应
### 3.1 格式一:SSE(推荐,`Accept: text/event-stream`
每发生一个事件,服务端推送一条 `data:`,事件之间以空行分隔:
```
data:{"type":"AGENT_START","id":"4f9c1e2d8a7b4c5d9e0f1a2b3c4d5e6f","createdAt":"2026-09-18T02:30:45.123456Z","sessionId":"sess-20260918-001","replyId":"reply-7f3a91","name":"assistant","role":"assistant"}
data:{"type":"THINKING_BLOCK_START","id":"...","createdAt":"...","replyId":"reply-7f3a91","blockId":"blk-001"}
data:{"type":"TEXT_BLOCK_DELTA","id":"...","createdAt":"...","replyId":"reply-7f3a91","blockId":"blk-002","delta":"已完成"}
```
### 3.2 格式二:JSON 数组(默认 / `Accept: application/json`
整个事件流序列化为一个 JSON 数组,随事件产生逐个写出:
```json
[
{ "type": "AGENT_START", "...": "..." },
{ "type": "THINKING_BLOCK_START", "...": "..." },
{ "type": "TEXT_BLOCK_DELTA", "...": "..." }
]
```
### 3.3 HTTP 状态
| 状态码 | 说明 |
| --- | --- |
| `200` | 正常,返回事件流 |
| `400` | 校验失败(`sessionId` / `userId` / `input` 为空时抛 `400 Bad Request` |
| `500` | 智能体执行异常(模型未配置、会话中断等) |
## 4. 事件通用结构
所有事件(`AgentEvent`)都包含以下通用字段,通过 `type` 字段区分具体事件类型:
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `type` | String | **类型判别器**,取值见 §5 |
| `id` | String | 事件唯一 ID(32 位十六进制,无连字符 UUID) |
| `createdAt` | String | 事件创建时间,ISO-8601 格式(如 `2026-09-18T02:30:45.123456Z` |
| `source` | String | 事件来源路径。顶层智能体事件为 `null`;子智能体转发的事件为 `main/researcher` 形式。**无值时缺省(不输出)** |
| `metadata` | Object | 附加元数据,**空时不输出** |
`type` / `id` / `createdAt` 必现;其余字段视事件类型而定。以下各事件示例均基于同一会话回环 `"replyId":"reply-7f3a91"`
## 5. AgentEvent 类型详解与数据示例
### 5.1 AGENT_START — 智能体开始处理
表示一次智能体调用开始。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `sessionId` | String | 会话 ID |
| `replyId` | String | 本轮回复 ID,用于关联同一轮事件 |
| `name` | String | 智能体名称 |
| `role` | String | 默认 `"assistant"` |
```json
{
"type": "AGENT_START",
"id": "4f9c1e2d8a7b4c5d9e0f1a2b3c4d5e6f",
"createdAt": "2026-09-18T02:30:45.123456Z",
"sessionId": "sess-20260918-001",
"replyId": "reply-7f3a91",
"name": "assistant",
"role": "assistant"
}
```
### 5.2 THINKING_BLOCK_START — 思考块开始
模型开始推理(ReAct 的 reasoning 阶段)。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `replyId` | String | 回复 ID |
| `blockId` | String | 思考块 ID |
```json
{
"type": "THINKING_BLOCK_START",
"id": "1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
"createdAt": "2026-09-18T02:30:45.200000Z",
"replyId": "reply-7f3a91",
"blockId": "blk-001"
}
```
### 5.3 THINKING_BLOCK_DELTA — 思考内容增量
逐段推送思考内容。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `replyId` | String | 回复 ID |
| `blockId` | String | 思考块 ID |
| `delta` | String | 增量文本 |
```json
{
"type": "THINKING_BLOCK_DELTA",
"id": "2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e",
"createdAt": "2026-09-18T02:30:45.210000Z",
"replyId": "reply-7f3a91",
"blockId": "blk-001",
"delta": "用户希望将任务清单整理成 markdown 文件并保存,需要先规划目录结构。"
}
```
### 5.4 THINKING_BLOCK_END — 思考块结束
```json
{
"type": "THINKING_BLOCK_END",
"id": "3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f",
"createdAt": "2026-09-18T02:30:45.350000Z",
"replyId": "reply-7f3a91",
"blockId": "blk-001"
}
```
### 5.5 MODEL_CALL_START — 模型调用开始
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `replyId` | String | 回复 ID |
```json
{
"type": "MODEL_CALL_START",
"id": "4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f90",
"createdAt": "2026-09-18T02:30:45.180000Z",
"replyId": "reply-7f3a91"
}
```
### 5.6 MODEL_CALL_END — 模型调用结束(含 token 用量)
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `replyId` | String | 回复 ID |
| `usage` | Object | token 用量统计 |
`usage` 结构:
```json
{
"type": "MODEL_CALL_END",
"id": "5e6f7a8b9c0d1e2f3a4b5c6d7e8f9001",
"createdAt": "2026-09-18T02:30:45.680000Z",
"replyId": "reply-7f3a91",
"usage": {
"inputTokens": 1250,
"outputTokens": 320,
"cachedTokens": 512,
"time": 0.482,
"totalTokens": 1570
}
}
```
| usage 字段 | 类型 | 说明 |
| --- | --- | --- |
| `inputTokens` | Integer | 输入 token 数(含缓存部分) |
| `outputTokens` | Integer | 输出 token 数 |
| `cachedTokens` | Integer | 命中 prompt 缓存的输入 token 数(来自 inputTokens 的子集) |
| `time` | Number | 本次调用耗时(秒) |
| `totalTokens` | Integer | `inputTokens + outputTokens`(派生字段) |
### 5.7 TOOL_CALL_START — 工具调用开始
模型决定调用某个工具(ReAct 的 acting 阶段)。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `replyId` | String | 回复 ID |
| `toolCallId` | String | 工具调用 ID |
| `toolCallName` | String | 工具名 |
```json
{
"type": "TOOL_CALL_START",
"id": "6f7a8b9c0d1e2f3a4b5c6d7e8f900112",
"createdAt": "2026-09-18T02:30:45.700000Z",
"replyId": "reply-7f3a91",
"toolCallId": "call_9f2c4d",
"toolCallName": "shell_execute"
}
```
### 5.8 TOOL_CALL_DELTA — 工具入参流式增量
工具参数以 JSON 字符串形式分片送达。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `replyId` | String | 回复 ID |
| `toolCallId` | String | 工具调用 ID |
| `toolCallName` | String | 工具名 |
| `delta` | String | 入参 JSON 片段 |
```json
{
"type": "TOOL_CALL_DELTA",
"id": "7a8b9c0d1e2f3a4b5c6d7e8f90011223",
"createdAt": "2026-09-18T02:30:45.720000Z",
"replyId": "reply-7f3a91",
"toolCallId": "call_9f2c4d",
"toolCallName": "shell_execute",
"delta": "{\"command\":\"cat /tasks.json > "
}
```
```json
{
"type": "TOOL_CALL_DELTA",
"id": "8b9c0d1e2f3a4b5c6d7e8f9001122334",
"createdAt": "2026-09-18T02:30:45.730000Z",
"replyId": "reply-7f3a91",
"toolCallId": "call_9f2c4d",
"toolCallName": "shell_execute",
"delta": "\\\"/workspace/tasks.md\"}"
}
```
### 5.9 TOOL_CALL_END — 工具调用结束
```json
{
"type": "TOOL_CALL_END",
"id": "9c0d1e2f3a4b5c6d7e8f900112233445",
"createdAt": "2026-09-18T02:30:45.740000Z",
"replyId": "reply-7f3a91",
"toolCallId": "call_9f2c4d",
"toolCallName": "shell_execute"
}
```
### 5.10 TOOL_RESULT_START — 工具执行结果开始
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `replyId` | String | 回复 ID |
| `toolCallId` | String | 工具调用 ID |
| `toolCallName` | String | 工具名 |
| `metadata` | Object | 可选,如携带 `taskId` 等转发元数据(缺省) |
```json
{
"type": "TOOL_RESULT_START",
"id": "0d1e2f3a4b5c6d7e8f90011223344556",
"createdAt": "2026-09-18T02:30:46.050000Z",
"replyId": "reply-7f3a91",
"toolCallId": "call_9f2c4d",
"toolCallName": "shell_execute"
}
```
### 5.11 TOOL_RESULT_TEXT_DELTA — 工具结果文本增量
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `replyId` | String | 回复 ID |
| `toolCallId` | String | 工具调用 ID |
| `toolCallName` | String | 工具名 |
| `delta` | String | 结果文本片段 |
```json
{
"type": "TOOL_RESULT_TEXT_DELTA",
"id": "1e2f3a4b5c6d7e8f9001122334455667",
"createdAt": "2026-09-18T02:30:46.060000Z",
"replyId": "reply-7f3a91",
"toolCallId": "call_9f2c4d",
"toolCallName": "shell_execute",
"delta": "exit_code=0\n"
}
```
```json
{
"type": "TOOL_RESULT_TEXT_DELTA",
"id": "2f3a4b5c6d7e8f9001122334455667788",
"createdAt": "2026-09-18T02:30:46.070000Z",
"replyId": "reply-7f3a91",
"toolCallId": "call_9f2c4d",
"toolCallName": "shell_execute",
"delta": "任务清单已保存到 /workspace/tasks.md"
}
```
### 5.12 TOOL_RESULT_DATA_DELTA — 工具结果二进制数据增量
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `replyId` | String | 回复 ID |
| `toolCallId` | String | 工具调用 ID |
| `toolCallName` | String | 工具名 |
| `data` | Object | 一个多态 ContentBlock`type` 判别器),常见为 `data` 类型携带 base64 数据 |
`data``type` 取值:`text` / `thinking` / `image` / `audio` / `video` / `tool_use` / `tool_result` / `hint` / `data`
```json
{
"type": "TOOL_RESULT_DATA_DELTA",
"id": "3a4b5c6d7e8f900112233445566778899",
"createdAt": "2026-09-18T02:30:46.080000Z",
"replyId": "reply-7f3a91",
"toolCallId": "call_9f2c4d",
"toolCallName": "render_chart",
"data": {
"type": "data",
"source": {
"type": "base64",
"media_type": "image/png",
"data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=="
},
"id": "d4a3b2c1d5e6f7a8b9c0d1e2f3a4b5c6",
"name": "chart.png"
}
}
```
> URL 型数据源示例:`"source": { "type": "url", "url": "https://cdn.example.com/tmp/chart.png", "mime_type": "image/png" }`
### 5.13 TOOL_RESULT_END — 工具结果结束(含执行状态)
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `replyId` | String | 回复 ID |
| `toolCallId` | String | 工具调用 ID |
| `toolCallName` | String | 工具名 |
| `state` | String | 执行结果:`success` / `error` / `interrupted` / `denied` / `running` |
```json
{
"type": "TOOL_RESULT_END",
"id": "4b5c6d7e8f90011223344556677889900",
"createdAt": "2026-09-18T02:30:46.150000Z",
"replyId": "reply-7f3a91",
"toolCallId": "call_9f2c4d",
"toolCallName": "shell_execute",
"state": "success"
}
```
**失败示例(state = error):**
```json
{
"type": "TOOL_RESULT_END",
"id": "5c6d7e8f9001122334455667788990011",
"createdAt": "2026-09-18T02:30:47.200000Z",
"replyId": "reply-7f3a91",
"toolCallId": "call_9f2c4d",
"toolCallName": "shell_execute",
"state": "error"
}
```
### 5.14 DATA_BLOCK_START — 二进制数据块开始
用于向用户直接推送二进制内容(图片 / 音频 / 视频 / 文件),通常出现在最终答案阶段。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `replyId` | String | 回复 ID |
| `blockId` | String | 数据块 ID |
```json
{
"type": "DATA_BLOCK_START",
"id": "6d7e8f900112233445566778899001122",
"createdAt": "2026-09-18T02:30:48.000000Z",
"replyId": "reply-7f3a91",
"blockId": "blk-003"
}
```
### 5.15 DATA_BLOCK_DELTA — 二进制数据块增量
`delta` 为二进制内容的 **base64** 分片。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `replyId` | String | 回复 ID |
| `blockId` | String | 数据块 ID |
| `delta` | String | base64 数据分片 |
```json
{
"type": "DATA_BLOCK_DELTA",
"id": "7e8f90011223344556677889900112233",
"createdAt": "2026-09-18T02:30:48.010000Z",
"replyId": "reply-7f3a91",
"blockId": "blk-003",
"delta": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=="
}
```
### 5.16 DATA_BLOCK_END — 二进制数据块结束
```json
{
"type": "DATA_BLOCK_END",
"id": "8f9001122334455667788990011223344",
"createdAt": "2026-09-18T02:30:48.100000Z",
"replyId": "reply-7f3a91",
"blockId": "blk-003"
}
```
### 5.17 TEXT_BLOCK_START — 文本块开始
```json
{
"type": "TEXT_BLOCK_START",
"id": "900112233445566778899001122334455",
"createdAt": "2026-09-18T02:30:47.500000Z",
"replyId": "reply-7f3a91",
"blockId": "blk-002"
}
```
### 5.18 TEXT_BLOCK_DELTA — 文本块流式增量(最终答案)
前端据此逐字渲染智能体回复。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `replyId` | String | 回复 ID |
| `blockId` | String | 文本块 ID |
| `delta` | String | 文本增量 |
```json
{
"type": "TEXT_BLOCK_DELTA",
"id": "a011223344556677889900112233445566",
"createdAt": "2026-09-18T02:30:47.510000Z",
"replyId": "reply-7f3a91",
"blockId": "blk-002",
"delta": "已完成,"
}
```
```json
{
"type": "TEXT_BLOCK_DELTA",
"id": "b112233445566778899001122334455667",
"createdAt": "2026-09-18T02:30:47.520000Z",
"replyId": "reply-7f3a91",
"blockId": "blk-002",
"delta": "任务清单已保存至 /workspace/tasks.md"
}
```
### 5.19 TEXT_BLOCK_END — 文本块结束
```json
{
"type": "TEXT_BLOCK_END",
"id": "c223344556677889900112233445566778",
"createdAt": "2026-09-18T02:30:47.600000Z",
"replyId": "reply-7f3a91",
"blockId": "blk-002"
}
```
### 5.20 AGENT_RESULT — 智能体最终结果(含完整 Msg)
`AGENT_END` 之前发出,携带本轮最终回复消息 `Msg`。调用方可以从事件流直接取结果,无需另外订阅返回值。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `result` | Object | 最终消息体(多态,`role` 为判别器:`USER` / `ASSISTANT` / `SYSTEM` / `TOOL` |
`result`Msg)字段:
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `id` | String | 消息 IDUUID |
| `name` | String | 消息发送方名称,可为 `null` |
| `role` | String | 角色:`USER` / `ASSISTANT` / `SYSTEM` / `TOOL` |
| `content` | Array | 内容块数组(多态,`type` 判别器) |
| `metadata` | Object | 元数据,如 `agentscope_generate_reason` |
| `timestamp` | String | 消息时间戳,格式 `yyyy-MM-dd HH:mm:ss.SSS` |
| `usage` | Object | token 用量(同 §5.6),可为 `null` |
```json
{
"type": "AGENT_RESULT",
"id": "d33445566778899001122334455667788",
"createdAt": "2026-09-18T02:30:48.200000Z",
"result": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "assistant",
"role": "ASSISTANT",
"content": [
{
"type": "text",
"text": "已完成,任务清单已保存至 /workspace/tasks.md"
}
],
"metadata": {
"agentscope_generate_reason": "MODEL_STOP"
},
"timestamp": "2026-09-18 10:30:48.200",
"usage": {
"inputTokens": 1250,
"outputTokens": 320,
"cachedTokens": 512,
"time": 2.46,
"totalTokens": 1570
}
}
}
```
> 多模态回复的 `content` 举例(图片 + 文本混排):
> ```json
> "content": [
> { "type": "text", "text": "这是生成的图表:" },
> { "type": "data", "source": { "type": "url", "url": "https://cdn.example.com/chart.png", "mime_type": "image/png" }, "id": "d4a3b2c1d5e6f7a8b9c0d1e2f3a4b5c6", "name": "chart.png" }
> ]
> ```
### 5.21 AGENT_END — 智能体结束处理
```json
{
"type": "AGENT_END",
"id": "e455667788990011223344556677889900",
"createdAt": "2026-09-18T02:30:48.300000Z",
"replyId": "reply-7f3a91"
}
```
### 5.22 EXCEED_MAX_ITERS — ReAct 循环超过最大迭代次数
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `replyId` | String | 回复 ID |
| `maxIters` | Integer | 配置的最大迭代次数 |
| `currentIter` | Integer | 实际到达的迭代次数 |
```json
{
"type": "EXCEED_MAX_ITERS",
"id": "f566778899001122334455667788990011",
"createdAt": "2026-09-18T02:30:52.000000Z",
"replyId": "reply-7f3a91",
"maxIters": 10,
"currentIter": 10
}
```
### 5.23 REQUIRE_USER_CONFIRM — 需要用户确认工具调用(HITL 暂停)
智能体在执行敏感工具前暂停,等待用户逐条确认(前端应弹出授权窗口)。工具调用状态为 `asking`
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `replyId` | String | 回复 ID |
| `toolCalls` | Array | 待确认的 `ToolUseBlock` 列表 |
`ToolUseBlock` 字段:`id``name``input`Map)、`content`(流式原始内容,可空)、`metadata``state``pending` / `asking` / `allowed` / `submitted` / `finished`)。
```json
{
"type": "REQUIRE_USER_CONFIRM",
"id": "6778899001122334455667788990011223",
"createdAt": "2026-09-18T02:30:45.750000Z",
"replyId": "reply-7f3a91",
"toolCalls": [
{
"id": "call_9f2c4d",
"name": "shell_execute",
"input": {
"command": "rm -rf /workspace/old/"
},
"content": null,
"metadata": {},
"state": "asking"
},
{
"id": "call_5a1b02",
"name": "http_post",
"input": {
"url": "https://api.example.com/orders",
"body": "{\"id\": 10086}"
},
"content": null,
"metadata": {},
"state": "asking"
}
]
}
```
### 5.24 USER_CONFIRM_RESULT — 用户确认结果回传
用户对 `REQUIRE_USER_CONFIRM` 的响应结果(同一会话的下一轮调用事件流中可能出现)。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `replyId` | String | 回复 ID |
| `confirmResults` | Array | `ConfirmResult` 列表 |
`ConfirmResult` 字段:
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `confirmed` | Boolean | 是否批准 |
| `toolCall` | Object | 对应的 `ToolUseBlock`(用户可修改入参) |
| `rules` | Array | 用户新增的权限规则(允许后续免确认),可为空 |
```json
{
"type": "USER_CONFIRM_RESULT",
"id": "7889900112233445566778899001122334",
"createdAt": "2026-09-18T02:31:05.000000Z",
"replyId": "reply-7f3a91",
"confirmResults": [
{
"confirmed": true,
"toolCall": {
"id": "call_9f2c4d",
"name": "shell_execute",
"input": {
"command": "rm -rf /workspace/old/"
},
"content": null,
"metadata": {},
"state": "asking"
},
"rules": [
{
"tool_name": "shell_execute",
"rule_content": "rm -rf /workspace/*",
"behavior": "allow",
"source": "userSettings"
}
]
},
{
"confirmed": false,
"toolCall": {
"id": "call_5a1b02",
"name": "http_post",
"input": {
"url": "https://api.example.com/orders",
"body": "{\"id\": 10086}"
},
"content": null,
"metadata": {},
"state": "asking"
},
"rules": null
}
]
}
```
### 5.25 ALL_TOOLS_DENIED — 本轮所有工具均被拒绝
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `deniedToolCalls` | Array | 被拒绝的 `ToolUseBlock` 列表 |
```json
{
"type": "ALL_TOOLS_DENIED",
"id": "89900112233445566778899001122334455",
"createdAt": "2026-09-18T02:31:05.100000Z",
"deniedToolCalls": [
{
"id": "call_5a1b02",
"name": "http_post",
"input": {
"url": "https://api.example.com/orders",
"body": "{\"id\": 10086}"
},
"content": null,
"metadata": {},
"state": "asking"
}
]
}
```
### 5.26 REQUIRE_EXTERNAL_EXECUTION — 需要外部(进程外)执行工具
工具需由调用方在进程外执行,智能体暂停等待结果。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `replyId` | String | 回复 ID |
| `toolCalls` | Array | 待外部执行的 `ToolUseBlock` 列表 |
```json
{
"type": "REQUIRE_EXTERNAL_EXECUTION",
"id": "9001122334455667788990011223344556",
"createdAt": "2026-09-18T02:30:45.900000Z",
"replyId": "reply-7f3a91",
"toolCalls": [
{
"id": "call_0f3e9a",
"name": "human_approval_flow",
"input": {
"title": "发布订单 10086 到生产环境"
},
"content": null,
"metadata": {},
"state": "pending"
}
]
}
```
### 5.27 EXTERNAL_EXECUTION_RESULT — 外部执行结果回传
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `replyId` | String | 回复 ID |
| `toolResults` | Array | `ToolResultBlock` 列表 |
`ToolResultBlock` 字段:`id``name``output`ContentBlock 数组)、`metadata``state``success` / `error` / `interrupted` / `denied` / `running`)。
```json
{
"type": "EXTERNAL_EXECUTION_RESULT",
"id": "a112233445566778899001122334455667",
"createdAt": "2026-09-18T02:31:20.000000Z",
"replyId": "reply-7f3a91",
"toolResults": [
{
"id": "call_0f3e9a",
"name": "human_approval_flow",
"output": [
{
"type": "text",
"text": "审批人张三已批准,订单 10086 已发布。"
}
],
"metadata": {},
"state": "success"
}
]
}
```
### 5.28 REQUEST_STOP — 请求暂停执行
中间件 / 权限引擎要求智能体在当前步骤结束后暂停(如预算超限、合规审查点)。调用方可在下一轮使用相同 `sessionId` 继续该会话,待执行的工具调用会自动恢复。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `reason` | String | 停止原因(人类可读) |
| `generateReason` | String | 停止原因枚举名:`MODEL_STOP` / `TOOL_CALLS` / `STRUCTURED_OUTPUT` / `TOOL_SUSPENDED` / `REASONING_STOP_REQUESTED` / `ACTING_STOP_REQUESTED` / `PERMISSION_ASKING` / `MIDDLEWARE_STOP_REQUESTED` / `ALL_TOOLS_DENIED` / `INTERRUPTED` / `MAX_ITERATIONS`,默认 `MIDDLEWARE_STOP_REQUESTED` |
```json
{
"type": "REQUEST_STOP",
"id": "b223344556677889900112233445566778",
"createdAt": "2026-09-18T02:30:49.000000Z",
"reason": "单轮 token 消耗超过预算上限 100K,已暂停"
}
```
```json
{
"type": "REQUEST_STOP",
"id": "c334455667788990011223344556677889",
"createdAt": "2026-09-18T02:30:49.100000Z",
"reason": "权限引擎要求用户确认高风险操作",
"generateReason": "PERMISSION_ASKING"
}
```
### 5.29 SUBAGENT_EXPOSED — 子智能体对外暴露
通过 `agent_spawn(expose_to_user=true)` 生成的子智能体成为可寻址的独立会话入口,SSE 消费端据此在 UI 渲染新的会话卡片。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `subagentId` | String | 子智能体实例 ID |
| `agentId` | String | 子智能体定义 ID |
| `sessionId` | String | 子智能体会话 ID |
| `label` | String | 展示名称 |
```json
{
"type": "SUBAGENT_EXPOSED",
"id": "d445566778899001122334455667788990",
"createdAt": "2026-09-18T02:31:02.000000Z",
"subagentId": "sub-0a1b2c3d",
"agentId": "data-analyst",
"sessionId": "sess-sub-88",
"label": "数据分析助手"
}
```
### 5.30 HINT_BLOCK — 一次性提示块
一次性完整下发(不流式),用途包括团队消息、后台工具结果、用户打断等。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `replyId` | String | 回复 ID |
| `blockId` | String | 提示块 ID |
| `hintSource` | String | 来源(团队消息发送者姓名、`system``null` |
| `hint` | String | 完整提示内容 |
```json
{
"type": "HINT_BLOCK",
"id": "e556677889900112233445566778899001",
"createdAt": "2026-09-18T02:31:03.000000Z",
"replyId": "reply-7f3a91",
"blockId": "blk-hint-01",
"hintSource": "alice",
"hint": "alice 加入了会话,可以开始协作。"
}
```
### 5.31 CUSTOM — 自定义扩展事件
业务中间件用于推送自有状态(未知 `name` 前端应跳过不报错)。约定 `name``state_updated`(任务/权限状态变化)、`team_updated`(团队变更)等。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `name` | String | 事件名 |
| `value` | Object | 任意 JSON 负载 |
```json
{
"type": "CUSTOM",
"id": "f667788990011223344556677889900112",
"createdAt": "2026-09-18T02:31:04.000000Z",
"name": "task_progress",
"value": {
"taskId": "task-201",
"progress": 66,
"status": "RUNNING",
"detail": "正在生成页面截图"
}
}
```
```json
{
"type": "CUSTOM",
"id": "a778899001122334455667788990011223",
"createdAt": "2026-09-18T02:31:04.500000Z",
"name": "team_updated",
"value": {
"action": "MEMBER_ADDED",
"member": "bob",
"teamId": "team-007"
}
}
```
## 6. 典型一轮完整事件流(SSE,按顺序)
以「用户要求整理任务清单并保存为 markdown」为例(含工具调用):
```text
data:{"type":"AGENT_START","id":"...","createdAt":"...","sessionId":"sess-20260918-001","replyId":"reply-7f3a91","name":"assistant","role":"assistant"}
data:{"type":"MODEL_CALL_START","id":"...","createdAt":"...","replyId":"reply-7f3a91"}
data:{"type":"THINKING_BLOCK_START","id":"...","createdAt":"...","replyId":"reply-7f3a91","blockId":"blk-001"}
data:{"type":"THINKING_BLOCK_DELTA","id":"...","createdAt":"...","replyId":"reply-7f3a91","blockId":"blk-001","delta":"先读取任务源文件,再生成 markdown"}
data:{"type":"THINKING_BLOCK_END","id":"...","createdAt":"...","replyId":"reply-7f3a91","blockId":"blk-001"}
data:{"type":"MODEL_CALL_END","id":"...","createdAt":"...","replyId":"reply-7f3a91","usage":{"inputTokens":520,"outputTokens":80,"cachedTokens":0,"time":0.41,"totalTokens":600}}
data:{"type":"TOOL_CALL_START","id":"...","createdAt":"...","replyId":"reply-7f3a91","toolCallId":"call_9f2c4d","toolCallName":"shell_execute"}
data:{"type":"TOOL_CALL_DELTA","id":"...","createdAt":"...","replyId":"reply-7f3a91","toolCallId":"call_9f2c4d","toolCallName":"shell_execute","delta":"{\"command\":\"cat /tasks.json\"}"}
data:{"type":"TOOL_CALL_END","id":"...","createdAt":"...","replyId":"reply-7f3a91","toolCallId":"call_9f2c4d","toolCallName":"shell_execute"}
data:{"type":"TOOL_RESULT_START","id":"...","createdAt":"...","replyId":"reply-7f3a91","toolCallId":"call_9f2c4d","toolCallName":"shell_execute"}
data:{"type":"TOOL_RESULT_TEXT_DELTA","id":"...","createdAt":"...","replyId":"reply-7f3a91","toolCallId":"call_9f2c4d","toolCallName":"shell_execute","delta":"3 个任务待办..."}
data:{"type":"TOOL_RESULT_END","id":"...","createdAt":"...","replyId":"reply-7f3a91","toolCallId":"call_9f2c4d","toolCallName":"shell_execute","state":"success"}
data:{"type":"MODEL_CALL_START","id":"...","createdAt":"...","replyId":"reply-7f3a91"}
data:{"type":"MODEL_CALL_END","id":"...","createdAt":"...","replyId":"reply-7f3a91","usage":{"inputTokens":1600,"outputTokens":330,"cachedTokens":512,"time":1.8,"totalTokens":1930}}
data:{"type":"TEXT_BLOCK_START","id":"...","createdAt":"...","replyId":"reply-7f3a91","blockId":"blk-002"}
data:{"type":"TEXT_BLOCK_DELTA","id":"...","createdAt":"...","replyId":"reply-7f3a91","blockId":"blk-002","delta":"已完成,"}
data:{"type":"TEXT_BLOCK_DELTA","id":"...","createdAt":"...","replyId":"reply-7f3a91","blockId":"blk-002","delta":"任务清单已保存至 /workspace/tasks.md"}
data:{"type":"TEXT_BLOCK_END","id":"...","createdAt":"...","replyId":"reply-7f3a91","blockId":"blk-002"}
data:{"type":"AGENT_RESULT","id":"...","createdAt":"...","result":{"id":"550e8400-e29b-41d4-a716-446655440000","name":"assistant","role":"ASSISTANT","content":[{"type":"text","text":"已完成,任务清单已保存至 /workspace/tasks.md"}],"metadata":{"agentscope_generate_reason":"MODEL_STOP"},"timestamp":"2026-09-18 10:30:48.200","usage":{"inputTokens":1600,"outputTokens":330,"cachedTokens":512,"time":1.8,"totalTokens":1930}}}
data:{"type":"AGENT_END","id":"...","createdAt":"...","replyId":"reply-7f3a91"}
```
事件一般顺序:`AGENT_START``MODEL_CALL_*` / `THINKING_BLOCK_*` / `TOOL_CALL_*` / `TOOL_RESULT_*` 可能多轮循环) → `TEXT_BLOCK_*``AGENT_RESULT``AGENT_END`。涉及 HITL 时会插入 `REQUIRE_USER_CONFIRM`(见 §5.23)。
## 7. 注意事项
1. **延续会话**:同一 `(userId, sessionId)` 组合的上下文会自动累积;不同会话互不干扰。`REQUEST_STOP``REQUIRE_USER_CONFIRM` 暂停后,用相同 `sessionId` 再发一次请求即可恢复执行。
2. **事件 ID**`id` 为 32 位十六进制(无连字符 UUID),可用于调试与去重;`createdAt` 为 ISO-8601UTC)。
3. **未知事件**:前端对 `type: CUSTOM` 中未知的 `name` 应静默跳过;对表外未知 `type` 应尽量容忍(服务端可能升级新增事件)。
4. **空字段省略**:顶层事件的 `source``metadata` 及无值字段在 JSON 中缺省(`NON_NULL` 策略);`Msg` 内部字段(如 `name``usage`)则为 `null` 或对象。