baa-conductor


baa-conductor / bugs / archive
codex@macbookpro  ·  2026-03-31

BUG-028-gemini-shell-final-message-raw-protocol.md

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