Files
next-tjwater-frontend/docs/agent-answer-ui.md
T
jiang 2d8506fea0
Generic Container CI/CD / test-build-publish (push) Successful in 2m9s
Frontend CI/CD / build-test-publish-and-deploy (push) Successful in 2m39s
feat: add project-aware agent workspace
2026-10-22 18:52:18 +08:00

8.2 KiB
Raw Blame History

本地交互式回答

统一样式见 样式设计指南,聊天布局与报告交互见 Agent 交互与报告设计。本文保留协议、组件参数与业务交互约定。

聊天保留 AI SDK UIMessage、AI Elements 与现有 Agent 后端,新增 @json-render/core / @json-render/react 的本地注册组件。 组件代码随前端构建发布,无 ChatKit iframe、domain key 或 Vercel/OpenAI 托管 UI 请求。模型仍使用 Agent 的既有配置与工具调用能力。

可用内容与交互

Stack、Section、Text、Metric、Table、Chart、Evidence、 MapLocation、FollowUpForm 共九种组件。图表可切换折线、柱状和数据表; 表格可搜索、排序和选择行,图表可切换已加载区间、显隐序列并选点追问; 证据可按类别筛选、折叠并标注来源;地图定位通过现有控制器执行;表单从空值开始, 由用户主动提交,提交形成普通用户消息。业务证据是否保存以 Agent 实际工具结果为准。

Agent 通过 present_answer 发布完整的局部界面块,可在两块之间继续输出文字。 消息顺序为文字、data-answer_ui、后续文字与最终报告。同一轮内相同 block_id 更新原块;下一轮不会修改上一轮回答。 这是按内容块逐步出现的界面,不是逐 token 编译 JSX 或每个 JSON 属性都立即显示。 结构化消息与普通聊天共用持久化、历史与断线恢复通道。

生成期间展开显示过程;final_answer 到达后,仅展开最后报告的完整文字与 ui_block_ids 明确引用的已发布组件,其余文字、界面与工具轨迹默认折叠在 “查看处理过程”中。报告组件按引用顺序排列,同一组件不会同时作为报告和过程 挂载,避免重复表单。未被报告引用的过程界面只供回看。

已发布交互界面的普通/协作聊天在最终答复完成、且没有待完成工具时停止本轮原生 生成,防止最终报告之后反复自动修改界面。该收尾不标记后台调查任务完成; 后台执行继续等待其原有运行生命周期与 Server 完成/失败接口。

后台调查执行继续走任务报告与任务展示通道,聊天界面块不构成业务完成或浏览器回执。

正式报告与主工作区

正式报告可携带 ui_blocks?: Array<{ block: AnswerUiBlock; evidence_refs: string[] }>,最多 8 块,总 UTF-8 JSON 不超过 400000 字节。每块绑定报告中的已有证据,Server 验证任务归属;事实字段与审批不由 UI 块替代。组件树与聊天共用 answer-ui@1。例如:

{
  "ui_blocks": [{
    "evidence_refs": ["saved-evidence-id"],
    "block": {
      "version": "answer-ui@1",
      "block_id": "pressure-summary",
      "fallback_text": "已保存记录中的压力为 0.30 MPa。",
      "spec": {
        "root": "pressure",
        "elements": {
          "pressure": { "type": "Metric", "children": [], "props": {
            "label": "压力", "value": "0.30", "unit": "MPa", "source": "已保存监测记录"
          } }
        }
      }
    }
  }]
}

此片段仅展示新增字段,发布时仍需完整报告与真实存在的证据编号。保存沿用 agent-artifacts、报告 JSON、幂等键和 revision;读取沿用报告列表、指定版本、任务详情及 Agent context,不新增写入端点或数据库表。

InvestigationReportBlocks 将正式报告接入 AnswerUiView,证据组件使用保存记录中的摘要、来源、时间与类别。未知版本或无法解析的块展示 fallback,报告固定事实仍可读。报告追问携带 report_revision、reportGeneration 和引用文本;表单先带入会话,确认后才发送。

ExpandableReading 将同一个 React 内容实例移至主工作区,保留图表视图、搜索、行选择、表单草稿。关闭恢复入口焦点,重开恢复阅读位置。主工作区宽度至少 960px 可对照地图,其余宽度在两者之间切换;原地图实例保留。

扩展组件

  1. 在 src/features/agent/answer-ui/catalog.ts 增加严格的 Zod 参数定义、用途描述与必要的数据上限。
  2. 在 answer-ui-view.tsx 注册 React 组件。需要工作台交互时通过 Agent 公共 API 的回调接入,保持依赖方向。
  3. 从本仓库运行 pnpm export:answer-ui-contract,更新相邻 Agent 仓库的 src/chat/answer-ui-catalog.json 和 Server 的 contracts/answer-ui-catalog.json。组件目录是唯一参数定义源,生成文件需随三端一起交付。
  4. 如新组件存在跨字段约束,同时更新三端的协议校验并加边界和交互测试。

导出脚本接受可选目标文件:

node scripts/export-answer-ui-contract.mjs /path/to/agent/src/chat/answer-ui-catalog.json

前端沿用 Zod 3,json-render 0.21 两个包通过作用域 override 使用相同 schema 运行时;实际组件渲染和参数校验已有聚焦测试。升级 json-render 时必须保留这组 兼容性测试,不能只根据包版本判断可用。Agent 原生插件仍使用其 Zod 4 工具边界, 执行后再按生成的 JSON Schema 校验组件参数。

校验边界

三端拒绝未知组件、额外属性、任意脚本/事件定义、缺失引用、循环、重复或游离节点。 每块最多 48 节点、深度 12、完整序列化结果不超过 100000 个 JavaScript UTF-16 代码单元,图表必须对齐且数值有限;表格每行与列数 一致,表单字段名唯一。组件只消费明确的 props,没有动态代码、网络 URL 或任意动作 DSL。 无法解析的历史内容显示该块的 fallback_text。

验证

pnpm lint
pnpm typecheck
pnpm test src/features/agent/answer-ui src/features/workbench/hooks/agent-session-message-state.test.ts
pnpm test:browser tests/browser/agent-answer-ui.e2e.ts tests/browser/agent-start-page.e2e.ts tests/browser/agent-report-workspace.e2e.ts
pnpm build

Agent 仓库:

bun run check
bun test tests/chat/answer-stream-projection.test.ts tests/chat/answer-ui.test.ts tests/routes/chatStream.test.ts tests/routes/taskCollaboration.test.ts tests/runtime/opencode.test.ts
bun run tests/integration/answer-ui-smoke.ts

原生 smoke 使用独立临时数据库,不发模型推理请求。浏览器用例用明确标注的演练 事件验证组件、更新、历史恢复、键盘展开证据、表单提交和 320/375px 布局,不能当作 真实模型已正确选择组件或现场资料已核验的证明。

前端、Agent 与 Server 需同步更新;Agent 进程需重新加载原生插件,Server 需加载新报告 schema。无需新增环境变量、 domain key 或数据库迁移。本轮不重启既有服务;浏览器演练和本地测试不代表运行中的服务已完成同步。

真实模型验收(显式启用)

以下浏览器用例直接连接本机 Agent,输入均为明确的演练资料。工作台地图与项目 读取使用测试数据,聊天、模型工具调用、流式 UI、聊天持久化与表单回传使用真实 服务。每次创建独立验收会话,结束后仅删除该会话,不删除既有用户记录。此用例 会发送模型请求,默认浏览器测试不执行它。

TJWATER_ANSWER_UI_REAL_AGENT_URL=http://127.0.0.1:18787 \
TJWATER_ANSWER_UI_REAL_MODEL_LABEL=专家 \
pnpm test:browser tests/browser/agent-answer-ui-real.e2e.ts --workers=1

先在 Agent 仓库启动隔离实例,可指定独立 INTEGRATION_DATA_DIR 保留联调数据。 可省略模型标签来使用默认模型。该用例不是生产 OAuth 登录或真实供水业务核验。

Vite 统一解析 React/React DOM,Playwright 按端口使用独立的依赖缓存,避免同时 运行的开发服务将旧临时目录的 React 预构建写回测试缓存。

消息入口为 POST /api/v1/responses,采用 Responses 文本输入、Response 输出和标准 SSE 生命周期。前端 ResponsesChatTransport 将网络事件转换为已有 UIMessage 渲染数据;审批、凭据续期、地图动作及 answer-ui 走 tjwater.* 扩展事件,不将 AI SDK 的 UIMessage 流作为网络协议。会话、模型及动作回执等接口统一使用 /api/v1 前缀,原 /agent/chat 路径已移除;Agent 服务和现有会话数据保留。