feat(spec): json-render v0.15.0 官方架构迁移规格(扩展版)

- Intent: 4 个高优先级改进(useChatUI、pipeJsonRender、Catalog Prompt、Action 简化)
- Tasks: 8 个详细任务,包含代码示例和验收标准
- Code Map: 7 个前端文件变更
- 验收标准: 功能/技术/文档三维度

批准记录:
- 批准者: 外层 BMAD 专家
- 批准日期: 2026-03-25
- 批准理由: Intent 包含所有 4 个高优先级改进,Tasks 清晰可执行

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
This commit is contained in:
Claude AI
2026-03-25 04:51:26 +00:00
parent 69f8c60592
commit 6e69405aca

View File

@@ -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
<ChatInput
value={input}
onChange={handleInputChange}
onSubmit={handleSubmit}
isLoading={isLoading}
onStop={stop}
/>
```
**目标代码**:
```typescript
<ChatInput
value={input}
onChange={handleInputChange}
onSubmit={(message) => 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';
<ActionProvider actions={actionContext()}>
<div className="flex-1 overflow-y-auto">
{messages.map((msg, idx) => (
<ChatMessage key={idx} {...msg} />
))}
</div>
</ActionProvider>
```
**目标代码**:
```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);
},
};
<JSONUIProvider registry={registry} handlers={handlers}>
<div className="flex-1 overflow-y-auto">
{messages.map((msg, idx) => (
<ChatMessage key={idx} {...msg} />
))}
</div>
</JSONUIProvider>
```
**验收标准**:
- [ ] 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): 初始规格创建 - 扩展版