Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@ Versions follow the merge of a `*_release-v*` branch; CI publishes to npm on tag

### Fixes

- **Windows: spaced client/extension paths no longer break launched clients or silently drop extensions (#679, PR #682)**: `runClient` spawned clients with `shell: true` and no per-token quoting, so on Windows cmd.exe re-split the joined line at the first space — a client binary under a spaced path (`C:\Users\John Doe\...`) died with `'C:\Users\John' is not recognized`, and a surviving client whose `-e <extension>` path was split launched WITHOUT the bili extension (compression silently never activates). Spawning is now routed by executable class: real `.exe`/node binaries spawn directly (the OS quotes argv, spaces intact), npm `.cmd`/`.bat`/extensionless shims go through an explicit `comspec /d /s /c "…"` line with correct per-token quoting (`windowsVerbatimArguments`); `shell: true` is gone (also silences Node's DEP0190 warning). Known edge: `BILI_CLIENT_BIN` pointing at a `.js` file now fails loudly instead of relying on file association via the old shell path.
- **Windows: codex MCP server delivered via CODEX_HOME overlay, not inline `-c` (#681, PR #683)**: cmd.exe cannot transmit a literal `"` to a child, but every valid TOML string needs one — so the inline `-c mcp_servers.bili.command="C:\\Program Files\\nodejs\\node.exe"` arg arrived at codex as an unquoted, space-split, invalid TOML value for ANY absolute Windows path (spaced stock install just the common case), the bili MCP server never registered, and plugin-mode compression silently never activated. On `win32` the launcher now writes `[mcp_servers.bili]` (command/args/env.BILI_MCP_PROXY/env.BILI_CONVERSATION_ID) into a persistent `<CODEX_HOME>-bili` overlay's merged `config.toml` — sharing every other real-home entry (auth.json, sessions, model settings) — and points the spawned codex at it via `CODEX_HOME`. POSIX keeps the working inline `-c` path byte-identical; if the overlay can't be built the launch degrades to wire mode (server-side compression still active) with a warning. Real-Windows end-to-end verification tracked in #686.
- **`bili plugin install codex` self-heals malformed config blocks instead of short-circuiting (#638, PR #685)**: the "already installed" check compared only the `BILI_MCP_PROXY` line, so a malformed `[mcp_servers.bili]` block (e.g. `args` written as a quoted string — legal TOML, invalid codex schema) survived reinstall untouched and codex kept failing with `expected a sequence`. The whole block is now compared against the canonical `codexBlock()` (trimEnd-normalized): byte-equal → `already installed`; anything else → rewritten in place, with an explicit `(repaired args: was not an array)` hint when args was string-valued.
- **codex reports the folded request's own usage — #408 uncompressed-baseline backfill suppressed for codex (#645, PR #647)**: codex fell through every #408 backfill exemption, so its context meter showed a virtual cumulative baseline the model never receives — drifting turn-to-turn (the meter could DECREASE with no compress), exceeding the window (1315/950k = 138%), and driving nothing (codex auto-compact keys off `total_tokens`, which the backfill never touches). `armHostUsageCredit` now exempts codex clients — detected by UA, the same signal as native-compact interception, because bili-launched codex sessions carry `pluginAgent:"mcp"` shared with claude. `isCodexClient` also gained a lenient fallback (UA containing `codex`, case-sensitive) so new codex client variants (codex_sdk_ts/…) can't silently fall out of detection. Plain proxy clients keep the #408 behavior; `hostUsageCredit:"off"` (#648) still opts out entirely.
- **Upstream fetch no longer follows redirects on the client's behalf (#661, PR #664)**: `fetchWithTimeout` left `redirect` unset, so undici's default `"follow"` kicked in — a 301/302/303 on a POST was downgraded to GET with the body dropped, and the redirect target (a POST-only API behind a CDN/WAF) answered **405**. A forward proxy must hand the 3xx (status + `Location`) back to the client; `redirect:"manual"` now does exactly that.
- **Codex (ChatGPT-login) preflight summaries work end-to-end (#663, PR #665)**: the ChatGPT codex backend rejects the Responses `max_output_tokens` parameter outright (400), killing preflight summaries with a 502 — the proxy now detects that rejection, retries the summary without the optional parameter, and learns it per session+upstream+model (bounded, at most once per capability). The summary call also no longer forwards the Codex-Lite header (`x-openai-internal-codex-responses-lite`) that demands `reasoning.context: all_turns` the summary body doesn't carry — stripped from the independently-built summary call only; the main request keeps it.
- **Tag-echo filter tolerates typo'd tag names; degenerate end_turn turns get a warning (#673, PR #674)**: a model echo with a typo'd tag name (an `acp` permutation plus one stray char — `acpi`/`acip`) bypassed every exact-spelling strip pattern, and the 43-char fragment became the turn's ENTIRE visible text (`stop_reason=end_turn`, zero tool_use, the real plan stranded in thinking) — the agent stalls until nudged. All strip patterns now match a programmatically-built acplike name set (66 members, strict name boundaries so `acpi.h`/`<caption>`/`ACPI_DEVICE` in real text stay untouched), the swallow-scan recognizes loose close variants, and a degenerate-turn detector logs `[degenerate-turn]` when a turn carries echo-only text with no tool calls — the groundwork for auto-retry. Follows #644/#646 (v0.1.97 incident family).

### Features

- **Per-route `passthrough` option for providers (#661, PR #662)**: `"providers": { "mitm://zcode.z.ai": { "passthrough": true } }` forwards matching requests byte-for-byte — no kernel round-trip, no render tags, no `prompt_cache_key` removal, response piped verbatim, no session state — the scoped sibling of the global `passthrough` switch. `mitm://` keys target only MITM (login-client) traffic; plain `https://` host keys cover both MITM and `/bili/` traffic.

- **Round-evidence closure for compress-reasoning drop (#651, #348 twin)**: the closure gate shipped with the reasoning drop — "compress call followed by a genuine user message" — is unreachable in long agentic sessions (no user messages after the opening prompt, observed: 0 drops while 30 compress rounds retained 20.6K/8.4K/10.6K-char thinking floors). A round now closes on tool-result evidence: the compress call's `tool-result` (matching `toolCallId`) exists at a later index and at least one message follows it. In-flight rounds (result missing or still the last message) stay untouched; per-provider `compress.providers.<name>.reasoning.drop=false` escape hatch preserved for reasoning-replay models (GLM). Mirrors billion-context-pi #348 (PR #349).
- **`hostUsageCredit` config switch: opt plain proxy clients out of the #408 uncompressed-baseline usage backfill (#648)**: plain anthropic proxy clients (ZCode — base-url → proxy, no `x-bili-plugin` header, no special UA) fell through every #408 backfill exemption (pi/omp by `pluginAgent`, codex by UA in #647) and got the full uncompressed-baseline backfill armed, so their UI showed a cumulative, drifting baseline (real folded value + per-compression backfill) instead of the actually-forwarded context — overstating real pressure and going non-monotonic on pure-append turns (est drift). New `hostUsageCredit` option (`"auto" | "off"`, default `auto` = current behavior; `BILI_HOST_USAGE_CREDIT` env / `hostUsageCredit` file key). `off` disables the #408 backfill entirely so the usage reported to the host is the actually-forwarded (folded) request, matching `[acp-usage] input=`. `auto` keeps today's behavior for everyone; ZCode users set `off` to get the actually-forwarded value.

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "billion-context",
"version": "0.1.100",
"version": "0.1.101",
"description": "Universal context-compression proxy for AI coding agents. Sits between any agent and its model API, rewriting Anthropic/OpenAI streams with acp-kernel compression. Any agent that can set a base URL (Claude Code, Codex, Cursor, Aider) works out of the box.",
"type": "module",
"main": "dist/index.js",
Expand Down
Loading