baa-conductor

git clone 

commit
8c3090b
parent
e7c1701
author
codex@macbookpro
date
2026-03-30 15:45:40 +0800 CST
docs: add BUG-028 for gemini shell final-message parsing
2 files changed,  +154, -0
A bugs/BUG-028-gemini-shell-final-message-raw-protocol.md
+153, -0
  1@@ -0,0 +1,153 @@
  2+# BUG-028: Gemini shell 页经 `conductor` API 发送后,`final_message` 返回协议碎片而非可读回复
  3+
  4+> 提交者:Codex
  5+> 日期:2026-03-30
  6+
  7+## 现象
  8+
  9+当前通过内网 `conductor` 接口对 Gemini shell 页发消息,发送链路本身可以成功:
 10+
 11+- `POST /v1/browser/gemini/send` 返回 `200`
 12+- `proxy.path` 指向 `/_/BardChatUi/data/assistant.lamda.BardFrontendService/StreamGenerate`
 13+- `proxy.status` 为 `200`
 14+
 15+但后续读取 `GET /v1/browser/gemini/current` 时,`final_message` / `messages[0].text` 不是人类可读的 assistant 回复,而是 Gemini 协议层原始片段,例如:
 16+
 17+```text
 18+[[[[2,15,2],1,0,[1774860674,754000000],80,80],[[2,4,2],1,8,[1774865703,894000000],25,23]],"e6fa609c3fa255c0"]
 19+```
 20+
 21+在同一轮验证里,发送的 prompt 明确要求:
 22+
 23+```text
 24+Reply with exactly: conductor-ok-731. No punctuation, no explanation.
 25+```
 26+
 27+预期至少应能在 `current.final_message.raw_text` 或 `messages[].text` 中读到 `conductor-ok-731` 或等价的可读 assistant 文本;当前没有。
 28+
 29+## 触发路径
 30+
 31+```text
 32+POST /v1/browser/actions { action: "tab_reload", platform: "gemini" }
 33+-> POST /v1/browser/actions { action: "request_credentials", platform: "gemini" }
 34+-> Gemini shell 页重新抓到 fresh 凭证
 35+-> POST /v1/browser/gemini/send { prompt: "Reply with exactly: conductor-ok-731..." }
 36+-> upstream StreamGenerate 返回 200
 37+-> Firefox 插件继续上报 browser.final_message
 38+-> conductor /v1/browser/gemini/current 读到的不是 assistant 文本,而是 Gemini 协议碎片
 39+```
 40+
 41+## 根因
 42+
 43+根因还未完全确认,但高概率在 Gemini shell 页的最终消息提取逻辑:
 44+
 45+- `browser.gemini.send` 的发送链路已经通了,说明问题不在 `local-api` 路由分发本身
 46+- `Gemini` 当前页的 `request_hooks` 与凭证刷新后均正常,说明问题不在“没有请求发出去”
 47+- `plugins/baa-firefox/final-message.js` 负责 Gemini 响应解析与 `browser.final_message` 上报
 48+- 当前 live 数据表明它在 shell 页上拿到的是 `batchexecute` / `StreamGenerate` 相关协议片段,但没有稳定提取出最终 assistant 文本
 49+
 50+当前判断更像是:
 51+
 52+- 解析器把 shell 页上的非最终文本帧、元数据帧或 batchexecute 结构误判成了最终消息
 53+- 或者 `shell_page: true` 这一路径缺少稳定的 Gemini DOM / 协议 fallback
 54+
 55+## 复现步骤
 56+
 57+以下步骤可在 `mini` 内网直接复现。
 58+
 59+先确保 Gemini shell 页凭证是 fresh:
 60+
 61+```bash
 62+curl -sS -X POST http://100.71.210.78:4317/v1/browser/actions \
 63+  -H 'content-type: application/json' \
 64+  --data '{"action":"tab_reload","platform":"gemini"}'
 65+
 66+curl -sS -X POST http://100.71.210.78:4317/v1/browser/actions \
 67+  -H 'content-type: application/json' \
 68+  --data '{"action":"request_credentials","platform":"gemini"}'
 69+
 70+curl -sS http://100.71.210.78:4317/v1/browser/gemini/current
 71+```
 72+
 73+验证点:
 74+
 75+- `data.page.credentials.freshness` 应为 `fresh`
 76+- `data.page.credentials.header_count` 应大于 `0`
 77+
 78+然后发一条最小可验证消息:
 79+
 80+```bash
 81+curl -sS -X POST http://100.71.210.78:4317/v1/browser/gemini/send \
 82+  -H 'content-type: application/json' \
 83+  --data '{"prompt":"Reply with exactly: conductor-ok-731. No punctuation, no explanation."}'
 84+```
 85+
 86+2026-03-30 实测关键返回:
 87+
 88+- HTTP 成功
 89+- JSON `ok: true`
 90+- `data.proxy.path = "/_/BardChatUi/data/assistant.lamda.BardFrontendService/StreamGenerate"`
 91+- `data.proxy.status = 200`
 92+
 93+等待数秒后再读:
 94+
 95+```bash
 96+curl -sS http://100.71.210.78:4317/v1/browser/gemini/current
 97+```
 98+
 99+当前实际结果:
100+
101+- `data.final_message.raw_text` 是协议碎片
102+- `data.messages[0].text` 也是协议碎片
103+- 看不到 `conductor-ok-731`
104+
105+## 当前影响
106+
107+- `browser.gemini.send` 不能形成“发出消息 -> 回读可读回复”的稳定闭环
108+- 从 `conductor` 侧无法把 Gemini shell 页当成可靠的文本对话目标来验证
109+- 上层如果依赖 `GET /v1/browser/gemini/current` 获取最终回复,会把协议层噪声误当业务文本
110+- 这不是“Gemini 完全不可发”,而是“发送可用,回复提取失真”
111+
112+## 修复建议
113+
114+### 方案 A(推荐)
115+
116+修正 `plugins/baa-firefox/final-message.js` 对 Gemini shell 页的最终消息提取逻辑:
117+
118+- 明确区分 `StreamGenerate` / `batchexecute` 中的最终 assistant 文本与元数据帧
119+- 对 shell 页增加更严格的候选打分与过滤
120+- 不把纯数组/时间戳/ID 结构误判成最终 assistant 消息
121+
122+### 方案 B
123+
124+当协议解析拿不到稳定文本时,对 Gemini shell 页增加 DOM fallback:
125+
126+- 发送完成后回读当前页面最后一条 assistant 文本
127+- 仅在协议提取结果明显不是自然语言时启用
128+
129+### 方案 C
130+
131+在 `GET /v1/browser/gemini/current` 侧增加“非文本 final_message”保护:
132+
133+- 如果 `raw_text` 看起来是纯协议碎片,则不要把它直接作为 `messages[].text`
134+- 返回明确的 `unparsed_final_message` / `parse_status`,避免上层误用
135+
136+## 严重程度
137+
138+**High**
139+
140+Gemini shell 的发送能力已经暴露为正式 legacy helper 路由,但当前不能稳定拿到可读回复,等于闭环只完成了一半。
141+
142+## 发现时间
143+
144+`2026-03-30 by Codex`
145+
146+## 备注
147+
148+相关代码位置:
149+
150+- Gemini 响应解析与候选提取:[plugins/baa-firefox/final-message.js](/Users/george/code/baa-conductor/plugins/baa-firefox/final-message.js#L487)
151+- Gemini `browser.final_message` 上报入口:[plugins/baa-firefox/final-message.js](/Users/george/code/baa-conductor/plugins/baa-firefox/final-message.js#L869)
152+- conductor 接收 `browser.final_message`:[apps/conductor-daemon/src/firefox-ws.ts](/Users/george/code/baa-conductor/apps/conductor-daemon/src/firefox-ws.ts#L1232)
153+- Gemini legacy helper 路由:[apps/conductor-daemon/src/local-api.ts](/Users/george/code/baa-conductor/apps/conductor-daemon/src/local-api.ts#L596)
154+- 当前测试只覆盖 stubbed happy path,未覆盖 live shell 协议碎片场景:[apps/conductor-daemon/src/index.test.js](/Users/george/code/baa-conductor/apps/conductor-daemon/src/index.test.js#L3418)
M bugs/README.md
+1, -0
1@@ -15,6 +15,7 @@ bugs/
2 
3 - `BUG-026`:[`BUG-026-artifact-repo-root-fallback-broken.md`](./BUG-026-artifact-repo-root-fallback-broken.md)
4 - `BUG-027`:[`BUG-027-startup-plugin-diagnostic-events-lost-before-ws-open.md`](./BUG-027-startup-plugin-diagnostic-events-lost-before-ws-open.md)
5+- `BUG-028`:[`BUG-028-gemini-shell-final-message-raw-protocol.md`](./BUG-028-gemini-shell-final-message-raw-protocol.md)
6 - `OPT-002`:[`OPT-002-executor-timeout.md`](./OPT-002-executor-timeout.md)
7 - `OPT-003`:[`OPT-003-policy-configurable.md`](./OPT-003-policy-configurable.md)
8 - `OPT-004`:[`OPT-004-final-message-claude-sse-fallback.md`](./OPT-004-final-message-claude-sse-fallback.md)