Files
social-app/docs/protocols/ui/data-flow.md
T
qzl b34697660d feat: 实现 Auth 全局状态机与 401 统一处理机制
- 新增 AuthSessionInvalidated 事件处理 token 失效场景
- ApiInterceptor 新增 authFailureCallback 单飞机制
- AuthBloc 区分 manual logout 与 auto expiry 语义
- 新增 startup recovery fallback 防止启动卡死

feat: 重构 Calendar DayWeek 视图事件布局引擎

- 新增 DayEventLayoutEngine 解耦事件计算与渲染
- 新增 DayTimelineMetrics 统一时间轴常量
- 新增 DayViewScale 支持捏合缩放

feat: 新增 Settings 页面共享 UI 组件

- 新增 BackTitlePageHeader 统一页面 header
- 新增 DetailHeaderActionMenu 统一操作菜单
- 新增 DestructiveActionSheet 统一删除确认
- 新增 AppToggleSwitch 统一开关组件

feat: Chat UI Schema 支持导航操作

- 支持 navigation 类型 action 触发内部路由跳转
- 新增路径验证与参数处理

chore: 更新相关测试覆盖 auth 失效路径
2026-03-18 13:35:25 +08:00

4.0 KiB
Raw Blame History

前后端数据流通指南(Agent Chat)

本文档仅描述当前后端实现的 runs/events/history 数据流,不定义视觉细节。


1) 总体流程

  1. 客户端 POST /api/v1/agent/runs 提交 RunAgentInput
  2. 后端返回 202 + taskId/threadId/runId/created
  3. 客户端 GET /api/v1/agent/runs/{threadId}/events 订阅 SSE
  4. 后端输出 AG-UI 事件(如 RUN_STARTEDTOOL_CALL_RESULTTEXT_MESSAGE_END
  5. 客户端按需 GET /api/v1/agent/history 拉取历史快照(按天)

2) /runs 请求与响应

请求

  • Body: RunAgentInput
  • user message 可为纯文本,也可为文本+binary(图片 URL)

响应

{
  "taskId": "...",
  "threadId": "...",
  "runId": "...",
  "created": true
}

created 语义:是否在本次请求中创建了新会话。


3) /runs/{threadId}/events 事件流

SSE 形式

id: <stream-id>
event: <EVENT_TYPE>
data: <json>

事件类型

docs/protocols/agent/sse-events.md 为准。当前重点是:

  • 运行生命周期:RUN_STARTED / RUN_FINISHED / RUN_ERROR
  • 阶段:STEP_STARTED / STEP_FINISHED
  • 工具:TOOL_CALL_START / TOOL_CALL_ARGS / TOOL_CALL_END / TOOL_CALL_RESULT
  • 文本完成:TEXT_MESSAGE_END

文本流策略

当前后端不提供 token 级 TEXT_MESSAGE_CONTENT 增量流作为主路径; 而是在 worker 完成后通过 TEXT_MESSAGE_END 一次性携带完整语义结果。


4) /history 快照

GET /api/v1/agent/history 返回 HistorySnapshotResponse

{
  "scope": "history_day",
  "threadId": "...",
  "day": "2026-03-16",
  "hasMore": false,
  "messages": []
}

说明:

  • 这是普通 JSON 响应,不是 SSE 事件包装。
  • messages 已按 seq 升序组织。
  • before 采用 YYYY-MM-DD,语义是向更早日期翻页。

5) events 与 history 的一致性机制

5.1 语义来源一致

两条链路都来自同一运行时输出(worker/tool output)及其持久化元数据。

5.2 UI 编译器一致

两条链路都使用后端 ui_compiler.compile(...)workerui_hints 编译为可渲染结构:

  • events:在 runtime 发送事件前编译,字段名为 ui_schema
  • history:在历史转换时编译,字段名为 ui_schema

tool 结果不再走 UI 编译链路:TOOL_CALL_RESULT 提供 tool_call_args + result 组合。

  • metadata.tool_agent_output 是 tool 消息的完整信源(用于 runtime observation 与 history replay)。
  • message.content 保持轻量摘要(当前等于 result)。
  • tool_call_args 记录输入参数,result 记录输出事实,二者不做冗余重复。

5.3 当前命名差异(实现现状)

两条链路字段命名已统一:

  • events: ui_schemasnake_case
  • history: ui_schemasnake_case

6) 推荐消费顺序(面向客户端重构)

  1. 先以 /history 获取首屏快照
  2. 再接入 /events 处理后续增量
  3. runId + messageId/toolCallId 做去重与合并
  4. 统一消费 ui_schema

7) Navigation Action 数据流(ui_schema.actions

7.1 后端生成

  • runtime 使用 ui_hints.action.type = navigation 产出导航动作。
  • 编译后在 ui_schema 中保持 action.type = navigationaction.pathaction.params
  • 路由来源应受后端静态路由目录约束:
    • backend/src/core/config/static/route/frontend_routes.yaml

7.2 前端消费(统一解析规则)

  • type = navigation,前端仅走一条解析路径:
    1. 读取 path 作为内部路由目标;
    2. params 仅视为 query 参数(不用于 path 模板替换);
    3. 执行 GoRouter 跳转(建议 context.go(...))。
  • path 必须是已落地页面路由,且应是已实参化路径(如 /todo/123,而非 /todo/:id)。

7.3 约束建议

  • 为了让前端只保留一种解析逻辑,推荐强约束:
    • path 只接受内部路由;
    • params 只接受标量值(string/number/boolean);
    • 禁止在 params 里放嵌套对象数组。