Repository navigation
feat: OpenCode 1.x native support — V1 .server() hooks on the standard install path - #919
Conversation
…d install path - src/agent/opencode-native.ts: V1 plugin surface — config hook rewrites provider baseURLs to <proxy>/bili/<upstream> on the shared in-process config object (idempotent, unwraps stale wraps), chat.headers stamps the plugin headers, tool registers the bili tool set with real zod shapes, /acp command renders the same status panel. Reuses the self-spawn/attach bootstrap; degrades to plain proxy mode when zod is unresolvable. - src/agent/opencode-acp-command.ts: /acp hooks extracted from the launcher plugin, shared by V1 (.server) and V2 (setup) entries. - src/agent/opencode.ts: launcher plugin now consumes the shared factory. - zod 4.1.8 (exact, matches the opencode host's zod) added as the only runtime dependency; dist/index.js stays zod-free. - tests/opencode-native-v1.test.ts: 11 tests (schema->zod mapping incl. cross-instance interop, provider rewrite idempotency, hooks + degrade). - E2E verified in-container on opencode-ai 1.14.46 and 1.18.31 via 'bili plugin install opencode': providers rewritten, plugin-mode headers, native acp_status round-trip, /acp panel render, tag-echo guard.
[bot] 🏷 收到。这是 [PR] 类唤醒,不重做实现——正在核对:拉取 |
Verification complete — all green. Details: CI status (head
Local verification (branch checked out, node 22)
Diff audit (every referenced symbol cross-checked against
Minor observation (non-blocking, nothing pushed): in Merge planning note: when this lands toward 一句话:PR 代码核对与本地 typecheck / test(1692 通过)/ build 全部干净,dist/index.js 确认无 zod、原生插件懒加载外置,无阻塞问题,可以合并。 |
…lared limits Completes V1<->V2 header parity flagged during #919 review. The V1 .server() path reads provider.<id>.models.<m>.limit.context from the shared config object (V1 exposes no catalog API like V2's ctx.catalog.model.list()) into a provider/model map rebuilt on each config reload, then chat.headers stamps x-bili-plugin-context-window only when the requested model carries a finite, positive declared limit -- byte-compatible with the V2/pi stamping guard. When absent (common for registry-discovered models) nothing is stamped, so the proxy falls back to its models.dev registry window as before; never fabricates a threshold. Adds extractV1Windows (+4 unit tests incl. end-to-end stamping). Local pre-flight: typecheck + build + full suite green (1696 pass).
The V1 config-hook rewrite only reaches providers with an explicit options.baseURL; providers relying on the SDK default (e.g. bare @ai-sdk/openai -> api.openai.com) silently bypassed the proxy. Install the shared native fetch intercept (pi-native's mechanism) in both the native V1 server() and the launcher plugin server() — v1's provider stack resolves fetch per-request, so a global patch catches those calls. Verified end-to-end on opencode-ai 1.18.31 (container, hosts-redirect api.openai.com -> local https shim -> sglang): leaktest provider with no baseURL produced proxy log 'forward POST -> https://api.openai.com/v1/ responses' with x-bili-plugin headers — the request was captured, /bili/-wrapped, and answered.
Adds the 1.x/2.x client-table rows, the native-vs-standalone mutual exclusion note, the 2.x launcher bullet, and a condensed Chinese counterpart of the OpenCode-specific section (launcher / native install / V1 .server() details incl. the SDK-default fetch patch).
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.
…ons, bili owns new ones (ranxianglei#920) OpenCode 1.x hosts migrating from opencode-acp keep their pre-migration sessions WORKING. The V1 native entry absorbs the installed opencode-acp package (loadLegacyAcp: .opencode/node_modules > project node_modules > global npm root > config-scope modules) by importing its server() with BILLION_CONTEXT_PROXY unset strictly around the call (its only env check is at entry), then routes per session: - legacy session (acp state file exists in <XDG_DATA_HOME>/opencode/storage/plugin/acp/<sid>.json) — compression runs INSIDE the absorbed acp (its dcp refs, block store, all five tools). Model requests carry x-bili-plugin-bypass: 1; the proxy forwards them verbatim (no injection/nudge/binding). - new session — tool executors forward to the proxy plugin endpoints (plugin mode). Tool slots carry the DCP schemas for both lanes (v1 registers one def per name process-wide); the executor picks the lane. acp's transforms (system/messages/text.complete) are gated on the legacy predicate so new sessions never enter its registry; its config hook runs on a provider-hidden shadow (its /bili/ self-disable is neutered) and owned keys are merged back. /acp and /dcp route per lane. Degradation: package absent/import-failed -> bili alone, legacy sessions read-only (documented). Also: cherry-picked 74701fb (installer strips legacy opencode-acp entries, ranxianglei#918) — it was pushed to the already-merged ranxianglei#919 branch and orphaned.
Fixes #918
What
The same
bili plugin install opencodewrapper now serves OpenCode 1.x through the V1.server()hook surface, delivering near-v2 effectiveness on the standard install path:options.baseURLto<proxy>/bili/<upstream>by mutating the shared in-process config object (idempotent; unwraps stale wraps from other proxy origins) +compaction.auto: falsez.object— zod pinned to 4.1.8 matching the host)opencode-acp-command.tsfactorybili: attaching to running proxy …observed across processes); degrades to plain proxy mode when zod is unresolvable (rewrite only, wire-injected tools)Refactor
src/agent/opencode-acp-command.ts(new):/acphooks extracted from the launcher plugin — V1.serverand V2setupnow share one implementationsrc/agent/opencode.ts: launcher plugin consumes the shared factoryzodbecomes the package's only runtime dependency (external; onlydist/agent/opencode-native.jsimports it lazily —dist/index.jsverified zod-free)Verification
npm run typecheck/npm run buildclean; fullnpm test1692 pass / 0 fail (11 new tests: schema→zod mapping incl. cross-instancez.objectinterop, provider-rewrite idempotency/unwrapping, hooks wiring, zod-unavailable degrade)bili plugin install opencode+ plainopencodeon 1.14.46 and 1.18.31:[bili-opencode-native] v1 active (proxy http://127.0.0.1:PORT)+rewrote 2 provider baseURL(s)[plugin] [acp-usage] input=… cached=… (cache hit 98%)[plugin] tool acp_status executed via plugin (378 chars)/acpin the TUI command palette + full panel rendered into the session (idle + live variants)Known V1 limitation (documented in README): providers without an explicit
baseURL(SDK defaults) keep going direct — V1 has no request-level URL seam to catch them.