feat: opencode v1 — keep opencode-acp legacy sessions working under bili (#920) - #923
Conversation
…ili (#920) On OpenCode 1.x hosts, `bili opencode` now runs new sessions through the bili proxy while existing opencode-acp ("legacy") sessions keep working with their own in-process machinery: - src/agent/acp-bridge.ts (new): imports the installed opencode-acp package as a library (BILLION_CONTEXT_PROXY temporarily unset around import + init), wraps its hooks behind a per-session legacy gate (acp store-file existence), excludes its config hook (the global /bili/ self-disable), and degrades to null on any failure. - src/agent/opencode.ts: the V1 plugin merges the bridge hooks/tools, registers /dcp, chains command handlers (acp first), and stamps x-bili-plugin-bypass: 1 on legacy-session requests via chat.headers. - src/server.ts: honors x-bili-plugin-bypass as raw passthrough ahead of any pipeline processing; wire-tool injection drops same-named client tools so upstream sees one definition per name in proxy mode. - src/launcher.ts: the temp-config clone strips opencode-acp entries (all spec forms) so the host never loads it armed; the first stripped spec rides along as BILI_OPENCODE_ACP_SPEC for the bridge.
[bot] 🏷 Reviewing PR #923 (branch
Running local typecheck/test/build and a rebase dry-run now; will follow up with the full verdict. |
3917336 to
0ff133a
Compare
📦 Built Package ArtifactBranch: Option A — Install from npm PR tag (recommended)npm install -g billion-context@pr-923Each push to this PR publishes a new version under the Option B — Download artifact
tar xzf billion-context-pr923.tgz
npm install -g packageInstall instructions are refreshed on each push. |
[bot] 🏷 Rebased onto current master (
Evidence on the rebased head: typecheck clean · 中文摘要:分支已 rebase 到最新 master(解决 launcher/server 两处冲突,均按双方意图合并,保留了 #890 的 env 剥离修复),rebase 后全量测试与 CI 全绿,可以合并。 |
[bot] 🏷 PR #923 review complete — independent verification done. Code is correct; the single red CI cell is an environmental flake, now re-running. I re-ran the checks myself on the rebased head ( Local (Node v22.23.2):
Code review (reasoned across both compression modes, §6): sound, no correctness issues. Highlights: CI correction: the earlier "CI all green" note missed one cell. On head
I've already triggered a re-run of just that failed job ( Bottom line: no code changes needed (nothing to fix); I did not modify or merge anything. Once the re-running 中文摘要:代码本身正确(本地 typecheck / build / 1751 通过、0 失败,全绿);唯一红的 CI 是某个 Windows runner 磁盘写满(ENOSPC)导致未被本 PR 触及的 CA 证书测试断言失败——属环境抖动而非回归;我已触发该 job 重跑(现运行中),转绿后即可由你合并。 |
[bot] 🏷 Re-run landed green — PR #923 is now fully verified. The re-run of Nothing else outstanding on my side: code reviewed across both compression modes, local typecheck/build/test clean, dist wiring confirmed, 中文摘要:重跑后 windows-22 通过,确认此前失败是磁盘写满(ENOSPC)的环境抖动而非代码问题;整条 CI 现已全绿,PR #923 验证完毕,可由你合并。 |
Union of the pi/opencode native branch stack (PRs #706/#919/#921 + #927 jsonc fix) with master's #923 lineage: - Legacy opencode-acp sessions: keep the branch's opencode-legacy.ts (docker E2E verified on opencode 1.18.31 + acp 1.18.1: absorbed-acp compress/decompress/acp_status + x-bili-plugin-bypass verbatim forwarding) as the single legacy machinery; master's acp-bridge.ts is dropped as the duplicate. Its BILI_OPENCODE_ACP_SPEC launcher hint is adopted into legacyAcpCandidates (authoritative when the cache slot exists). - src/agent/opencode.ts stays the branch's thin version-dispatch entry (V1 -> opencode-native server, V2 -> opencode-v2 setup). - pi.ts: event-time proxy ownership gate (#519 native) UNION master's omp auto_compaction_start announcement tracking (#851). - server.ts: master's early-return legacy bypass (BILI_PLUGIN_BYPASS_HEADER from util) replaces the branch's late pipeline exclusion; branch's pluginBypassHeader plumbing removed. - plugin-install.ts: branch's full native installer (jsonc-first #927, plugin-entry + compaction.auto + stripLegacyOpencodeAcp) + master's claudeStatus isPlainMcpObject hardening (#839). - Docs: table rows and launcher notes merged to describe both the native installer and the launcher legacy-session behavior; CHANGELOG union. Verified: typecheck clean, 1822 tests (1820 pass / 2 E2E-gated skip), build ok.
What
On OpenCode 1.x hosts,
bili opencodenow runs new sessions through the bili proxy while existingopencode-acp("legacy") sessions keep working with their own in-process machinery — per the user-directed design in #920. Previously acp globally self-disabled on/bili/baseURLs and its store (~/.local/share/opencode/storage/plugin/acp/<sessionID>.json) became unreachable:decompresson an old ref returned[Block … not found]and numbering restarted.Bili-side absorption, zero opencode-acp changes:
src/agent/acp-bridge.ts(new) — imports the installed opencode-acp package as a library (await import()around a temporarily unsetBILLION_CONTEXT_PROXY, saved/restored infinally). Wraps every hook behind a per-session legacy gate = an acp store file exists for this session; non-legacy sessions are never touched, so acp's eagerregistry.getOrCreateadoption never fires. Itsconfighook is excluded entirely (that's where the global/bili/self-disable lives). Tool executors are gated too (v1 tool registry is process-global/static — no per-request filtering hook exists). Any failure (package missing / import fails / version ≠ 1 / hooks shape mismatch) →null→ exact pre-change behavior.src/agent/opencode.ts— V1 plugin merges the bridge hooks + acp's DCP tool map, registers/dcpalongside/acp, chains command handlers (acp first — its abort sentinel wins for legacy sessions), and adds achat.headershook stampingx-bili-plugin-bypass: 1on legacy-session requests (verified the v1.14.46 binary routes plugin headers onto the real LLM request). V2setup()untouched.src/server.ts— new bypass mode:x-bili-plugin-bypass: 1→ raw passthrough via the existingforward()ahead of JSON.parse / window resolution / session binding / injection / compression. Also flips the three wire-tool inject helpers from union to drop-same-named-then-inject: in proxy mode bili owns the compression tool names, so upstream sees exactly one definition per name (opencode ships acp's static DCP schemas in every body).src/launcher.ts— the temp-config clone stripsopencode-acpentries (string / tuple / object forms; fork-safe matcher —my-opencode-acp-forksurvives) so the host never loads acp armed; the first stripped spec rides along asBILI_OPENCODE_ACP_SPECso the bridge imports exactly the copy the host would have loaded.Both compression modes reasoned (§6)
pluginModeis set), so plugin-mode clients see no behavior change.Graceful degradation (documented in README zh/en)
Package not found / import fails / not v1 → the plugin behaves exactly as before this change; legacy sessions degrade the way they did when
opencode-acpself-disabled on/bili/baseURLs. One once-per-process warning is logged.Pre-flight results (rebased head
0ff133a, base = current master0cfde7a)stripInheritedProxyenv fix preserved alongside the opencode v1: keep opencode-acp legacy sessions working after switching to bili #920 strip-from-clone mechanism.npm run typecheck: cleannpm test: 1751 pass, 0 fail, 2 skipped (pre-existing gated skips)npm run build: success; dist sanity checked (BILI_OPENCODE_ACP_SPECindist/agent/opencode.js,x-bili-plugin-bypassindist/index.js)tests/acp-bridge.test.ts(probe order/authority, validation rejections, store-dir resolution matrix, env save/restore around acp init, full gating matrix, all degradation paths) ·tests/fix-920-bypass-drop.test.ts(bypass byte-fidelity incl. unparseable bodies, proxy-mode same-name drop) ·tests/launcher.test.ts(updated expectations + all-spec-forms strip)test (ubuntu-latest, 24)✅ ·test (windows-latest, 24)✅ ·real codex vs deterministic fake upstream (zero tokens)✅No config schema, persistence format, or cross-repo dependency changes. No
versionbump (content branch).Closes #920