generateThinkingSignature() returned an object
({type, hash, length, timestamp}) but Anthropic requires a thinking
block's `signature` to be a non-empty opaque STRING. The object made
the thinking block invalid, breaking the stream against reasoning
backends and surfacing as a false 502 "did not respond within 600s".
Return a deterministic base64 token instead (no Date.now()), and
narrow ThinkingSignature to a string alias so existing imports stay
intact. The signature is only ever assigned, never read as an object,
so consumers are unaffected. Update the existing unit test to the
corrected string contract.
Built [OnSteroids](https://onsteroids.ai)
Add two contract tests on the public proxy path
createAnthropicProxyResponse: JSON and SSE. Anthropic requires a
thinking block's signature to be a non-empty opaque string, but ccs
currently fabricates the signature as an object via
generateThinkingSignature(), which breaks the stream against reasoning
backends.
Built [OnSteroids](https://onsteroids.ai)
Cross-reference the two helpers that solve the persisted-settings-env
override (overlay in launch-settings.ts, strip in
openai-compat-launch-settings.ts) and mark shell-executor's
ANTHROPIC_MODEL_ENV_KEYS as the intentional superset distinct from the
4-key list in extended-context-utils. See issue #1609.
Add a test for the env-only overlay fallback when the persisted settings
file is corrupt (the existing 'missing file' test skips JSON.parse), and
a POSIX-gated assertion that the overlay is written 0600 inside a 0700
dir, since it carries an auth token.
The runtime settings overlay cleanup was registered only on the child
'exit'/'error' events, which run after spawn() returns. A synchronous
spawn() throw (e.g. invalid arg/env) propagated out of launchClaude
before those handlers were wired, orphaning the secret-bearing 0600
overlay file in os.tmpdir(). Wrap the spawn in try/catch and run the
idempotent cleanup before rethrowing.
Google retired the gemini CLI on 2026-06-18, so the gemini websearch fallback no longer
works. Add agy (Antigravity) as the primary CLI websearch provider end to end: runtime spawn
in websearch-transformer.cjs (agy --dangerously-skip-permissions --print-timeout Ns -p),
detection (agy.ts), config schema and defaults, hook env, status, dashboard persistence, and docs.
The legacy gemini provider stays present but is marked deprecated for enterprise users who
retain access. Image analysis already supported the agy provider (no change). The CLIProxy
gemini quota fetcher (Gemini API OAuth, not the cli binary) is untouched.
Validation: typecheck, lint, and the websearch + config + web-server unit suites pass.
Add a Requesty provider preset to the provider preset catalog, mirroring the existing OpenRouter preset (base https://router.requesty.ai/v1, default model openai/gpt-4o-mini, OpenAI-compatible).
Normalize Codex Responses base URLs so CCS-backed Codex launches use /backend-api/codex on the original CLIProxy backend. Share the Codex Responses route builder with ccsxp provider repair, and repair stale native Codex provider auth blocks when env_key token injection is used.
Claude Code applies the --settings `env` block over the process
environment, so the persisted ANTHROPIC_BASE_URL (CLIProxy-direct)
overrode the ephemeral proxy-chain URL CCS injects via env. Claude then
bypassed the tool-sanitization / codex-reasoning proxies, surfacing as
`400 {"detail":"System messages are not allowed"}` for Codex.
Write a runtime settings overlay (in os.tmpdir(), matching
createOpenAICompatLaunchSettings) whose routing env keys reflect the
resolved launch environment, and pass it to `--settings`. The overlay is
cleaned up on Claude exit; subcommands keep the persisted path untouched.
Reuse the canonical routing/model env key lists from shell-executor
instead of duplicating them.
Addresses two review focus areas:
- Stale Parked Rows: profiles with no on-disk credentials cached their parked
row for the full quota TTL, so a fresh login stayed dimmed for up to 10 min.
Parked rows (quotaStatus 'unsupported') now use a 30s TTL so a new login is
picked up within seconds.
- Codex Fallback: a named codex profile whose token authenticated but whose
response lacked core windows was downgraded to a parked/needsAuth row, hiding
a real subscription. It now emits an active (quota-less) row; only the bare
default still falls back to global local session data.
Also fixes a latent coalescing bug the short TTL exposed: a synchronous return
inside the pending IIFE cleared state.pending during its own assignment, leaving
a stale resolved promise that the next call reused. The IIFE now yields once so
the assignment lands before the finally clears it.
The Codex CLI provider config uses wire_api = "responses", so the Codex CLI
appends "/responses" to its base_url. buildCodexCliproxyProviderBaseUrl derived
the base URL from the backend-aware route helper, which returns the bare root for
the original backend. Codex then called http://127.0.0.1:<port>/responses, which
the original CLIProxy binary does not serve, producing a 404 on every request.
The original backend serves the Codex Responses API only at /v1/responses and the
chatgpt_base_url-compatible alias /backend-api/codex/responses. Use that alias for
the original backend; keep the provider-scoped alias for the Plus backend.
Closes#1597