feat: 实现 AgentScope ReAct Runner 两阶段执行并重构事件处理
This commit is contained in:
@@ -0,0 +1,449 @@
|
||||
# Agent Run Input Protocol
|
||||
|
||||
> **NOTE**: This document defines the RunAgentInput data structure for `POST /api/v1/agent/runs`.
|
||||
|
||||
## Version
|
||||
|
||||
- **Current**: `1.0`
|
||||
- **Status**: Active
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
`POST /api/v1/agent/runs` accepts `RunAgentInput` as request body to initiate an agent execution.
|
||||
|
||||
---
|
||||
|
||||
## RunAgentInput Schema
|
||||
|
||||
```typescript
|
||||
interface RunAgentInput {
|
||||
threadId: string; // 必须是有效 UUID
|
||||
runId: string; // 最大 128 字符
|
||||
parentRunId?: string;
|
||||
state?: any;
|
||||
messages: Message[]; // 最多 200 条
|
||||
tools?: Tool[];
|
||||
context?: Context[];
|
||||
forwardedProps?: any;
|
||||
}
|
||||
```
|
||||
|
||||
### Required Fields
|
||||
|
||||
| Field | Type | Constraints |
|
||||
|-------|------|-------------|
|
||||
| `threadId` | string | 必须为有效 UUID |
|
||||
| `runId` | string | 最大 128 字符 |
|
||||
| `messages` | array | 最多 200 条,**必须恰好包含 1 条 user message** |
|
||||
| `state` | any | - |
|
||||
| `tools` | array | 可选 |
|
||||
| `context` | array | 可选 |
|
||||
| `forwardedProps` | any | - |
|
||||
|
||||
---
|
||||
|
||||
## Message Types
|
||||
|
||||
### UserMessage
|
||||
|
||||
```typescript
|
||||
interface UserMessage {
|
||||
id: string;
|
||||
role: "user";
|
||||
content: string | ContentBlock[];
|
||||
name?: string;
|
||||
encryptedValue?: string;
|
||||
}
|
||||
|
||||
type ContentBlock = TextContentBlock | BinaryContentBlock;
|
||||
|
||||
interface TextContentBlock {
|
||||
type: "text";
|
||||
text: string;
|
||||
}
|
||||
|
||||
interface BinaryContentBlock {
|
||||
type: "binary";
|
||||
mimeType: string; // 必须为 image/* 类型
|
||||
id?: string;
|
||||
url?: string; // 必须是有效的 signed URL
|
||||
data?: string; // 不允许使用 data 字段
|
||||
filename?: string;
|
||||
}
|
||||
```
|
||||
|
||||
### AssistantMessage
|
||||
|
||||
```typescript
|
||||
interface AssistantMessage {
|
||||
id: string;
|
||||
role: "assistant";
|
||||
content?: string | null;
|
||||
name?: string | null;
|
||||
toolCalls?: ToolCall[];
|
||||
encryptedValue?: string | null;
|
||||
}
|
||||
|
||||
interface ToolCall {
|
||||
id: string;
|
||||
type: "function";
|
||||
function: {
|
||||
name: string;
|
||||
arguments: string;
|
||||
};
|
||||
encryptedValue?: string | null;
|
||||
}
|
||||
```
|
||||
|
||||
### SystemMessage
|
||||
|
||||
```typescript
|
||||
interface SystemMessage {
|
||||
id: string;
|
||||
role: "system";
|
||||
content: string;
|
||||
name?: string | null;
|
||||
encryptedValue?: string | null;
|
||||
}
|
||||
```
|
||||
|
||||
### ToolMessage
|
||||
|
||||
```typescript
|
||||
interface ToolMessage {
|
||||
id: string;
|
||||
role: "tool";
|
||||
content: string;
|
||||
toolCallId: string;
|
||||
error?: string | null;
|
||||
encryptedValue?: string | null;
|
||||
}
|
||||
```
|
||||
|
||||
### Other Message Types
|
||||
|
||||
- **DeveloperMessage**: `role: "developer"`
|
||||
- **ReasoningMessage**: `role: "reasoning"`
|
||||
- **ActivityMessage**: `role: "activity"` (for progress updates)
|
||||
|
||||
---
|
||||
|
||||
## Tool Schema
|
||||
|
||||
```typescript
|
||||
interface Tool {
|
||||
name: string;
|
||||
description: string;
|
||||
parameters: object; // JSON Schema 格式
|
||||
}
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "get_weather",
|
||||
"description": "Get current weather for a location",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"type": "string",
|
||||
"description": "City name"
|
||||
},
|
||||
"unit": {
|
||||
"type": "string",
|
||||
"enum": ["celsius", "fahrenheit"]
|
||||
}
|
||||
},
|
||||
"required": ["location"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Backend Processing
|
||||
|
||||
Backend 使用 `build_tools_prompt` 函数将 tools 转换为 prompt 格式:
|
||||
|
||||
```
|
||||
<!-- TOOLS_START -->
|
||||
- get_weather: Get current weather for a location
|
||||
- args_schema: {"type":"object","properties":{"location":{"type":"string","description":"City name"},"unit":{"type":"string","enum":["celsius","fahrenheit"]}},"required":["location"]}
|
||||
- searchDocuments: Search for documents
|
||||
- args_schema: {"type":"object","properties":{"query":{"type":"string"}},"required":["query"]}
|
||||
Note: tool arguments must strictly match args_schema.
|
||||
<!-- TOOLS_END -->
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Context Schema
|
||||
|
||||
```typescript
|
||||
interface Context {
|
||||
description: string;
|
||||
value: string;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Validation Rules
|
||||
|
||||
Backend 实现了以下验证规则:
|
||||
|
||||
| Rule | Error Message |
|
||||
|------|---------------|
|
||||
| payload ≤ 256KB | `RunAgentInput payload exceeds size limit` |
|
||||
| threadId 必须是 UUID | `threadId must be a valid UUID` |
|
||||
| runId 最大 128 字符 | `runId exceeds length limit` |
|
||||
| messages ≤ 200 条 | `RunAgentInput.messages exceeds limit` |
|
||||
| user text ≤ 10,000 字符 | `RunAgentInput user message text exceeds limit` |
|
||||
| **恰好 1 条 user message** | `RunAgentInput.messages must contain exactly one user message` |
|
||||
| user message 必须在第一条 | `RunAgentInput.messages[0].role must be user` |
|
||||
| binary 必须是 image/* | `binary content requires image mimeType` |
|
||||
| binary 必须有 url | `binary content requires url` |
|
||||
| binary 不允许使用 data | `binary content data is not allowed` |
|
||||
|
||||
---
|
||||
|
||||
## Request Example
|
||||
|
||||
### 纯文本请求
|
||||
|
||||
```json
|
||||
{
|
||||
"threadId": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"runId": "run-001",
|
||||
"state": {},
|
||||
"messages": [
|
||||
{
|
||||
"id": "msg-001",
|
||||
"role": "user",
|
||||
"content": "帮我查一下北京今天的天气"
|
||||
}
|
||||
],
|
||||
"tools": [],
|
||||
"context": [],
|
||||
"forwardedProps": {}
|
||||
}
|
||||
```
|
||||
|
||||
### 多模态请求 (带图片)
|
||||
|
||||
```json
|
||||
{
|
||||
"threadId": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"runId": "run-002",
|
||||
"state": {},
|
||||
"messages": [
|
||||
{
|
||||
"id": "msg-001",
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "这张图片里的内容是什么?"
|
||||
},
|
||||
{
|
||||
"type": "binary",
|
||||
"mimeType": "image/png",
|
||||
"url": "https://storage.example.com/agent-inputs/user-123/image.png?signature=xxx"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"tools": [],
|
||||
"context": [],
|
||||
"forwardedProps": {}
|
||||
}
|
||||
```
|
||||
|
||||
### 带 Tools 的请求
|
||||
|
||||
```json
|
||||
{
|
||||
"threadId": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"runId": "run-003",
|
||||
"state": {},
|
||||
"messages": [
|
||||
{
|
||||
"id": "msg-001",
|
||||
"role": "user",
|
||||
"content": "北京天气怎么样?"
|
||||
}
|
||||
],
|
||||
"tools": [
|
||||
{
|
||||
"name": "get_weather",
|
||||
"description": "获取指定城市的天气信息",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"city": {
|
||||
"type": "string",
|
||||
"description": "城市名称"
|
||||
}
|
||||
},
|
||||
"required": ["city"]
|
||||
}
|
||||
}
|
||||
],
|
||||
"context": [],
|
||||
"forwardedProps": {}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Response
|
||||
|
||||
成功响应返回 `TaskAcceptedResponse`:
|
||||
|
||||
```typescript
|
||||
interface TaskAcceptedResponse {
|
||||
taskId: string;
|
||||
threadId: string;
|
||||
runId: string;
|
||||
created: string; // ISO-8601 timestamp
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## History API
|
||||
|
||||
`GET /api/v1/agent/history` 返回对话历史快照。
|
||||
|
||||
### Request
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|-----------|------|-------------|
|
||||
| `threadId` | string (query) | 可选,指定会话 ID,不指定则返回最新会话 |
|
||||
| `before` | string (query) | 可选,日期格式 `YYYY-MM-DD`,返回该日期之前的快照 |
|
||||
|
||||
### Response
|
||||
|
||||
返回 `HistorySnapshotResponse`:
|
||||
|
||||
```typescript
|
||||
interface HistorySnapshotResponse {
|
||||
scope: "history_day";
|
||||
threadId: string | null;
|
||||
day: string | null; // ISO date format "YYYY-MM-DD"
|
||||
hasMore: boolean;
|
||||
messages: HistoryMessage[];
|
||||
}
|
||||
```
|
||||
|
||||
### HistoryMessage
|
||||
|
||||
根据消息 role 不同,返回字段有所差异:
|
||||
|
||||
```typescript
|
||||
// role = "user"
|
||||
interface HistoryMessageUser {
|
||||
id: string;
|
||||
seq: number;
|
||||
role: "user";
|
||||
content: string;
|
||||
url: string | null; // 附件临时访问 URL
|
||||
timestamp: string; // ISO-8601 timestamp
|
||||
}
|
||||
|
||||
// role = "tool"
|
||||
interface HistoryMessageTool {
|
||||
id: string;
|
||||
seq: number;
|
||||
role: "tool";
|
||||
content: string;
|
||||
uiSchema: UiSchemaRenderer | null; // 由 tool_agent_output.ui_hints 编译
|
||||
timestamp: string;
|
||||
}
|
||||
|
||||
// role = "assistant"
|
||||
interface HistoryMessageAssistant {
|
||||
id: string;
|
||||
seq: number;
|
||||
role: "assistant";
|
||||
content: string;
|
||||
uiSchema: UiSchemaRenderer | null; // 由 worker_agent_output.ui_hints 编译
|
||||
timestamp: string;
|
||||
}
|
||||
|
||||
type HistoryMessage = HistoryMessageUser | HistoryMessageTool | HistoryMessageAssistant;
|
||||
```
|
||||
|
||||
### UiSchemaRenderer
|
||||
|
||||
编译后的 UI 渲染结构,详见 [UiSchema Protocol](../ui/ui-schema.md):
|
||||
|
||||
```typescript
|
||||
interface UiSchemaRenderer {
|
||||
version: "2.0";
|
||||
locale: string;
|
||||
status: "info" | "success" | "warning" | "error" | "pending";
|
||||
theme: "default" | "light" | "dark";
|
||||
meta?: {
|
||||
requestId?: string;
|
||||
toolId?: string;
|
||||
traceId?: string;
|
||||
userId?: string;
|
||||
};
|
||||
root: UiLayoutNode;
|
||||
}
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
```json
|
||||
{
|
||||
"scope": "history_day",
|
||||
"threadId": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"day": "2026-03-15",
|
||||
"hasMore": true,
|
||||
"messages": [
|
||||
{
|
||||
"id": "msg-001",
|
||||
"seq": 1,
|
||||
"role": "user",
|
||||
"content": "帮我创建一个日程",
|
||||
"url": null,
|
||||
"timestamp": "2026-03-15T10:00:00Z"
|
||||
},
|
||||
{
|
||||
"id": "msg-002",
|
||||
"seq": 2,
|
||||
"role": "assistant",
|
||||
"content": "好的,我来帮您创建日程。",
|
||||
"uiSchema": {
|
||||
"version": "2.0",
|
||||
"locale": "zh-CN",
|
||||
"status": "success",
|
||||
"theme": "default",
|
||||
"root": {
|
||||
"type": "stack",
|
||||
"appearance": "card",
|
||||
"children": [
|
||||
{"type": "text", "content": "日程已创建", "role": "title"},
|
||||
{"type": "badge", "label": "SUCCESS", "status": "success"},
|
||||
{"type": "text", "content": "您的会议日程创建成功", "role": "body"}
|
||||
]
|
||||
}
|
||||
},
|
||||
"timestamp": "2026-03-15T10:00:05Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Compatibility Notes
|
||||
|
||||
- `UserMessage.content` 支持 string 或 array 格式,前端优先使用 array 格式以支持多模态
|
||||
- binary content 的 url 必须是有效的 signed URL,由 `/api/v1/agent/attachments` 端点生成
|
||||
- backend 验证通过后,会将 binary url 转换为内部存储路径
|
||||
- tools 为空数组时,prompt 中不会包含工具说明
|
||||
Reference in New Issue
Block a user