Commit Graph

749 Commits

Author SHA1 Message Date
Luis Pater
00c63a5669 feat(pluginhost): expose outbound HTTP wire profile to plugin requests
- Add HTTPWireProfile to sdk/pluginapi on HTTPRequest with wire_profile JSON tag
- Decode wire_profile in host callbacks for flat and nested RPC payloads
- Match header casing in httpwire ordered_conn and allow non-HTTP handshakes
- Apply wire profile settings (HTTP/1.1 enforcement, auto compression disable, header ordering) in plugin host HTTP client
- Preserve proxy configuration, custom TLS dialers, redirect handling, and connection lifecycle

Closes: #5062
2026-09-06 20:41:58 +08:00
Luis Pater
fa01468e95 perf(auth): optimize scheduler result updates with targeted model shards
- Add `upsertAuthResult` to incrementally update only affected model shards after request completion.
- Cache supported model sets per auth using registry epoch tracking to avoid redundant lookups.
- Preserve full shard synchronization for auth lifecycle events and credential-scoped results.

Closes: #5061
2026-09-06 16:42:59 +08:00
sususu
580df36423 feat(usage): propagate session and parent session hierarchy to usage reporting queue
- Reuse coresession.ExtractSessionInfo across HTTP headers and request payloads to unify canonical session prefix namespaces with the scheduler.
- Extract hierarchical session identities in two phases: initial extraction from request headers on entry, and authoritative deep extraction once request payloads and metadata are available.
- Support Claude Code multi-level subagents (X-Claude-Code-Agent-Id, metadata.agent_id) and Codex thread fork lineages.
- Propagate SessionID and ParentSessionID across ClientRequestMetadata, UsageReporter, and coreusage.Record without root_session_id.
- Include session_id and parent_session_id in queuedUsageDetail for Home LPushUsage forwarding and Redis consumption with self-loop guards.
- Add comprehensive test coverage for canonical headers, body extraction, ghost parent elimination, and self-referential loop guards.
2026-09-06 10:45:32 +08:00
Luis Pater
5ab0bca040 fix(codex): scope usage limit errors to credentials and parse flexible quota resets
- Mark Codex usage limit errors as credential-scoped across HTTP and WebSocket executors.
- Support both top-level and nested error structures with case-insensitive matching when parsing retry-after resets.
- Propagate prevalidated candidate context to session affinity and built-in selectors during auth selection.

Closes: #5529
2026-09-06 06:20:20 +08:00
Luis Pater
4c1bebe837 fix(auth): preserve concurrent modifications during auth refresh and preparation
- Implement three-way merge for refreshed and prepared auth updates against base and current runtime state.
- Retain user modifications to metadata, attributes, proxy URL, and error/cooldown status across background refresh operations.
- Guard against stale registration epochs and enforce per-auth generation ordering during persistence.

Closes: #5465
2026-09-04 07:03:40 +08:00
Luis Pater
649a8bdb6f feat(plugin): omit stream chunk history on payload chunks for schema v5
- Bump plugin schema version to 5 and introduce `SchemaVersionStreamChunkOmitHistory`.
- Omit `HistoryChunks` on payload stream chunks for schema version 5+ to avoid per-chunk cloning and serialization overhead.
- Conditionally accumulate and clone history chunks only when legacy plugins with schema version < 5 are active.

Closes: #5451
2026-09-04 01:19:50 +08:00
Luis Pater
2a6b87aca0 feat(openai): send periodic ping control frames during responses websocket streaming
- Add `writePing` to responses websocket writer to emit Ping control frames.
- Send periodic keep-alive Ping frames based on streaming configuration during response forwarding.
- Reset keep-alive interval upon receiving data chunks and abort session if ping write fails.

Closes: #5413
2026-09-03 21:27:23 +08:00
Luis Pater
291cfb87ef feat(codex): support orphan delegation compatibility via orphan-delegation-compatibility
- Add `codex.orphan-delegation-compatibility` configuration option and mirror it to SDK configuration.
- Convert orphan Codex delegation outputs into standard user messages for requests with `X-Openai-Subagent: collab_spawn`.
- Integrate orphan delegation rewriting into OpenAI responses request handling pipeline.

Closes: #5401
2026-09-03 20:21:24 +08:00
sususu98
e899f0e539 feat(session): derive distinct branch session ID, parent lineage on Merkle LCP forks, and enhance Codex fork/subagent affinity (#5418) (#5454) 2026-09-03 17:52:40 +08:00
Luis Pater
09471dd9da fix(auth): prevent individual model quota cooldowns from blocking credential
- Ignore aggregated single-model quota cooldowns during credential-level availability checks.
- Keep credentials eligible unless marked completely unavailable or subject to a credential-wide quota.

Closes: #5371
2026-09-03 17:49:57 +08:00
Luis Pater
d577e630b1 feat(routing): make subagent session affinity configurable via session-affinity-subagents
- Add routing.session-affinity-subagents (defaulting to true) to RoutingConfig.
- Unify subagent parent credential inheritance across all providers by removing hardcoded provider/model blacklists.
- When session-affinity-subagents is false, isolate subagents and distribute them via the fallback selector.
- Ensure changing session-affinity-subagents is a no-op when session-affinity is false.
- Preserve alias isolation and failure isolation invariants.

Closes: #5417
2026-09-03 17:05:35 +08:00
hkfires
6ff680e90a feat(auth): use home model capabilities for thinking 2026-09-03 13:10:30 +08:00
Luis Pater
18e01a76ac fix(auth): enforce minimum cooldown floor and track attempted credentials on 429
- Enforce a 10-second minimum cooldown floor for quota errors to prevent retry storms from sub-second `Retry-After` values.
- Track attempted authentication credentials per round across execution flows.
- Ensure credentials attempted during a failed 429 round respect the cooldown floor instead of triggering zero-wait retries.

Closes: #5265
2026-09-03 10:02:51 +08:00
Luis Pater
f416175fcd fix(home): map user_credits_insufficient to 402 and user_period_limit_exceeded to 429
- Map `user_credits_insufficient` to `402 Payment Required` in `decodeHomeDispatchError`.
- Map `user_period_limit_exceeded` to `429 Too Many Requests` in `decodeHomeDispatchError`.
- Add unit test coverage for billing and period limit error mappings.

Closes: #5170
2026-09-03 02:59:34 +08:00
Luis Pater
9812b1e768 fix(auth): validate access token expiration and retain valid credentials on refresh failure
- Parse and prioritize JWT `exp` claims when determining access token expiration.
- Retain active credentials and schedule backoff retries on refresh failures if the access token remains unexpired.
- Demote and block auth credentials with expired access tokens during model scheduling and candidate selection.
- Reduce Codex token refresh lead duration to 24 hours.

Closes: #5095
2026-09-03 01:33:11 +08:00
Luis Pater
272c1cff4e fix(antigravity): bypass quota cooldowns and credit hints when cooling is disabled
- Bypass short cooldown checks and recording in execution flows when cooling is disabled globally or per auth.
- Skip marking credits permanently disabled and refreshing credit hints when cooling is disabled.
- Export quota cooldown status helper functions for auth and configuration evaluations.

Closes: #4793
2026-09-02 22:01:55 +08:00
Luis Pater
02c02cda50 fix: harden concurrent session handling, listener lifecycle, and token accounting
- Use `context.AfterFunc` and buffered delivery in websocket relay sessions to avoid per-request goroutine leaks.
- Synchronize in-flight puts and drain queued connections upon mux listener close.
- Ensure home streaming log writer goroutines terminate cleanly when the log client is unhealthy.
- Prevent integer arithmetic overflow in token breakdown validations and calculations.
- Clone request headers in logging middleware to prevent concurrent mutation issues.
- Implement standard `io.WriterTo` return signature for file body sources.

Closes: #4709
2026-09-02 20:02:42 +08:00
sususu
dc0f7a594b fix(session): derive LCP session ID from rolling prefix keys and harden matcher
- root derived session ID in rolling prefix key to disambiguate conversations with different system prompts
- sanitize matcher config to guarantee MaxPrefixes >= MaxTurns
- tie-break tool parts sorting with digest for determinism
2026-09-01 18:00:13 +08:00
sususu
5679bbf330 fix(auth): optimize session cache LRU capacity eviction
- replace O(N log N) sorting under global write lock with container/list LRU eviction
- track primary alias groups for O(1) group lookup and clean group eviction
- capture timestamps inside lock and add nil receiver guards
2026-09-01 18:00:09 +08:00
sususu
35e3d97dac fix(registry): remove defunct gemini-3-flash-agent model from antigravity provider
Remove gemini-3-flash-agent and legacy gemini-3.5-flash entries from the embedded antigravity model registry in models.json, as upstream Google Cloud Code / Antigravity endpoints return 500 UNKNOWN for these model IDs. Update excluded model tests to assert against active model gemini-pro-agent instead.
2026-09-01 15:26:57 +08:00
Luis Pater
fae57a3a88 fix(session): support identity and subagent extraction from nested request payloads
- Extract subagent IDs, user IDs, and prompt cache keys from nested `request` objects across session identity, session info, and auth selection.
- Normalize and fall back appropriately when top-level prompt cache key fields are empty strings.
- Inspect nested request fields when validating explicit session identities.
2026-09-01 11:23:38 +08:00
Luis Pater
7070785140 fix(auth): preserve upstream status codes in antigravity auth errors
- Introduce `HTTPStatusError` to retain upstream HTTP status codes across Antigravity OAuth and project lookup calls.
- Propagate status codes and retry-after metadata from cause errors in `missingAntigravityProjectIDError`.

Closes: #5368
2026-09-01 08:37:02 +08:00
Luis Pater
f2e2d713b2 fix(auth): propagate upstream error causes in auth selection failures
- Attach candidate upstream errors as causes to scheduler availability and cooldown errors.
- Introduce `errorWithCause` wrapper to extract and display upstream error summaries.
- Enrich auth selection error messages with upstream details and preserve model cooldown errors.
- Forward `Retry-After` response headers for model cooldown errors in Claude Code handler.

Closes: #5365
2026-09-01 08:15:51 +08:00
Luis Pater
ff811577eb fix(auth): isolate subagent session affinity for antigravity and gemini
- Prevent subagent sessions from inheriting parent credentials on Antigravity and Gemini providers and models to mitigate concurrency rate limiting.
- Avoid aliasing subagent session keys to parent fallback keys or mutating parent bindings during subagent result handling.

Closes: #5364
2026-08-31 22:34:58 +08:00
Luis Pater
9721d9939e feat(usage): track streaming execution state in usage records
- Add `Stream` field to usage records, context helpers, and Redis queue payloads.
- Propagate streaming mode across execution handlers, conductors, and usage reporters.

Closes: #5361
2026-08-31 20:29:19 +08:00
sususu
5755d00b1b refactor(session): prune in-memory session tree store in favor of flat KV affinity and pure info extraction
- Replace complex materialized tree structures with lightweight (session_id, parent_id) extraction
- Maintain O(1) flat KV cache for subagent-to-parent prompt cache inheritance
- Add tree_compat.go with deprecated stubs to preserve SDK compatibility
- Add comprehensive regression tests for multi-protocol session headers and payloads
2026-08-31 20:28:15 +08:00
sususu
c99ce12123 fix(session): harden depth-cap index cleanup, bound lcp fingerprints, and support nested payloads (#5202) 2026-08-31 14:55:37 +08:00
sususu
100c564313 fix(session): harden nil fallback, normalize agent id, and support nested antigravity payloads (#5202) 2026-08-31 14:00:10 +08:00
sususu
8211388946 feat(session): implement Merkle LCP session affinity, session tree, and distributed Home hierarchy (#5202)
- Implement Merkle Longest Common Prefix (LCP) session affinity engine across OpenAI, Claude, Gemini, Interactions, and Responses protocols in sdk/cliproxy/session/lcp.go
- Implement in-memory hierarchical session tree store with dynamic lineage recalculation, reparenting, cycle prevention, and parentIndex descendant cascading in sdk/cliproxy/session/tree.go
- Integrate Merkle prefix matching and hierarchical session tree into SessionAffinitySelector
- Bound SessionCache capacity to 65,536 entries with deterministic eviction
- Support Claude nested metadata parent extraction and Header+Body parent merging
- Enforce TTL expiration checks in touchLocked and bindLocked
- Propagate ParentSessionID in authDispatchRequest and RPopAuthWithSessionHierarchy for distributed Home dispatch
- Add isHierarchyParent in home_session_alias.go covering Claude, Codex, Pi slot, Antigravity, and Gemini caching
- Add comprehensive test suites in lcp_test.go, tree_test.go, selector_lcp_test.go, client_test.go, and home_session_alias_test.go
2026-08-31 11:18:41 +08:00
Luis Pater
d31b15916d feat(executor): support token usage parsing for plugin executors
- Add `ParsePluginExecutorResponseUsage` to extract token usage from non-streaming plugin responses across Claude, Gemini, Interactions, Antigravity, and OpenAI/Codex protocols.
- Add `ObservePluginExecutorStreamUsage` to observe and aggregate token usage across streaming chunks.

Closes: #5340
2026-08-30 14:51:08 +08:00
Luis Pater
12b88f3ad6 fix(auth): synchronize auth lifecycle and registry state with epochs and generations
- Add `RegistrationEpoch` and `Generation` tracking to `Auth` and model registry to prevent stale scheduling and snapshot reconciliation races.
- Implement scheduler removal tombstones and `ApplyClientModelProjections` in the model registry to atomically discard out-of-order state updates.
- Track logical route models across execution results and preserve active model cooldowns during registry reconciliation.
2026-08-30 12:53:39 +08:00
hkfires
6a489fa84d fix(auth): prefer errors from upstream attempts
Track when executor calls cross an upstream transport boundary and use that
signal to keep model/provider errors from being replaced by later local
preparation, selection, or internal failures.

Mark HTTP, websocket, relay, and usage-tracked transports as upstream
attempts, while avoiding marks for local validation, logging, missing
sessions, and successful websocket handshakes before request send.

Parse relative auth expiry metadata and adjust Antigravity refresh timing.
2026-08-29 12:50:46 +08:00
hkfires
e4a8f98913 fix(logging): enhance error diagnostics and logging for home refresh operations 2026-08-29 12:50:45 +08:00
hkfires
9a2201c36a fix(auth): forward Home unauthorized upstream errors
Stop refreshing Home-owned OAuth credentials after upstream 401s.
Preserve marked upstream response bodies for direct responses, usage
records, request logs, and websocket handshake failures.
2026-08-29 12:50:44 +08:00
Luis Pater
8dd78042e0 fix(proxyutil): enforce HTTP/1.1 ALPN and configure TLS dial context for HTTPS proxies
- Add `buildHTTPSProxyDialTLSContext` to handle HTTPS proxy TLS handshakes with configurable timeout and TLS options.
- Restrict ALPN `NextProtos` to HTTP/1.1 for HTTPS proxy connections to prevent HTTP/2 negotiation issues during proxy CONNECT tunneling.
- Support custom TLS configuration in `httpConnectDialer` for HTTPS proxy connections.

Closes: #5287
2026-08-28 16:50:33 +08:00
sususu
7bc16ee3db fix(auth): preserve round-robin successor across ready view rebuilds
Keep round-robin rotation stable in the scheduler fast path when
credentials enter cooldown or are removed. Replace the numeric readyView
cursor modulo normalization with ID-based successor binary search,
aligning readyView with RoundRobinSelector.
2026-08-28 09:17:57 +08:00
Luis Pater
1cc72b9d13 fix(codex): filter extended reasoning levels for older client versions
- Filter `max` and `ultra` reasoning effort levels for Codex client versions prior to `0.144.0`.
- Extract and forward the `client_version` query parameter across model catalog response handlers.
- Add dotted version parsing and comparison utilities to verify extended reasoning level compatibility.

Closes: #5262
2026-08-27 16:51:33 +08:00
Luis Pater
4b5f1eab25 feat(plugin): support observing upstream websocket response events
- Introduce `WebSocketResponseObserver` capability and bump plugin ABI schema version to 4.
- Forward upstream WebSocket response frames from Codex and xAI executors to configured observers.
- Wire `WebSocketResponseObserver` across API handlers and plugin host dispatchers.

Closes: #5248
2026-08-27 05:30:19 +08:00
sususu
1f53b2eb03 fix(auth): keep credential rotation fair when candidates are filtered
Both built-in rotation strategies lost their position whenever the candidate
set shrank, which happens on every retry that excludes an already tried
credential and on every cooldown transition.

Smooth weighted round-robin reset every accumulated credit as soon as the
weight vector differed from the previous call. A transient subset is not a
configuration change, so the reset fired constantly. With all credits back at
zero and equal weights, the strict `>` comparison always resolves ties to the
first entry in slice order, and candidates are sorted by auth ID, so every
retry restarted the cascade at the alphabetically first credential. Credits are
now reset only when a credential's configured weight actually changes, and the
accumulator is bounded so permanently removed credentials cannot leak entries.

Plain round-robin indexed a monotonic counter into the filtered slice via
`available[index%len(available)]`. Once the slice shrank, the modulo re-seated
the rotation instead of resuming it. Rotation now continues from the identity
of the previous pick, resolved with a binary search over the sorted ring.

Measured over 9 equally weighted credentials with a realistic mix of long
sessions, new sessions and retries, the busiest-to-quietest ratio drops from
11331x to 1.1x. Distribution is exact for equal weights, matches configured
ratios for unequal weights, and tracks the theoretical optimum within 3% under
random credential unavailability.
2026-08-25 18:55:00 +08:00
Luis Pater
80de901550 fix: preserve multi-reference video durations 2026-08-25 12:44:00 +08:00
Luis Pater
ba510f85a2 fix(pluginhost): add plugin quiesce handling with safe rollback during hot reload
- Add new `plugin.quiesce` ABI method and propagate RPC error codes from plugin call failures.
- Invoke quiesce on the replaced plugin before loading a new version, then only activate replacement after quiesce succeeds.
- Improve hot-reload safety by serializing lifecycle transitions, cleaning up failed/canceled loads, and rolling back to the previous plugin state when replacement fails or is canceled.

Closes: #5134
2026-08-25 01:32:57 +08:00
sususu98
ca601db05d feat: observe upstream provider quota signals (#5211)
Codex and Claude already emit credential-level quota watermarks on ordinary
responses. CPA used to drop them. Keep the latest watermark in memory and
return it from the management auth-file API.

Hard rule: this is observation only. It must not change scheduling, cooldown
selection, or auth-file persistence.

Snapshot, not accumulation
- QuotaState now has ObservedAt and a bounded Signals map. MarkResult fills
  them from the response headers already recorded on the request.
- Signals is the current response, not a union of earlier ones. Retry-After
  and "limit reached" only appear on the response that produced them; merging
  across responses would keep an expired value forever.
- A response with no quota header (transport failure, 5xx, unrelated endpoint)
  leaves the previous snapshot in place.
- ObservedAt is the time of the current snapshot. It advances even when the
  values did not change, so a consumer can tell a fresh reading from a stale
  one.
- When two model states merge, keep the newer snapshot. Do not union keys
  captured at different times.

What is observed, and what is not
- One predicate, ProviderSupportsQuotaObservation, decides the provider set.
- Keep Codex and Claude. Drop Kimi, xAI/Grok, Antigravity, and the Gemini
  family (gemini/vertex/aistudio): their ordinary headers are not a reliable
  credential-level remaining quota.
- Count-tokens reuses the credential but is not generation traffic.
  ExecuteCount sets SkipQuotaObservation so those headers cannot replace the
  last generation snapshot. Cooldown and success/failure accounting still run.

Cooldown must not overwrite the last snapshot
- Observation writes only ObservedAt and Signals.
- Cooldown writes only Exceeded, Reason, NextRecoverAt, and BackoffLevel,
  through applyCooldownFields. Never assign a fresh QuotaState{...} over a
  live value: that would zero the snapshot on 429, Cloudflare, credential-
  scope sibling updates, and cooldown clears.
- If a credential-quota cooldown is still active, MarkResult still observes
  an already-present model state. It does not create scheduler state just to
  record a watermark.
- .cds files persist cooldownFieldsOf(Quota) only. Restore keeps the newer
  ObservedAt, so reloading cooldown cannot clobber a newer in-memory snapshot.
- cooldownQuotaEqual still ignores observation fields, so a watermark change
  cannot by itself persist cooldown or move the scheduler.
- The management payload omits every cooldown field, so it cannot be mistaken
  for scheduler state or wired back into scheduling.
- Manual ResetQuota still clears the full QuotaState.

Codex websocket events
- Codex WS reports quota as codex.rate_limits frames, not HTTP headers.
  ParseCodexQuotaEventHeaders turns one event into the same bounded header
  shape, and MergeResponseHeaders folds it into the request-scoped holder.
  additional_rate_limits is accepted as an object (websocket) or an array
  (/wham/usage).
- Parse only through AppendCodexAPIWebsocketResponse. The shared
  AppendAPIWebsocketResponse is also used by xAI, and xAI error frames really
  do carry x-ratelimit-* headers. Parsing every frame as Codex quota would
  forge Codex headers into another provider's request log.
- Also capture code_review_rate_limits.
- A malformed active-limit name drops only that one header, not the window
  watermarks parsed from the same event.
- The type discriminator scans a bounded frame prefix, not every byte of
  every frame.
- HTTP namespaces an extra limit by short name (x-codex-bengalfox-*); WS
  namespaces it by limit name (GPT-5.3-Codex-Spark). The two paths cannot
  emit the same header names. The X-Codex-Additional- prefix marks the WS
  origin, and snapshot replacement keeps the two spellings from piling up.

Hardening
- Reject observed values with control characters. These strings reach the
  plain-text request log, and Limit-Name is upstream-controlled, so CR/LF
  could forge a header line.
- When the header cap is hit, keep plan/credits/primary ahead of
  additional-limit namespaces, then sort names so truncation is deterministic.
- QuotaState.Clone deep-copies Signals and is used by Auth.Clone and
  ModelState.Clone.
- Token stores still serialize credential metadata only, so observation adds
  no auth-file writes.
2026-08-24 17:15:37 +08:00
hkfires
e04d620cc1 feat(auth): normalize credential metadata keys
Canonicalize legacy config-style credential keys across stores,
management handlers, plugin auth, and file synthesis while preserving
explicit canonical values. Expose per-auth request_retry in auth file
management and add max-retry-credentials management routes.
2026-08-22 12:01:06 +08:00
hkfires
0a14eb70ce feat(auth): add retry round credential filtering 2026-08-22 01:20:02 +08:00
hkfires
601ca43090 feat(auth): add credential retry round contract
Redefine request-retry as additional credential retry rounds and
enforce max-retry-credentials per round. Home dispatch now carries
excluded and pinned auth constraints, supports remote retry limits, and
propagates cooldown retry-after metadata across exhausted rounds.

Move Antigravity upstream retries under conductor ownership to avoid
double-consuming retry attempts. Update configuration comments and add
coverage for Home retry rounds, cooldown handling, pinned credentials,
and legacy dispatcher compatibility.
2026-08-22 01:19:58 +08:00
Luis Pater
1d5b7612c6 fix(cliproxy): add protocol-aware plugin executor usage parsing for response and streaming payloads
Closes: #5122
2026-08-21 13:05:54 +08:00
sususu98
4b9d404fb0 feat(codex): add opt-in stream bootstrap buffering and overload failover (#5115)
* feat(codex): add opt-in stream bootstrap buffering

The upstream smuggles capacity rejections into an HTTP 200 stream. The
handshake events arrive normally and only a later event carries
{"error":{"type":"service_unavailable_error","code":
"server_is_overloaded"}}. By then the executor has already handed the
first chunk downstream, the response is committed, and the conductor can
no longer retry on another credential, so the request fails even though
other credentials were available.

When codex.stream-bootstrap-buffering is enabled the executor holds back
the handshake events until it can tell whether the stream carries real
output or a rejection. An overload rejection then fails the attempt
before any chunk is delivered, letting the conductor retry on another
credential; every other terminal failure is flushed in order and
delivered in-stream exactly as before.

Detection uses an event-type allow-list rather than a fixed count. On the
websocket transport codex.rate_limits and codex.response.metadata arrive
before response.created, making the first generated event the fifth
frame, so a small counter would release the stream before the rejection
is visible. Buffering is bounded and hitting the bound degrades to the
original unbuffered behaviour.

Two details are load-bearing. The error must be returned synchronously:
delivering it as the first stream chunk makes ExecuteStream downgrade it
into a committed 200 and the status is lost. And the websocket path must
not signal an upstream disconnect for a rejection it intends to retry,
because the downstream handler closes the client connection on that
signal and the retry would have nowhere to deliver.

The 503 status is produced only on this path rather than in the shared
codexTerminalFailureStatus mapping, so disabling the feature restores the
previous behaviour exactly, including cooldown classification and
retry-after parsing.

Defaults to false: response headers are withheld until generation
starts, which can trip client or reverse-proxy read timeouts.

* test(codex): pin bootstrap overload failover through the conductor

Executor-level tests cannot show what the client finally receives. These
exercise ExecuteStream end to end to pin three properties that are easy
to regress:

- consecutive overloaded credentials are skipped until one serves the
  request, and retries are capped by max-retry-credentials rather than
  multiplying with request-retry
- exhausting the pool surfaces the upstream status instead of a
  committed 200 stream
- with buffering disabled the rejection stays an in-stream error on a
  committed stream, which is the behaviour the feature must preserve

The third case also documents why the executor returns its error
synchronously: an error arriving as the first stream chunk is wrapped and
downgraded into a committed 200, silently losing the status.
2026-08-20 21:31:53 +08:00
Luis Pater
92d96e0b72 fix(cliproxy): support base_URL-only config credentials and skip stale auth headers
- Preserve API key entries with empty `api_key` when `base_url` is configured, and extend config dedupe/ID logic to include base URL, proxy, prefix, and headers so identities are stable.
- Update config/auth handling so `auth_kind=apikey` is treated as config API-key auth even without an `api_key` field, enabling base_url-only credential records.
- Ensure Gemini/Codex/XAI request path clears `Authorization`/provider auth headers when token is empty to avoid leaking unrelated auth state.
2026-08-20 15:19:07 +08:00
Luis Pater
4874971764 fix(cliproxy): add warn-level diagnostics for auth cooldown and upstream execution failures
Closes: #5085
2026-08-20 03:40:46 +08:00
Luis Pater
9dc51b1f87 feat(cliproxy): add OAuth request-scoped error rules support
- Add `oauth-request-scoped-errors` configuration with normalization, sanitization, and YAML management persistence/hot-reload hooks.
- Route request-scoped error classification to use per-provider rules only for OAuth auth entries.
- Add config diff reporting and management CRUD endpoints for `oauth-request-scoped-errors` (get/put/patch/delete) with input sanitization.

Closes: #5085
2026-08-20 02:55:49 +08:00