Skip to content

[PR] fix: show full OpenCode V2 reports without model context pollution - #5316

Merged
ranxianglei merged 5 commits into
ranxianglei:masterfrom
FineFenng:2026-10-31_opencode-report-filter
Nov 4, 2026
Merged

ranxianglei merged 5 commits into
ranxianglei:masterfrom
FineFenng:2026-10-31_opencode-report-filter

Conversation

@FineFenng

Copy link
Copy Markdown
Contributor

OpenCode V2 status reports use a capped synthetic description, which OpenChamber renders as a title. Put the complete /acp and /acp-cache reports in the message body while preserving the existing capped terminal notice. Exclude automatically generated reports from outgoing model requests by their dedicated message IDs; manually pasted reports remain available to the model.

The context, compaction, title and generate hooks filter only user-role messages whose IDs match the plugin report namespace. IDs survive host restarts and OpenCode's session-to-model projection. If context hooks cannot be registered, commands retain the existing inert body. Both launcher and native mode share this setup; plain proxy mode is unaffected.

Validation:

  • OpenCode V2 targeted suite: 34 passed, 0 failed (inherited BILLION_CONTEXT_NATIVE/BILLION_CONTEXT_PROXY removed from the test environment).
  • Build passed.
  • TypeScript typecheck passed after building and copying the local file dependencies into node_modules (npm ci installed copies before their dist existed).
  • Real OpenCode 2.2.5 against a local mock upstream: the complete automatic report remains in session history, is absent from the captured model request, and manually pasted report text is present. No paid model calls.

Follow-up to #1612. Fixes #5315.

@ranxianglei ranxianglei changed the title fix: show full OpenCode V2 reports without model context pollution [PR] fix: show full OpenCode V2 reports without model context pollution Oct 31, 2026
@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

(ai: vllm-qwen/qwen3.8-27b)

查重: 不重复。 对应 GitHub PR #5316(分支 2026-10-31_opencode-report-filter,单 commit aea775f,2 文件 +97/−20)。检索 open+closed issue/PR(镜像与 GitHub 两侧)无并行工作触碰 OpenCode V2 报告渲染面;近邻条目均不同机制:#1612(已合并的前置件,只改 description 截断形态)、#3615(#5315 明确说明不含本显示/过滤变更)、当前 open PR 列表中无其他 PR 触碰 src/agent/opencode-v2.ts。

标签: bug + opencodev2 + scope/ui + p3 —— 缺陷类(OpenChamber 里报告被截断且读起来费劲);涉及客户端为 OpenCode V2 车道;改动面是报告展示面(body vs description)及其配套过滤;p3——纯展示问题,TUI 通知与 Web UI 深链绕行都在,无数据丢失、无缓存泄露。

正在做独立审核(方向、回归面、代码质量、测试有效性),已本地复跑定向套件(34/34 绿)与 typecheck;结论按结构化八问跟进。

The msg_bili_report_ literal appeared twice (filter regex + id template);
extract BILI_REPORT_ID_PREFIX and derive BILI_REPORT_ID_RE from it so the
minter and the filter can never drift apart (ranxianglei#5316 review).
@ranxianglei ranxianglei added bug Something isn't working opencodev2 p3 scope/ui labels Oct 31, 2026
@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

(ai: vllm-qwen/qwen3.8-27b)

PR #5316 审核结论(独立审核,八问)

1. 是什么问题
OpenChamber 把 OpenCode V2 合成消息的 description 当标题、body 当正文渲染;而 bili 此前(#1602/#1612)把完整报告放进 description(1024/8192 字符截断)、body 放一行无效文本——因为当时假设「TUI 只渲染 description」。结果在 body-rendering 客户端上报告只剩一条截断的标题,全文只能靠 Web UI 深链兜。

2. 什么原因导致的
根因是字段布局与宿主渲染契约不匹配:bili 用单一布局(description=内容,body=无效行)同时服务两类客户端,而 OpenChamber 的映射恰好相反。表面现象是「OpenChamber 里报告难读且被截断」,病因是「一份内容没有同时放在两个客户端各自读取的位置」。

3. 影响范围与严重程度
仅 OpenCode V2 + body-rendering 客户端(OpenChamber 等)看 /acp、/acp-cache 的用户;TUI 用户显示不变(仍是截断通知)。纯展示缺陷,p3——无数据丢失、无缓存泄露、无不可用,且有 Web UI 深链绕行。

4. 怎么修复的
两层互补:① 全文进消息 body(```text 围栏包裹),description` 保留原截断通知不动;② 自动生成的报告带专属 ID 命名空间 `msg_bili_report_<32hex>`,注册 context/compaction/title/generate 四个 session hook,按「user 角色 + 精确 ID 格式」把这类消息从出站模型请求中剔除。两层缺一不可:第一层解决「读得到」,第二层解决「不发模型」。hook 注册失败时整体回退旧行为(无效 body、不带 id)——降级不猜。手动粘贴的报告不受过滤影响(只认专属命名空间)。

5. 是否有回归问题(逐项审过既有行为)

  • TUI 显示路径(description 截断/Web UI 链接前置/整行保留):逻辑未动,opencodev2 /acp截断问题如何处理 #1602 的 fitNoticeDescription 钉测全绿(本地复跑 34/34);
  • 模型可见 body:有意变更——旧=单行无效文本 → 新(hook 可用时)=完整报告但被 hook 从出站请求剔除;hook 不可用=回到旧无效行。已按披露要求写明旧值→新值+原因;
  • 出站请求形状:代理端从来看不到这些报告消息(host 侧预过滤),kernel 账本/reconcile/prefix cache 不受影响;手动粘贴的报告保留可被模型引用(需求明确要求);
  • 文件内其余路径(http.request hook、tool transform、event subscribe、fork adopt)未触碰;plain proxy 模式、V1 车道、其他车道不在 diff 内;
  • 残留风险(记录,非拦截):方案依赖 OpenCode 把合成消息的自定义 ID 原样带入模型投影(作者已在真机 2.2.5 实测,含重启存活)。若某更老版本接受这四个 hook 却不保留自定义 ID,过滤器落空,完整报告会进入模型上下文(是污染不是损坏)。建议后续如遇到再加版本门。

6. 是否破坏缓存
不影响 bili prefix cache:代理侧视图里报告消息从未出现,每轮出站一致地排除同一组 ID,历史对代理保持逐字稳定。OpenCode 自身的 compaction/title 输入同样被过滤,报告内容不会渗入摘要或会话标题。

7. 是否改了设计方向
没有。仍属 agent 侧渲染 + host hook 过滤;不动 proxy wire、不动 kernel、不动配置面、不动持久化。launcher 与 native 两模式共用 createOpencodeV2Setup(src/agent/opencode.ts:165 / src/agent/opencode-native.ts:953),一并生效,与 PR 声明一致。

8. 是否引入新配置
无。没有新 env/config/CLI 面。

测试有效性:两个新测试有牙——正向(生成的 ID 在四个 hook 下均被剔除、持久化历史本身不被改写、跨「重启」的第二进程实例仍能过滤)+ 负向(无 id 的 user 消息保留、同 id 但 assistant 角色保留、畸形 id msg_bili_report_invalid 保留、hook 抛错回退无效 body)。gate 双向纪律(#3617)满足。

顺手小修(已直接修,独立 commit):msg_bili_report_ 字面量在 src 出现两处(过滤 regex + id 模板),已抽成 BILI_REPORT_ID_PREFIX / BILI_REPORT_ID_RE,铸造方与过滤方从此不可能漂移——commit 0a835e4 已推到 PR 分支,本地定向套件 34/34 + typecheck 绿。

状态:分支 behind master,但 base 以来无任何 master 提交触碰这两个文件,merge-tree 验证无冲突。CI 在新 head(0a835e4)上运行中(22 项排队/执行)。

判定:方向正确(修的是字段布局错配这个根因,不是继续调截断参数)、机制成立(ID 命名空间是该宿主下唯一可靠的排除手段——metadata 会被投影丢弃,ID 不会)、代码与测试达标。CI 全绿后可合(人工合并)。

@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

(ai: vllm-qwen/qwen3.8-27b)

CI 状态补充:新 head 9ed67afec 上 docs-sync 与 unused-exports 两项红——继承性失败,非本 PR 引入:master head(d108df3)同样红这三项(docs-sync / unused-exports / lifecycle-ledger-guard)。已按 CI 协调规程把 origin/ci-fixes(带入 LIFECYCLE.md 注册修复)merge 进分支;剩余两红的归属与在途修复:unused-exports → #5321(修复 PR #5318 在途),docs-sync = master packs 重做中的 promptPack 文档漂移。本 PR diff(仅 src/agent/opencode-v2.ts + 测试)不触碰任何相关面。已在 #4599(CI 总控)留档。待 master 侧收敛后 CI 复跑即可绿。

@ranxianglei

Copy link
Copy Markdown
Owner

ework解决ci和冲突 并重新review

ci-check added 2 commits November 3, 2026 22:40
…ontext hooks

The PR adds context/compaction/title/generate session-hook registrations to
createOpencodeV2Setup; the strict hook-name inventory assertion in
tests/opencode-native.test.ts pinned the pre-PR two-hook list and broke on
rebased heads (3 of 12 CI shards red). Update the expected list to the full
registration order — the assertion keeps its exact-inventory teeth.
@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

(ai: vllm-qwen/qwen3.8-27b)

CI 修复完成(自动修复车道 attempt 1/3)。三个红 shard 的根因已定位,修复已在分支 head 上,新一轮 CI 全部测试 shard 已绿。

结构化结论

  1. 是什么问题:PR 的三个 test shard(ubuntu 22 / ubuntu 24 / windows 22)红了,且都是同一个确定性断言失败——tests/opencode-native.test.ts 的子测试 setup(route): header stamping applies to the REPLACED request, tools register natively(非 flake:runner 对同一文件重试 3 次同样失败)。
  2. 什么原因导致的:本 PR 给共享的 createOpencodeV2Setup(src/agent/opencode-v2.ts)新增了 4 个报告过滤 session hook(context / compaction / title / generate,按 msg_bili_report_* id 过滤出站历史——launcher 与 native 模式共用此 setup)。而 native 模式的既有测试用 deepStrictEqual 钉死了 PR 之前的两元素 hook 清单 ["http.request", "experimental.ws.handshake"] → 实际注册出 6 个,严格清单断言必然失败。作者本地只跑了 OpenCode V2 定向套件(34 passed),没覆盖到这个未改动文件里的过期断言。
  3. 影响范围与严重程度:仅 CI(本 PR 的合并阻塞项),零运行时影响——产品代码一行未动,坏的只是一条过期的测试期望。
  4. 怎么修复的:把期望数组扩成全量注册顺序 ["http.request", "experimental.ws.handshake", "context", "compaction", "title", "generate"],断言保留「精确清单」的牙齿(hook 缺失/改名/乱序仍会红)。我先在本地做了这个修复并跑通该文件;推送时发现作者已在分支上推了语义完全相同的修复 commit(2405b0177,"opencode-native hook inventory includes the four report-context hooks")→ 我丢弃了自己的重复 commit,保留作者 head,不重复提交。
  5. 是否有回归问题:无。改动是单条测试断言,test-only;不触碰 wire/配置/持久化/kernel。验证:①本地定向跑 tests/opencode-native.test.ts 通过;②新 head 2405b0177 的 CI 全 11 个 test shard 于 16:19 UTC 确认 completed/success(含原红的 ubuntu-22-1、ubuntu-24-1、windows-22-5),其余 check 无红项。
  6. 是否破坏缓存:不涉及。
  7. 是否改了设计方向:不涉及。
  8. 是否引入了新的配置:不涉及。

备注:本次运行期间镜像 check 缓存长时间停在旧 sha 的快照上未刷新(约 30 分钟),最终状态是用单次直接 check-runs 拉取核实的(非轮询)。若镜像 poller 持续停摆建议运维看一眼。

收工判定:阻塞已解除,PR head 2405b0177 测试面全绿,等其余 gate 收尾即可由 owner 合并。

@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

(ai: vllm-qwen/qwen3.8-27b)

冲突与 CI 已全部解决,并做了独立重新 review。当前分支头 2405b0177,CI 全绿(主 CI 12 shard + E2E real codex / codex-persona / native-dsh / native-opencode / native-pi / fake-codex / registry / pi-codex-ws / codex overlay 全部通过)。

做了什么

  1. 冲突:把 master 最新(9dc4c9459)合入 PR 分支——零冲突(master 自 PR 基线起没有动过这两个文件,GitHub 上的 dirty 状态是过期的)。顺带把之前继承自 master 的两个红(unused-exports、docs-sync)一并清掉。
  2. 新发现并修掉一个 PR 自己引入的红:PR 给 createOpencodeV2Setup 新增了 4 个会话钩子注册(context/compaction/title/generate),但 tests/opencode-native.test.ts:270 有一处严格断言「注册的钩子名列表」仍钉着旧的 2 项——rebase 后 12 个 shard 里 3 个红在这。已把断言更新为完整注册顺序(断言保留「精确清点」的牙,不是放松),本地该套件跑绿。这是外部提交按惯例直接在 PR 分支上修掉的,独立 commit 已标注。
  3. 重新 review(独立重读 diff):方向正确——根因是字段布局错配(OpenChamber 渲染 description=标题截断、body=正文,bili 原来把完整报告塞进 description 被截到 1KB,body 放惰性占位行)。修法:完整报告进 body(```text 围栏)+ 自动报告铸专用 ID 命名空间 msg_bili_report_<32hex> + 四个钩子在出站模型请求前按精确 ID 格式过滤;钩子注册失败则逐字节回退旧行为。测试有牙:对抗性控制(同文不同 id 的 user 消息保留、assistant 角色同 id 保留、非法命名空间 id 保留、持久化历史数组不被改)、回退路径钉死旧字节。

结构化八问

  1. 是什么问题:OpenCode V2 里 /acp、/acp-cache 自动报告只能看到约 1KB 的截断,完整报告用户看不到;同时 PR 与 master 冲突、CI 红。
  2. 什么原因导致的:bili 假设 description 是全文字段、body 是辅助信息,实际 OpenChamber 恰好相反(description 渲染为标题且截断 1024/8192,body 才是正文区)——完整报告被显示层截掉。
  3. 影响范围与严重程度:所有用 OpenCode V2 原生插件模式看自动报告的用户,只能看到截断摘要;纯体验缺陷,压缩功能本身不受影响(p2)。
  4. 怎么修复的:报告放对位置(body 全文+围栏,description 留封顶提示)+ 客户端侧按 ID 命名空间把自动报告挡在模型上下文之外;不可用即回退旧行为。本轮另加:同步 master + 修兄弟测试断言。
  5. 是否有回归问题:审过的既有行为:TUI 展示路径不变、手动粘贴的报告不受过滤影响(用户构造不出该 ID 格式)、V1 车道不动、钩子注册失败/部分失败均安全(不全不铸 ID,钩子滤不到东西)。无回归。已知残留风险(不阻塞):更老的 OpenCode 版本若接受钩子但不保留自定义消息 ID,过滤会漏报→报告进入模型上下文;建议后续加版本门,等 owner 拍板。
  6. 是否破坏缓存:被过滤的消息根本不到 bili 代理,不影响代理侧缓存与会话账本;前缀缓存策略无变化。
  7. 是否改了设计方向:无架构转向,只调整报告内容落位(客户端侧)和模型可见性边界。
  8. 是否引入了新的配置:无,没有新增 env/config。

行为变更披露(旧→新):旧:完整报告在 description(被显示层截断)、body 为惰性占位行;新:完整报告在 body(```text 围栏)、description 为封顶提示,自动报告带 msg_bili_report_* ID 并从出站模型请求中过滤。原因:OpenChamber 的渲染布局使原位置下完整报告不可见。

判定:可合并——冲突已解、CI 全绿、review 通过,等你点合并:#5316

@ranxianglei ranxianglei left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(ai: vllm-qwen/qwen3.8-27b)

审核结论(独立重读全 diff @ 2405b0177)

1. 是什么问题:OpenChamber 把 OpenCode V2 合成消息的 description 渲染成标题(截断)、body 渲染成正文;而 bili 此前把完整报告放进 description(1024/8192 截断)、body 只放一行无效占位文本——结果在 body-rendering 客户端上 /acp、/acp-cache 的报告只剩一条截断标题,全文读不到。

2. 什么原因导致的:字段布局错配——bili 用单一布局(description=全文、body=无效行)同时服务两类客户端,OpenChamber 的映射恰好相反。病因是「完整报告只存在于会被显示层截断的那个字段里」,不是截断参数问题。

3. 影响范围与严重程度:仅 OpenCode V2 原生插件 + body-rendering 客户端(OpenChamber 等)看自动报告的用户;纯展示缺陷(p3)——无数据丢失、无缓存泄露,TUI 显示不受影响,Web UI 深链可绕行。

4. 怎么修复的:两层互补。① 完整报告进消息 body(```text 围栏包裹),description` 保留原截断通知(TUI 不变);② 自动生成的报告铸专属 ID 命名空间 `msg_bili_report_<32hex>`,注册 `context`/`compaction`/`title`/`generate` 四个 session hook,按「user 角色 + 精确 ID 格式」在出站模型请求前剔除(in-place splice,兼容宿主数组引用传播)。hook 注册失败→整体回退旧行为(无效 body、不铸 ID)——降级不猜。手动粘贴的报告不匹配命名空间(ID 由宿主铸造),永不被过滤。

5. 是否有回归问题(逐项审过既有行为):

  • TUI 显示链(fitNoticeDescription 截断/Web UI 链接前置/整行保留,#1602/#1612):代码未动,保持;
  • resume:false 投递语义(#809,防每次 /acp 触发空模型回合):保持;
  • 文件内其余路径(http.request / ws handshake hook、tool transform、conditional tools、event subscription / fork adopt、dispose 循环):未触碰,新注册并入同一 registrations 数组统一 dispose,保持;
  • 代理侧账本/reconcile/prefix cache:被过滤消息根本到不了代理(host 侧预过滤),不受影响;
  • plain proxy 模式、V1 车道、其他车道:不在 diff 内,不受影响;
  • 无 kernel/ 改动、无配置面变更、无版本/lockfile 变动。结论:无回归。
  • 有意行为变更(披露):旧=模型可见 body 恒为无效占位行 → 新(hook 可用时)=body 为完整报告、由 ID 从出站请求剔除;hook 不可用=逐字节回到旧值。原因:报告必须落 body 才能被 OpenChamber 显示,ID 过滤保证它不进模型上下文。
  • 残留风险(记录,不拦截):机制依赖两个宿主契约——OpenCode 把合成消息自定义 ID 原样带入模型投影(作者真机 2.2.5 实测含重启存活)、四个 hook 实际收到可变 messages 数组。若某宿主版本静默接受这些 hook 但不保留自定义 ID,完整报告会进入模型上下文(是污染,不是损坏);对未知 hook 名抛错的版本则安全回退。如遇此类版本再加版本门,不阻塞本 p3 修复。

6. 是否破坏缓存:不涉及——代理侧视图从未包含这些报告消息,prefix cache 与会话账本不变;compaction/title 的输入同样被过滤,报告内容不会渗入摘要或会话标题。

7. 是否改了设计方向:没有。仍是 agent 侧渲染 + host hook 过滤,不动 proxy wire、kernel、配置面、持久化。launcher 与 native 两模式共用 createOpencodeV2Setup(src/agent/opencode.ts:165、src/agent/opencode-native.ts:960),一并生效,与 PR 声明一致。

8. 是否引入了新的配置:无。没有新 env/config/CLI 面。

测试有效性:两个新测试有牙——正向(生成的 ID 在四个 hook 下均被剔除、持久化历史数组本身不改写、第二实例跨「重启」仍能过滤)+ 负向(无 id 的 user 消息保留、同 id 但 assistant 角色保留、畸形 ID msg_bili_report_invalid 保留、hook 抛错→回退无效 body 且不带 id),gate 双向纪律(#3617)满足;tests/opencode-native.test.ts 的 hook 清点断言从 2 项扩为 6 项并保留「精确清点」的牙齿(缺失/改名/乱序仍会红)。作者另提供真机 e2e(OpenCode 2.2.5 + mock upstream):完整报告留在会话历史、缺席于捕获到的模型请求、手动粘贴文本在场。

CI 与基线:head 2405b0177 全部 49 个 check-run completed、0 红 0 pending(单次拉取核实);分支 merge-base 即当前 master,mergeable=true,无冲突。

判定:方向打中根因(字段布局错配而非继续调截断),机制成立(ID 命名空间是该宿主下可靠的排除手段——metadata 会被投影丢弃,ID 不会),测试有牙,diff 干净(3 文件,每行都服务于目的),无回归。APPROVE,可由 owner 合并:#5316

@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

(ai: vllm-qwen/qwen3.8-27b)

review-worker-r1 完成:PR #5316 @ 2405b0177 独立重审通过,GitHub 已发 APPROVE(review,八问+回归清点+行为变更披露齐备);本轮无顺手小修;CI 49 项 check 全绿、与 master 无冲突——等 owner 合并。

@ranxianglei
ranxianglei merged commit 1e7d400 into ranxianglei:master Nov 4, 2026
49 checks passed
@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

📦 Merged Build Published

This merge to master was published as 0.0.1023-master.1e7d400 (rolling master tag).

npm install -g billion-context@0.0.1023-master.1e7d400  # this exact build
npm install -g billion-context@master  # always the newest merged build

npm view billion-context@master prints the current version at any time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OpenCode V2: show full ACP reports in OpenChamber without sending them to the model

2 participants