Skip to content

fix(ai): route Z.AI API keys by usage#5275

Open
roboomp wants to merge 3 commits into
mainfrom
farm/2220e024/zai-api-key-usage-ranking
Open

fix(ai): route Z.AI API keys by usage#5275
roboomp wants to merge 3 commits into
mainfrom
farm/2220e024/zai-api-key-usage-ranking

Conversation

@roboomp

@roboomp roboomp commented Jul 12, 2026

Copy link
Copy Markdown
Collaborator

Repro

A focused AuthStorage reproduction configured two stored Z.AI login API keys with a custom usage provider: the first key reported an exhausted shared zai:requests:5h window and the second reported request headroom. Before the fix, bun test tmp-repro/zai-api-key-ranking-repro.test.ts failed because getApiKey("zai") returned "zai-exhausted" instead of "zai-healthy".

Cause

packages/ai/src/auth-storage.ts only applied CredentialRankingStrategy usage reports in the OAuth path (#rankOAuthSelections / #resolveOAuthSelection). Stored API-key credentials still used the synchronous round-robin selector, and packages/ai/src/usage/zai.ts exported only zaiUsageProvider, so Z.AI usage data populated /usage but never affected request-time credential selection.

Fix

  • Added a Z.AI ranking strategy that ranks request quota windows by duration/reset and registers it in the default ranking strategy map.
  • Extended API-key credential selection to prefetch cached usage reports, proactively mark exhausted credentials blocked until reset, and return the highest-ranked healthy sibling before dispatch.
  • Kept OAuth ranking on the same shared ordering path and added a Z.AI API-key AuthStorage regression test.

Verification

bun test packages/ai/test/auth-storage-zai-api-key-selection.test.ts packages/ai/test/auth-storage-codex-selection.test.ts packages/ai/test/auth-storage-antigravity-selection.test.ts passed: 47 tests, 112 expects. bun check passed. Fixes #5265.

- Added Z.AI credential ranking so API-key accounts use request-window usage before dispatch.
- Extended API-key selection to prefetch usage reports and block exhausted siblings until reset.
- Covered the regression with an AuthStorage Z.AI API-key selection test.

Fixes #5265

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2010f01cd5

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +2533 to +2535
return {
type: "api_key",
apiKey: credential.key,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Resolve stored API keys before usage probes

When an API-key credential stores a config reference, the same getApiKey path later resolves it through #configValueResolver, but the new usage-ranking path passes the raw stored string to the usage provider here. In coding-agent configurations that use env/!command values, the Z.AI quota probe runs with Authorization: ZAI_API_KEY or !cmd, returns no report, and the exhausted referenced key is ranked as unknown even though the actual request uses the resolved secret. Resolve the key before building the UsageCredential, or skip usage ranking when it cannot be resolved.

Useful? React with 👍 / 👎.

Comment thread packages/ai/src/usage/zai.ts Outdated
Comment on lines +195 to +197
function rankZaiRequestLimits(report: UsageReport): UsageLimit[] {
const requestLimits = report.limits.filter(limit => limit.id.startsWith("zai:requests:"));
const limits = requestLimits.length > 0 ? requestLimits : report.limits;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Exclude feature-specific Z.AI quotas from ranking

When the quota payload includes the Web Search / Reader / Zread TIME_LIMIT that this provider labels separately, this prefix match treats that feature counter as the general request window. Because zaiRankingStrategy does not scope limits, #rankApiKeySelections can mark the entire credential blocked when only that feature quota is exhausted, causing ordinary Z.AI model requests to avoid an otherwise healthy key. Filter or scope those feature-specific limits separately before using them for credential-wide ranking/blocking.

Useful? React with 👍 / 👎.

- Resolved stored API-key config references before Z.AI usage ranking probes.
- Scoped Z.AI ranking to model request/token quotas so feature-only exhaustion does not block model routing.
- Added regressions for config references and feature-specific quota rows.

Fixes #5265
@roboomp

roboomp commented Jul 12, 2026

Copy link
Copy Markdown
Collaborator Author

Resolved stored API-key config references before usage-ranking probes so Z.AI quota checks use the same secret as request dispatch.
Scoped Z.AI ranking/blocking to model request/token quotas and excluded Web Search / Reader / Zread feature counters from credential-wide blocking.
Added regressions for resolved API-key references and feature-only quota exhaustion; bun test packages/ai/test/auth-storage-zai-api-key-selection.test.ts packages/ai/test/auth-storage-codex-selection.test.ts packages/ai/test/auth-storage-antigravity-selection.test.ts and bun check pass.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8d4e4fde57

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

const featureLimit = isZaiFeatureRequestLimit(parsed);
limits.push({
id: `zai:requests:${window.id}`,
id: featureLimit ? `zai:features:web-search-reader-zread:${window.id}` : `zai:requests:${window.id}`,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Update the stale Z.AI usage parser expectation

With the existing fixture in packages/ai/test/zai-usage.test.ts, this branch now emits zai:features:web-search-reader-zread:1mo for the Web Search / Reader / Zread limit, while that committed test still asserts the first id is zai:requests:1mo. Once the package test suite runs with workspace aliases available, the parser contract test will fail unless the expectation is updated to match this intentional feature-quota split (or this id change is reverted).

Useful? React with 👍 / 👎.

- Updated the Z.AI usage parser fixture to expect feature-specific Web Search / Reader / Zread quota ids.
- Asserted the feature quota is not marked as a shared model-routing quota.

Fixes #5265
@roboomp

roboomp commented Jul 12, 2026

Copy link
Copy Markdown
Collaborator Author

Updated packages/ai/test/zai-usage.test.ts to expect the Web Search / Reader / Zread feature quota id zai:features:web-search-reader-zread:1mo and assert it is not a shared model-routing quota.
Verified bun test packages/ai/test/zai-usage.test.ts packages/ai/test/auth-storage-zai-api-key-selection.test.ts and bun check pass.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

vouched Passed the vouch gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

API-key multi-account selection ignores per-account usage, routing Z.AI requests to an exhausted account (429 [1308])

1 participant