- Adjusted `resolveConfigCodexStyleKey` to include `validateIndexCredentials` for stricter credential checks.
- Enhanced logic in `buildCodexConfigModels` to handle empty model lists more effectively.
- Standardized credential matching with helper functions for improved maintainability.
- Adjusted `responseSchema` logic to only set schema for `json_schema` type while ensuring it is excluded for `json_object`.
- Updated tests to reflect changes in `responseSchema` handling, ensuring correct validation for both response formats.
- Renamed test function for better clarity regarding `json_object` behavior.
Closes: #4667
- Added safeguards against repository corruption with improved recovery mechanisms, including remote re-cloning and worktree restoration.
- Introduced fine-grained repository integrity checks and missing file restoration logic.
- Centralized repository locking with `ensureRepositoryLocked` to standardize synchronization.
- Enhanced conflict resolution during pulls with automated reconciliation of remote and local changes.
- Improved worktree and index reset workflows to handle dirty and missing paths gracefully.
- Increased robustness for garbage collection with extended grace period and recovery paths.
Closes: #4629
- Replaced boolean parameters with a `jsonSchemaCleanOptions` struct in `cleanJSONSchema` to improve readability and scalability.
- Updated `CleanJSONSchemaForAntigravity` and related methods to utilize the new options struct.
- Enhanced flexibility for schema transformations with fine-grained control over operations like union flattening, enum type enforcement, and metadata removal.
- Added comprehensive tests to verify correct handling of unions and enum types in schemas.
Closes: #4666
- Added logic to merge consecutive tool responses into a single user message for better grouping.
- Updated `ConvertOpenAIRequestToClaude` to track previous roles and adjust message blocks accordingly.
- Introduced a comprehensive test to validate tool result grouping behavior and content preservation.
Closes: #4656
- Replaced `pendingCodexFunctionCall` with `codexFunctionCallStream` for enhanced function call tracking.
- Introduced `DeferredStreamEvents` to handle deferred event processing.
- Simplified and standardized codex function call state management with consolidated methods.
- Enhanced reasoning and thinking block handling to ensure proper closure and new block initiation.
- Removed redundant methods, improving maintainability.
Closes: #4655
- Updated `OpenAIUsage` to include `cachedCreationTokens` for improved token tracking.
- Adjusted token calculations and usage mapping to incorporate `cachedCreationTokens`.
- Expanded tests to verify inclusion of `cachedCreationTokens` in usage details.
- Replaced instances of `thinking.ApplyThinking` with `helps.ApplyRequestThinking` across all executors for consistency.
- Updated `applyGeminiInteractionsThinking` to accept `cliproxyexecutor.Request` and `Options`.
- Centralized logic for request thinking application to `helps` package for improved maintainability.
Closes: #4618
Client.KVCompareAndSwap sent Redis EVAL with a Lua script, but the Home RESP
subset does not implement EVAL, so Home replied "ERR unknown command 'eval'".
That broke the Antigravity and Codex reasoning replay caches in Home mode.
Switch the transport to Home's dedicated CAS command:
CAS <key> <expected-exists 0|1> <expected-value> <new-value> [PX <ttl-ms>]
The semantics match the old script argument for argument, so KVCompareAndSwap's
signature and all its callers are unchanged. Omitting PX when ttl <= 0 mirrors
the script's SET-without-PX branch, which clears the TTL.
Deployments that predate CAS reject the command. Detect that by matching the
unsupported-command error, latch ErrCompareAndSwapUnsupported for the client
lifetime so later calls skip the round trip, and warn exactly once. The latch is
deliberately not carried across NewLifetime, so a Home upgrade takes effect on
the next reconnect rather than requiring a CPA restart.
Also stop replay-state failures from failing the request. A bare replay error has
no HTTP status, so resultErrorFromError does not classify it as request-scoped and
MarkResult marks the credential unavailable for that model, walking every
candidate credential until alias resolution has nothing left and returns 503. A
ledger miss is already a tolerated outcome, so degrade to "no replay this turn"
instead. The pairing failure still returns its 400.
Verified end to end against a real Home over RESP/mTLS on PostgreSQL with
Antigravity OAuth credentials: patched Home recreates the replay row through CAS
with its TTL, while a pre-CAS Home latches once, keeps returning 200 instead of
503, and records no credential error attributable to the replay path.
Refs router-for-me/CLIProxyAPIHome#79
- Added `ClientRequestMetadata` struct to capture client IP, `X-Forwarded-For` headers, and user agent.
- Implemented metadata extraction in HTTP handlers and propagation through context.
- Updated Redis queue plugin to include client request metadata in payloads.
- Added tests to validate metadata extraction and inclusion in request contexts.
- Added support for weighted round-robin authentication scheduling strategy.
- Implemented credential weight validation for attributes and metadata, with strict error handling for invalid weights.
- Enhanced scheduler with smooth weighted state handling and proportional selection logic.
- Introduced tests for credential weight parsing, validation, and weighted round-robin behavior.
- Updated configuration to include `weight` field for credentials with range validation.
Closes: #4470
A cached text signature is pinned to its part by that part's own content
fingerprint. Gemini validates a signature's own integrity and never its
binding to the surrounding history, so drift elsewhere in the conversation
cannot invalidate it. Gating the fingerprinted lookup on the context hash
only discarded reasoning the model then had to redo. The legacy positional
fallback has no such proof and stays gated.
Reasoning replay treated a changed history as proof that a cached thought
signature had become invalid, so a drifted context or a ledger miss dropped the
signature and left the call on the bypass sentinel. Once that happened the
damage cascaded: every later ledger item verifies its contextHash against the
restored bytes of all preceding contents, so one broken link cost the whole tail
of the conversation its reasoning.
Testing the assumption directly against daily-cloudcode-pa.googleapis.com shows
it does not hold. Gemini validates a thought signature's own integrity and
nothing else -- corrupting one byte returns "Corrupted thought signature", while
changing the system instruction, adding a tool, rewriting an earlier call's
args, rewriting a tool result, or swapping two turns' signatures are all
accepted. Only the newest functionCall group has to carry a signature at all,
and the bypass sentinel satisfies that.
Keeping the signature is worth doing rather than merely harmless: on an
otherwise identical request, replacing every signature with the sentinel raises
thoughtsTokenCount from 11-15 to 41-53, so a broken chain makes the model
re-reason from scratch.
Restore the signature on the identity-only path, and stop deleting the client's
in-band signature while degrading unresolved provenance IDs. Argument integrity
is unaffected: that is the opaque digest ID's job, not the signature's.
Since #4525 a Claude Code session against Antigravity Gemini could die
permanently with HTTP 400 "missing Claude tool provenance". The reserved
cpa_gemini_<digest> IDs live in the client transcript forever, so once the
replay ledger cannot resolve them every later request fails the same way and
the request never reaches upstream.
Live testing against gemini-3.6-flash-high confirmed four independent ways the
ledger lookup breaks, all producing the same 400:
A contents mutated earlier in the history -> contextHash rejects an exact
opaque-ID match, so proven identity is discarded along with the signature
B one extra system block -> the session key embeds the
system lane, so the whole ledger bucket switches and comes back empty
C process restart or TTL expiry -> empty bucket
D one mid-stream client abort -> that turn never commits
D needs nothing but a single interrupted stream and kills the session from its
very first tool turn, which matches the reported symptom most closely. Parallel
tool calls are not the trigger; they only lengthen the history.
Split tool identity recovery from context-bound signature replay:
- antigravityFunctionCallProvenanceLocation resolves a call when the payload ID
equals the opaque digest derived from a ledger item. That digest is
sha256(call_id, name, args), so an exact match already proves the identity and
the context hash adds nothing to it. Such a call is restored to its native
id/name/args with its paired functionResponse, but deliberately stays
unsigned - the cached signature belongs to a different history.
- Unresolved reserved IDs are now rewritten to deterministic neutral IDs rather
than aborting the request. Pairing is preserved, untrusted signatures are
dropped, and only genuinely malformed histories still error.
- antigravityRepairUnsignedFirstFunctionCalls re-asserts the leading-call
signature invariant after replay, because the request-level sanitizer runs
before it. Native signatures are never touched.
Also fixes a corruption the fail-closed check was masking: when a client changed
a call's arguments, replay inserted a duplicate native functionCall next to the
mutated one, leaving more calls than responses.
Adds forensic debug logging (hashed session keys and counts only) that
distinguishes a ledger miss from a context-hash rejection.
Verified live: happy path unchanged over 20 upstream requests and 100 parallel
call groups (0 residual reserved IDs, every group 1 native-signed + 4 unsigned);
all four failure modes now return 200; and a session survives a mid-stream abort
plus 5 further requests that previously died.
- Added `applyOpenAIResponseFormatToGemini` for translating OpenAI Chat Completions `response_format` to Gemini configuration.
- Supported automatic mapping of `json_object` and `json_schema` types to Gemini `responseMimeType` and `responseJsonSchema`.
- Updated structured output handling to pass schemas through and clean unsupported fields.
Closes: #4582
- Implemented a Go-based dynamic library plugin for request lifecycle management.
- Added concurrency controls, keyword-based request termination, and response handling.
- Supported optional capabilities for request interception and active lifecycle termination.
- Included tests for schema compatibility, concurrency limits, and policy-based termination.
- Added build instructions and configuration details in README.
- Updated host support for lifecycle plugin RPC methods.
Closes: #4568
- Added detailed specifications for `Gemini 3.1 Pro Preview`, `Gemini 3.5 Flash Lite`, and `Gemini 3.6 Flash` models, including token limits, generation methods, and thought levels.
- Updated `models.json` to include entries for all three versions.
Closes: #4555
- Introduced a new reasoning level, `minimal`, to the `codexClientAllowedReasoningLevels` map.
- Updated response-building logic to include descriptive messaging for the `minimal` level.
Closes: #4542
- Added detailed specifications for `Gemini 3.5 Flash Lite` and `Gemini 3.6 Flash` models, including token limits, generation methods, and thought levels.
- Updated `models.json` to include entries for both versions across relevant segments.
Closes: #4521
- Introduced `DisableCloakingModelList` in `ClaudeCodeConfig` to control model ID cloaking in Anthropic model list responses.
- Updated relevant APIs and handlers to respect the new configuration.
- Added comprehensive tests for enabling/disabling cloaking behavior and config-driven hot reload scenarios.
- Extended example configuration and documentation to include the new setting.
Closes: #4473
- Added handling for `input_image` in `toolOutputContentPart` and updated related parsing logic.
- Introduced `hasToolOutputImagePart` to check content for image-related types.
- Improved `setToolCallOutputContent` to handle structured content with image parts recursively.
- Refined detail extraction and type mapping for `input_image` and `image_url` cases.
Closes: #4458
- Introduced `NormalizeClaudeToolInputSchema` in `util` package to standardize tool input schemas for compatibility with Claude.
- Replaced local `normalizeClaudeToolInputSchema` implementations in translator functions with the new utility method.
- Improved handling of schema validation, union elimination, and property merging.
- Removed redundant code in response and chat-completions translators, streamlining schema normalization logic.
Closes: #4428
- Introduced `InjectXSearch` in `XAIConfig` to enable automatic injection of the native `x_search` tool when not explicitly declared.
- Updated `XAIExecutor` to honor the `InjectXSearch` configuration, ensuring consistent tool availability.
- Enhanced configuration handling with support for dynamic diffing to track changes in `InjectXSearch`.
- Added comprehensive tests to validate `InjectXSearch` behavior, including preparation and tool choice synchronization.
- Updated example config and documentation to outline `InjectXSearch` usage.
Closes: #4339
- Introduced `PostgresCooldownStateStore` for saving and loading cooldown states in a PostgreSQL database.
- Supported runtime cooldown state management with efficient upsert and deletion.
- Added configurable integration via `PostgresStoreConfig` and updated schema management to include cooldown-related tables.
- Included tests to validate persistence, normalization, and concurrent handling of cooldown state records.
- Enabled overriding cooldown state stores via service builder and SDK configuration.
Closes: #4254