# 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(支持 runtime_mode + client_time) `RunAgentInput.forwardedProps` 支持透传运行模式与客户端时间上下文。日历相关能力必须使用以下结构: ```typescript interface ForwardedProps { runtime_mode: "chat" | "automation"; // 必填,运行模式 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 毫秒 }; } ``` ### 运行模式说明 | runtime_mode | 说明 | Pipeline | 差异 | |--------------|------|----------|------| | `chat` | 标准对话模式 | `router` -> `worker` | `enabled_tools` 和 `context` 来自 `system_agents.yaml` | | `automation` | 自动化任务模式 | `router` -> `worker` | `enabled_tools` 和 `context` 来自 `AutomationJob.config`(通过 `runtime_config` 注入)| > `runtime_mode` 仅影响 `RuntimeConfig`(工具列表与上下文配置),不改变执行阶段。两模式均使用固定两阶段 pipeline。 ### 时间来源优先级(固定) 后端在运行时按以下顺序解析事件时区: 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.runtime_mode` 必填,值必须为 `"chat"` 或 `"automation"`。 - `forwardedProps` 仅允许 `runtime_mode` 与 `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.runtime_mode 必填 | `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": { "runtime_mode": "chat" } } ``` ### 多模态请求 (带图片) ```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": { "runtime_mode": "chat" } } ``` ### 带 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": { "runtime_mode": "chat" } } ``` ### 带 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": { "runtime_mode": "chat", "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.runtime_mode` 是受控路由字段,必须由调用方显式传入;后端 task 不做默认赋值 - tool 消息在存储层用于运行时上下文续接,不在 `/history` 对外返回