billion-context 0.1.122 → 0.1.123

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +174 -143
  2. package/README.zh-CN.md +71 -49
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -150,8 +150,7 @@ Pick by your client:
150
150
  | Client | Use |
151
151
  |---|---|
152
152
  | **pi** | [`billion-context-pi`](https://github.com/ranxianglei/billion-context-pi) (in-process extension) |
153
- | **opencode 1.x** | `bili plugin install opencode` (self-spawning native plugin — pre-migration [`opencode-acp`](https://github.com/ranxianglei/opencode-acp) sessions keep working, see "OpenCode 1.x") or `bili opencode` (launcher) or standalone `opencode-acp` (in-process extension) |
154
- | **opencode 2.0+** | `bili opencode` (built-in V2 plugin — native tools, no separate package) or `bili plugin install opencode` (self-spawning native plugin, no launcher) |
153
+ | **opencode** (1.x / 2.x) | [`billion-context`](https://github.com/ranxianglei/billion-context) — `bili opencode` (launcher) or `bili plugin install opencode` (native, no launcher); standalone [`opencode-acp`](https://github.com/ranxianglei/opencode-acp) remains usable on 1.x. Full guide: [OpenCode](#opencode) |
155
154
  | **omp** | [`billion-context`](https://github.com/ranxianglei/billion-context) via `bili omp` (built-in plugin) or `bili plugin install omp` (self-spawning native plugin, no launcher) |
156
155
  | **dsh** | `bili dsh` (launcher — full native plugin via `--patch`: tools, session-bound `/acp`, fetch intercept) or `bili plugin install dsh` ≡ `dsh plugin --profile <name> add billion-context` (one unified lane — pnpm-installs the package into each profile so dsh mounts the bundled patch layer; the bili form just drives dsh's own channel per profile and migrates legacy managed blocks) |
157
156
  | **kimi** | `bili plugin install kimi` (self-spawning native plugin, no launcher — Kimi Code ≥ 2.0.0; per-session routing block in `~/.kimi-code/config.toml`) or `bili kimi` (launcher, cert-MITM) or `/bili/` prefix |
@@ -160,12 +159,6 @@ Pick by your client:
160
159
 
161
160
  **Native mode vs standalone extensions.** The host-native plugins (`bili plugin install pi` / `opencode` — they spawn the proxy inside the host process) and the standalone in-process extensions (`billion-context-pi`, `opencode-acp`) are **mutually exclusive**: both active means double compression. The installer makes the switch: `bili plugin install pi` replaces the legacy `npm:billion-context-pi` entry (with a reminder that a project-scope entry in `<project>/.pi/settings.json` from `pi install -l` lives outside the global settings), and `bili plugin install opencode` strips legacy `opencode-acp` entries from the global opencode.json — bare name, `npm:` alias, versioned (`opencode-acp@stable`), or path form, array or object shape; the original config is snapshotted to `.bili-bak` once. A **project-local** install (`opencode plugin opencode-acp` writes `<project>/.opencode/opencode.json`, not the global config) is not touched — remove it by hand; the installer note reminds you. As a runtime safety net for manual installs, the native entries set `BILLION_CONTEXT_NATIVE=<host>` synchronously at load so a standalone extension can stand down at action time — its own load-time `BILLION_CONTEXT_PROXY` check cannot see a proxy that native mode spawns asynchronously, and its `/bili/` baseUrl check never sees the fetch-layer rewrite. On the pi side the marker needs `billion-context-pi` **0.1.72+** (the per-event re-check landed after 0.1.71); the pi-native entry additionally scans both pi settings files once its proxy is up and warns loudly when it spots a co-resident legacy entry the installer never saw — that warning is the only visible signal while an old `billion-context-pi` silently double-compresses.
162
161
 
163
- **Legacy sessions from opencode-acp (v1 lane routing).** On OpenCode 1.x, `bili plugin install opencode` keeps pre-migration sessions WORKING: the native entry absorbs the installed `opencode-acp` package (imported directly from `node_modules` — `.opencode/node_modules`, project `node_modules`, global npm root, or opencode's config-scope modules, first hit wins) and routes per session. A session is legacy iff opencode-acp's persisted state file exists (`<XDG_DATA_HOME>/opencode/storage/plugin/acp/<sessionID>.json`):
164
-
165
- - **Legacy session** — compression runs through the absorbed opencode-acp (its own `<dcp-message-id>` refs and block store keep working: `compress` / `decompress` / `search_context` / `acp_status` / `acp_context_recap` all execute in it). Its model requests carry `x-bili-plugin-bypass: 1`, and the proxy forwards them VERBATIM — no wire injection, no nudge, no session binding.
166
- - **New session** — bili owns it: tool calls forward to the proxy's plugin endpoints (plugin mode). The tool slots the model sees carry the DCP schemas (one def per name process-wide on v1), but the executor routes by session lane, so a new session's `compress` reaches the proxy while a legacy session's reaches opencode-acp. `acp_context_recap` has no proxy counterpart — on new sessions the proxy answers it with its unknown-tool message.
167
-
168
- `/acp` and `/dcp` route the same way. Adoption of new sessions into opencode-acp's registry is prevented by gating its transforms (system / messages / text.complete) on the legacy predicate. Degradation: when the opencode-acp package is absent or fails to import, bili runs alone and legacy sessions behave as read-only archives (old `<acp>` tags render, `decompress` returns `[Block … not found]`, new refs restart from m00001).
169
162
 
170
163
  ## Install
171
164
 
@@ -202,10 +195,26 @@ bili plugin install kimi # writes $KIMI_CODE_HOME/plugins/managed/billion
202
195
  bili plugin remove <client> # undo (dsh removes through the same channel; config snapshots go to .bili-bak)
203
196
  ```
204
197
 
205
- dsh users can skip bili entirely: `dsh plugin --profile <name> add
206
- billion-context` is the very command `bili plugin install dsh` drives per
207
- profile — same end state either way (pnpm into the profile, bundled patch
208
- layer mounted by dsh itself). See the dsh section below.
198
+ Where a client has its own plugin channel you can also install natively,
199
+ skipping bili commands entirely:
200
+
201
+ - **dsh:** `dsh plugin --profile <name> add billion-context` is the very
202
+ command `bili plugin install dsh` drives per profile — same end state
203
+ either way (pnpm into the profile, bundled patch layer mounted by dsh
204
+ itself); remove through the same channel. See the dsh section below.
205
+ - **opencode:** add the bare npm name to your real config's plugin list —
206
+ `"plugin": ["billion-context"]` (npm form only; a git checkout has no
207
+ published entry). The package publishes `exports["./server"]` →
208
+ `dist/agent/opencode-native.js`, so opencode loads it through its own
209
+ Npm.add machinery and the plugin self-spawns exactly like the
210
+ bili-installed form. Do the two things the bili installer would have done
211
+ for you too: set `"compaction": { "auto": false }` in the same config
212
+ (otherwise OpenCode's native auto-compaction double-compresses) and keep a
213
+ manual backup of the file first.
214
+
215
+ For pi / omp / kimi / claude there is no client-side channel — `bili plugin
216
+ install <client>` writes their config entries for you (kimi's declarative
217
+ `kimi.plugin.json` + registry record, claude's managed settings block, …).
209
218
 
210
219
  At load the plugin **spawns its own proxy** (or attaches to a healthy
211
220
  running one — a parent-pid watchdog tears it down when the client exits),
@@ -261,8 +270,7 @@ Notes:
261
270
  the entries and snapshots the original config (`.bili-bak`); migration
262
271
  details in the client table above (pi needs `billion-context-pi` 0.1.72+
263
272
  to stand down cleanly).
264
- - On OpenCode 1.x, pre-migration `opencode-acp` sessions keep working
265
- (v1 lane routing, #920) — see "OpenCode 1.x" below.
273
+ - OpenCode: legacy `opencode-acp` sessions, the V1/V2 plugin shapes, and all caveats are consolidated in the [OpenCode](#opencode) section.
266
274
  - `kimi` reports runtime-info at bootstrap only (static `custom_headers` can't
267
275
  carry per-request window/model headers without going stale on model switch)
268
276
  and binds subagent conversations by per-call `conversation_id` — full
@@ -319,7 +327,7 @@ bili pi # launch pi through the proxy — file-fre
319
327
  bili codex # launch codex through the proxy
320
328
  bili claude # launch claude through the proxy
321
329
  bili omp # pi-style, file-free (#535): env + extension registerProvider + compaction cancel, real ~/.omp untouched
322
- bili opencode # MITM for HTTPS + temp opencode.json (/bili/ for HTTP) + thin /acp plugin; OpenCode 1.x: existing opencode-acp sessions keep working (entries stripped from the clone, package imported as a library, #920); OpenCode 2.0+: built-in V2 plugin with native bili tools, native compaction auto-disabled. Reads the user's opencode.jsonc / opencode.json / config.json (JSONC comments accepted, merged the same way opencode itself merges them); relative local plugin specs (`./x`, `../x`) are re-anchored to absolute paths in the clone — opencode resolves them against the declaring config file's dir (#826)
330
+ bili opencode # OpenCode (1.x & 2.x): full guide in the [OpenCode](#opencode) section below
323
331
  bili hermes # file-free (#535): hermes proxy env (HTTPS_PROXY + HERMES_CA_BUNDLE) — https via CONNECT MITM, http via absolute-form forward proxy; real ~/.hermes untouched
324
332
  bili dsh # deepseek-harness: full native plugin injected via --patch (#941) — compress/decompress/acp_status registered as real dsh tools, requests stamped with the dsh session id (plugin mode), /acp session-bound; non-loopback upstreams ride proxy envs (https MITM, http absolute-form), loopback keeps the overlay DSH_HOME (~/.dsh-bili) rewrite (#535), built-in deepseek route via DEEPSEEK_BASE_URL; dsh native auto-compaction disabled (compaction-basic auto:false)
325
333
  bili codebuddy # Tencent CodeBuddy Code CLI: CODEBUDDY_BASE_URL /bili/ rewrite (OpenAI chat completions wire), budget aligned via CODEBUDDY_AUTO_COMPACT_WINDOW; real ~/.codebuddy untouched
@@ -355,133 +363,7 @@ automatically.
355
363
  For per-client configuration examples (OpenCode, Codex, Pi, login-client
356
364
  MITM, …) see the web UI guide at [http://localhost:8787](http://localhost:8787).
357
365
 
358
- ### OpenCode 1.x
359
-
360
- On a 1.x host, `bili opencode` runs **new sessions through the bili proxy** and
361
- keeps **existing `opencode-acp` ("legacy") sessions working with their own
362
- machinery** (#920). The launcher strips the `opencode-acp` entry from its temp
363
- config clone (the host never loads it armed), and the thin bili plugin imports
364
- the installed package as a library instead:
365
-
366
- - every acp hook is gated on "an acp store file exists for this session"
367
- (`~/.local/share/opencode/storage/plugin/acp/<sessionID>.json`, or the dir
368
- from `storagePath` in `acp.jsonc`) — legacy sessions keep their DCP compress /
369
- decompress / search_context / acp_status tools and the `/dcp` command; new
370
- sessions are never adopted and run plain proxy mode.
371
- - legacy LLM requests are stamped `x-bili-plugin-bypass: 1`, which the proxy
372
- honors as raw passthrough (no injection, no compression, no session state).
373
- - in proxy mode the proxy owns the compression tool names: same-named client
374
- tools in the body are dropped before injection, so upstream sees one
375
- definition per name.
376
-
377
- Graceful degradation: if the package can't be found/imported or isn't v1, the
378
- plugin behaves exactly as before this change — legacy sessions degrade the way
379
- they did when `opencode-acp` self-disabled on `/bili/` baseURLs.
380
-
381
- ### OpenCode 2.0
382
-
383
- OpenCode 2.0 ships a new plugin API (`@opencode/plugin`); the standalone
384
- `opencode-acp` extension is V1-only and does not load under 2.0. Both bili
385
- modes work on 2.0. The 2.x plugin API surface is still moving between builds
386
- (adjacent npm `dev`-channel builds expose different `ctx` shapes), so the
387
- hook/tool details below are version-specific observations, not a stable
388
- contract:
389
-
390
- - **Launcher:** `bili opencode` works unchanged. On a 2.x host it injects the
391
- built-in V2 plugin (`dist/agent/opencode.js`) into the temp config as a temp
392
- wrapper directory whose `index.js` re-exports the plugin file — 2.x rejects
393
- bare file paths in the config `plugin` array (directory entries use
394
- `index.js` as entrypoint); 1.x hosts get the bare file path. Host generation
395
- is detected with a `--version` probe (a failed probe defaults to the 1.x
396
- shape). The V2 plugin registers the bili tools natively in-host — compress /
397
- decompress / search_context / acp_status (+ absorb), JSON-Schema inputs — and
398
- stamps the proxy headers on every outgoing provider request, so compression
399
- runs in plugin mode with no wire-level tool injection. Native auto-compaction
400
- is disabled automatically (`compaction.auto: false`). Every registration is
401
- defensive (optional chaining): on any 2.x build where a seam is missing or
402
- never fires, the plugin stays inert and the session transparently runs in
403
- plain proxy mode (wire-level tool injection) instead of breaking — observed
404
- on two adjacent `dev` builds (2026-09-13 / 2026-09-14) whose API surfaces
405
- differ from each other (#754 review probes); conversely verified end-to-end
406
- on `@opencode/cli` 2.0.3 (native `acp_status` executed through the plugin
407
- endpoint, zero wire-level injection).
408
- - **Native (no launcher):** with the package installed from npm, run
409
- `bili plugin install opencode` — it registers a self-spawning plugin in your
410
- real opencode config and sets `compaction.auto: false`, after which plain
411
- `opencode` works as-is. No `mcp.bili` MCP face is added by default (the
412
- native plugin already provides the bili tools, session-bound); pass
413
- `--with-mcp` to add one — the entry then carries no origin pin, so it
414
- survives the plugin's ephemeral-port proxy restarts (#926). The entry form
415
- depends on how THIS bili was installed: an **npm install** writes the bare
416
- package name (`"plugin":
417
- ["billion-context"]`) — the package publishes `exports["./server"]` →
418
- `dist/agent/opencode-native.js`, so opencode loads it through its own
419
- Npm.add machinery and manages install/upgrade itself; zero absolute paths,
420
- portable across machines. A **git checkout / dev build** has no published
421
- entry and falls back to a local shim dir
422
- (`<configDir>/plugins/billion-context/index.js` → this checkout's
423
- `dist/agent/opencode-native.js`) — machine-local by construction, not
424
- portable; re-running install from an npm install migrates the entry back to
425
- the bare name. At load the plugin bootstraps its own
426
- proxy (attaches to a healthy instance instead of doubling; parent-pid
427
- watchdog kills it when opencode exits), routes model-API traffic to
428
- `<proxy>/bili/<upstream-url>`, and exposes the same native bili tools as
429
- launcher mode — no fixed port, no env var, no launcher.
430
- Opt-out: `BILI_NATIVE_OPENCODE=0`. If no proxy can be made healthy, requests
431
- go direct (uncompressed) with a one-time warning and recover automatically.
432
- Under a `bili opencode` launch this entry is skipped entirely (the launcher
433
- owns the proxy).
434
-
435
- The same wrapper serves **OpenCode 1.x** through the V1 `.server()` hooks
436
- (verified on 1.14.46 and 1.18.31): the `config` hook mutates the shared
437
- config object in-process to rewrite every provider `options.baseURL` to
438
- `<proxy>/bili/…` and sets `compaction.auto: false`; `chat.headers` stamps
439
- the plugin headers per request; `tool` registers the bili tools with real
440
- zod shapes (zod is a runtime dependency — when it cannot be resolved the
441
- plugin degrades to plain proxy mode: rewrite only, wire-injected tools);
442
- the `/acp` command renders the same status panel. Providers **without**
443
- an explicit `baseURL` (SDK defaults, e.g. bare `@ai-sdk/openai` →
444
- api.openai.com) are caught by a global `fetch` patch (the pi-native
445
- mechanism) that reroutes model-API calls to the proxy — verified end-to-end
446
- on 1.14.46 and 1.18.31 (log: `v1: fetch patch installed`), including the
447
- OpenAI Responses endpoint. The patch is idempotent and passes
448
- `/bili/`-wrapped URLs through untouched.
449
- - **Pure proxy:** point the provider baseURL at the proxy like any other
450
- client:
451
-
452
- ```json
453
- {
454
- "provider": {
455
- "myprovider": {
456
- "npm": "@ai-sdk/openai-compatible",
457
- "options": {
458
- "baseURL": "http://localhost:8787/bili/http://upstream.example/v1",
459
- "apiKey": "sk-any"
460
- }
461
- }
462
- }
463
- }
464
- ```
465
-
466
- Note: 2.0 AI-SDK providers require an `apiKey` field even for local
467
- endpoints that never check it — set any non-empty value.
468
-
469
- Caveats: the 2.x line publishes as npm package `@opencode/cli`. Command
470
- support is build-dependent: one pre-release exposed only
471
- list/get/update/remove, while 2.0.x stable lets plugins ADD commands via
472
- `ctx.command.transform((editor) => editor.add(...))` — invocable in the TUI by
473
- accepting the slash-menu completion (Tab + Enter); note `opencode run` mode
474
- dispatches no slash commands at all (they pass through to the model). The
475
- bundled plugin deliberately registers no commands on either shape — call the
476
- `acp_status` tool instead of an `/acp` command. The bundled agent file keeps
477
- the V1 `server()` export alongside the V2 `setup()`, so the same artifact also
478
- loads on hosts ≥ 1.18.29 that support dual-shape plugins. Design note: the V2 plugin is a thin protocol client (no
479
- acp-kernel inside) because the proxy stays the single compression authority,
480
- which eliminates kernel-version drift between agent and proxy — it does not
481
- rely on the plugin API being unable to mutate context (that capability varies
482
- by 2.x build).
483
-
484
- #### dsh (deepseek-harness)
366
+ ### dsh (deepseek-harness)
485
367
 
486
368
  Two lanes, same plugin (#941):
487
369
 
@@ -525,7 +407,7 @@ untouched except for header stamping. Known limitation: manual
525
407
  `/compact` has no dsh-side event hook, so its boundary is left to the
526
408
  kernel's natural ingest diff (auto-compaction is off, so this is rare).
527
409
 
528
- #### Kimi Code (Moonshot)
410
+ ### Kimi Code (Moonshot)
529
411
 
530
412
  Three aligned modes: `bili kimi` (launcher, cert-MITM — Option 2), `/bili/`
531
413
  URL prefix, and native plugin mode (`bili plugin install kimi`, #963). Kimi
@@ -610,6 +492,155 @@ This failure mode is now loud instead of silent:
610
492
 
611
493
  To actually compress such a client: add its model domain to `"mitm".domains` in `billion-context.json` (e.g. `"mitm": { "domains": ["copilot.tencent.com"] }`) or via `BILI_MITM_DOMAINS`, restart bili, and make the client trust bili's root CA (`NODE_EXTRA_CA_CERTS=~/.local/share/billion-context/ca/root-ca.pem` for Node-based clients, or the client's own CA-path setting). The `/bili/` prefix trick does not apply here — there is no URL to change. Details: [CONFIGURATION.md → MITM](CONFIGURATION.md#mitm-transparent-proxy-login-clients).
612
494
 
495
+ ## OpenCode
496
+
497
+ One bundled plugin serves **both** OpenCode generations: the agent file keeps
498
+ the V1 `server()` export alongside the V2 `setup()`, so hosts ≥ 1.18.29 load
499
+ the V1 shape and 2.x hosts load the V2 `setup()`. The standalone
500
+ [`opencode-acp`](https://github.com/ranxianglei/opencode-acp) extension is
501
+ V1-only and does **not** load under 2.x — for OpenCode 2.x, billion-context
502
+ is the recommended context manager. Everything below is verified end-to-end
503
+ on `@opencode/cli` 2.0.3 (V1 lane: 1.14.46 and 1.18.31).
504
+
505
+ | Path | Command | When |
506
+ |---|---|---|
507
+ | Launcher (easiest) | `bili opencode` | one command brings up proxy + client; real config untouched |
508
+ | Native (no launcher) | `bili plugin install opencode` | self-spawning plugin in your real config; start `opencode` as usual |
509
+ | Pure proxy (fallback) | baseURL `/bili/` prefix | no plugin — wire-level tool injection |
510
+
511
+ ### Launcher — `bili opencode`
512
+
513
+ HTTPS rides cert-MITM, HTTP a temp `opencode.json` clone with `/bili/`
514
+ (JSONC comments accepted, merged the way opencode itself merges them;
515
+ relative local plugin specs re-anchored to absolute paths in the clone —
516
+ opencode resolves them against the declaring config file's dir, #826). Host
517
+ generation is detected with a `--version` probe (failed probe defaults to
518
+ 1.x): on a **2.x** host the built-in V2 plugin (`dist/agent/opencode.js`) is
519
+ injected as a temp wrapper directory whose `index.js` re-exports the plugin
520
+ file (2.x rejects bare file paths in the config `plugin` array); **1.x**
521
+ hosts get the bare file path.
522
+
523
+ What the plugin does (both generations): registers the bili tools natively
524
+ in-host — compress / decompress / search_context / acp_status (+ absorb) —
525
+ and stamps the proxy headers on every outgoing provider request, including
526
+ context-window / max-output read from the host's own model catalog
527
+ (`ctx.catalog.model.list()`, refreshed every 60s) and reported to the proxy
528
+ as runtime-info (#955) — compression runs in plugin mode with **no**
529
+ wire-level tool injection. Native auto-compaction is disabled automatically
530
+ (`compaction.auto: false`). Every registration is defensive (optional
531
+ chaining): on any 2.x build where a seam is missing or never fires, the
532
+ plugin stays inert and the session transparently runs in plain proxy mode
533
+ instead of breaking — observed across adjacent `dev` builds whose API
534
+ surfaces differ from each other (#754 review probes).
535
+
536
+ 1.x specifics (verified 1.14.46 + 1.18.31): the V1 `.server()` hooks rewrite
537
+ every provider `options.baseURL` to `<proxy>/bili/…` in-process and set
538
+ `compaction.auto: false`; `chat.headers` stamps the plugin headers per
539
+ request; `tool` registers the bili tools with real zod shapes (zod is a
540
+ runtime dependency — when it cannot be resolved the plugin degrades to
541
+ rewrite-only). Providers **without** an explicit `baseURL` (SDK defaults,
542
+ e.g. bare `@ai-sdk/openai` → api.openai.com) are caught by a global `fetch`
543
+ patch (log: `v1: fetch patch installed`) — idempotent, passes
544
+ `/bili/`-wrapped URLs through untouched; verified including the OpenAI
545
+ Responses endpoint.
546
+
547
+ ### Native (no launcher) — `bili plugin install opencode`
548
+
549
+ Registers a self-spawning plugin in your real opencode config and sets
550
+ `compaction.auto: false`; afterwards plain `opencode` works as-is. No MCP
551
+ face is added by default (the native plugin already provides the bili tools,
552
+ session-bound); pass `--with-mcp` to add one — the entry then carries no
553
+ origin pin, so it survives the plugin's ephemeral-port proxy restarts (#926).
554
+ Entry form depends on how THIS bili was installed: an **npm install** writes
555
+ the bare package name (`"plugin": ["billion-context"]`) — the package
556
+ publishes `exports["./server"]` → `dist/agent/opencode-native.js`, so
557
+ opencode loads it through its own Npm.add machinery; zero absolute paths, portable. (That exact bare-name entry doubles as a hand-install without bili — see Option 1.) A **git checkout / dev build** falls back to a local shim dir
558
+ (`<configDir>/plugins/billion-context/index.js` → this checkout's
559
+ `dist/agent/opencode-native.js`) — machine-local by construction; re-running
560
+ install from an npm install migrates the entry back to the bare name.
561
+
562
+ At load the plugin bootstraps its own proxy (attaches to a healthy instance
563
+ instead of doubling; parent-pid watchdog kills it when opencode exits),
564
+ routes model-API traffic to `<proxy>/bili/<upstream-url>`, and exposes the
565
+ same native bili tools as launcher mode — no fixed port, no env var, no
566
+ launcher. Opt-out: `BILI_NATIVE_OPENCODE=0`. If no proxy can be made
567
+ healthy, requests go direct (uncompressed) with a one-time warning and
568
+ recover automatically. Under a `bili opencode` launch this entry is skipped
569
+ entirely (the launcher owns the proxy).
570
+
571
+ ### Pure proxy (no plugin)
572
+
573
+ Point the provider baseURL at the proxy like any other client:
574
+
575
+ ```json
576
+ {
577
+ "provider": {
578
+ "myprovider": {
579
+ "npm": "@ai-sdk/openai-compatible",
580
+ "options": {
581
+ "baseURL": "http://localhost:8787/bili/http://upstream.example/v1",
582
+ "apiKey": "sk-any"
583
+ }
584
+ }
585
+ }
586
+ }
587
+ ```
588
+
589
+ Note: 2.0 AI-SDK providers require an `apiKey` field even for local
590
+ endpoints that never check it — set any non-empty value.
591
+
592
+ ### Status: `/acp` and `acp_status`
593
+
594
+ The `/acp` panel is session-bound in all modes, and the `acp_status` tool is
595
+ its in-host equivalent everywhere. On 2.0.x stable, where the command editor
596
+ supports adding entries (`editor.add`), the V2 plugin additionally registers
597
+ an `/acp` slash command — rendered as a synthetic non-model message,
598
+ panel-first like the `acp_status` tool; on older shapes the registration
599
+ stays inert. Note `opencode run` mode dispatches no slash commands at all
600
+ (they pass through to the model) — use the TUI.
601
+
602
+ ### Legacy opencode-acp sessions (#920)
603
+
604
+ On 1.x hosts, pre-migration [`opencode-acp`](https://github.com/ranxianglei/opencode-acp)
605
+ sessions keep working under both lanes: the launcher strips the
606
+ `opencode-acp` entry from its temp config clone (the host never loads it
607
+ armed), and each lane absorbs the installed package (imported directly from
608
+ `node_modules` — `.opencode/node_modules`, project `node_modules`, global npm
609
+ root, or opencode's config-scope modules, first hit wins). A session is
610
+ legacy iff opencode-acp's persisted state file exists
611
+ (`<XDG_DATA_HOME>/opencode/storage/plugin/acp/<sessionID>.json`, or the dir
612
+ from `storagePath` in `acp.jsonc`):
613
+
614
+ - **Legacy session** — compression runs through the absorbed opencode-acp
615
+ (its own refs and block store keep working: `compress` / `decompress` /
616
+ `search_context` / `acp_status` / `acp_context_recap` all execute in it).
617
+ Its model requests carry `x-bili-plugin-bypass: 1`; the proxy forwards
618
+ them VERBATIM — no wire injection, no nudge, no session binding.
619
+ - **New session** — bili owns it: tool calls forward to the proxy's plugin
620
+ endpoints (plugin mode). The executor routes by session lane, so a new
621
+ session's `compress` reaches the proxy while a legacy session's reaches
622
+ opencode-acp. `acp_context_recap` has no proxy counterpart — on new
623
+ sessions the proxy answers with its unknown-tool message.
624
+
625
+ `/acp` and `/dcp` route the same way. Adoption of new sessions into
626
+ opencode-acp's registry is prevented by gating its transforms (system /
627
+ messages / text.complete) on the legacy predicate. Degradation: when the
628
+ package is absent or fails to import (or isn't v1), bili runs alone and
629
+ legacy sessions behave as read-only archives (old tags render, `decompress`
630
+ returns `[Block … not found]`, new refs restart from m00001).
631
+
632
+ ### Caveats
633
+
634
+ - The 2.x line publishes as npm package `@opencode/cli`, and its plugin API
635
+ surface is still moving between builds (adjacent `dev`-channel builds
636
+ expose different `ctx` shapes) — the hook/tool details above are
637
+ version-specific observations, not a stable contract.
638
+ - Design note: the V2 plugin is a thin protocol client (no acp-kernel
639
+ inside) because the proxy stays the single compression authority — that
640
+ eliminates kernel-version drift between agent and proxy; it does not rely
641
+ on the plugin API being unable to mutate context (that capability varies
642
+ by 2.x build).
643
+
613
644
  ## Running the proxy
614
645
 
615
646
  ### Flags
package/README.zh-CN.md CHANGED
@@ -78,9 +78,7 @@ AI 编程助手的<strong>通用上下文压缩代理</strong>
78
78
  | 客户端 | 用这个 |
79
79
  |---|---|
80
80
  | **pi** | [`billion-context-pi`](https://github.com/ranxianglei/billion-context-pi)(进程内扩展) |
81
- | **opencode 1.x** | [`billion-context`](https://github.com/ranxianglei/billion-context) —— `bili plugin install opencode`(V1 `.server()` 钩子,与 2.x 同一个包装器)或 `bili opencode`(启动器);[`opencode-acp`](https://github.com/ranxianglei/opencode-acp)(进程内扩展)仍可用 |
82
- | **opencode 2.0+** | `bili opencode`(内置 V2 插件 —— 原生工具,无需另装包)或 `bili plugin install opencode`(自拉起原生插件,免启动器) |
83
- | **opencode** | [`billion-context`](https://github.com/ranxianglei/billion-context),`bili opencode`(新会话走 bili 代理;现有 [`opencode-acp`](https://github.com/ranxianglei/opencode-acp) 会话继续可用,见下文「OpenCode 1.x」) |
81
+ | **opencode**(1.x / 2.x) | [`billion-context`](https://github.com/ranxianglei/billion-context) —— `bili opencode`(启动器)或 `bili plugin install opencode`(原生,免启动器);独立 [`opencode-acp`](https://github.com/ranxianglei/opencode-acp) 在 1.x 上仍可用。完整指南:[OpenCode](#opencode) |
84
82
  | **omp** | [`billion-context`](https://github.com/ranxianglei/billion-context),`bili omp`(内置插件)或 `bili plugin install omp`(自拉起原生插件,免启动器) |
85
83
  | **dsh** | [`billion-context`](https://github.com/ranxianglei/billion-context) —— `bili dsh`(启动器,经 `--patch` 注入完整原生插件:工具、会话绑定 `/acp`、fetch 拦截)或 `bili plugin install dsh` ≡ `dsh plugin --profile <name> add billion-context`(统一泳道 —— pnpm 把包装进各 profile、由 dsh 挂载包内 patch 层;bili 形式只是替你按 profile 驱动 dsh 自己的通道,并顺带迁移旧版受管块) |
86
84
  | **kimi** | `bili plugin install kimi`(自拉起原生插件,免启动器 —— 需 Kimi Code ≥ 2.0.0;每会话在 `~/.kimi-code/config.toml` 写入路由块)或 `bili kimi`(启动器,证书 MITM)或 `/bili/` 前缀 |
@@ -89,12 +87,6 @@ AI 编程助手的<strong>通用上下文压缩代理</strong>
89
87
 
90
88
  **原生模式 vs 独立扩展。** 宿主原生插件(`bili plugin install pi` / `opencode` —— 代理在宿主进程内拉起)与独立进程内扩展(`billion-context-pi`、`opencode-acp`)**互斥**:两者同时生效意味着双重压缩。安装器负责切换:`bili plugin install pi` 会替换旧的 `npm:billion-context-pi` 条目;`bili plugin install opencode` 会从全局 opencode.json 里剔除旧的 `opencode-acp` 条目 —— 裸名、`npm:` 别名、带版本号(`opencode-acp@stable`)、路径形式都认,数组/对象两种形态都处理;原配置会快照到 `opencode.json.bili-bak`。**项目级**安装(`opencode plugin opencode-acp` 写的是 `<project>/.opencode/opencode.json`,不是全局配置)不会被碰 —— 需手动移除,安装器输出里会提醒。作为手动安装的运行期安全网,原生入口在加载时同步设置 `BILLION_CONTEXT_NATIVE=<host>`,让独立扩展在动作时自动退出 —— 它自己的加载期 `BILLION_CONTEXT_PROXY` 检查看不见原生模式异步拉起的代理,`/bili/` baseURL 检查也看不见 fetch 层改写。
91
89
 
92
- **从 opencode-acp 迁移旧会话(v1 泳道路由)。** 在 OpenCode 1.x 上,`bili plugin install opencode` 让迁移前的旧会话继续可用:原生入口会吸收已安装的 `opencode-acp` 包(直接从 `node_modules` 导入 —— `.opencode/node_modules`、项目 `node_modules`、全局 npm root、opencode 配置级 modules,先到先得),并按会话路由。会话属于 legacy ⟺ opencode-acp 的持久化状态文件存在(`<XDG_DATA_HOME>/opencode/storage/plugin/acp/<sessionID>.json`):
93
-
94
- - **旧会话** —— 压缩由被吸收的 opencode-acp 执行(它自己的 `<dcp-message-id>` 引用号与块存储照常工作:`compress` / `decompress` / `search_context` / `acp_status` / `acp_context_recap` 全部在它里面执行)。其模型请求带 `x-bili-plugin-bypass: 1`,代理原样转发 —— 不注入 wire 工具、不注 nudge、不绑定会话。
95
- - **新会话** —— bili 接管:工具调用转发到代理的 plugin 端点(plugin 模式)。模型看到的工具槽位带 DCP schema(v1 进程级每个名字仅一份定义),但执行器按会话分泳道:新会话的 `compress` 发到代理,旧会话的发给 opencode-acp。`acp_context_recap` 没有代理端对应 —— 新会话调用会收到代理的 unknown-tool 消息。
96
-
97
- `/acp` 与 `/dcp` 同样路由。新会话被 opencode-acp 注册表收编的可能被其 transform 门控(system / messages / text.complete 都过 legacy 谓词)阻断。退化路径:opencode-acp 包缺失或导入失败时 bili 单独运行,旧会话退化为只读存档(旧 `<acp>` 标签照常渲染、`decompress` 返回 `[Block … not found]`、新引用号从 m00001 重新开始)。
98
90
 
99
91
  ## 安装
100
92
 
@@ -127,7 +119,12 @@ bili plugin install kimi # 写 $KIMI_CODE_HOME/plugins/managed/billion-co
127
119
  bili plugin remove <client> # 卸载(dsh 经同一通道移除;配置快照存 .bili-bak)
128
120
  ```
129
121
 
130
- dsh 用户可以完全不用 bili:`dsh plugin --profile <name> add billion-context` 正是 `bili plugin install dsh` 按 profile 驱动的那条命令 —— 两种走法终态一致(pnpm 装进 profile、patch 层由 dsh 自己挂载)—— 见下文 dsh 段。
122
+ 客户端有自己的插件通道时,也可以原生安装、完全不用 bili 命令:
123
+
124
+ - **dsh:** `dsh plugin --profile <name> add billion-context` 正是 `bili plugin install dsh` 按 profile 驱动的那条命令 —— 两种走法终态一致(pnpm 装进 profile、patch 层由 dsh 自己挂载);经同一通道卸载。见下文 dsh 段。
125
+ - **opencode:** 把裸 npm 包名直接写进你真实配置的插件列表 —— `"plugin": ["billion-context"]`(仅 npm 形态;git checkout 没有已发布入口)。包通过 `exports["./server"]` → `dist/agent/opencode-native.js` 暴露插件入口,opencode 用自己的 Npm.add 机制加载,插件自拉起的行为与 bili 安装的形态完全一致。另外要做两件 bili 安装器会替你做的事:在同一份配置里设 `"compaction": { "auto": false }`(否则 OpenCode 的原生自动压缩会双重压缩),并先手工备份该配置文件。
126
+
127
+ pi / omp / kimi / claude 没有客户端侧通道 —— 它们的配置条目由 `bili plugin install <client>` 代写(kimi 的声明式 `kimi.plugin.json` + 注册记录、claude 的受管 settings 块等)。
131
128
 
132
129
  插件加载时**自拉起自己的代理**(已有健康实例则直接复用 —— 父进程 pid 看门狗在客户端退出时收掉它),把模型流量改写到 `<proxy>/bili/<上游URL>`,并把 `compress` / `decompress` / `acp_status` 注册为客户端原生工具(plugin 模式),`/acp` 面板绑定当前会话。插件还会把客户端**自己的模型配置**上报给代理(runtime-info 协议,#955),压缩预算用真实窗口而不是注册表猜测。退出开关:`BILI_NATIVE_PI=0`、`BILI_NATIVE_OMP=0`、`BILI_NATIVE_OPENCODE=0`、`BILI_NATIVE_DSH=0`、`BILI_NATIVE_KIMI=0`。
133
130
 
@@ -149,7 +146,7 @@ launcher 环境变量这档覆盖纯代理客户端(无进程内插件):`bili <c
149
146
  注意:
150
147
 
151
148
  - 原生模式与独立进程内扩展(`billion-context-pi`、`opencode-acp`)**互斥** —— 安装器负责换条目并把原配置快照(`.bili-bak`);迁移细节见上方客户端表(pi 需 `billion-context-pi` 0.1.72+ 才能干净退让)。
152
- - OpenCode 1.x 上,迁移前的 `opencode-acp` 旧会话继续可用(v1 泳道路由,#920)—— 见下文 "OpenCode 1.x"。
149
+ - OpenCode:legacy `opencode-acp` 会话、V1/V2 插件形态与全部注意事项已并入 [OpenCode](#opencode) 一节。
153
150
  - `kimi` 仅在自举时上报 runtime-info(静态 `custom_headers` 无法承载逐请求的窗口/模型头,否则会在模型切换后过期),子代理会话按每次调用的 `conversation_id` 绑定 —— 完整机制见下文「Kimi Code」小节。
154
151
  - `claude` 有**原生姿态**(hybrid,#964):Claude Code 没有进程内扩展点,所以 `bili plugin install claude` 往 `~/.claude/settings.json` 写一个受管块(env `ANTHROPIC_BASE_URL=http://127.0.0.1:48787/bili/<upstream>`、`DISABLE_AUTO_COMPACT=1`、`SessionStart` hook),外加同样指向该稳定端口的用户级 MCP shell。hook 在首个模型请求前触发:附着到端口上健康的代理,或拉起一个 pid 看门狗追踪 claude 本身的代理 —— 代理随会话生灭。端口覆盖:`BILI_CLAUDE_NATIVE_PORT` > config `claude.nativePort` > 48787;上游覆盖:`BILI_CLAUDE_UPSTREAM`(或既有 `claude.anthropicBaseUrl`)。`BILI_NATIVE_CLAUDE=0` 退出 —— hook 改为拉起同端口的 **passthrough** 代理(原样转发、关闭压缩)。块是纯 JSON merge/strip:外部键从不触碰,`bili plugin remove claude` 精确还原。装有原生块的机器上 `bili claude` 仍可用 —— 它用自身临时代理覆盖静态 URL,hook 保持休眠。
155
152
  - `codex` / `omp` 也有配套安装(MCP shell 与轻量扩展),但它们需要一个在跑的代理 —— 不属于原生模式。
@@ -167,7 +164,7 @@ bili pi # 拉起 pi,走代理 —— file-free(#53
167
164
  bili codex # 拉起 codex
168
165
  bili claude # 拉起 claude
169
166
  bili omp # pi 同款,file-free(#535):环境变量 + 扩展 registerProvider + 压缩取消,真实 ~/.omp 不动
170
- bili opencode # HTTPS 走 MITM + 临时 opencode.json(HTTP 走 /bili/)+ 轻量 /acp 插件;OpenCode 2.0+:内置 V2 插件带原生 bili 工具,自动关掉原生 auto-compaction;OpenCode 1.x:旧 opencode-acp 会话继续可用(条目从副本中移除、包以库形式导入,#920)。详见下方「OpenCode 专属说明」
167
+ bili opencode # OpenCode(1.x 与 2.x):完整指南见下文 [OpenCode](#opencode) 一节
171
168
  bili hermes # file-free(#535):hermes 代理环境变量(HTTPS_PROXY + HERMES_CA_BUNDLE)—— https 走 CONNECT MITM,http 走绝对形式转发;真实 ~/.hermes 不动
172
169
  bili dsh # deepseek-harness:经 --patch 注入完整原生插件(#941) —— compress/decompress/acp_status 注册为真实 dsh 工具,请求盖 dsh 会话 id(plugin 模式),/acp 会话绑定;非回环上游走代理 env(https MITM、http absolute-form),回环上游保留 overlay DSH_HOME(~/.dsh-bili)改写(#535),内置 deepseek 路由走 DEEPSEEK_BASE_URL;dsh 原生自动压缩被禁用(compaction-basic auto:false)
173
170
  bili codebuddy # Tencent CodeBuddy Code CLI:CODEBUDDY_BASE_URL /bili/ 重写(OpenAI chat completions wire),预算对齐走 CODEBUDDY_AUTO_COMPACT_WINDOW;真实 ~/.codebuddy 不动
@@ -179,16 +176,6 @@ bili pi --mitm-domain api.foo.com # 向 MITM 白名单追加域名
179
176
  ```
180
177
 
181
178
 
182
- ### OpenCode 1.x —— 旧 opencode-acp 会话继续可用(#920)
183
-
184
- 在 1.x 主机上,`bili opencode` 会**通过 bili 代理运行新会话**,同时**让现有 `opencode-acp`("legacy")会话继续使用其自身机制正常工作**(#920)。启动器会从临时配置副本中移除 `opencode-acp` 条目(主机永远不会以激活状态加载它),而轻量的 bili 插件则改为以库的形式导入已安装的包:
185
-
186
- - 每个 ACP 钩子都以"该会话存在 ACP 存储文件"为门控条件(`~/.local/share/opencode/storage/plugin/acp/<sessionID>.json`,或 `acp.jsonc` 中 `storagePath` 指定的目录)——旧版会话保留其 DCP compress / decompress / search_context / acp_status 工具和 `/dcp` 命令;新会话不会被接管,而是运行纯代理模式。
187
- - 旧版 LLM 请求会被打上 `x-bili-plugin-bypass: 1` 标记,代理将其视为原始透传(无注入、无压缩、无会话状态)。
188
- - 在代理模式下,压缩工具的名称由代理独占:请求体中同名的客户端工具会在注入前被丢弃,因此上游对每个名称只看到一个定义。
189
-
190
- 优雅降级:如果包无法找到/导入或不是 v1 版本,插件的行为与此更改之前完全一致——旧版会话的降级方式与 `opencode-acp` 在 `/bili/` baseURL 上自我禁用时的表现相同。
191
-
192
179
  ### 方式 3 —— 改url(`/bili/` 前缀)
193
180
 
194
181
  启动代理:
@@ -206,7 +193,7 @@ bili
206
193
 
207
194
  更多客户端配置参考网页引导: [http://localhost:8787](http://localhost:8787) .
208
195
 
209
- #### dsh(deepseek-harness)
196
+ ### dsh(deepseek-harness)
210
197
 
211
198
  两条通道,同一个插件(#941):
212
199
 
@@ -216,7 +203,7 @@ bili
216
203
 
217
204
  `bili dsh` 启动下插件**附看**(attach)启动器的代理(不二次拉起)。裸上游 URL 与 spawn 模式一样重写为 `<proxy>/bili/<url>`(回环代理目标永不被代理 env 拦截,等于直接绕开 MITM);已经路由的 `/bili/` 前缀请求原样放行、只盖章。已知局限:手动 `/compact` 没有 dsh 侧事件钩子,其边界交给内核的自然 ingest diff(自动压缩已关,影响罕见)。
218
205
 
219
- #### Kimi Code(Moonshot)
206
+ ### Kimi Code(Moonshot)
220
207
 
221
208
  三种对齐模式:`bili kimi`(启动器,证书 MITM —— 方式 2)、`/bili/` URL 前缀,以及原生插件模式(`bili plugin install kimi`,#963)。Kimi Code v2 的插件体系是纯声明式的(`kimi.plugin.json`:MCP server、hooks、skills —— 没有进程内 JS 执行),所以 bili 无法像 pi/opencode/dsh 那样补丁客户端的 fetch 栈。取而代之,插件带两个小型 node 脚本,在客户端外围完成工作:
222
209
 
@@ -243,44 +230,79 @@ curl -s http://localhost:8787/__bili/stats
243
230
  同时也打到 stderr)。每个请求应该看到一行 `processTurn`,等对话变长后
244
231
  会出现 `[acp-usage] round N input=X cached=Y (cache hit Z%)` + `compress` 事件。
245
232
 
246
- ### OpenCode 专属说明
233
+ ### 客户端用 `http.proxy`(CONNECT)接入但从不压缩
234
+
235
+ 部分客户端(VS Code 系 IDE:CodeBuddy、Cursor、Windsurf……)只提供一个 HTTP **代理**设置(`http.proxy`、`codingcopilot.httpProxyURL` 等),没有可改写的模型 base-URL。这类客户端不走普通的 `/bili/…` 请求,而是把 `CONNECT <模型域名>:443` 发给代理。只有当模型域名在 bili 的 **MITM 白名单**里时这条路径才会被解密;否则 bili 只做盲隧道(不透明转发),永远看不到——也就无法压缩——模型请求(#897)。
236
+
237
+ 该失效模式现在不再静默:
238
+
239
+ - 日志里对每个目标域名打一次 `BLIND TUNNEL WARNING`,附修复步骤;
240
+ - `curl -s http://localhost:8787/__bili/health` 与 `/__bili/stats` 输出 `blindTunnels`(计数 + 精确目标域名,仅 loopback);
241
+ - 存在此类隧道时,`acp_status` 输出会多一节 `UNDECRYPTED TRAFFIC (instance-level)`。
242
+
243
+ 要真正压缩这类客户端:把它的模型域名加进 `billion-context.json` 的 `"mitm".domains`(如 `"mitm": { "domains": ["copilot.tencent.com"] }`)或环境变量 `BILI_MITM_DOMAINS`,重启 bili,并让客户端信任 bili 的根 CA(Node 系客户端用 `NODE_EXTRA_CA_CERTS=~/.local/share/billion-context/ca/root-ca.pem`,有 CA 路径设置的用其设置)。`/bili/` 前缀方案在这里不适用——没有 URL 可改。详见 [CONFIGURATION.zh-CN.md → MITM](CONFIGURATION.zh-CN.md#mitm-透明代理登录客户端)。
244
+
245
+ ## OpenCode
246
+
247
+ 同一个内置插件同时服务两代 OpenCode:agent 文件同时保留 V1 `server()` 与 V2 `setup()` 导出 —— ≥ 1.18.29 的 1.x 宿主加载 V1 形状,2.x 宿主加载 V2 `setup()`。独立扩展 [`opencode-acp`](https://github.com/ranxianglei/opencode-acp) 仅支持 V1,在 2.x 下**不加载** —— 对 OpenCode 2.x,**billion-context 是推荐的上下文管理方案**。以下均在 `@opencode/cli` 2.0.3 上端到端验证过(V1 泳道:1.14.46 与 1.18.31)。
247
248
 
248
- OpenCode 2.0 换了新插件 API(`@opencode/plugin`);独立扩展 `opencode-acp` 仅支持 V1,在 2.0 下不加载。bili 的两种模式在 2.0 都能用。2.x 插件 API 面在不同 build 间仍在变动(相邻的 npm `dev` 构建 `ctx` 形状不同),下面列的钩子/工具细节是针对具体版本的观察,不是稳定契约:
249
+ | 路径 | 命令 | 适用 |
250
+ |---|---|---|
251
+ | 启动器(最省事) | `bili opencode` | 一条命令拉起代理 + 客户端;不碰真实配置 |
252
+ | 原生(免启动器) | `bili plugin install opencode` | 自拉起插件写进真实配置;照常启动 `opencode` |
253
+ | 纯代理(兜底) | baseURL 加 `/bili/` 前缀 | 无插件 —— wire 级工具注入 |
254
+
255
+ ### 启动器 —— `bili opencode`
256
+
257
+ HTTPS 走证书 MITM,HTTP 走临时 `opencode.json` 副本(`/bili/` 改写;JSONC 注释照单接受,合并方式与 opencode 自身一致;相对本地插件路径在副本里重新锚定为绝对路径 —— opencode 按声明所在配置文件目录解析,#826)。宿主代次用 `--version` 探测(探测失败默认按 1.x):**2.x** 宿主注入内置 V2 插件(`dist/agent/opencode.js`),以临时包装目录形式给出(目录入口 `index.js` 再 re-export 插件文件 —— 2.x 拒绝配置 `plugin` 数组里的裸文件路径);**1.x** 宿主直接给裸文件路径。
258
+
259
+ 插件在两代宿主上做的事相同:在宿主内原生注册 bili 工具 —— compress / decompress / search_context / acp_status(另加 absorb)—— 并在每个 provider 请求上盖章代理头,含从宿主自身模型目录(`ctx.catalog.model.list()`,每 60s 刷新)读取的 context-window / max-output,并以 runtime-info 上报给代理(#955)—— 压缩走插件模式,**不做** wire 级工具注入;原生 auto-compaction 自动关闭(`compaction.auto: false`)。所有注册都是防御式的(可选链):任一 2.x build 上接缝缺失或未触发时,插件保持惰性,会话透明回退纯代理模式而不是报错 —— 在相邻的 `dev` build 上观察到过 API 面互不相同(#754 评审探针)。
260
+
261
+ 1.x 细节(1.14.46 + 1.18.31 验证):V1 `.server()` 钩子在进程内把每个 provider 的 `options.baseURL` 改写为 `<proxy>/bili/…` 并设 `compaction.auto: false`;`chat.headers` 每次请求盖章插件头;`tool` 用真实 zod 形状注册 bili 工具(zod 是运行时依赖 —— 解析不到时降级为只改写)。没有显式 `baseURL` 的 provider(SDK 默认值,如裸 `@ai-sdk/openai` → api.openai.com)由全局 `fetch` 补丁兜住(日志:`v1: fetch patch installed`)—— 幂等,`/bili/` 包装过的 URL 原样直通;含 OpenAI Responses 端点端到端验证。
262
+
263
+ ### 原生(免启动器)—— `bili plugin install opencode`
249
264
 
250
- - **启动器:** `bili opencode` 用法不变。在 2.x 宿主上,它把内置 V2 插件(`dist/agent/opencode.js`)以临时包装目录的形式注入临时配置(目录入口 `index.js` 再 re-export 插件文件 —— 2.x 拒绝配置 `plugin` 数组里的裸文件路径;1.x 宿主用裸文件路径)。宿主代次用 `--version` 探测(探测失败默认 1.x 形状)。V2 插件在宿主内原生注册 bili 工具 —— compress / decompress / search_context / acp_status(另加 absorb),JSON-Schema 入参 —— 并在每个 provider 请求上盖章代理头,压缩走插件模式,不做 wire 级工具注入;原生 auto-compaction 自动关闭(`compaction.auto: false`)。所有注册都是防御式的(可选链):任一 2.x build 上接缝缺失或未触发时,插件保持情性,会话透明回退纯代理模式(wire 级注入)而不是报错 —— 在两个相邻 `dev` build(2026-09-13 / 2026-09-14)上观察到过 API 面不同(#754 评审探针);反之在 `@opencode/cli` 2.0.3 上端到端验证过(原生 `acp_status` 经插件端点执行,零 wire 注入)。
251
- - **原生(免启动器):** npm 装好包后跑 `bili plugin install opencode` —— 它在真实 opencode 配置里注册一个自拉起插件并设 `compaction.auto: false`,之后直接跑 `opencode` 即可。入口形态取决于**本 bili 自身的安装来源**:**npm 安装**写裸包名(`"plugin": ["billion-context"]`)—— 包通过 `exports["./server"]` → `dist/agent/opencode-native.js` 暴露插件入口,opencode 用自己的 Npm.add 机制加载、自行管理安装与升级;零绝对路径、可跨机同步。**git checkout / 开发构建**没有已发布入口,回退到本机 shim 目录(`<configDir>/plugins/billion-context/index.js` → 该 checkout 的 `dist/agent/opencode-native.js`)—— 按构造即机器本地、不可跨机;之后改用 npm 安装再跑一次 install 会把条目迁回裸包名。加载时插件自拉起自己的代理(健康的已有实例直接复用不重复起;父进程 pid 看门狗在 opencode 退出时收掉它),把模型流量路由到 `<proxy>/bili/<upstream-url>`,并暴露与启动器模式相同的原生 bili 工具 —— 无固定端口、无环境变量、免启动器。退出:`BILI_NATIVE_OPENCODE=0`。若没有任何代理能拉到健康状态,请求直连(不压缩)并给一次性告警,之后自动恢复。在 `bili opencode` 启动下该入口整体跳过(代理归启动器管)。
265
+ 在真实 opencode 配置里注册一个自拉起插件并设 `compaction.auto: false`,之后直接跑 `opencode` 即可。默认不加 MCP 面(原生插件已提供会话绑定的 bili 工具);需要就传 `--with-mcp` —— 该条目不带 origin 钉扎,能扛过插件临时端口的代理重启(#926)。条目形态取决于**本 bili 自身的安装来源**:**npm 安装**写裸包名(`"plugin": ["billion-context"]`)—— 包经 `exports["./server"]` → `dist/agent/opencode-native.js` 暴露插件入口,opencode 用自己的 Npm.add 机制加载、自行管理安装与升级;零绝对路径、可跨机。(这个裸包名条目也可以不经 bili 直接手写进配置 —— 见方式 1。)**git checkout / 开发构建**回退到本机 shim 目录(`<configDir>/plugins/billion-context/index.js` → 该 checkout 的 `dist/agent/opencode-native.js`)—— 按构造即机器本地;之后改用 npm 安装再跑一次 install 会把条目迁回裸包名。
252
266
 
253
- 同一个包装器也服务 **OpenCode 1.x**(V1 `.server()` 钩子;在 1.14.46 和 1.18.31 上验证):`config` 钩子在进程内直接改共享配置对象,把每个 provider 的 `options.baseURL` 改写为 `<proxy>/bili/…` 并设 `compaction.auto: false`;`chat.headers` 每次请求盖章插件头;`tool` 用真实 zod 形状注册 bili 工具(zod 是运行时依赖 —— 解析不到时插件降级纯代理模式:只改写、wire 注入工具);`/acp` 命令渲染同一张状态面板。**没有显式 `baseURL`** 的 provider(SDK 默认值,如裸 `@ai-sdk/openai` → api.openai.com)由全局 `fetch` 补丁(pi-native 同机制)兑住 —— 模型 API 调用重路由到代理(日志:`v1: fetch patch installed`),在 1.14.46 / 1.18.31 上含 OpenAI Responses 端点端到端验证;补丁幂等,`/bili/` 包装过的 URL 原样直通。
254
- - **纯代理:** 与其它客户端一样,把 provider baseURL 指向代理:
267
+ 加载时插件自拉起自己的代理(健康的已有实例直接复用不重复起;父进程 pid 看门狗在 opencode 退出时收掉它),把模型流量路由到 `<proxy>/bili/<upstream-url>`,暴露与启动器模式相同的原生 bili 工具 —— 无固定端口、无环境变量、免启动器。退出:`BILI_NATIVE_OPENCODE=0`。若没有任何代理能拉到健康状态,请求直连(不压缩)并给一次性告警,之后自动恢复。在 `bili opencode` 启动下该条目整体跳过(代理归启动器管)。
255
268
 
256
- ```json
257
- {
258
- "provider": {
259
- "myprovider": {
260
- "npm": "@ai-sdk/openai-compatible",
261
- "options": {
262
- "baseURL": "http://localhost:8787/bili/http://upstream.example/v1",
263
- "apiKey": "sk-any"
264
- }
269
+ ### 纯代理(无插件)
270
+
271
+ 与其它客户端一样,把 provider baseURL 指向代理:
272
+
273
+ ```json
274
+ {
275
+ "provider": {
276
+ "myprovider": {
277
+ "npm": "@ai-sdk/openai-compatible",
278
+ "options": {
279
+ "baseURL": "http://localhost:8787/bili/http://upstream.example/v1",
280
+ "apiKey": "sk-any"
265
281
  }
266
282
  }
267
283
  }
268
- ```
284
+ }
285
+ ```
269
286
 
270
- 注意:2.0 AI-SDK provider 即使本地端点从不校验也要求 `apiKey` 字段 —— 随便填个非空值。
287
+ 注意:2.0 AI-SDK provider 即使本地端点从不校验也要求 `apiKey` 字段 —— 随便填个非空值。
271
288
 
272
- 注意事项:2.x 系列以 npm 包 `@opencode/cli` 发布。命令支持随 build 而定:某个预发布版只暴露 list/get/update/remove,而 2.0.x 稳定版允许插件经 `ctx.command.transform((editor) => editor.add(...))` 新增命令 —— TUI 里接受斜杠菜单补全(Tab + Enter)即可调用;注意 `opencode run` 模式完全不派发斜杠命令(它们会透传给模型)。内置插件在两种形状上都刻意不注册命令。
273
- ### 客户端用 `http.proxy`(CONNECT)接入但从不压缩
289
+ ### 状态:`/acp` 与 `acp_status`
274
290
 
275
- 部分客户端(VS Code 系 IDE:CodeBuddy、Cursor、Windsurf……)只提供一个 HTTP **代理**设置(`http.proxy`、`codingcopilot.httpProxyURL` 等),没有可改写的模型 base-URL。这类客户端不走普通的 `/bili/…` 请求,而是把 `CONNECT <模型域名>:443` 发给代理。只有当模型域名在 bili 的 **MITM 白名单**里时这条路径才会被解密;否则 bili 只做盲隧道(不透明转发),永远看不到——也就无法压缩——模型请求(#897)。
291
+ `/acp` 面板在所有模式下都绑定当前会话,`acp_status` 工具是其宿主内等价手段。在命令编辑器支持新增条目的宿主(2.0.x 稳定版,`editor.add`)上,V2 插件额外注册 `/acp` 斜杠命令 —— 以合成非模型消息渲染,面板优先(与 `acp_status` 工具一致);旧形状上该注册保持惰性。注意 `opencode run` 模式完全不派发斜杠命令(它们会透传给模型)—— 请用 TUI。
276
292
 
277
- 该失效模式现在不再静默:
293
+ ### 旧 opencode-acp 会话(#920)
278
294
 
279
- - 日志里对每个目标域名打一次 `BLIND TUNNEL WARNING`,附修复步骤;
280
- - `curl -s http://localhost:8787/__bili/health` 与 `/__bili/stats` 输出 `blindTunnels`(计数 + 精确目标域名,仅 loopback);
281
- - 存在此类隧道时,`acp_status` 输出会多一节 `UNDECRYPTED TRAFFIC (instance-level)`。
295
+ 在 1.x 宿主上,迁移前的 [`opencode-acp`](https://github.com/ranxianglei/opencode-acp) 旧会话在两条泳道下都继续可用:启动器从临时配置副本中移除 `opencode-acp` 条目(宿主永远不会以激活状态加载它),各泳道把已安装的包作为库吸收(直接从 `node_modules` 导入 —— `.opencode/node_modules`、项目 `node_modules`、全局 npm root、opencode 配置级 modules,先到先得)。会话属于 legacy ⟺ opencode-acp 的持久化状态文件存在(`<XDG_DATA_HOME>/opencode/storage/plugin/acp/<sessionID>.json`,或 `acp.jsonc` 中 `storagePath` 指定的目录):
282
296
 
283
- 要真正压缩这类客户端:把它的模型域名加进 `billion-context.json` 的 `"mitm".domains`(如 `"mitm": { "domains": ["copilot.tencent.com"] }`)或环境变量 `BILI_MITM_DOMAINS`,重启 bili,并让客户端信任 bili 的根 CA(Node 系客户端用 `NODE_EXTRA_CA_CERTS=~/.local/share/billion-context/ca/root-ca.pem`,有 CA 路径设置的用其设置)。`/bili/` 前缀方案在这里不适用——没有 URL 可改。详见 [CONFIGURATION.zh-CN.md → MITM](CONFIGURATION.zh-CN.md#mitm-透明代理登录客户端)。
297
+ - **旧会话** —— 压缩由被吸收的 opencode-acp 执行(它自己的引用号与块存储照常工作:`compress` / `decompress` / `search_context` / `acp_status` / `acp_context_recap` 全部在它里面执行)。其模型请求带 `x-bili-plugin-bypass: 1`,代理原样转发 —— 不注入 wire 工具、不注 nudge、不绑定会话。
298
+ - **新会话** —— bili 接管:工具调用转发到代理的 plugin 端点(plugin 模式)。执行器按会话分泳道:新会话的 `compress` 发到代理,旧会话的发给 opencode-acp。`acp_context_recap` 没有代理端对应 —— 新会话调用会收到代理的 unknown-tool 消息。
299
+
300
+ `/acp` 与 `/dcp` 同样路由。新会话被 opencode-acp 注册表收编的可能被其 transform 门控(system / messages / text.complete 都过 legacy 谓词)阻断。退化路径:包缺失、导入失败或不是 v1 时,bili 单独运行,旧会话退化为只读存档(旧标签照常渲染、`decompress` 返回 `[Block … not found]`、新引用号从 m00001 重新开始)。
301
+
302
+ ### 注意事项
303
+
304
+ - 2.x 系列以 npm 包 `@opencode/cli` 发布,且插件 API 面在不同 build 间仍在变动(相邻 `dev` 通道构建暴露不同 `ctx` 形状)—— 上文钩子/工具细节是针对具体版本的观察,不是稳定契约。
305
+ - 设计说明:V2 插件是薄协议客户端(不含 acp-kernel)—— 代理始终是唯一的压缩权威,消除 agent 与代理间的内核版本漂移;它不依赖插件 API 无法改上下文这一事实(该能力随 2.x build 变化)。
284
306
 
285
307
  ## 运行代理
286
308
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "billion-context",
3
- "version": "0.1.122",
3
+ "version": "0.1.123",
4
4
  "description": "Context-compression proxy that lets AI coding agents run for days — billions of tokens through one context window. Sits between any agent (Claude Code, Codex, Cursor, Aider, …) and its model API, folding consumed conversation into reversible, prefix-cache-friendly summaries. Zero per-agent code: just point your base URL at the proxy.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",