641d847008
- Update api-endpoints.md with new agent endpoints - Update run-agent-input.md with new input schemas - Update sse-events.md with new event types - Update ui-schema.md with schema changes
536 lines
13 KiB
Markdown
536 lines
13 KiB
Markdown
# 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"]
|
||
}
|
||
}
|
||
```
|
||
|
||
### Frontend Tool Channel Semantics
|
||
|
||
- `RunAgentInput.tools` 用于前端工具通道(供前端/HITL 审批链路透传与回放)。
|
||
- 当前后端 AgentScope 执行阶段**不**使用该字段来注册或筛选后端工具。
|
||
- 后端可调用工具以 `toolkit.register_tool_function(...)` 注册结果为准(例如 `calendar_write`)。
|
||
- 因此 `tools` 可为空数组,不影响后端已注册工具的调用能力。
|
||
|
||
> 注意:请勿把后端已注册工具重复写入 `RunAgentInput.tools`,避免命名/参数描述冲突。
|
||
|
||
---
|
||
|
||
## Context Schema
|
||
|
||
```typescript
|
||
interface Context {
|
||
description: string;
|
||
value: string;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## forwardedProps Schema(支持 agent_type + client_time)
|
||
|
||
`RunAgentInput.forwardedProps` 支持透传运行模式与客户端时间上下文。日历相关能力必须使用以下结构:
|
||
|
||
```typescript
|
||
interface ForwardedProps {
|
||
agent_type: string; // 必填,运行模式(如 "worker" / "memory")
|
||
client_time?: {
|
||
device_timezone: string; // IANA 时区,例如 "America/Los_Angeles"
|
||
client_now_iso: string; // RFC3339 带偏移时间,例如 "2026-03-16T09:12:33-07:00"
|
||
client_epoch_ms: number; // Unix epoch 毫秒
|
||
};
|
||
}
|
||
```
|
||
|
||
### 时间来源优先级(固定)
|
||
|
||
后端在运行时按以下顺序解析事件时区:
|
||
|
||
1. `event_timezone`(工具调用显式传参)
|
||
2. `forwardedProps.client_time.device_timezone`
|
||
3. `users.profile.settings.timezone`
|
||
4. `UTC`
|
||
|
||
### 约束
|
||
|
||
- `device_timezone` 必须是有效 IANA 时区。
|
||
- `client_now_iso` 必须是 RFC3339 且包含时区偏移。
|
||
- `client_epoch_ms` 必须是整数毫秒时间戳。
|
||
- `forwardedProps.agent_type` 必填,且必须匹配后端已注册的 agent type。
|
||
- `agent_type=memory` 为自动化任务内部模式,HTTP `/agent/runs` 入口不接受该值。
|
||
- `forwardedProps` 仅允许 `agent_type` 与 `client_time`,额外字段会触发 `422 invalid RunAgentInput.forwardedProps`。
|
||
- 业务代码不得使用服务器本地时区作为事件语义时区。
|
||
|
||
### 说明
|
||
|
||
- `forwardedProps` 是透传字段,不改变 AG-UI 主体协议结构。
|
||
- 当 `forwardedProps.client_time` 缺失或非法时,运行时回退到 `users.profile.settings.timezone`。
|
||
- 日历写入必须在最终工具调用中带上 `event_timezone`,不得依赖工具默认值。
|
||
|
||
---
|
||
|
||
## 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` |
|
||
| forwardedProps.agent_type 必填 | `invalid RunAgentInput.forwardedProps` |
|
||
| **恰好 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` |
|
||
| 单条消息最多 3 张附件 | `Too many attachments` |
|
||
|
||
### forwardedProps.client_time Validation
|
||
|
||
建议在后端校验层返回以下错误(按业务实现映射到 4xx):
|
||
|
||
| Rule | Error Message |
|
||
|------|---------------|
|
||
| `device_timezone` 非 IANA 时区 | `invalid client_time.device_timezone` |
|
||
| `client_now_iso` 无法解析或缺少时区 | `invalid client_time.client_now_iso` |
|
||
| `client_epoch_ms` 非整数毫秒值 | `invalid client_time.client_epoch_ms` |
|
||
|
||
---
|
||
|
||
## Request Example
|
||
|
||
### 纯文本请求
|
||
|
||
```json
|
||
{
|
||
"threadId": "550e8400-e29b-41d4-a716-446655440000",
|
||
"runId": "run-001",
|
||
"state": {},
|
||
"messages": [
|
||
{
|
||
"id": "msg-001",
|
||
"role": "user",
|
||
"content": "帮我查一下北京今天的天气"
|
||
}
|
||
],
|
||
"tools": [],
|
||
"context": [],
|
||
"forwardedProps": {
|
||
"agent_type": "worker"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 多模态请求 (带图片)
|
||
|
||
```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": {
|
||
"agent_type": "worker"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 带 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": {
|
||
"agent_type": "worker"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 带 forwardedProps.client_time 的请求
|
||
|
||
```json
|
||
{
|
||
"threadId": "550e8400-e29b-41d4-a716-446655440000",
|
||
"runId": "run-004",
|
||
"state": {},
|
||
"messages": [
|
||
{
|
||
"id": "msg-001",
|
||
"role": "user",
|
||
"content": "帮我明天早上9点创建一个日历"
|
||
}
|
||
],
|
||
"tools": [],
|
||
"context": [],
|
||
"forwardedProps": {
|
||
"agent_type": "worker",
|
||
"client_time": {
|
||
"device_timezone": "America/Los_Angeles",
|
||
"client_now_iso": "2026-03-16T09:12:33-07:00",
|
||
"client_epoch_ms": 1773658353000
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Response
|
||
|
||
成功响应返回 `TaskAcceptedResponse`:
|
||
|
||
```typescript
|
||
interface TaskAcceptedResponse {
|
||
taskId: string;
|
||
threadId: string;
|
||
runId: string;
|
||
created: boolean; // 是否新建会话
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 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;
|
||
attachments: HistoryAttachment[];
|
||
timestamp: string; // ISO-8601 timestamp
|
||
}
|
||
|
||
interface HistoryAttachment {
|
||
mimeType: string;
|
||
url: string;
|
||
}
|
||
|
||
// role = "assistant"
|
||
interface HistoryMessageAssistant {
|
||
id: string;
|
||
seq: number;
|
||
role: "assistant";
|
||
content: string;
|
||
ui_schema: UiSchemaRenderer | null; // 由 agent_output.ui_hints 编译
|
||
timestamp: string;
|
||
}
|
||
|
||
type HistoryMessage = HistoryMessageUser | 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": "帮我创建一个日程",
|
||
"attachments": [
|
||
{
|
||
"mimeType": "image/png",
|
||
"url": "https://project.supabase.co/storage/v1/object/sign/agent-inputs/..."
|
||
}
|
||
],
|
||
"timestamp": "2026-03-15T10:00:00Z"
|
||
},
|
||
{
|
||
"id": "msg-002",
|
||
"seq": 2,
|
||
"role": "assistant",
|
||
"content": "好的,我来帮您创建日程。",
|
||
"ui_schema": {
|
||
"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
|
||
- `RunAgentInput` 同时接受 camelCase 与 snake_case 别名输入(推荐统一使用 camelCase)
|
||
- 日历能力依赖 `forwardedProps.client_time` 透传设备时间上下文;缺失时回退用户 profile 时区
|
||
- `forwardedProps.agent_type` 是受控路由字段,必须由调用方显式传入;后端 task 不做默认赋值
|
||
- tool 消息在存储层用于运行时上下文续接,不在 `/history` 对外返回
|