baa-conductor

git clone 

commit
3c1e65e
parent
26bd7b6
author
im_wower
date
2026-03-28 02:15:05 +0800 CST
docs(claude): BUG-022 final-message.js missing Claude platform — critical blocker for BAA instruction loop
1 files changed,  +131, -0
A bugs/BUG-022-final-message-claude-missing.md
+131, -0
  1@@ -0,0 +1,131 @@
  2+# BUG-022: final-message.js 缺少 Claude 平台支持,有机回复永远不会被捕获
  3+
  4+> 提交者:Claude(代码审查 + 实测验证)
  5+> 日期:2026-03-27
  6+
  7+## 现象
  8+
  9+用户在 mini 的 Firefox 上打开 Claude 对话,发消息请求 AI 输出 baa 代码块。Claude 正常回复了,但 conductor 的 instruction_ingest 没有收到任何 Claude 平台的 final_message。recent_ingests 全是 Gemini,0 条 Claude。
 10+
 11+## 根因
 12+
 13+`plugins/baa-firefox/final-message.js` 的 `isRelevantStreamUrl` 函数缺少 Claude 分支:
 14+
 15+```javascript
 16+function isRelevantStreamUrl(platform, url) {
 17+    if (platform === "chatgpt") {
 18+      return lower.includes("/conversation");
 19+    }
 20+    if (platform === "gemini") {
 21+      return lower.includes("streamgenerate") || ...;
 22+    }
 23+    return false;  // ← Claude 走到这里,永远 false
 24+}
 25+```
 26+
 27+`observeSse` 第一行就返回 null:
 28+```javascript
 29+if (!isRelevantStreamUrl(state.platform, detail.url)) {
 30+  return null;  // Claude 的 SSE 永远不会被处理
 31+}
 32+```
 33+
 34+同时,`observeSse` 最终提取候选时也没有 Claude 分支:
 35+```javascript
 36+const finalCandidate = state.platform === "chatgpt"
 37+  ? extractChatgptCandidateFromText(...)
 38+  : extractGeminiCandidateFromText(...);  // Claude 走 Gemini 分支,无法提取
 39+```
 40+
 41+## 缺失的三样东西
 42+
 43+1. `isRelevantStreamUrl` 缺少 Claude case:URL 包含 `/completion`
 44+2. `extractClaudeCandidateFromText` 不存在:需要解析 Claude SSE 格式
 45+3. `observeSse` 的候选提取缺少 Claude 分支
 46+
 47+## Claude SSE 格式
 48+
 49+```
 50+event: completion
 51+data: {"type":"completion","id":"chatcompl_xxx","completion":" hello","stop_reason":null,...}
 52+
 53+event: completion
 54+data: {"type":"completion","id":"chatcompl_xxx","completion":" world","stop_reason":"end_turn",...}
 55+```
 56+
 57+- `completion` 字段拼接 = 完整回复文本
 58+- `id` 字段 = assistant message id
 59+- URL 格式:`/api/organizations/{org}/chat_conversations/{conv_id}/completion`
 60+  → conv_id 可从 URL 提取
 61+
 62+## 修复
 63+
 64+### 1. isRelevantStreamUrl 加 Claude
 65+
 66+```javascript
 67+if (platform === "claude") {
 68+  return lower.includes("/completion");
 69+}
 70+```
 71+
 72+### 2. 新增 extractClaudeCandidateFromText
 73+
 74+```javascript
 75+function extractClaudeConversationIdFromUrl(url) {
 76+  const match = String(url || "").match(
 77+    /\/chat_conversations\/([a-f0-9-]+)\/completion/i
 78+  );
 79+  return match?.[1] || null;
 80+}
 81+
 82+function extractClaudeCandidateFromText(text, context) {
 83+  let fullText = "";
 84+  let assistantMessageId = null;
 85+
 86+  for (const line of String(text || "").split("\n")) {
 87+    const trimmed = line.trim();
 88+    if (!trimmed.startsWith("data:")) continue;
 89+    const payload = parseJson(trimmed.slice(5).trimStart());
 90+    if (!payload || payload.type !== "completion") continue;
 91+    if (typeof payload.completion === "string") {
 92+      fullText += payload.completion;
 93+    }
 94+    if (!assistantMessageId && payload.id) {
 95+      assistantMessageId = String(payload.id);
 96+    }
 97+  }
 98+
 99+  const rawText = normalizeMessageText(fullText);
100+  if (!rawText) return null;
101+
102+  return {
103+    assistantMessageId: assistantMessageId || null,
104+    conversationId: extractClaudeConversationIdFromUrl(context.url)
105+      || extractClaudeConversationIdFromUrl(context.pageUrl),
106+    rawText
107+  };
108+}
109+```
110+
111+### 3. observeSse 加 Claude 分支
112+
113+```javascript
114+let finalCandidate;
115+if (state.platform === "chatgpt") {
116+  finalCandidate = extractChatgptCandidateFromText(fullText, context);
117+} else if (state.platform === "claude") {
118+  finalCandidate = extractClaudeCandidateFromText(fullText, context);
119+} else {
120+  finalCandidate = extractGeminiCandidateFromText(fullText, context);
121+}
122+```
123+
124+## 严重度
125+
126+**Critical** — Claude 是 Phase 1 的主要平台,没有这个修复整个 BAA 指令系统的端到端闭环对 Claude 完全不工作
127+
128+## 验收
129+
130+1. 用户在 Firefox 上的 Claude 对话中发消息
131+2. Claude 回复后,conductor 的 `instruction_ingest.recent_ingests` 出现 `platform: "claude"` 的记录
132+3. 如果回复包含 baa 代码块,`status` 应为 `"executed"` 而非 `"ignored_no_instructions"`