Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions docs-site/src/content/docs/reference/configuration/routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,15 +153,17 @@ CLI: `ocx route policy list [--json]`, `ocx route policy show <id> [--json]`, an
Dry-run evaluates candidates without sending any upstream request.

Quota evidence (`optimize.quota`, `require.minQuotaHeadroom`, `unknownEvidence.quota`) comes from
the local Codex pool and Anthropic account quota caches, which are keyed by account. In **Pool** mode
the canonical `openai` provider preserves its existing account selection, then reads quota for the
selected account; **Direct** mode reads quota only from the current (caller/main) account. For other
providers (e.g. Anthropic), runtime candidates use the provider's active account. Quota evidence
never changes account selection, session affinity, cooldowns, or switching behavior — it only feeds
policy scoring. To see quota-aware behavior in a dry-run, supply account refs through the dry-run/API
candidate evidence: `candidates[].codexAccountId` (Codex pool, provider `openai`) or
`candidates[].accountRef` (Anthropic) derives the matching cached account quota; an explicit
`candidates[].quota` object is echoed as given.
account-keyed Codex and Anthropic quota caches. A runtime candidate receives cached quota only when
the evidence already identifies the account. Unbound canonical `openai` and Anthropic candidates
remain unknown during policy evaluation because Pool selection, Direct caller identity, provider
rotation, and thread affinity are resolved after the policy chooses a provider/model; a process-active
account is not used as a substitute.
Quota evidence never changes account selection, session affinity, cooldowns, or switching behavior —
it only feeds policy scoring. To see quota-aware behavior in an API dry-run, supply account refs in
the candidate evidence sent to `POST /api/routing-profiles/dry-run`:
`candidates[].codexAccountId` (Codex pool, provider `openai`) or `candidates[].accountRef`
(Anthropic) derives the matching cached account quota; an explicit `candidates[].quota` object is
echoed as given. The CLI dry-run cannot supply these per-candidate account fields.

### Combos vs policy profiles

Expand Down
20 changes: 0 additions & 20 deletions src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ import {
import { decodeRoutedModelId, encodeRoutedModelId } from "./providers/slug-codec";
import { getStaleCached } from "./codex/model-cache";
import { codexAccountNamespaceEntries } from "./codex/account-namespaces";
import { getEffectiveActiveCodexAccountId } from "./codex/routing";
import { getAccountSet } from "./oauth/store";
import {
buildRouteDecisionTrace,
type RouteDecisionKind,
Expand Down Expand Up @@ -513,24 +511,6 @@ function routeModelInternal(
quota: quotaEvidenceForCandidate({
provider: candidate.provider,
model: candidate.model,
...(candidate.provider === OPENAI_CODEX_PROVIDER_ID
&& providerCodexAccountMode(
OPENAI_CODEX_PROVIDER_ID,
config.providers[OPENAI_CODEX_PROVIDER_ID],
) === "pool"
? (() => {
const codexAccountId = getEffectiveActiveCodexAccountId(config);
return {
codexAccountId,
codexAccountPlan: codexAccountId
? config.codexAccounts?.find(account => account.id === codexAccountId)?.plan
: undefined,
};
})()
: {}),
accountRef: candidate.provider === "anthropic"
? getAccountSet("anthropic")?.activeAccountId
: undefined,
}),
Comment on lines 511 to 514

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 Preserve quota for non-pooled Anthropic accounts

When anthropicAccountPool.enabled is false (the default), request execution deterministically uses the store's active account through getValidAccessTokenSnapshot, so its cached quota is not ambiguous. Removing accountRef here makes every such policy candidate report unknown quota; profiles with unknownEvidence.quota: "exclude" reject the route, while minQuotaHeadroom and quota optimization stop using valid evidence. Only omit the active account when Anthropic pooling can actually select a different account, and mirror that condition in management dry-runs.

Useful? React with 👍 / 👎.

cost: costEvidenceForCandidate({
provider: candidate.provider,
Expand Down
22 changes: 0 additions & 22 deletions src/server/management/routing-profile-routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,6 @@ import { candidateCapabilityEvidence } from "../../routing/capability";
import { policyCandidateHealthEvidence } from "../../routing/health";
import { quotaEvidenceForCandidate } from "../../routing/quota";
import { costEvidenceForCandidate } from "../../routing/cost";
import { providerCodexAccountMode } from "../../providers/registry";
import { getEffectiveActiveCodexAccountId } from "../../codex/routing";
import { getAccountSet } from "../../oauth/store";
import { OPENAI_CODEX_PROVIDER_ID } from "../../providers/openai-tiers";
import { saveConfigPreservingClaudeCode } from "../../config";
import { reconcileLiveStateStores } from "../../lib/state-store-registrations";
import { isPlainRecord } from "./shared";
Expand Down Expand Up @@ -115,24 +111,6 @@ function assembleCandidateEvidence(
quota: quotaEvidenceForCandidate({
provider: candidate.provider,
model: candidate.model,
...(candidate.provider === OPENAI_CODEX_PROVIDER_ID
&& providerCodexAccountMode(
OPENAI_CODEX_PROVIDER_ID,
config.providers[OPENAI_CODEX_PROVIDER_ID],
) === "pool"
? (() => {
const codexAccountId = getEffectiveActiveCodexAccountId(config);
return {
codexAccountId,
codexAccountPlan: codexAccountId
? config.codexAccounts?.find(account => account.id === codexAccountId)?.plan
: undefined,
};
})()
: {}),
accountRef: candidate.provider === "anthropic"
? getAccountSet("anthropic")?.activeAccountId
: undefined,
}),
cost: costEvidenceForCandidate({
provider: candidate.provider,
Expand Down
40 changes: 37 additions & 3 deletions tests/quota-scoring.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { setCachedProviderAccountQuotaForTests, clearAccountQuotaCache } from ".
import { quotaEvidenceForCandidate, quotaScore } from "../src/routing/quota";
import { evaluatePolicyProfile, QUOTA_UNKNOWN_PENALTY_SCORE } from "../src/routing/evaluator";
import { routeModel } from "../src/router";
import { getAccountSet, saveCredential } from "../src/oauth/store";
import { closeRequestHistoryIndex } from "../src/routing/history/indexer";
import type { OcxConfig } from "../src/types";

Expand Down Expand Up @@ -195,7 +196,7 @@ describe("quota-aware scoring (RI-07)", () => {
expect(penalized.candidates[0]!.score!.components.quota).toBe(QUOTA_UNKNOWN_PENALTY_SCORE);
});

test("execution path passes the active codex account into quota evidence", async () => {
test("execution path does not invent Codex quota evidence from the active pool account", async () => {
updateAccountQuota("pool-a", 30, 1_800_000_000_000, 20, 1_900_000_000_000);
const cfg = config({
codexAccounts: [{ id: "pool-a", email: "pool-a@example.test", isMain: false }],
Expand All @@ -205,8 +206,41 @@ describe("quota-aware scoring (RI-07)", () => {
},
});
const route = routeModel(cfg, "policy/quotaRoute");
expect(route.routeDecision!.candidates[0]!.quota?.known).toBe(true);
expect(route.routeDecision!.candidates[0]!.quota?.headroom).toBeCloseTo(0.7, 2);
expect(route.routeDecision!.candidates[0]!.accountRef).toBeUndefined();
expect(route.routeDecision!.candidates[0]!.quota?.known).toBe(false);
expect(route.routeDecision!.candidates[0]!.quota?.headroom).toBeUndefined();
});
Comment thread
luvs01 marked this conversation as resolved.

test("execution path does not invent Anthropic quota evidence from the active account", async () => {
await saveCredential("anthropic", {
access: "access-a",
refresh: "refresh-a",
expires: Date.now() + 3_600_000,
accountId: "uuid-a",
email: "a@example.test",
});
const activeId = getAccountSet("anthropic")!.activeAccountId;
setCachedProviderAccountQuotaForTests("anthropic", activeId, {
fiveHourPercent: 40,
updatedAt: Date.now(),
});
Comment thread
coderabbitai[bot] marked this conversation as resolved.
const cfg = config({
providers: {
anthropic: {
adapter: "anthropic",
baseUrl: "https://api.anthropic.com",
authMode: "oauth",
models: ["claude-sonnet-5"],
},
},
routingProfiles: {
quotaRoute: { candidates: [{ provider: "anthropic", model: "claude-sonnet-5" }] },
},
});
const route = routeModel(cfg, "policy/quotaRoute");
expect(route.routeDecision!.candidates[0]!.accountRef).toBeUndefined();
expect(route.routeDecision!.candidates[0]!.quota?.known).toBe(false);
expect(route.routeDecision!.candidates[0]!.quota?.headroom).toBeUndefined();
});

test("exact account selectors and pool strategies remain authoritative", () => {
Expand Down
Loading