# UI Schema Protocol > **NOTE**: This document is the single source of truth. All implementations must follow this specification. ## Overview A generic UI schema for rendering tool/agent execution results. Designed for AI Agent / Tool ecosystem with extensibility. ## Version - **Current**: `1.0` - **Status**: Frozen (no new node types) ## Architecture ``` ┌─────────────────────────────────────────────────────────────┐ │ UiSchemaDocument (root) │ │ - version / schemaType / status / docId │ │ - meta (protocol-level metadata) │ │ - nodes (array of UiNode) │ ├─────────────────────────────────────────────────────────────┤ │ Field Layers: │ │ 1. Public fields (all renderers must handle) │ │ id / type / title / description / icon / status / │ │ timestamp / actions │ │ 2. meta (protocol-level, not rendered) │ │ requestId / toolId / traceId / userId │ │ 3. extensions (tool私有扩展, renderer透传) │ └─────────────────────────────────────────────────────────────┘ ``` --- ## Data Types ### SchemaType ```typescript type SchemaType = 'tool_result' | 'agent_response' | 'notification'; ``` ### UiStatus ```typescript type UiStatus = 'info' | 'success' | 'warning' | 'error' | 'pending'; ``` ### IconSource ```typescript type IconSource = 'icon' | 'emoji' | 'url'; ``` ### ActionType ```typescript type ActionType = 'navigation' | 'url' | 'event' | 'tool' | 'copy' | 'payload'; ``` --- ## Root Structure ```typescript interface UiSchemaDocument { // Protocol identifier version: string; // "1.0" schemaType: SchemaType; // tool_result | agent_response | notification // Document metadata docId?: string; // For local refresh / diff / analytics timestamp?: string; // ISO 8601 locale?: string; // "zh-CN" // Unified status status: UiStatus; // Render control renderer?: { renderer?: string; // Dedicated renderer name theme?: 'default' | 'dark' | 'light'; }; // Protocol-level metadata (not rendered) meta?: { requestId?: string; toolId?: string; traceId?: string; userId?: string; [key: string]: any; }; // Root nodes nodes: UiNode[]; } ``` --- ## Node Types (v1 Whitelist) ``` ✅ Supported in v1: - card 卡片 - list 列表 - table 表格 - text 文本/Markdown - kv 键值对 - operation 操作结果 - error 错误提示 - container 容器 ❌ Not supported in v1 (reserved for v2): - chart / metric / image / video / tabs / accordion / form ``` --- ## Common Node Fields All nodes share these fields: ```typescript interface UiBaseNode { id?: string; // For local refresh / action targeting type: string; // Node type identifier } interface UiTitledNode extends UiBaseNode { title?: string; description?: string; icon?: UiIcon; status?: UiStatus; timestamp?: string; } interface UiActionableNode extends UiTitledNode { actions?: UiAction[]; } interface UiExtendableNode extends UiActionableNode { extensions?: Record; // Tool私有扩展, 通用renderer透传 } ``` --- ## Node Definitions ### 1. Card Node ```typescript interface UiCardNode extends UiExtendableNode { type: 'card'; children?: UiNode[]; // Nested nodes footer?: UiTextNode; } ``` ### 2. List Node ```typescript interface UiListNode extends UiExtendableNode { type: 'list'; items: ListItem[]; pagination?: { page: number; pageSize: number; total: number; hasMore: boolean; }; emptyText?: string; } interface ListItem { id: string; title: string; subtitle?: string; description?: string; icon?: UiIcon; badge?: { label: string; variant?: 'default' | 'success' | 'warning' | 'error' | 'info' }; metadata?: Record; actions?: UiAction[]; } ``` ### 3. Table Node ```typescript interface UiTableNode extends UiExtendableNode { type: 'table'; columns: TableColumn[]; rows: TableRow[]; pagination?: Pagination; } interface TableColumn { key: string; label: string; width?: string; align?: 'left' | 'center' | 'right'; } interface TableRow { id: string; cells: Record; metadata?: Record; actions?: UiAction[]; } ``` ### 4. Text Node ```typescript interface UiTextNode extends UiBaseNode { type: 'text'; content: string; format?: 'plain' | 'markdown'; icon?: UiIcon; actions?: UiAction[]; } ``` ### 5. Key-Value Node ```typescript interface UiKvNode extends UiExtendableNode { type: 'kv'; pairs: KeyValuePair[]; layout?: 'vertical' | 'horizontal' | 'grid'; } interface KeyValuePair { key: string; label?: string; value: string | number | boolean; copyable?: boolean; } ``` ### 6. Operation Node ```typescript interface UiOperationNode extends UiExtendableNode { type: 'operation'; operation: 'create' | 'update' | 'delete' | 'execute'; result: 'success' | 'failure' | 'partial'; message?: string; affectedCount?: number; details?: UiNode; rollback?: UiAction; } ``` ### 7. Error Node ```typescript interface UiErrorNode extends UiBaseNode { type: 'error'; title?: string; icon?: UiIcon; errorCode: string; message: string; details?: string; stack?: string; retryable: boolean; suggestions?: string[]; retry?: UiAction; support?: UiAction; actions?: UiAction[]; } ``` ### 8. Container Node ```typescript interface UiContainerNode extends UiBaseNode { type: 'container'; direction: 'vertical' | 'horizontal'; gap?: number; children: UiNode[]; actions?: UiAction[]; } ``` --- ## Action Structure ```typescript interface UiAction { id: string; label: string; icon?: UiIcon; style?: 'primary' | 'secondary' | 'ghost' | 'danger'; disabled?: boolean; action: ActionSpec; confirm?: { title?: string; message?: string; confirmLabel?: string; cancelLabel?: string; }; } type ActionSpec = | { type: 'navigation'; path: string; params?: Record } | { type: 'url'; url: string; target?: '_self' | '_blank' } | { type: 'event'; event: string; payload?: Record } | { type: 'tool'; toolId: string; params?: Record } | { type: 'copy'; content: string; successMessage?: string } | { type: 'payload'; payload: Record; submitTo?: string }; ``` --- ## Icon Structure ```typescript interface UiIcon { source: IconSource; // 'icon' | 'emoji' | 'url' value: string; // icon name / emoji / URL color?: string; // "#FF0000" size?: number; // pixels } ``` --- ## Usage Rules ### operation vs error | Scenario | Node Type | |----------|-----------| | Tool execution failed, system exception | `UiErrorNode` | | Business operation result (CRUD) | `UiOperationNode` | | Network error / permission denied | `UiErrorNode` | ### extensions Usage Constraints 1. ❌ NO: Any rendering-related style / text / layout 2. ❌ NO: Any fields other renderers need to read 3. ✅ YES: Business identifiers (eventId, orderId) 4. ✅ YES: Dedicated renderer private config 5. ✅ YES: Analytics / logging context data 6. ✅ YES: Data that generic renderer doesn't care about --- ## JSON Examples ### Example 1: Success Card ```json { "version": "1.0", "schemaType": "tool_result", "docId": "doc_evt_001", "timestamp": "2026-03-12T10:30:00Z", "status": "success", "renderer": { "renderer": "calendar" }, "meta": { "requestId": "req_abc", "toolId": "calendar.create_event" }, "nodes": [ { "id": "node_card_1", "type": "card", "title": "日程已创建", "description": "会议日程创建成功", "icon": { "source": "icon", "value": "event_available" }, "extensions": { "eventId": "evt_abc123", "color": "#3B82F6" }, "children": [ { "type": "kv", "pairs": [ { "key": "title", "label": "主题", "value": "Q1 规划会议" }, { "key": "time", "label": "时间", "value": "2026-03-15 14:00" } ] } ], "actions": [ { "id": "action_view", "label": "查看详情", "style": "primary", "action": { "type": "navigation", "path": "/calendar/evt_abc123" } } ] } ] } ``` ### Example 2: List Result ```json { "version": "1.0", "schemaType": "tool_result", "status": "success", "meta": { "toolId": "search.documents" }, "nodes": [ { "type": "text", "content": "找到 **3** 个相关文档" }, { "id": "node_list_1", "type": "list", "items": [ { "id": "item_1", "title": "API 设计规范", "subtitle": "v2.1", "icon": { "source": "emoji", "value": "📄" }, "actions": [ { "id": "a1", "label": "查看", "action": { "type": "url", "url": "/docs/api" } } ] } ], "pagination": { "page": 1, "pageSize": 10, "total": 3, "hasMore": false } } ] } ``` ### Example 3: Error Result ```json { "version": "1.0", "schemaType": "tool_result", "status": "error", "meta": { "toolId": "user.delete" }, "nodes": [ { "id": "node_error_1", "type": "error", "title": "删除用户失败", "icon": { "source": "icon", "value": "error_outline" }, "errorCode": "PERMISSION_DENIED", "message": "您没有权限执行此操作", "details": "需要管理员权限", "retryable": true, "suggestions": ["联系管理员", "联系技术支持"], "retry": { "id": "action_retry", "label": "重试", "style": "primary", "action": { "type": "tool", "toolId": "user.delete", "params": { "userId": "u1" } } } } ] } ``` --- ## Evolution (v2) Reserved for future: - Nested containers: `tabs`, `accordion`, `carousel` - Data visualization: `chart`, `metric`, `progress` - Rich media: `image`, `video`, `audio`, `file` - Internationalization: `i18nKey` field - Version migration: `deprecated` flag - Offline support: `offline` flag