diff --git a/_bmad/implementation-artifacts/spec-json-render-migration-official.md b/_bmad/implementation-artifacts/spec-json-render-migration-official.md new file mode 100644 index 0000000..e6fc81a --- /dev/null +++ b/_bmad/implementation-artifacts/spec-json-render-migration-official.md @@ -0,0 +1,484 @@ +# json-render 官方架构迁移规格(扩展版) + +**项目**: 模板 240 - AI MCP Web UI +**当前版本**: @json-render/* 0.14.1 +**创建日期**: 2026-03-25 +**状态**: ready-for-dev +**批准日期**: 2026-03-25 +**批准者**: 外层 BMAD 专家 + +--- + +## 批准记录 + +| 日期 | 决策 | 批准者 | 理由 | +|------|------|--------|------| +| 2026-03-25 | ✅ 批准 | 外层 BMAD 专家 | Intent 包含所有 4 个高优先级改进,Tasks 清晰可执行,Code Map 准确 | + +--- + +## 执行摘要 + +### 问题陈述 + +当前项目使用 Vercel AI SDK 的 `useChat` hook,但未充分利用 `@json-render/react` 的官方 API。存在以下差距: + +| 领域 | 当前实现 | 官方推荐 | 差距 | +|------|----------|----------|------| +| 前端 Hook | `useChat` from `ai/react` | `useChatUI` from `@json-render/react` | ❌ 未使用官方 Hook | +| 后端流式 | `streamText` + `toTextStreamResponse()` | `pipeJsonRender` + `streamText` | ❌ 未使用 pipeJsonRender | +| 消息解析 | 手动解析 SpecStream | `useChatUI` 自动解析 | ❌ 自定义解析逻辑 | +| Action 处理 | 自定义 `ActionProvider` | `JSONUIProvider` handlers | ⚠️ 部分冗余 | +| AI 指令 | 简单的 catalog.prompt() | catalog.prompt() with mode | ⚠️ 未充分优化 | + +### 迁移收益 + +- **代码简化**: 减少约 500 行自定义解析逻辑 +- **类型安全**: 使用官方类型定义 +- **官方特性**: 获得 `$computed`、`watch`、`repeat` 支持 +- **维护性**: 跟随官方更新,减少维护成本 +- **性能优化**: 官方优化的流式解析管道 + +--- + +## Intent + +将模板 240 的 json-render 实现从自定义架构迁移到官方推荐架构,包括: + +1. **前端 Hook 迁移**: 从 `useChat` (Vercel AI SDK) 迁移到 `useChatUI` (@json-render/react) +2. **后端流式优化**: 集成 `pipeJsonRender` 模式处理 SpecStream +3. **Catalog Prompt 集成**: 在 AI agent 指令中充分使用 catalog 能力 +4. **Action 处理简化**: 使用官方 JSONUIProvider 的 handlers 机制 + +--- + +## Approach + +### 阶段 1: 依赖验证与架构准备 + +**目标**: 确认当前依赖版本支持所需功能 + +| 步骤 | 描述 | 文件 | +|------|------|------| +| 1.1 | 验证 @json-render/* 版本 | package.json | +| 1.2 | 确认 Vercel AI SDK 集成 | package.json | + +### 阶段 2: 前端 Hook 迁移 + +**目标**: 从 `useChat` 迁移到 `useChatUI` + +| 步骤 | 描述 | 文件 | 风险 | +|------|------|------|------| +| 2.1 | 替换 useChat 为 useChatUI | app/page.tsx | 中 | +| 2.2 | 更新消息渲染逻辑 | components/ChatMessage.tsx | 中 | +| 2.3 | 更新 ChatInput 集成 | app/page.tsx | 低 | +| 2.4 | 移除 action-context 依赖 | lib/action-context.tsx | 低 | + +### 阶段 3: 后端流式优化 + +**目标**: 集成 `pipeJsonRender` 模式 + +| 步骤 | 描述 | 文件 | 风险 | +|------|------|------|------| +| 3.1 | 集成 pipeJsonRender | app/api/chat/route.ts | 低 | +| 3.2 | 验证流式输出格式 | app/api/chat/route.ts | 低 | + +### 阶段 4: Catalog Prompt 集成 + +**目标**: 优化 AI agent 指令 + +| 步骤 | 描述 | 文件 | 风险 | +|------|------|------|------| +| 4.1 | 优化 system prompt | app/api/chat/route.ts | 低 | +| 4.2 | 验证 AI 输出质量 | - | 低 | + +### 阶段 5: Action 处理简化 + +**目标**: 使用官方 handlers 机制 + +| 步骤 | 描述 | 文件 | 风险 | +|------|------|------|------| +| 5.1 | 定义 handlers 对象 | app/page.tsx | 低 | +| 5.2 | 更新 JSONUIProvider | components/JsonRenderer.tsx | 低 | +| 5.3 | 清理 ActionProvider | app/page.tsx | 低 | + +--- + +## Code Map + +### 前端文件 + +| 文件路径 | 变更类型 | 描述 | +|----------|----------|------| +| `frontend-v2/app/page.tsx` | **修改** | 迁移 useChat → useChatUI,添加 handlers | +| `frontend-v2/app/api/chat/route.ts` | **修改** | 集成 pipeJsonRender,优化 system prompt | +| `frontend-v2/components/ChatMessage.tsx` | **修改** | 简化消息渲染逻辑 | +| `frontend-v2/components/ChatInput.tsx` | **修改** | 更新 send/stop 处理 | +| `frontend-v2/components/JsonRenderer.tsx` | **修改** | 添加 JSONUIProvider handlers | +| `frontend-v2/lib/hooks.ts` | **修改** | 移除 useChat 相关注释 | +| `frontend-v2/lib/action-context.tsx` | **删除** | 不再需要自定义 ActionProvider | +| `frontend-v2/lib/registry.tsx` | **修改** | 更新组件使用 handlers 而非 emit | + +### 后端文件 + +| 文件路径 | 变更类型 | 描述 | +|----------|----------|------| +| `backend/app_fastapi.py` | **无变更** | FastAPI 后端暂不修改 | + +### 配置文件 + +| 文件路径 | 变更类型 | 描述 | +|----------|----------|------| +| `frontend-v2/package.json` | **验证** | 确认依赖版本 | +| `frontend-v2/next.config.js` | **可选** | 添加 serverComponentsExternalPackages | + +--- + +## Tasks + +### Task 1: 依赖验证 + +**描述**: 验证当前依赖版本支持所需功能 + +**步骤**: +1. 检查 `frontend-v2/package.json` +2. 确认 `@json-render/core` >= 0.14.1 +3. 确认 `@json-render/react` >= 0.14.1 +4. 确认 `ai` >= 6.0.0 + +**验收标准**: +- [ ] 所有依赖版本符合要求 +- [ ] 无需升级(当前 0.14.1 已支持) + +--- + +### Task 2: 前端 Hook 迁移 - useChat → useChatUI + +**描述**: 将前端 Hook 从 Vercel AI SDK 的 `useChat` 迁移到 `@json-render/react` 的 `useChatUI` + +**文件**: `frontend-v2/app/page.tsx` + +**当前代码**: +```typescript +import { useChat } from 'ai/react'; + +const { messages, input, handleInputChange, handleSubmit, isLoading, stop } = useChat({ + api: '/api/chat', + headers: async () => { + const tokens = mcpTokenManager.getAllTokens(); + const enabledMcpList = mcpTokenManager.getEnabledMcpList(); + return { + 'X-MCP-Tokens': JSON.stringify(tokens), + 'X-MCP-Enabled': JSON.stringify(enabledMcpList), + }; + }, +}); +``` + +**目标代码**: +```typescript +import { useChatUI } from '@json-render/react'; + +const { + messages, // 包含 text 和 specs + input, + handleInputChange, + isStreaming, + send, // 替代 handleSubmit + stop +} = useChatUI({ + api: '/api/chat', + headers: async () => { + const tokens = mcpTokenManager.getAllTokens(); + const enabledMcpList = mcpTokenManager.getEnabledMcpList(); + return { + 'X-MCP-Tokens': JSON.stringify(tokens), + 'X-MCP-Enabled': JSON.stringify(enabledMcpList), + }; + }, +}); +``` + +**验收标准**: +- [ ] useChatUI 正确导入 +- [ ] messages 包含 text 和 specs 字段 +- [ ] send() 方法正确发送消息 +- [ ] MCP Token 正确传递 +- [ ] 聊天功能正常工作 + +--- + +### Task 3: 更新消息渲染逻辑 + +**描述**: 简化 ChatMessage 组件,使用 useChatUI 自动解析的 specs + +**文件**: `frontend-v2/components/ChatMessage.tsx` + +**关键变化**: +- 移除 `isSpecStreamFormat()` 检测 +- 移除 `compileSpecFromStream()` 编译 +- 移除 `extractRenderableElements()` 提取 +- 直接使用 `specs` prop + +**目标接口**: +```typescript +interface ChatMessageProps { + role: 'user' | 'assistant'; + text?: string; // 分离的文本内容 + specs?: Spec[]; // 直接从 useChatUI 获取 + isStreaming?: boolean; +} +``` + +**验收标准**: +- [ ] 移除所有手动解析逻辑(约 100 行) +- [ ] specs 正确渲染 +- [ ] Markdown 正确渲染 +- [ ] 流式状态正确显示 + +--- + +### Task 4: 更新 ChatInput 组件 + +**描述**: 更新 ChatInput 使用 useChatUI 的 send() 方法 + +**文件**: `frontend-v2/app/page.tsx` + +**当前代码**: +```typescript + +``` + +**目标代码**: +```typescript + send(message)} + isLoading={isStreaming} + onStop={stop} +/> +``` + +**验收标准**: +- [ ] send() 方法正确发送消息 +- [ ] stop() 方法正确中断流式输出 +- [ ] 输入框状态正确管理 + +--- + +### Task 5: 后端流式优化 - 集成 pipeJsonRender + +**描述**: 在 Next.js API Route 中集成 `pipeJsonRender` 处理混合流 + +**文件**: `frontend-v2/app/api/chat/route.ts` + +**当前代码**: +```typescript +const result = streamText({ + model: anthropicModel, + system: catalog.prompt({ mode: 'inline' }), + messages, + tools: allTools, + temperature: 0.7, +}); + +return result.toTextStreamResponse(); +``` + +**目标代码**: +```typescript +import { pipeJsonRender } from '@json-render/core/server'; + +const result = streamText({ + model: anthropicModel, + system: catalog.prompt({ mode: 'inline' }), + messages, + tools: allTools, + temperature: 0.7, +}); + +// 使用 pipeJsonRender 处理混合流 +const stream = result.toTextStreamResponse(); +return pipeJsonRender(stream); +``` + +**验收标准**: +- [ ] pipeJsonRender 正确导入 +- [ ] 流式响应正常工作 +- [ ] MCP 工具调用正常 + +--- + +### Task 6: Catalog Prompt 集成 + +**描述**: 优化 AI agent 指令,确保 catalog.prompt() 充分利用 + +**文件**: `frontend-v2/app/api/chat/route.ts` + +**当前代码**: +```typescript +system: catalog.prompt({ mode: 'inline' }), +``` + +**验证项**: +- [ ] mode 参数正确设置为 'inline' +- [ ] catalog 定义包含所有组件 +- [ ] AI 能够正确输出组件 spec + +**验收标准**: +- [ ] AI 正确识别可用组件 +- [ ] AI 正确输出 SpecStream 格式 +- [ ] 组件渲染正常 + +--- + +### Task 7: Action 处理简化 - 使用 handlers + +**描述**: 使用 JSONUIProvider 的 handlers 机制替代自定义 ActionProvider + +**文件**: `frontend-v2/app/page.tsx`, `frontend-v2/components/JsonRenderer.tsx` + +**当前代码**: +```typescript +import { ActionProvider } from '@/lib/action-context'; + + +
+ {messages.map((msg, idx) => ( + + ))} +
+
+``` + +**目标代码**: +```typescript +// 定义 handlers +const handlers = { + sendMessage: async (params: { message: string }) => { + send(params.message); + }, + selectNovel: async (params: { id: string; title: string }) => { + send(`查看小说:${params.title}`); + }, + copy: async (params: { text: string }) => { + await navigator.clipboard.writeText(params.text); + }, +}; + + +
+ {messages.map((msg, idx) => ( + + ))} +
+
+``` + +**验收标准**: +- [ ] ActionProvider 移除 +- [ ] handlers 正确定义 +- [ ] 组件交互正常工作 +- [ ] SuggestionButtons 正确发送消息 + +--- + +### Task 8: 清理废弃代码 + +**描述**: 删除迁移后不再需要的文件和代码 + +**删除文件**: +- [ ] `frontend-v2/lib/action-context.tsx` + +**清理代码**: +- [ ] `frontend-v2/lib/hooks.ts` - 移除 useChat 相关注释 +- [ ] `frontend-v2/lib/registry.tsx` - 移除 useActionEmit 依赖 + +**验收标准**: +- [ ] 无编译错误 +- [ ] 无运行时错误 +- [ ] 功能完整 + +--- + +## 验收标准 + +### 功能验收 + +| 功能 | 描述 | 验证方法 | +|------|------|----------| +| 聊天发送 | 用户可以发送消息 | 发送 "你好" | +| 流式输出 | AI 响应实时显示 | 发送长文本问题 | +| 组件渲染 | MCP 工具结果正确渲染 | 发送 "获取小说列表" | +| 组件交互 | 组件交互事件正常 | 点击小说卡片 | +| MCP Token | Token 正确传递到后端 | 登录后调用 MCP 工具 | + +### 技术验收 + +| 指标 | 当前 | 目标 | 验证方法 | +|------|------|------|----------| +| 代码行数 | ~1500 | ~1000 | cloc | +| 依赖大小 | ~120KB | ~95KB | npm ls | +| 渲染性能 | 基线 | +15% | Lighthouse | +| 类型覆盖 | 部分 | 完整 | tsc --noEmit | + +### 文档验收 + +- [ ] CLAUDE.md 更新 +- [ ] JSON_RENDER_USAGE.md 更新 +- [ ] 迁移文档创建 + +--- + +## 风险与缓解 + +| 风险 | 概率 | 影响 | 缓解措施 | +|------|------|------|----------| +| useChatUI API 变化 | 低 | 高 | 保留旧代码作为回滚 | +| MCP Token 传递失效 | 中 | 高 | 充分测试 headers 函数 | +| 组件渲染异常 | 中 | 中 | 渐进式迁移,逐个验证 | +| 性能回归 | 低 | 低 | 基准测试对比 | + +--- + +## 回滚方案 + +### 快速回滚 + +```bash +# 1. 恢复 page.tsx +git checkout HEAD -- frontend-v2/app/page.tsx + +# 2. 恢复 ChatMessage.tsx +git checkout HEAD -- frontend-v2/components/ChatMessage.tsx + +# 3. 恢复 api/chat/route.ts +git checkout HEAD -- frontend-v2/app/api/chat/route.ts +``` + +### 完整回滚 + +```bash +git reset --hard HEAD +``` + +--- + +## 参考资源 + +- [json-render 官方文档](https://json-render.com) +- [Vercel AI SDK 文档](https://sdk.vercel.ai) +- [useChatUI API 参考](https://json-render.com/docs/hooks/use-chat-ui) +- [pipeJsonRender 服务器端集成](https://json-render.com/docs/server/pipe-json-render) + +--- + +**版本历史**: +- v1.0 (2026-03-25): 初始规格创建 - 扩展版