# Clarify 工具前端交互 + 微信降级 实现计划 > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. > **Post-task review:** After each task commit, run the `simplify` skill to review changed code for reuse, quality, and efficiency. **Goal:** 在前端 Agent 对话页面实现 clarify 工具的交互 UI,并在后端为微信渠道实现纯文本降级方案。 **Architecture:** 收到 `clarify_request` WS 事件时,在聊天流中插入 `role='clarify'` 的特殊消息,由新建的 `clarify-card.vue` 组件渲染为交互卡片(选项按钮 + 自定义输入)。用户回答后通过 WS 发送 `clarify_response`,卡片变为只读。微信端通过 `agent_executor.ts` 透传 `onClarifyRequest` 回调,`agent_channel.ts` 用 pendingClarify Map 阻塞等待用户回复。 **Tech Stack:** Vue 3 + TypeScript + Element Plus + Pinia + Socket.IO (前端) / Midway.js + TypeScript (后端) **Base path (前端):** `packages/frontend/src/modules/agent` **Base path (后端):** `packages/backend/src/modules/netaclaw` --- ### Task 1: 类型定义扩展 **Files:** - Modify: `packages/frontend/src/modules/agent/types/index.d.ts` - [ ] **Step 1: 扩展 ChatMessage.role 联合类型** 在 `types/index.d.ts` 第 21 行,`ChatMessage.role` 联合追加 `'clarify'`: ```typescript // 旧: role: 'user' | 'assistant' | 'tool' | 'system'; // 新: role: 'user' | 'assistant' | 'tool' | 'system' | 'clarify'; ``` - [ ] **Step 2: 扩展 WSClientMessage.type 联合类型并追加字段** 在 `types/index.d.ts` 第 131-136 行,修改 `WSClientMessage`: ```typescript // 旧: export interface WSClientMessage { type: 'chat' | 'ping'; sessionId?: string; content?: string; agentId?: number; } // 新: export interface WSClientMessage { type: 'chat' | 'ping' | 'clarify_response'; sessionId?: string; content?: string; agentId?: number; requestId?: string; answer?: string; } ``` - [ ] **Step 3: 扩展 WSServerEvent.type 联合类型** 在 `types/index.d.ts` 第 142 行,`WSServerEvent.type` 联合追加 `'clarify_request'`: ```typescript // 旧: type: 'token' | 'thinking' | 'tool_call' | 'tool_result' | 'skill_start' | 'skill_end' | 'progress' | 'token_update' | 'done' | 'error' | 'pong' | 'todo_update' | 'thinking_delta' | 'thinking_done'; // 新: type: 'token' | 'thinking' | 'tool_call' | 'tool_result' | 'skill_start' | 'skill_end' | 'progress' | 'token_update' | 'done' | 'error' | 'pong' | 'todo_update' | 'thinking_delta' | 'thinking_done' | 'clarify_request'; ``` - [ ] **Step 4: 新增 ClarifyRequestData 和 ClarifyMessageMeta 接口** 在 `types/index.d.ts` 文件末尾(`TokenUpdateEvent` 之后)追加: ```typescript // === Clarify 工具类型 === export interface ClarifyRequestData { requestId: string; question: string; choices?: string[]; } export interface ClarifyMessageMeta { requestId: string; choices?: string[]; status: 'pending' | 'answered'; answer?: string; } ``` - [ ] **Step 5: Commit** ```bash git add packages/frontend/src/modules/agent/types/index.d.ts git commit -m "feat(agent): extend WS types for clarify tool interaction" ``` --- ### Task 2: Store 变更 — 处理 clarify_request + 发送 clarify_response **Files:** - Modify: `packages/frontend/src/modules/agent/store/chat.ts` - [ ] **Step 1: 在 handleWSEvent 中新增 clarify_request 提前处理** 在 `store/chat.ts` 的 `handleWSEvent` 函数中,clarify_request 不依赖 assistantMsg,需要在现有的 `if (!loading.value ...)` 和 `const assistantMsg = ...` 守卫之前处理。在函数开头(第 246 行 `function handleWSEvent` 之后)插入: ```typescript function handleWSEvent(event: WSServerEvent) { // clarify_request 不依赖 assistantMsg,提前处理 if (event.type === 'clarify_request') { const data = event.data; if (data?.requestId && data?.question) { messages.value.push({ role: 'clarify', content: data.question, metadata: { requestId: data.requestId, choices: data.choices || [], status: 'pending', answer: undefined, }, }); _onTokenCbs.forEach(cb => cb()); } return; } // 以下是原有逻辑,不变 if (!loading.value && event.type !== 'done') return; const assistantMsg = messages.value[messages.value.length - 1]; if (!assistantMsg || assistantMsg.role !== 'assistant') return; switch (event.type) { // ... 现有 cases 不变 ... } } ``` - [ ] **Step 2: 新增 sendClarifyResponse 函数** 在 `store/chat.ts` 的 `setThinkLevel` 函数之后(第 562 行后)追加: ```typescript /** * 发送 clarify 回答 */ function sendClarifyResponse(requestId: string, answer: string) { const msg = messages.value.find( m => m.role === 'clarify' && m.metadata?.requestId === requestId ); if (msg && msg.metadata) { msg.metadata.status = 'answered'; msg.metadata.answer = answer; } if (wsInstance) { wsInstance.send({ type: 'clarify_response', sessionId: sessionId.value, requestId, answer, } as any); } } ``` - [ ] **Step 3: 在 return 对象中导出 sendClarifyResponse** 在 `store/chat.ts` 第 738 行 `init` 之后追加 `sendClarifyResponse`: ```typescript return { // ... 现有导出 ... init, sendClarifyResponse, }; ``` - [ ] **Step 4: Commit** ```bash git add packages/frontend/src/modules/agent/store/chat.ts git commit -m "feat(agent): handle clarify_request WS event and send clarify_response" ``` --- ### Task 3: clarify-card.vue 交互卡片组件 **Files:** - Create: `packages/frontend/src/modules/agent/components/clarify-card.vue` - [ ] **Step 1: 创建 clarify-card.vue 模板和脚本** 创建 `packages/frontend/src/modules/agent/components/clarify-card.vue`: ```vue ``` - [ ] **Step 2: 添加样式** 在同一文件 `` 之后追加样式(遵循 todo-card 的卡片风格): ```vue ``` - [ ] **Step 3: Commit** ```bash git add packages/frontend/src/modules/agent/components/clarify-card.vue git commit -m "feat(agent): add clarify-card interactive component" ``` --- ### Task 4: 集成到聊天视图 **Files:** - Modify: `packages/frontend/src/modules/agent/views/chat.vue` - Modify: `packages/frontend/src/modules/agent/components/message-item.vue` - [ ] **Step 1: chat.vue — 导入 ClarifyCard 组件** 在 `views/chat.vue` 的 `