diff --git a/CHANGELOG.md b/CHANGELOG.md index 68689cb8..27878fb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 ` 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 `-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`/``/`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..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. diff --git a/package-lock.json b/package-lock.json index 72ddfd9a..5e40b691 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "billion-context", - "version": "0.1.100", + "version": "0.1.101", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "billion-context", - "version": "0.1.100", + "version": "0.1.101", "license": "MIT", "bin": { "bili": "dist/index.js", diff --git a/package.json b/package.json index 960224c8..4656dd09 100644 --- a/package.json +++ b/package.json @@ -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",