@bitkyc08/opencodex 2.52.0-preview.20260911 → 2.52.0-preview.20260912
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/gui/dist/assets/index-D_t6sCWs.js +115 -0
- package/gui/dist/assets/index-EdoPnm9_.css +1 -0
- package/gui/dist/index.html +2 -2
- package/gui/dist/provider-icons/devin.svg +49 -0
- package/gui/dist/provider-icons/omo.svg +42 -0
- package/package.json +3 -1
- package/src/AGENTS.md +1 -1
- package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +0 -1
- package/src/adapters/command-code.ts +0 -1
- package/src/adapters/cursor/checkpoint-store.ts +37 -0
- package/src/adapters/cursor/live-transport.ts +74 -2
- package/src/adapters/cursor.ts +6 -0
- package/src/adapters/devin/cloud-direct/auth.ts +264 -0
- package/src/adapters/devin/cloud-direct/catalog.ts +306 -0
- package/src/adapters/devin/cloud-direct/chat.ts +1274 -0
- package/src/adapters/devin/cloud-direct/index.ts +65 -0
- package/src/adapters/devin/cloud-direct/metadata.ts +134 -0
- package/src/adapters/devin/cloud-direct/wire.ts +206 -0
- package/src/adapters/devin/live-models.ts +133 -0
- package/src/adapters/devin-cli/acp.ts +204 -0
- package/src/adapters/devin-cli/adapter.ts +345 -0
- package/src/adapters/devin-cli/binary.ts +69 -0
- package/src/adapters/devin-cli/models.ts +57 -0
- package/src/adapters/devin.ts +326 -0
- package/src/adapters/google.ts +1 -1
- package/src/adapters/openai-chat.ts +31 -10
- package/src/adapters/openai-responses.ts +16 -1
- package/src/adapters/registry.ts +25 -1
- package/src/bridge.ts +8 -2
- package/src/claude/inbound-cache-stabilize.ts +130 -0
- package/src/claude/inbound.ts +45 -5
- package/src/cli/account-auth.ts +60 -1
- package/src/cli/account-extended.ts +23 -30
- package/src/cli/account.ts +2 -1
- package/src/cli/capabilities.ts +50 -8
- package/src/cli/config-command.ts +2 -2
- package/src/cli/dispatch.ts +14 -2
- package/src/cli/export-command.ts +11 -25
- package/src/cli/help.ts +2 -2
- package/src/cli/opencode.ts +5 -0
- package/src/cli/registry.ts +15 -4
- package/src/clients/config-export/cline.ts +71 -0
- package/src/clients/config-export/contracts.ts +10 -1
- package/src/clients/config-export/model-metadata.ts +33 -0
- package/src/clients/config-export/zcode.ts +23 -12
- package/src/clients/config-export.ts +156 -4
- package/src/codex/account-store.ts +7 -2
- package/src/codex/auth-context.ts +1 -1
- package/src/codex/catalog/effort.ts +4 -3
- package/src/codex/catalog/metadata.ts +8 -4
- package/src/codex/catalog/native-models.ts +24 -4
- package/src/codex/catalog/parsing.ts +19 -1
- package/src/codex/catalog/provider-fetch.ts +57 -0
- package/src/codex/catalog/sync.ts +1 -1
- package/src/codex/context-compat.ts +97 -0
- package/src/codex/context-owner.ts +201 -0
- package/src/codex/history-provider.ts +161 -14
- package/src/codex/inject-coordination.ts +3 -2
- package/src/codex/inject.ts +128 -9
- package/src/codex/pool-rotation.ts +8 -292
- package/src/codex/quota.ts +41 -12
- package/src/codex/retired-model-migration.ts +41 -0
- package/src/codex/routing.ts +327 -22
- package/src/codex/warmup.ts +2 -2
- package/src/combos/failover.ts +5 -0
- package/src/combos/resolve.ts +11 -15
- package/src/config.ts +46 -14
- package/src/generated/compatibility-version.json +293 -113
- package/src/grok/grpc-web.ts +120 -0
- package/src/grok/reset-coupon-ledger.ts +139 -0
- package/src/grok/reset-coupons.ts +278 -0
- package/src/integrations/catalog-refresh.ts +1 -1
- package/src/integrations/cline-document.ts +73 -0
- package/src/integrations/cline-io.ts +149 -0
- package/src/integrations/cline-transaction.ts +42 -0
- package/src/integrations/config-io.ts +21 -2
- package/src/integrations/journal.ts +43 -1
- package/src/integrations/omp-yaml-source.ts +123 -4
- package/src/integrations/ownership-policy.ts +7 -0
- package/src/integrations/ownership.ts +36 -0
- package/src/integrations/registry.ts +27 -0
- package/src/integrations/state.ts +5 -2
- package/src/integrations/store.ts +6 -0
- package/src/integrations/writer.ts +53 -9
- package/src/lab/subject/behavior-fingerprint.ts +1 -1
- package/src/lib/abort.ts +36 -0
- package/src/lib/local-destinations.ts +1 -1
- package/src/lib/upstream-retry.ts +36 -1
- package/src/oauth/account-quota-rank.ts +11 -0
- package/src/oauth/callback-server.ts +10 -5
- package/src/oauth/devin/api-base.ts +63 -0
- package/src/oauth/devin/login.ts +1 -0
- package/src/oauth/devin/register-user.ts +186 -0
- package/src/oauth/devin/types.ts +71 -0
- package/src/oauth/devin-cli.ts +149 -0
- package/src/oauth/devin.ts +170 -0
- package/src/oauth/generic-account-failover.ts +169 -1
- package/src/oauth/index.ts +20 -1
- package/src/oauth/login-cli.ts +19 -5
- package/src/oauth/pool-kernel.ts +321 -0
- package/src/oauth/pool-settings-capability.ts +127 -9
- package/src/oauth/store.ts +7 -3
- package/src/oauth/token-guardian.ts +1 -1
- package/src/providers/codebuddy-models.ts +0 -3
- package/src/providers/command-code-efforts.ts +23 -4
- package/src/providers/default-aliases.ts +4 -0
- package/src/providers/derive.ts +8 -0
- package/src/providers/devin-cli-authmode-migration.ts +57 -0
- package/src/providers/key-failover.ts +175 -0
- package/src/providers/model-rename-startup.ts +21 -1
- package/src/providers/qoder-models.ts +0 -1
- package/src/providers/quota-key-accounts.ts +50 -0
- package/src/providers/quota-routing-cache.ts +65 -6
- package/src/providers/quota-types.ts +7 -0
- package/src/providers/quota.ts +113 -30
- package/src/providers/registry.ts +237 -77
- package/src/providers/stale-context-window-migration.ts +92 -0
- package/src/providers/zai-responses-migration.ts +45 -0
- package/src/quota/reset-observer.ts +2 -1
- package/src/quota/reset-seen-store.ts +9 -1
- package/src/remote-control/crypto.ts +442 -0
- package/src/remote-control/host.ts +175 -0
- package/src/remote-control/index.ts +100 -0
- package/src/remote-control/protocol.ts +200 -0
- package/src/remote-control/relay.ts +162 -0
- package/src/remote-control/workspace-agent-protocol.ts +246 -0
- package/src/remote-control/workspace-rpc-framing.ts +128 -0
- package/src/remote-control/workspace-tools.ts +237 -0
- package/src/remote-control/workspace-utf8.ts +24 -0
- package/src/responses/custom-tool-compat.ts +23 -0
- package/src/router.ts +6 -1
- package/src/routing/compatibility/behavior.ts +3 -0
- package/src/server/adapter-resolve.ts +6 -2
- package/src/server/auth-cors.ts +71 -6
- package/src/server/chat-completions.ts +5 -3
- package/src/server/chat-native.ts +9 -0
- package/src/server/claude-messages.ts +25 -30
- package/src/server/context-history.ts +207 -0
- package/src/server/images.ts +28 -1
- package/src/server/index.ts +42 -22
- package/src/server/live.ts +2 -1
- package/src/server/management/agent-settings-routes.ts +7 -1
- package/src/server/management/config-routes.ts +3 -3
- package/src/server/management/grok-coupon-routes.ts +287 -0
- package/src/server/management/integration-routes.ts +6 -1
- package/src/server/management/oauth-account-routes.ts +124 -7
- package/src/server/management/provider-routes.ts +77 -2
- package/src/server/management/route-registry.ts +6 -1
- package/src/server/management-api.ts +7 -0
- package/src/server/request-log.ts +4 -0
- package/src/server/responses/codex-ws-exchange.ts +90 -14
- package/src/server/responses/codex-ws-wire.ts +51 -1
- package/src/server/responses/compact.ts +8 -1
- package/src/server/responses/core.ts +188 -22
- package/src/server/responses/ws-upstream.ts +1 -1
- package/src/server/responses-undeclared-tool-guard.ts +261 -12
- package/src/server/zai-responses-startup.ts +21 -0
- package/src/types/config.ts +33 -3
- package/src/types/provider.ts +54 -4
- package/src/types/request.ts +1 -1
- package/src/types/tools.ts +36 -6
- package/src/update/job.ts +33 -11
- package/src/vision/plan.ts +40 -37
- package/src/web-search/index.ts +1 -0
- package/gui/dist/assets/index-BoBRSehJ.css +0 -1
- package/gui/dist/assets/index-Dx0xv2EA.js +0 -115
package/src/providers/quota.ts
CHANGED
|
@@ -39,7 +39,9 @@ import {
|
|
|
39
39
|
} from "./quota-wire";
|
|
40
40
|
import {
|
|
41
41
|
clearCachedProviderQuotas,
|
|
42
|
+
providerQuotaRoutingBinding,
|
|
42
43
|
replaceCachedProviderQuotas,
|
|
44
|
+
type ProviderQuotaRoutingEvidence,
|
|
43
45
|
} from "./quota-routing-cache";
|
|
44
46
|
import {
|
|
45
47
|
aggregateCodexPoolCapacity,
|
|
@@ -52,6 +54,7 @@ import type {
|
|
|
52
54
|
ProviderQuota,
|
|
53
55
|
ProviderQuotaCreditsUsd,
|
|
54
56
|
ProviderQuotaWindow,
|
|
57
|
+
ProviderRoutingQuota,
|
|
55
58
|
} from "./quota-types";
|
|
56
59
|
import {
|
|
57
60
|
clearKiroAccountUsageState,
|
|
@@ -103,6 +106,7 @@ const XAI_CREDITS_URL = `${XAI_BILLING_URL}?format=credits`;
|
|
|
103
106
|
const LAST_GOOD_MAX_AGE_MS = CODEX_CAPACITY_MAX_QUOTA_AGE_MS;
|
|
104
107
|
const nativeMainReportGenerations = new WeakMap<ProviderQuotaReport, number>();
|
|
105
108
|
const accountReportCurrent = new WeakMap<ProviderQuotaReport, () => boolean>();
|
|
109
|
+
const routingEvidence = new WeakMap<ProviderQuotaReport, ProviderQuotaRoutingEvidence>();
|
|
106
110
|
let providerQuotaBeforePublishForTests: (() => void | Promise<void>) | null = null;
|
|
107
111
|
|
|
108
112
|
/** Test-only seam for identity/config invalidation after probes but before publication. */
|
|
@@ -136,6 +140,8 @@ export interface ProviderQuotaReport {
|
|
|
136
140
|
source: string;
|
|
137
141
|
quota: ProviderQuota;
|
|
138
142
|
updatedAt: number;
|
|
143
|
+
/** Added by the management response projection, never stored on a cached report. */
|
|
144
|
+
routingQuota?: ProviderRoutingQuota;
|
|
139
145
|
reverseEngineered?: boolean;
|
|
140
146
|
/**
|
|
141
147
|
* The row was OBSERVED in-band on a streaming turn rather than probed.
|
|
@@ -345,14 +351,26 @@ function isCanonicalOllamaCloudBaseUrl(baseUrl?: string): boolean {
|
|
|
345
351
|
}
|
|
346
352
|
}
|
|
347
353
|
|
|
354
|
+
function zaiQuotaMonitorHost(baseUrl: string): string | null {
|
|
355
|
+
// Admission and destination selection must share one mapping: admitting a new
|
|
356
|
+
// international wire must never fall through to the CN host/authentication scheme.
|
|
357
|
+
switch (normalizedBaseUrl(baseUrl)) {
|
|
358
|
+
case ZAI_BASE_URL:
|
|
359
|
+
case `${ZAI_BASE_URL}/api/coding/paas/v4`:
|
|
360
|
+
case `${ZAI_BASE_URL}/api/anthropic`:
|
|
361
|
+
case `${ZAI_BASE_URL}/api/v1`:
|
|
362
|
+
return ZAI_BASE_URL;
|
|
363
|
+
case ZAI_CN_BASE_URL:
|
|
364
|
+
case `${ZAI_CN_BASE_URL}/api/coding/paas/v4`:
|
|
365
|
+
case `${ZAI_CN_BASE_URL}/api/v1`:
|
|
366
|
+
return ZAI_CN_BASE_URL;
|
|
367
|
+
default:
|
|
368
|
+
return null;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
348
372
|
function isCanonicalZaiBaseUrl(baseUrl: string): boolean {
|
|
349
|
-
|
|
350
|
-
return normalized === ZAI_BASE_URL
|
|
351
|
-
|| normalized === `${ZAI_BASE_URL}/api/coding/paas/v4`
|
|
352
|
-
|| normalized === ZAI_CN_BASE_URL
|
|
353
|
-
|| normalized === `${ZAI_CN_BASE_URL}/api/coding/paas/v4`
|
|
354
|
-
// BigModel serves the same GLM Coding Plan on the OpenAI Responses wire at /api/v1.
|
|
355
|
-
|| normalized === `${ZAI_CN_BASE_URL}/api/v1`;
|
|
373
|
+
return zaiQuotaMonitorHost(baseUrl) !== null;
|
|
356
374
|
}
|
|
357
375
|
|
|
358
376
|
function isCanonicalMinimaxBaseUrl(baseUrl: string): boolean {
|
|
@@ -435,7 +453,9 @@ async function fetchA6apiQuota(provider: string, config: OcxProviderConfig): Pro
|
|
|
435
453
|
? { expiresAt: normalizedExpiry }
|
|
436
454
|
: {};
|
|
437
455
|
if (unlimited) {
|
|
438
|
-
|
|
456
|
+
// Every row is an API-credit constraint on inference, so the display quota is also
|
|
457
|
+
// the routing projection. Passing it explicitly is the opt-in.
|
|
458
|
+
const quota: ProviderQuota = {
|
|
439
459
|
creditsUsd: {
|
|
440
460
|
used: 0,
|
|
441
461
|
limit: 0,
|
|
@@ -446,7 +466,8 @@ async function fetchA6apiQuota(provider: string, config: OcxProviderConfig): Pro
|
|
|
446
466
|
},
|
|
447
467
|
customWindows: [{ label: "Unlimited API credits", percent: 0 }],
|
|
448
468
|
updatedAt: Date.now(),
|
|
449
|
-
}
|
|
469
|
+
};
|
|
470
|
+
return keyReport(provider, "a6api:billing", quota, config, apiKey, quota);
|
|
450
471
|
}
|
|
451
472
|
const limitUsd = firstFinite(subscription, ["hard_limit_usd"]);
|
|
452
473
|
const grantedUnits = firstFinite(token, ["total_granted"]);
|
|
@@ -469,7 +490,7 @@ async function fetchA6apiQuota(provider: string, config: OcxProviderConfig): Pro
|
|
|
469
490
|
const percent = normalizePercent((usedUsd / limitUsd) * 100);
|
|
470
491
|
if (percent === undefined) return TERMINAL_QUOTA_FAILURE;
|
|
471
492
|
const label = `API credits ($${remainingUsd.toFixed(2)} of $${limitUsd.toFixed(2)} remaining)`;
|
|
472
|
-
|
|
493
|
+
const quota: ProviderQuota = {
|
|
473
494
|
creditsUsd: {
|
|
474
495
|
used: usedUsd,
|
|
475
496
|
limit: limitUsd,
|
|
@@ -479,7 +500,9 @@ async function fetchA6apiQuota(provider: string, config: OcxProviderConfig): Pro
|
|
|
479
500
|
},
|
|
480
501
|
customWindows: [{ label, percent }],
|
|
481
502
|
updatedAt: Date.now(),
|
|
482
|
-
}
|
|
503
|
+
};
|
|
504
|
+
// The credit balance funds inference itself, so display and routing scope agree.
|
|
505
|
+
return keyReport(provider, "a6api:billing", quota, config, apiKey, quota);
|
|
483
506
|
}
|
|
484
507
|
|
|
485
508
|
function parseOpenCodeGoUsageWindow(value: unknown): { percent: number; resetAt?: number } | null {
|
|
@@ -527,7 +550,7 @@ async function fetchOpenCodeGoQuota(provider: string, config: OcxProviderConfig)
|
|
|
527
550
|
} : {}),
|
|
528
551
|
updatedAt: Date.now(),
|
|
529
552
|
};
|
|
530
|
-
return
|
|
553
|
+
return keyReport(provider, "opencode-go:usage", quota, config, apiKey, quota);
|
|
531
554
|
}
|
|
532
555
|
|
|
533
556
|
/**
|
|
@@ -571,10 +594,13 @@ async function fetchOpenRouterQuota(provider: string, config: OcxProviderConfig)
|
|
|
571
594
|
if (percent === undefined) return null;
|
|
572
595
|
const remaining = Math.max(0, limit - used);
|
|
573
596
|
const label = `API credits ($${remaining.toFixed(2)} of $${limit.toFixed(2)} remaining)`;
|
|
574
|
-
|
|
597
|
+
// The per-key spending cap stops every request this credential can make, so the
|
|
598
|
+
// whole report is inference-wide routing evidence.
|
|
599
|
+
const quota: ProviderQuota = {
|
|
575
600
|
customWindows: [{ label, percent }],
|
|
576
601
|
updatedAt: Date.now(),
|
|
577
|
-
}
|
|
602
|
+
};
|
|
603
|
+
return keyReport(provider, "openrouter:key-info", quota, config, apiKey, quota);
|
|
578
604
|
}
|
|
579
605
|
|
|
580
606
|
/**
|
|
@@ -673,7 +699,7 @@ async function fetchClineQuota(provider: string, config: OcxProviderConfig): Pro
|
|
|
673
699
|
windows += 1;
|
|
674
700
|
}
|
|
675
701
|
}
|
|
676
|
-
return windows > 0 ?
|
|
702
|
+
return windows > 0 ? keyReport(provider, "cline:plan-usage-limits", quota, config, apiKey, quota) : null;
|
|
677
703
|
}
|
|
678
704
|
|
|
679
705
|
/**
|
|
@@ -745,7 +771,7 @@ async function fetchOllamaCloudQuota(provider: string, config: OcxProviderConfig
|
|
|
745
771
|
}
|
|
746
772
|
const body = asRecord(await readQuotaJson(response));
|
|
747
773
|
const quota = parseOllamaCloudQuota(body);
|
|
748
|
-
return quota ?
|
|
774
|
+
return quota ? keyReport(provider, "ollama-cloud:usage", quota, config, apiKey, quota) : null;
|
|
749
775
|
}
|
|
750
776
|
|
|
751
777
|
/**
|
|
@@ -851,13 +877,10 @@ function parseZaiQuotaLegacyFields(data: Record<string, unknown> | null): Provid
|
|
|
851
877
|
* host or follow a redirect off-origin.
|
|
852
878
|
*/
|
|
853
879
|
async function fetchZaiQuota(provider: string, config: OcxProviderConfig): Promise<ProviderQuotaProbeResult> {
|
|
854
|
-
|
|
880
|
+
const monitorHost = zaiQuotaMonitorHost(config.baseUrl);
|
|
881
|
+
if (!monitorHost) return null;
|
|
855
882
|
const apiKey = resolveProviderApiKey(config.apiKey)?.trim();
|
|
856
883
|
if (!apiKey) return null;
|
|
857
|
-
const normalized = normalizedBaseUrl(config.baseUrl);
|
|
858
|
-
const monitorHost = normalized === ZAI_BASE_URL || normalized === `${ZAI_BASE_URL}/api/coding/paas/v4`
|
|
859
|
-
? ZAI_BASE_URL
|
|
860
|
-
: ZAI_CN_BASE_URL;
|
|
861
884
|
const authorization = monitorHost === ZAI_CN_BASE_URL ? apiKey : `Bearer ${apiKey}`;
|
|
862
885
|
const response = await fetch(`${monitorHost}/api/monitor/usage/quota/limit`, {
|
|
863
886
|
headers: { Accept: "application/json", Authorization: authorization },
|
|
@@ -878,10 +901,18 @@ async function fetchZaiQuota(provider: string, config: OcxProviderConfig): Promi
|
|
|
878
901
|
// model window — for example a plan reporting only the monthly MCP `TIME_LIMIT` row.
|
|
879
902
|
// Returning `null` here would preserve the previous token windows for up to 30 minutes
|
|
880
903
|
// and keep quota-aware routing acting on a report the provider has already superseded.
|
|
881
|
-
return quota
|
|
904
|
+
return quota
|
|
905
|
+
? keyReport(provider, "zai:quota-limit", quota, config, apiKey, quota)
|
|
906
|
+
: AUTHORITATIVE_EMPTY_QUOTA;
|
|
882
907
|
}
|
|
883
908
|
const legacy = parseZaiQuotaLegacyFields(data);
|
|
884
|
-
|
|
909
|
+
if (!legacy) return null;
|
|
910
|
+
// The legacy monthly figure also carries MCP usage; it is display evidence, not
|
|
911
|
+
// proof that model inference is unavailable. Modern TOKEN_LIMIT rows above are scoped.
|
|
912
|
+
const inferenceQuota = { ...legacy };
|
|
913
|
+
delete inferenceQuota.monthlyPercent;
|
|
914
|
+
delete inferenceQuota.monthlyResetAt;
|
|
915
|
+
return keyReport(provider, "zai:quota-limit", legacy, config, apiKey, inferenceQuota);
|
|
885
916
|
}
|
|
886
917
|
|
|
887
918
|
/**
|
|
@@ -1064,7 +1095,9 @@ async function fetchSyntheticQuota(provider: string, config: OcxProviderConfig):
|
|
|
1064
1095
|
quota.customWindows = [...(quota.customWindows ?? []), { label: "Search hourly", percent: searchHourly }];
|
|
1065
1096
|
windows += 1;
|
|
1066
1097
|
}
|
|
1067
|
-
|
|
1098
|
+
const inferenceQuota = { ...quota };
|
|
1099
|
+
delete inferenceQuota.customWindows; // search.hourly does not constrain model inference.
|
|
1100
|
+
return windows > 0 ? keyReport(provider, "synthetic:quotas", quota, config, apiKey, inferenceQuota) : null;
|
|
1068
1101
|
}
|
|
1069
1102
|
|
|
1070
1103
|
/**
|
|
@@ -1176,6 +1209,31 @@ function report(
|
|
|
1176
1209
|
};
|
|
1177
1210
|
}
|
|
1178
1211
|
|
|
1212
|
+
/**
|
|
1213
|
+
* Publish a credential-bound report, and routing evidence only when the producer
|
|
1214
|
+
* hands over its inference-only projection.
|
|
1215
|
+
*
|
|
1216
|
+
* The projection is deliberately not defaulted to the display quota. A producer must
|
|
1217
|
+
* decide that its rows really do constrain inference on the probed credential; omitting
|
|
1218
|
+
* the argument leaves the report display-only, so a new producer cannot inherit
|
|
1219
|
+
* provider-veto authority merely by calling this helper. Ownership alone is not the
|
|
1220
|
+
* scope decision: providerQuotaRoutingBinding resolving is necessary, never sufficient.
|
|
1221
|
+
*/
|
|
1222
|
+
function keyReport(
|
|
1223
|
+
provider: string,
|
|
1224
|
+
source: string,
|
|
1225
|
+
quota: ProviderQuota,
|
|
1226
|
+
config: OcxProviderConfig,
|
|
1227
|
+
probedCredential: string,
|
|
1228
|
+
inferenceQuota?: ProviderQuota,
|
|
1229
|
+
): ProviderQuotaReport | null {
|
|
1230
|
+
const result = report(provider, source, quota);
|
|
1231
|
+
if (!result || !inferenceQuota) return result;
|
|
1232
|
+
const binding = providerQuotaRoutingBinding(provider, config, probedCredential);
|
|
1233
|
+
if (binding) routingEvidence.set(result, { quota: inferenceQuota, binding });
|
|
1234
|
+
return result;
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1179
1237
|
function tagNativeMainReport(
|
|
1180
1238
|
value: ProviderQuotaReport | null,
|
|
1181
1239
|
generation: number,
|
|
@@ -1184,6 +1242,27 @@ function tagNativeMainReport(
|
|
|
1184
1242
|
return value;
|
|
1185
1243
|
}
|
|
1186
1244
|
|
|
1245
|
+
/**
|
|
1246
|
+
* Test-only seam: publish exactly as a credential-bound producer does, and hand back the
|
|
1247
|
+
* routing evidence the publication actually attached.
|
|
1248
|
+
*
|
|
1249
|
+
* Live producers all pass a projection today, so no probe fixture can prove the OTHER half
|
|
1250
|
+
* of the contract: that omitting it stays display-only. Routing an omitted argument through
|
|
1251
|
+
* the real helper keeps that provable, and a re-introduced `= quota` default would be
|
|
1252
|
+
* observed here (a defaulted parameter also fires for an explicitly undefined argument).
|
|
1253
|
+
*/
|
|
1254
|
+
export function publishKeyReportForTests(
|
|
1255
|
+
provider: string,
|
|
1256
|
+
source: string,
|
|
1257
|
+
quota: ProviderQuota,
|
|
1258
|
+
config: OcxProviderConfig,
|
|
1259
|
+
probedCredential: string,
|
|
1260
|
+
inferenceQuota?: ProviderQuota,
|
|
1261
|
+
): { report: ProviderQuotaReport | null; routing: ProviderQuotaRoutingEvidence | undefined } {
|
|
1262
|
+
const result = keyReport(provider, source, quota, config, probedCredential, inferenceQuota);
|
|
1263
|
+
return { report: result, routing: result ? routingEvidence.get(result) : undefined };
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1187
1266
|
function isProviderQuotaReportCurrent(value: ProviderQuotaReport): boolean {
|
|
1188
1267
|
const generation = nativeMainReportGenerations.get(value);
|
|
1189
1268
|
return (generation === undefined || isMainAccountIdentityGenerationLive(generation))
|
|
@@ -1879,7 +1958,7 @@ export function reconcileProviderAccountQuotaRows(context: GenerationContext): n
|
|
|
1879
1958
|
const reports = cache.response.reports.filter(report => context.providerNames.has(report.provider));
|
|
1880
1959
|
removed += cache.response.reports.length - reports.length;
|
|
1881
1960
|
cache = { ...cache, response: { ...cache.response, reports } };
|
|
1882
|
-
replaceCachedProviderQuotas(reports);
|
|
1961
|
+
replaceCachedProviderQuotas(reports, routingEvidence);
|
|
1883
1962
|
}
|
|
1884
1963
|
liveAccountQuotaKeys = new Set(context.oauthAccountKeys);
|
|
1885
1964
|
liveProviderQuotaKeys = new Set(context.providerNames);
|
|
@@ -2308,7 +2387,7 @@ async function fetchKimiQuota(provider: string, config: OcxProviderConfig, acces
|
|
|
2308
2387
|
});
|
|
2309
2388
|
if (!response.ok) return null;
|
|
2310
2389
|
const quota = parseKimiQuotaPayload(await readQuotaJson(response));
|
|
2311
|
-
return quota ?
|
|
2390
|
+
return quota ? keyReport(provider, "kimi:usages", quota, config, accessToken, quota) : null;
|
|
2312
2391
|
}
|
|
2313
2392
|
|
|
2314
2393
|
/**
|
|
@@ -2435,7 +2514,7 @@ async function fetchCommandCodeQuota(provider: string, config: OcxProviderConfig
|
|
|
2435
2514
|
const fiveHour = parseCommandCodeWindow(limits?.fiveHour);
|
|
2436
2515
|
const weekly = parseCommandCodeWindow(limits?.weekly);
|
|
2437
2516
|
const creditsUsd = await fetchCommandCodeSpend(bearer, credits, orgQuery);
|
|
2438
|
-
|
|
2517
|
+
const quota: ProviderQuota = {
|
|
2439
2518
|
...(fiveHour ? {
|
|
2440
2519
|
fiveHourPercent: fiveHour.percent,
|
|
2441
2520
|
...(fiveHour.resetAt !== undefined ? { fiveHourResetAt: fiveHour.resetAt } : {}),
|
|
@@ -2446,7 +2525,9 @@ async function fetchCommandCodeQuota(provider: string, config: OcxProviderConfig
|
|
|
2446
2525
|
} : {}),
|
|
2447
2526
|
...(creditsUsd ? { creditsUsd } : {}),
|
|
2448
2527
|
updatedAt: Date.now(),
|
|
2449
|
-
}
|
|
2528
|
+
};
|
|
2529
|
+
// Rolling windows and the credit balance both gate inference on this bearer.
|
|
2530
|
+
return keyReport(provider, "command-code:credits", quota, config, bearer, quota);
|
|
2450
2531
|
}
|
|
2451
2532
|
|
|
2452
2533
|
/** Cursor included usage via api2.cursor.sh (Bearer from OAuth) — unofficial, may change. */
|
|
@@ -2955,7 +3036,9 @@ async function maybeFetchProviderQuota(
|
|
|
2955
3036
|
// probe to run — the row is the active account's last in-band observation.
|
|
2956
3037
|
if (provider.authMode === "oauth" && hasPassiveAccountQuota(name)) return fetchPassiveProviderQuota(name);
|
|
2957
3038
|
const reader = keyQuotaReaderForProvider(name, provider);
|
|
2958
|
-
|
|
3039
|
+
// Keep destination/auth fields bound to the same request as the reader's captured
|
|
3040
|
+
// bearer, even if the live provider object changes while the quota probe awaits.
|
|
3041
|
+
return reader ? reader(name, { ...provider }) : null;
|
|
2959
3042
|
} catch {
|
|
2960
3043
|
return null;
|
|
2961
3044
|
}
|
|
@@ -3142,7 +3225,7 @@ export async function fetchProviderQuotaReports(config: OcxConfig, forceRefresh
|
|
|
3142
3225
|
) {
|
|
3143
3226
|
const reports = response.reports.filter(item => mayCommitProviderQuotaKey(item.provider, writerGeneration));
|
|
3144
3227
|
cache = { key, ts: Date.now(), response: { ...response, reports } };
|
|
3145
|
-
replaceCachedProviderQuotas(reports);
|
|
3228
|
+
replaceCachedProviderQuotas(reports, routingEvidence);
|
|
3146
3229
|
notifyProviderQuotaSnapshot(reports, config);
|
|
3147
3230
|
}
|
|
3148
3231
|
return response;
|