An OpenAI group that keeps a failover account for a shared public alias
produced a Codex model descriptor with no reasoning levels and text-only
input, which leaves the client's reasoning-effort slider with nothing to
select.
Two accounts explicitly mapping one alias to different upstream models
makes codexExplicitModelTargetsConflictForPlatform true. With no
upstream_model_metadata snapshot to intersect, groupCodexModelMetadata
short-circuits to {reasoningConflict, inputModalitiesConflict}, so
DefaultReasoningLevel is nil (the key vanishes under omitempty) and
SupportedReasoningLevels is an empty array. mergeMissingCodexModelFields
fills only missing-or-null fields, so an empty array is never repaired.
Failing closed is right when the alias target is genuinely ambiguous, but
a group that declares model_routing for the alias has already resolved
that ambiguity: the operator stated which accounts serve it and which is
primary. Treating that as a conflict rejects a deliberate failover setup.
Manifest side: when a routing rule names the alias, restrict capability
declaration to the routed accounts and skip the conflict override.
Capabilities then fall back to the same by-name derivation used for a
single account without a metadata snapshot. Groups with no rule, a
disabled rule, or a rule for another alias keep failing closed.
Scheduling side: model_routing was stored and read platform-agnostically
(admin_group.go, Group.GetRoutingAccountIDs) but four gates in
gateway_scheduling.go only consulted it for Anthropic, so an OpenAI
group's rules were accepted and displayed yet never honored. Without
this, the manifest would honor a rule that scheduling ignores. Both
gates now share one predicate, with the allowed platform set defined in
a single place.
Selection inside a routing list is unchanged: the list is a membership
set, and the winner is still decided by Priority, then load, then
LastUsedAt.
Tests: alias-failover manifest recovery plus the three negative cases,
the platform predicate table, and an OpenAI routed selection that must
beat a higher-priority unrouted account.
Cyber-policy detection only inspected response.failed, and the ingress check ran after error-specific early returns. As a result, error-shaped failures and the connection-pool, HTTP-bridge, and WSv2 paths could miss cyber-policy hits.
Centralize event marking and invoke it before retry and failover returns across the WebSocket implementations. Preserve the recorded guard during account failover and defer connection blocking until the logical failover chain completes, avoiding duplicate records while ensuring subsequent turns are blocked.
Official OpenAI hosts and models.dev entries without an api field left
Astra falling back to reasoning effort none and empty Fast tiers. Persist
complete per-model metadata, advertise Astra reasoning/Fast locally, and
surface partial sync warnings when image models remain incomplete.
Co-authored-by: Cursor <cursoragent@cursor.com>
Anthropic gates newer models on a minimum Claude Code client version. With
CLICurrentVersion pinned at 2.1.220, claude-fable-5-1 fails every request with
"Claude Code 2.1.220 does not support this model; version 2.1.251 or newer is
required", and the only fix is a release that bumps one constant.
Add SUB2API_CLAUDE_CLI_VERSION, mirroring what internal/pkg/xai already does
with XAI_GROK_CLI_VERSION. CLICurrentVersion remains the built-in pin; the new
CLIVersion() is what every consumer reads. With no env var set the resolved
value equals the pin, so existing deployments are unaffected.
The value is resolved once at package init rather than per call: the User-Agent
header and the request body's cc_version are written by different code paths for
the same request, and reading different values would make that request
contradict itself.
Validation is strict (three numeric segments, not below the pin) because
identity_service.go documents what a malformed version does once it reaches an
account's persistent fingerprint: sustained 429s without reset headers, 5s
fallback cooldown, pool collapse into a 503 storm, and no reset entry point.
Invalid values warn and fall back rather than being silently dropped.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0168uDMAj9anaJrnH8CeFze6