- Add `advisor-tool-2026-03-01` beta header support when advisor server tools are declared or explicitly requested.
- Ensure proper ordering of the advisor tool beta before advanced tool use and effort betas.
- Inject and preserve advisor tool beta across token counting and fingerprint preservation paths.
Closes: #5330
- Populate a default string `items` schema on tool array definitions missing an items property for Gemini and Antigravity.
- Add helper to identify array declarations across single strings and type lists during schema normalization.
Closes: #5292
- Support CRLF line endings and skip hidden dot directories in nocopy invariant tests.
- Handle environment variable overrides and skip case-sensitive token priority tests on Windows.
- Use static OS and architecture values in Claude header fingerprint assertions for deterministic test results.
Closes: #5295
- Avoid overwriting parent properties when resolving `anyOf`/`oneOf` unions on object schemas, merging branch properties instead.
- Add `contains` to unsupported constraints and preserve object/array constraint hints in descriptions.
- Strip `required` arrays when the schema does not define a `properties` object.
Closes: #5219
- Export `InlineLocalRefs` utility to resolve local JSON Pointer references.
- Inline local definitions and remove `$defs`/`definitions` in tool function parameters.
- Support `mcp__` prefixes and `codex_apps` namespace variations when identifying Codex app automation update tools.
- Handle `$ref` entries when inspecting and normalizing root union schema branches.
- Add `util.ResolveGitHubToken` to resolve GitHub API tokens with priority order (`GITHUB_TOKEN`, `github_token`, and `GITSTORE_GIT_TOKEN` for GitHub repositories).
- Set GitHub `Authorization` headers in management version check and asset updater requests when a token is resolved.
Closes: #5189
- Added a preprocessing pass to repair malformed MCP-style JSON schemas.
- Wraps bare property maps as object schemas, promotes `required: true` flags to parent `required` arrays, and removes boolean `required` from properties.
- Recurses through nested schema containers and skips known API request envelopes to avoid rewriting non-schema docs.
- Switched schema decoding/serialization path to preserve large numeric values and avoid HTML-escaping side effects.
Closes: #5178
- Add shared tool descriptor collection and winner selection for Responses tools (top-level vs `additional_tools`, direct vs namespace child, and ordering rules).
- Introduce sanitized Gemini function name mapping with collision disambiguation and 64-char-safe truncation.
- Build forward/reverse tool identity maps for restoring original tool identity (`name`, `namespace`, `custom`) during translation.
- Update Gemini→Responses streaming conversion to emit proper custom tool call events and identity-aware function call events.
- Add helpers for translating `tool_choice` to Gemini config and unwrapping custom tool input payloads.
Closes: #5088
- Propagate request headers into custom-header resolution for OpenAI/Gemini/XAI/Codex execution and websocket flows.
- Resolve auth `header:` values like `$ABC` from incoming request headers at request time and omit headers when no value is available.
- Add documentation for the dynamic custom-header behavior in `config.example.yaml`.
Closes: #5053
* feat(config): add fingerprint-profile to Claude keys and auth JSON
- Add FingerprintProfile to ClaudeKey configuration struct and normalizer
- Track fingerprint-profile in config diff
- Map fingerprint-profile / fingerprint_profile to auth attributes in file and config synthesizers
- Support fingerprint-profile in Management API PatchClaudeKey and normalization
- Add Claude billing attribution string manipulation utilities in internal/util
- Document fingerprint-profile options in config.example.yaml
* feat(claude): add fingerprint policy and request-local CLI identity
- Centralize Claude fingerprint policy resolution in claude_fingerprint_policy.go
- Support stable Claude CLI identity synthesis (UUIDv5 account_uuid and SHA-256 device_id)
seeded from API keys or stable OAuth IDs, keeping access tokens isolated
- Warn on unrecognized fingerprint-profile values
* feat(claude): apply CLI fingerprint to Messages and keep API keys caller-owned
- Wire centralized fingerprint policy into Claude and Kimi executors
- Keep first-party Anthropic API keys and delegated providers caller-owned by default
- Apply Claude Code CLI wire profile (betas, metadata, diagnostics, MCP aliases)
when fingerprint-profile=claude-code-cli is configured
- Strictly align CCH signing with native Claude Code 2.1.220: only first-party
api.anthropic.com and Vertex sign dynamic CCH; third-party gateways and Kimi
receive billing header without cch= to avoid prompt cache busting
- Respect caller-owned count_tokens bodies by default while aligning CLI shape on opt-in
- Fall back to CLIProxyAPI/<version> User-Agent when caller sends no UA in caller-owned mode
- Scope custom operator header overrides accurately in caller-owned mode
- Add comprehensive test coverage for policy resolution, gateway opt-in, Kimi, and token counting
- Add a cleanup pass to hoist `then`/`else` properties into the containing schema path (including nested and `allOf` cases).
- Remove `if`/`then`/`else` from the unsupported keyword list so sanitized schemas no longer retain conditional keywords.
Closes: #4984
- Add a sanitizer option to keep `additionalProperties: false` in response paths instead of converting it to description hints.
- Skip dropping `additionalProperties: false` in `removeUnsupportedKeywords` when response mode is enabled, while still removing non-false `additionalProperties`.
- Keep tool-schema behavior unchanged by continuing to remove `additionalProperties` and emit compatibility hints for non-response conversions.
Closes: #4961
Reviewing the guard against itself surfaced two defects. The allowlist was keyed
by file, so a new in-place write inside an already reviewed file passed silently,
and internal/wsrelay/manager.go was listed without ever matching a pattern.
Record the reviewed occurrence count per file and reject any deviation in either
direction: an added write in a reviewed file now fails, and a stale entry whose
writes disappeared fails too. Drop the entry that never matched.
TestConvertGeminiRequestToGeminiReusesLargeNormalizedPayload asserted the reuse
invariant with b.Fatal inside testing.Benchmark. A failing benchmark aborts
before completing an iteration and returns a zero BenchmarkResult, so
AllocedBytesPerOp reported 0 and the allocation check passed exactly when the
payload was being copied. Injecting a full copy into the translator left the
test green. Assert the invariant with t.Fatal and reject a zero-iteration
benchmark result; both injected regressions now fail the test.
Add two static guards for the no-copy invariant. Results handed out by the
no-copy helpers alias the caller's buffer, and mutating those bytes corrupts
already-derived values in a way the race detector cannot see. One guard rejects
in-place sjson options, the other keeps the set of in-place byte writes small
and documented: each reviewed site records why it cannot corrupt a no-copy
result, and a new site fails the test until it is justified.
gjson.ParseBytes copies the entire document before returning a result, which
is prohibitive for multi-megabyte requests. ParseGJSONBytesNoCopy mirrors the
existing GetGJSONBytesNoCopy contract: the returned result references the
caller's bytes, so callers must neither retain it nor mutate the buffer while
it is in use.
A Claude Messages request carrying MCP-style tool schemas failed before
inference when routed to Antigravity/Gemini: the private backend parses
function declarations as a limited proto-JSON Schema and rejects unknown
fields, so `propertyNames` produced
Unknown name "propertyNames" at
'request.tools[0].function_declarations[0].parameters.properties[0].value'
The cleaner already lists `propertyNames` as unsupported, but every
cleaning pass is skipped for nodes classified as property maps, and that
classification matched any path ending in ".properties". A tool may
declare a property named "properties" — Notion's page tools do — and the
schema for that property then sits at ".properties.properties", so it was
mistaken for a property map and nothing inside it was cleaned. The 400
above points at exactly that node.
Replace the suffix match with a parity check over the trailing run of
name-map keywords: the node a keyword names is a map only when its own
parent is a schema, so "properties" is a map, "properties.properties" is
the schema of a property named "properties", and a third repetition is a
map again. Only the trailing run is inspected, so a schema nested under
any prefix by the caller is classified the same way.
Codex/OpenAI egress is untouched: it converts input_schema separately,
uses non-strict tool mode, and accepts this shape.
- 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
- 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 a new `models` package for organizing Claude client model templates and building responses.
- Migrated Claude response handling to `claudemodels.BuildResponse`.
- Added comprehensive tests for model ID transformation, sorting, and metadata validation.
- Removed redundant utility functions and simplified integration with the API server.
- Added `GetGJSONBytesNoCopy` in `internal/util` for safe, no-copy JSON parse operations leveraging `unsafe`.
- Replaced `gjson.GetBytes` with the new helper in key payload processing paths (`kimi_executor`, `vertex_payload_helpers`, etc.) to improve performance.
- Added unit tests for behavior validation, including edge cases with empty input.
- Introduced `SanitizedFunctionNameMap` and `DisambiguatedToolNameMap` for consistent mapping between sanitized and original tool names.
- Added collision handling with deterministic hash suffixes for name disambiguation within character limits.
- Implemented logic to deduplicate and map tool and function names across translator components, including Interactions, Claude, and Gemini.
- Updated test cases to validate name restoration, deduplication, disambiguation, and mapping behaviors.
Closes: #4244
- Added `EnsureClaudeModelIDPrefix` and `ResolveClaudeModelIDPrefix` utilities for standardizing and decoding Claude model IDs.
- Updated handling of `claude-fable-5-dd-<reversed>` model IDs for request routing and response formatting.
- Incorporated logic to enforce disabled states for plugin virtual auths and their expanded children.
- Refactored code for applying and persisting disabled state metadata in plugin multi-auth scenarios.
- Implemented and extended unit tests to validate expected behavior.
- Replaced direct `strings.ToLower` usage with `util.OpenAICompatibleProviderKey` for generating provider keys.
- Updated auth and executor workflows to use namespaced keys for OpenAI-compatible providers.
- Adjusted tests to validate namespaced key handling, including new test cases for provider registration and execution logic.
- Added `OpenAICompatibleProviderKey` helper in `util` for consistent key transformations.
Closes: #3600
- Updated JSON schema handling to remove `$comment` and `enumDescriptions` fields during schema transformations.
- Adjusted test cases to validate the removal of these fields both at root and nested levels.
- Expanded unsupported schema keywords to include `$comment` and `enumDescriptions` for Gemini compatibility.
Closes: #3512
- Added `ConvertClaudeToolResultContent` to standardize Claude tool_result content, preserving JSON structure and splitting out base64-encoded images.
- Updated Gemini and Gemini-CLI translators to use the new utility for generating deterministic function responses and inline image parts.
- Added comprehensive test cases for content types and edge cases, ensuring correct handling of string, JSON, and image blocks.
Closes: #2781
When auth-dir is not specified in config.yaml, ResolveAuthDir returns
an empty string which causes os.MkdirAll to fail with no path. Use
the documented default ~/.cli-proxy-api instead.
Fixes#3272
- Updated all references from v6 to v7 for `github.com/router-for-me/CLIProxyAPI`.
- Ensured consistency in imports within core libraries, tests, and integration tests.
- Added missing tests for new features in Redis Protocol integration.
- Introduced a `Disabled` flag to OpenAI compatibility configurations.
- Updated routing, auth selection, and API handling logic to respect the `Disabled` state.
- Extended relevant APIs, YAML configurations, and data structures to include the `Disabled` field.
- Adjusted all relevant loops and filters to skip disabled providers.
Closes: #3060#3059#2977
Addressing the P1 note from the Codex reviewer: applyCustomHeaders is
also called with a synthetic &http.Request{Header: ...} from the
websockets executors (aistudio_executor.go, codex_websockets_executor.go),
which forward only the header map. The previous continue meant a custom
Host was dropped from that map, regressing virtual-host overrides on
those flows. Mirror the value to both r.Host (for real net/http) and
r.Header (for header-map-only consumers).
Custom headers configured under openai-compatibility (and any other
provider passing through applyCustomHeaders) were silently dropped for
the Host key, because Go's net/http reads the wire Host from
req.Host, not req.Header["Host"]. As a result, virtual-host routed
upstreams (e.g. LiteLLM behind an ingress) saw the base-url's host
instead of the user-configured override and returned 404.
Detect the Host key with http.CanonicalHeaderKey and assign it to
req.Host so it is actually written on the wire. Other headers continue
to use Header.Set as before.
Fixes#2833
- Deleted `QwenAuthenticator`, internal `qwen_auth`, and `qwen_executor` implementations.
- Removed all Qwen-related OAuth flows, token handling, and execution logic.
- Cleaned up dependencies and references to Qwen across the codebase.
Apply SanitizeFunctionName on request and RestoreSanitizedToolName on
response for: gemini/claude, gemini/openai/chat-completions,
gemini/openai/responses, antigravity/openai/chat-completions,
gemini-cli/openai/chat-completions.
Also update SanitizedToolNameMap to handle OpenAI format
(tools[].function.name) in addition to Claude format (tools[].name).
Claude Code and MCP clients may send tool names containing characters
invalid for Gemini's function_declarations (e.g. '/', '@', spaces).
Sanitize on request via SanitizeFunctionName and restore original names
on response for both antigravity/claude and gemini-cli/claude translators.
Gemini API rejects uniqueItems in tool schemas with 400. Add it to
unsupportedConstraints alongside minItems/maxItems where it belongs.
Same class of fix as #1424 and #1531.
feat(proxy): centralize proxy handling with `proxyutil` package and enhance test coverage
- Added `proxyutil` package to simplify proxy handling across the codebase.
- Refactored various components (`executor`, `cliproxy`, `auth`, etc.) to use `proxyutil` for consistent and reusable proxy logic.
- Introduced support for "direct" proxy mode to explicitly bypass all proxies.
- Updated tests to validate proxy behavior (e.g., `direct`, HTTP/HTTPS, and SOCKS5).
- Enhanced YAML configuration documentation for proxy options.
Add util.SanitizeClaudeToolID() to replace non-conforming characters in
tool_use.id fields across all five response translators (gemini, codex,
openai, antigravity, gemini-cli).
Upstream tool names may contain dots or other special characters
(e.g. "fs.readFile") that violate Claude's ID validation regex.
The sanitizer replaces such characters with underscores and provides
a generated fallback for empty IDs.
Fixes#1872, Fixes#1849
Made-with: Cursor
fix(gemini): add `deprecated` to unsupported schema keywords
Add `deprecated` to the list of unsupported schema metadata fields in Gemini and update tests to verify its removal.