Files
social-app/docs/protocols/ui-schema.md
T
qzl 01c36eb32e refactor: 移除前端 Mock API,新增共享组件,优化认证流程
- 删除 mock_api_client、mock_calendar_service、mock_history_service
- 新增 fixed_length_code_input、link_button、message_composer 共享组件
- 优化登录/注册/密码重置页面使用新组件
- 简化 injection.dart 移除 mock 分支
- 更新 env.dart 配置(BACKEND_URL 替换 API_URL)
- 后端 agentscope 工具和测试更新
- 重构 AGENTS.md 文档结构
- 新增 deploy/ 目录和 protocol 文档
2026-03-12 16:41:45 +08:00

11 KiB

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

type SchemaType = 'tool_result' | 'agent_response' | 'notification';

UiStatus

type UiStatus = 'info' | 'success' | 'warning' | 'error' | 'pending';

IconSource

type IconSource = 'icon' | 'emoji' | 'url';

ActionType

type ActionType = 'navigation' | 'url' | 'event' | 'tool' | 'copy' | 'payload';

Root Structure

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:

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<string, any>;  // Tool私有扩展, 通用renderer透传
}

Node Definitions

1. Card Node

interface UiCardNode extends UiExtendableNode {
  type: 'card';
  children?: UiNode[];       // Nested nodes
  footer?: UiTextNode;
}

2. List Node

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<string, any>;
  actions?: UiAction[];
}

3. Table Node

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<string, any>;
  metadata?: Record<string, any>;
  actions?: UiAction[];
}

4. Text Node

interface UiTextNode extends UiBaseNode {
  type: 'text';
  content: string;
  format?: 'plain' | 'markdown';
  icon?: UiIcon;
  actions?: UiAction[];
}

5. Key-Value Node

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

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

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

interface UiContainerNode extends UiBaseNode {
  type: 'container';
  direction: 'vertical' | 'horizontal';
  gap?: number;
  children: UiNode[];
  actions?: UiAction[];
}

Action Structure

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<string, any> }
  | { type: 'url'; url: string; target?: '_self' | '_blank' }
  | { type: 'event'; event: string; payload?: Record<string, any> }
  | { type: 'tool'; toolId: string; params?: Record<string, any> }
  | { type: 'copy'; content: string; successMessage?: string }
  | { type: 'payload'; payload: Record<string, any>; submitTo?: string };

Icon Structure

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

{
  "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

{
  "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

{
  "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