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)