@yansigit/opencodex 2.32.0 → 2.33.0
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/README.md +2 -2
- package/gui/dist/assets/index-DKLr4LTE.js +102 -0
- package/gui/dist/assets/index-DrSQdTRd.css +1 -0
- package/gui/dist/index.html +2 -2
- package/package.json +6 -5
- package/src/adapters/anthropic.ts +20 -6
- package/src/adapters/azure.ts +20 -4
- package/src/adapters/base.ts +3 -1
- package/src/adapters/command-code.ts +40 -7
- package/src/adapters/cursor/live-transport.ts +1 -1
- package/src/adapters/cursor/protobuf-events.ts +158 -7
- package/src/adapters/cursor/protobuf-request.ts +33 -15
- package/src/adapters/cursor/request-builder.ts +4 -3
- package/src/adapters/cursor/tool-definitions.ts +27 -1
- package/src/adapters/cursor/types.ts +4 -3
- package/src/adapters/cursor.ts +9 -0
- package/src/adapters/google-antigravity-replay.ts +2 -2
- package/src/adapters/google-antigravity-wire.ts +7 -0
- package/src/adapters/google-errors.ts +6 -2
- package/src/adapters/google-http.ts +30 -7
- package/src/adapters/google-truncation.ts +5 -0
- package/src/adapters/google-wire-compiler.ts +38 -6
- package/src/adapters/google.ts +148 -26
- package/src/adapters/kiro-tools.ts +20 -9
- package/src/adapters/openai-chat.ts +9 -0
- package/src/adapters/openai-responses.ts +1 -1
- package/src/bridge.ts +112 -9
- package/src/claude/context-windows.ts +16 -9
- package/src/cli/doctor.ts +2 -2
- package/src/cli/index.ts +9 -2
- package/src/cli/provider.ts +6 -0
- package/src/cli/status.ts +23 -0
- package/src/codex/auth-api.ts +4 -2
- package/src/codex/autostart-health.ts +16 -0
- package/src/codex/catalog/aggregation.ts +12 -12
- package/src/codex/catalog/effort.ts +18 -3
- package/src/codex/catalog/metadata.ts +27 -1
- package/src/codex/catalog/model-metadata.ts +39 -12
- package/src/codex/catalog/parsing.ts +38 -27
- package/src/codex/catalog/provider-fetch.ts +198 -133
- package/src/codex/catalog/sync.ts +1 -1
- package/src/codex/convergence.ts +5 -0
- package/src/codex/shim.ts +56 -3
- package/src/config/provider-validation.ts +37 -0
- package/src/config.ts +78 -2
- package/src/generated/compatibility-version.json +120 -96
- package/src/images/loop.ts +37 -6
- package/src/lib/azure-identity.ts +154 -0
- package/src/lib/debug.ts +42 -0
- package/src/lib/errors.ts +14 -0
- package/src/lib/provider-outbound.ts +45 -33
- package/src/lib/provider-tls-profile.ts +309 -0
- package/src/lib/proxy-env.ts +49 -0
- package/src/lib/redact.ts +10 -1
- package/src/oauth/antigravity-routing.ts +282 -236
- package/src/oauth/callback-server.ts +22 -2
- package/src/oauth/command-code.ts +5 -16
- package/src/oauth/google-antigravity.ts +42 -5
- package/src/oauth/index.ts +15 -3
- package/src/oauth/kimi.ts +9 -1
- package/src/oauth/open-browser-choice.ts +26 -0
- package/src/oauth/store.ts +6 -0
- package/src/providers/antigravity-quota.ts +3 -1
- package/src/providers/api-keys.ts +2 -1
- package/src/providers/auto-compact-budget.ts +65 -0
- package/src/providers/derive.ts +4 -0
- package/src/providers/key-failover.ts +5 -1
- package/src/providers/openai-tiers.ts +5 -0
- package/src/providers/provider-id-rewrite.ts +1 -0
- package/src/providers/quota.ts +59 -13
- package/src/providers/registry.ts +3 -1
- package/src/providers/request-pacing.ts +33 -6
- package/src/providers/xai-transport.ts +21 -0
- package/src/responses/google-provider-options.ts +36 -0
- package/src/responses/namespace-tool-compat.ts +84 -4
- package/src/responses/parser.ts +11 -0
- package/src/responses/provider-opaque-metadata.ts +3 -3
- package/src/responses/schema.ts +37 -0
- package/src/responses/state.ts +94 -4
- package/src/router.ts +8 -2
- package/src/server/auth-cors.ts +28 -0
- package/src/server/images.ts +19 -35
- package/src/server/management/agent-settings-routes.ts +205 -15
- package/src/server/management/combo-routes.ts +6 -0
- package/src/server/management/config-routes.ts +31 -5
- package/src/server/management/model-rows.ts +4 -0
- package/src/server/management/oauth-account-routes.ts +25 -4
- package/src/server/management/provider-routes.ts +113 -15
- package/src/server/management/routing-profile-routes.ts +3 -0
- package/src/server/request-log.ts +21 -0
- package/src/server/responses/agent-task-recovery.ts +1 -1
- package/src/server/responses/compact.ts +30 -1
- package/src/server/responses/core.ts +359 -153
- package/src/server/responses/empty-completion-guard.ts +35 -6
- package/src/server/responses/fetch-helpers.ts +18 -5
- package/src/server/responses/v2-native-parent-override.ts +59 -0
- package/src/server/responses/ws-upstream.ts +75 -2
- package/src/server/responses-undeclared-tool-guard.ts +90 -8
- package/src/service.ts +1 -1
- package/src/types/config.ts +16 -1
- package/src/types/provider.ts +16 -0
- package/src/types/request.ts +28 -0
- package/src/types/tools.ts +27 -0
- package/src/types.ts +6 -0
- package/src/web-search/gemini-executor.ts +6 -4
- package/src/web-search/loop.ts +42 -6
- package/gui/dist/assets/index-BG43zwVe.js +0 -102
- package/gui/dist/assets/index-CiSI-jrP.css +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Server } from "bun";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
|
-
import { bridgeToResponsesSSE, buildResponseJSON, formatErrorResponse, type ResponsesTerminalStatus } from "../../bridge";
|
|
3
|
+
import { adapterEventDiagnosticDetails, bridgeToResponsesSSE, buildResponseJSON, formatErrorResponse, type BridgeDiagnosticContext, type BridgeDiagnosticSequence, type ResponsesTerminalStatus } from "../../bridge";
|
|
4
4
|
import { formatPassthroughUpstreamError } from "./passthrough-error";
|
|
5
5
|
import {
|
|
6
6
|
createResponsesFieldBackfillBlockRewrite,
|
|
@@ -14,6 +14,8 @@ import {
|
|
|
14
14
|
resolveEnvValue,
|
|
15
15
|
} from "../../config";
|
|
16
16
|
import { parseRequest } from "../../responses/parser";
|
|
17
|
+
import { googleProviderOptionsRouteError } from "../../responses/google-provider-options";
|
|
18
|
+
import type { ProviderAdapter } from "../../adapters/base";
|
|
17
19
|
import {
|
|
18
20
|
bindReasoningReplayScope,
|
|
19
21
|
commitReasoningReplayServingIdentity,
|
|
@@ -70,9 +72,12 @@ import {
|
|
|
70
72
|
pickComboTarget,
|
|
71
73
|
targetKey,
|
|
72
74
|
} from "../../combos";
|
|
73
|
-
import { isInjectionDebugEnabled } from "../../lib/debug-settings";
|
|
75
|
+
import { isDebugEnabled, isInjectionDebugEnabled } from "../../lib/debug-settings";
|
|
76
|
+
import { debugStreamDiagnostic } from "../../lib/debug";
|
|
74
77
|
import { injectionDebugLog } from "../../lib/injection-debug-log";
|
|
78
|
+
import { OcxRequestValidationError } from "../../lib/errors";
|
|
75
79
|
import { resolveClientRetryAfter } from "../../lib/retry-after";
|
|
80
|
+
import { antigravityOAuthDestinationConfigError, isAntigravityOAuthProvider } from "../../lib/provider-tls-profile";
|
|
76
81
|
import { enrichOpenCodeZenRateLimitMessage } from "../../providers/opencode-zen-rate-limit";
|
|
77
82
|
import { modelInList, namespacedToolName } from "../../types";
|
|
78
83
|
import type {
|
|
@@ -90,6 +95,7 @@ import {
|
|
|
90
95
|
forceRefreshOAuthAccessSnapshot,
|
|
91
96
|
getOAuthCredentialApiBaseUrl,
|
|
92
97
|
getValidAccessTokenForAccount,
|
|
98
|
+
getValidAccessTokenSnapshotForAccount,
|
|
93
99
|
getValidAccessTokenSnapshot,
|
|
94
100
|
publicOAuthAuthenticationErrorMessage,
|
|
95
101
|
type OAuthAccessSnapshot,
|
|
@@ -108,12 +114,12 @@ import {
|
|
|
108
114
|
rotateAnthropicAccountOn429,
|
|
109
115
|
} from "../../oauth/anthropic-routing";
|
|
110
116
|
import {
|
|
111
|
-
antigravity429StickWaitMs,
|
|
112
117
|
antigravitySessionKeyFromParts,
|
|
113
|
-
bindAntigravityProject,
|
|
114
118
|
bindAntigravitySessionAffinity,
|
|
119
|
+
recordAntigravityCooldown,
|
|
120
|
+
recordAntigravitySyntheticFailure,
|
|
115
121
|
resolveAntigravityAccountForSession,
|
|
116
|
-
|
|
122
|
+
retryableAntigravity429DelayMs,
|
|
117
123
|
} from "../../oauth/antigravity-routing";
|
|
118
124
|
import {
|
|
119
125
|
CURSOR_POOL_MAX_FAILOVERS_PER_REQUEST,
|
|
@@ -170,6 +176,7 @@ import {
|
|
|
170
176
|
fetchWithResetRetry,
|
|
171
177
|
fetchWithTransientRetry,
|
|
172
178
|
prepareSameTarget429Wait,
|
|
179
|
+
sleepWithAbort,
|
|
173
180
|
} from "../../lib/upstream-retry";
|
|
174
181
|
import { ForwardAdmissionCredentialError, validateForwardAdmissionCredential } from "../auth-cors";
|
|
175
182
|
import type { DataPlaneAdmission } from "../auth-cors";
|
|
@@ -211,7 +218,7 @@ import {
|
|
|
211
218
|
rotateProviderTransportOn429,
|
|
212
219
|
} from "../../providers/key-failover";
|
|
213
220
|
import { shouldAttemptImageTierRetry } from "../image-retry";
|
|
214
|
-
import { resolveProviderTransport } from "../../providers/xai-transport";
|
|
221
|
+
import { isXaiResponsesDestination, resolveProviderTransport } from "../../providers/xai-transport";
|
|
215
222
|
import type { WsData } from "../ws-bridge";
|
|
216
223
|
import { codexAccountSelectionForTurn, registerTurn, trackStreamLifetime, unregisterTurn } from "../lifecycle";
|
|
217
224
|
import { redactSecretString, sanitizeLogMetadataString } from "../../lib/redact";
|
|
@@ -290,6 +297,7 @@ import { createResponsesModelPayloadRewrite, rewriteResponsesModelJson } from ".
|
|
|
290
297
|
import type { EffectiveSubagentRoster, SpawnAgentSurface } from "../../codex/catalog";
|
|
291
298
|
|
|
292
299
|
import { buildToolBridgeMaps, collabSurface, injectDeveloperMessage, multiAgentGuidanceText } from "./collaboration";
|
|
300
|
+
import { decideV2NativeParentOverride } from "./v2-native-parent-override";
|
|
293
301
|
import { mapCodexAuthContextErrorToResponse } from "./codex-auth-error";
|
|
294
302
|
import { hasUnreadableEncryptedAgentTask, looksLikeBackendCiphertext, sanitizeEncryptedContentInPlace } from "./encrypted-payload";
|
|
295
303
|
import { fetchWithHeaderTimeout, providerFetch, safeHostLabel, safeOriginLabel } from "./fetch-helpers";
|
|
@@ -328,12 +336,14 @@ import {
|
|
|
328
336
|
import {
|
|
329
337
|
collectDeclaredNamelessClientCallTypes,
|
|
330
338
|
collectDeclaredWireToolNames,
|
|
339
|
+
collectProviderExecutedCallTypes,
|
|
331
340
|
createUndeclaredToolCallGuardBlockRewrite,
|
|
332
341
|
currentTurnWireToolCatalogBody,
|
|
333
342
|
hasExplicitWireToolCatalog,
|
|
334
343
|
undeclaredToolCallMessage,
|
|
335
344
|
undeclaredToolCallName,
|
|
336
345
|
undeclaredToolCallNameInResponse,
|
|
346
|
+
type ProviderExecutedCallType,
|
|
337
347
|
} from "../responses-undeclared-tool-guard";
|
|
338
348
|
import { createGithubCopilotResponsesBlockRewrite } from "../github-copilot-responses-repair";
|
|
339
349
|
import { responsesJsonToSseStream } from "../responses-json-events";
|
|
@@ -349,6 +359,34 @@ import { preflightComboStreamResponse } from "./combo-stream-preflight";
|
|
|
349
359
|
// already-committed event boundary and can replay custom adapter work.
|
|
350
360
|
const runTurnAdapterSseResponses = new WeakSet<Response>();
|
|
351
361
|
|
|
362
|
+
function diagnoseAdapterEvents(
|
|
363
|
+
events: AsyncIterable<AdapterEvent>,
|
|
364
|
+
adapterName: string,
|
|
365
|
+
requestId: string | undefined,
|
|
366
|
+
logCtx: RequestLogContext,
|
|
367
|
+
state: BridgeDiagnosticSequence,
|
|
368
|
+
): AsyncIterable<AdapterEvent> {
|
|
369
|
+
if (!requestId) return events;
|
|
370
|
+
return (async function* () {
|
|
371
|
+
for await (const event of events) {
|
|
372
|
+
const attempt = logCtx.activeAttempt;
|
|
373
|
+
debugStreamDiagnostic(
|
|
374
|
+
{
|
|
375
|
+
requestId,
|
|
376
|
+
adapterName,
|
|
377
|
+
...(attempt?.ordinal !== undefined ? { attempt: attempt.ordinal } : {}),
|
|
378
|
+
...(attempt?.recoveryKinds.at(-1) !== undefined ? { recovery: attempt.recoveryKinds.at(-1) } : {}),
|
|
379
|
+
},
|
|
380
|
+
"adapter",
|
|
381
|
+
++state.value,
|
|
382
|
+
event.type,
|
|
383
|
+
adapterEventDiagnosticDetails(event),
|
|
384
|
+
);
|
|
385
|
+
yield event;
|
|
386
|
+
}
|
|
387
|
+
})();
|
|
388
|
+
}
|
|
389
|
+
|
|
352
390
|
/**
|
|
353
391
|
* Adapters whose continuation state must survive Codex's store:false requests.
|
|
354
392
|
*/
|
|
@@ -2256,6 +2294,7 @@ async function handleResponsesInner(
|
|
|
2256
2294
|
let toolBridgeMaps: ReturnType<typeof buildToolBridgeMaps>;
|
|
2257
2295
|
try {
|
|
2258
2296
|
parsed = parseRequest(body);
|
|
2297
|
+
parsed._promptCacheKeyIsSharedCohort = options.promptCacheKeyIsSharedCohort === true;
|
|
2259
2298
|
toolBridgeMaps = buildToolBridgeMaps(parsed, translatorBudget);
|
|
2260
2299
|
if (previousResponseInputExpanded) parsed._previousResponseInputExpanded = true;
|
|
2261
2300
|
const providerContinuationCandidate = options.comboReplaySnapshot
|
|
@@ -2381,6 +2420,27 @@ async function handleResponsesInner(
|
|
|
2381
2420
|
return formatErrorResponse(404, "invalid_request_error", err instanceof Error ? err.message : String(err));
|
|
2382
2421
|
}
|
|
2383
2422
|
|
|
2423
|
+
const parentOverride = decideV2NativeParentOverride({
|
|
2424
|
+
kind: "responses",
|
|
2425
|
+
config,
|
|
2426
|
+
headers: req.headers,
|
|
2427
|
+
parsed,
|
|
2428
|
+
sourceRoute: route,
|
|
2429
|
+
comboAttempt: options.comboAttempt,
|
|
2430
|
+
targetEvidence: evidenceFromBody(parsed._rawBody),
|
|
2431
|
+
});
|
|
2432
|
+
if (parentOverride.kind === "reject") {
|
|
2433
|
+
if (parentOverride.trace) logCtx.routeDecision = parentOverride.trace as typeof logCtx.routeDecision;
|
|
2434
|
+
return formatErrorResponse(404, "invalid_request_error", parentOverride.message);
|
|
2435
|
+
}
|
|
2436
|
+
if (parentOverride.kind === "override") {
|
|
2437
|
+
route = parentOverride.route;
|
|
2438
|
+
parsed.modelId = route.modelId;
|
|
2439
|
+
if (parsed._rawBody && typeof parsed._rawBody === "object") {
|
|
2440
|
+
(parsed._rawBody as { model?: string }).model = route.modelId;
|
|
2441
|
+
}
|
|
2442
|
+
}
|
|
2443
|
+
|
|
2384
2444
|
const hasUnexpandedPreviousResponse = !!parsed.previousResponseId
|
|
2385
2445
|
&& parsed._previousResponseInputExpanded !== true;
|
|
2386
2446
|
// Exact account selectors are isolated from Pool-wide quota work. A canonical replay miss must
|
|
@@ -2504,6 +2564,7 @@ async function handleResponsesInner(
|
|
|
2504
2564
|
"_providerContinuationOwner",
|
|
2505
2565
|
"_cursorConversationId",
|
|
2506
2566
|
"_clientThreadId",
|
|
2567
|
+
"_promptCacheKeyIsSharedCohort",
|
|
2507
2568
|
"_reasoningReplayScope",
|
|
2508
2569
|
"_cursorIsolateConversation",
|
|
2509
2570
|
];
|
|
@@ -2668,14 +2729,28 @@ async function handleResponsesInner(
|
|
|
2668
2729
|
|
|
2669
2730
|
// OAuth providers: swap in a fresh access token (auto-refreshed) as the Bearer key, so the
|
|
2670
2731
|
// existing openai-chat / anthropic adapters authenticate with no change.
|
|
2671
|
-
const
|
|
2672
|
-
|
|
2732
|
+
const isAntigravityOAuth = isAntigravityOAuthProvider(route.providerName, route.provider);
|
|
2733
|
+
if (route.providerName === "google-antigravity") {
|
|
2734
|
+
const antigravityConfigError = antigravityOAuthDestinationConfigError(route.providerName, route.provider);
|
|
2735
|
+
if (antigravityConfigError) {
|
|
2736
|
+
return formatErrorResponse(400, "invalid_request_error", antigravityConfigError);
|
|
2737
|
+
}
|
|
2738
|
+
}
|
|
2739
|
+
const isOAuth401ReplayProvider = isAntigravityOAuth
|
|
2740
|
+
|| ((route.providerName === "xai" || route.providerName === "github-copilot" || route.providerName === "kiro")
|
|
2741
|
+
&& route.provider.authMode === "oauth");
|
|
2673
2742
|
let sentOAuthSnapshot: OAuthAccessSnapshot | undefined;
|
|
2674
2743
|
let replayOAuthCredentialSnapshot: Pick<OAuthAccessSnapshot, "accountId" | "generation"> | undefined;
|
|
2675
2744
|
let anthropicPoolAccountId: string | null = null;
|
|
2676
2745
|
let anthropicPoolFailovers = 0;
|
|
2677
|
-
let antigravityAccountId: string |
|
|
2678
|
-
let
|
|
2746
|
+
let antigravityAccountId: string | null = null;
|
|
2747
|
+
let antigravitySessionKey: string | null = null;
|
|
2748
|
+
let antigravity429RetryAttempted = false;
|
|
2749
|
+
const observeAntigravityProviderError = isAntigravityOAuth
|
|
2750
|
+
? (error: { code?: string; status?: number; message?: string }) => {
|
|
2751
|
+
if (antigravityAccountId) recordAntigravitySyntheticFailure(antigravityAccountId, error);
|
|
2752
|
+
}
|
|
2753
|
+
: undefined;
|
|
2679
2754
|
let cursorPoolAccountId: string | null = null;
|
|
2680
2755
|
let cursorPoolFailovers = 0;
|
|
2681
2756
|
const oauthSessionKeyParts = {
|
|
@@ -2688,18 +2763,16 @@ async function handleResponsesInner(
|
|
|
2688
2763
|
const anthropicSessionKey = route.providerName === "anthropic" && route.provider.authMode === "oauth"
|
|
2689
2764
|
? anthropicSessionKeyFromParts(oauthSessionKeyParts)
|
|
2690
2765
|
: null;
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
? antigravitySessionKeyFromParts(oauthSessionKeyParts)
|
|
2695
|
-
: null;
|
|
2766
|
+
if (isAntigravityOAuth) {
|
|
2767
|
+
antigravitySessionKey = antigravitySessionKeyFromParts(oauthSessionKeyParts);
|
|
2768
|
+
}
|
|
2696
2769
|
const cursorSessionKey = route.providerName === "cursor"
|
|
2697
2770
|
&& route.provider.authMode === "oauth"
|
|
2698
2771
|
? cursorSessionKeyFromParts({
|
|
2699
2772
|
clientThreadId: typeof parsed._clientThreadId === "string" ? parsed._clientThreadId : null,
|
|
2700
2773
|
})
|
|
2701
2774
|
: null;
|
|
2702
|
-
if (route.provider.authMode === "oauth") {
|
|
2775
|
+
if (route.provider.authMode === "oauth" || isAntigravityOAuth) {
|
|
2703
2776
|
try {
|
|
2704
2777
|
if (route.providerName === "anthropic" && isAnthropicAccountPoolEnabled(config)) {
|
|
2705
2778
|
const selection = resolveAnthropicAccountForSession(anthropicSessionKey, config);
|
|
@@ -2721,50 +2794,6 @@ async function handleResponsesInner(
|
|
|
2721
2794
|
promoteAnthropicActiveAccount(selection.accountId);
|
|
2722
2795
|
route.provider = { ...route.provider, apiKey: accessToken };
|
|
2723
2796
|
logCtx.provider = formatAnthropicProviderForLog("anthropic", selection.accountId, config);
|
|
2724
|
-
} else if (
|
|
2725
|
-
route.providerName === "google-antigravity"
|
|
2726
|
-
&& route.provider.googleMode === "cloud-code-assist"
|
|
2727
|
-
) {
|
|
2728
|
-
const selection = resolveAntigravityAccountForSession(antigravitySessionKey);
|
|
2729
|
-
if (!selection.accountId) {
|
|
2730
|
-
if (selection.reason === "all-cooled") {
|
|
2731
|
-
return formatErrorResponse(
|
|
2732
|
-
429,
|
|
2733
|
-
"rate_limit_error",
|
|
2734
|
-
"All Google Antigravity OAuth accounts are temporarily unavailable",
|
|
2735
|
-
);
|
|
2736
|
-
}
|
|
2737
|
-
return formatErrorResponse(
|
|
2738
|
-
401,
|
|
2739
|
-
"authentication_error",
|
|
2740
|
-
"No eligible Google Antigravity OAuth account available",
|
|
2741
|
-
);
|
|
2742
|
-
}
|
|
2743
|
-
let resolved = await getValidAccessTokenSnapshot(route.providerName);
|
|
2744
|
-
if (selection.accountId !== resolved.accountId) {
|
|
2745
|
-
const accessToken = await getValidAccessTokenForAccount("google-antigravity", selection.accountId);
|
|
2746
|
-
const nextCredential = getAccountCredential("google-antigravity", selection.accountId);
|
|
2747
|
-
resolved = {
|
|
2748
|
-
...resolved,
|
|
2749
|
-
accountId: selection.accountId,
|
|
2750
|
-
accessToken,
|
|
2751
|
-
// Always replace; omitting a missing id would keep the previous account's projectId.
|
|
2752
|
-
projectId: nextCredential?.projectId,
|
|
2753
|
-
};
|
|
2754
|
-
}
|
|
2755
|
-
replayOAuthCredentialSnapshot = {
|
|
2756
|
-
accountId: resolved.accountId,
|
|
2757
|
-
generation: resolved.generation,
|
|
2758
|
-
};
|
|
2759
|
-
if (selection.reason === "failover") replayOAuthCredentialSnapshot = undefined;
|
|
2760
|
-
route.provider = { ...route.provider, apiKey: resolved.accessToken };
|
|
2761
|
-
antigravityAccountId = selection.accountId;
|
|
2762
|
-
bindAntigravitySessionAffinity(antigravitySessionKey, selection.accountId);
|
|
2763
|
-
const bound = bindAntigravityProject(route.provider, resolved.projectId);
|
|
2764
|
-
if (!bound.ok) {
|
|
2765
|
-
return formatErrorResponse(bound.status, bound.type, bound.message);
|
|
2766
|
-
}
|
|
2767
|
-
route.provider = bound.provider;
|
|
2768
2797
|
} else if (
|
|
2769
2798
|
route.providerName === "cursor"
|
|
2770
2799
|
&& route.provider.authMode === "oauth"
|
|
@@ -2796,7 +2825,28 @@ async function handleResponsesInner(
|
|
|
2796
2825
|
route.provider = { ...route.provider, apiKey: resolved.accessToken };
|
|
2797
2826
|
logCtx.provider = formatCursorProviderForLog("cursor", selection.accountId);
|
|
2798
2827
|
} else {
|
|
2799
|
-
|
|
2828
|
+
let resolved: OAuthAccessSnapshot;
|
|
2829
|
+
if (isAntigravityOAuth) {
|
|
2830
|
+
const selection = resolveAntigravityAccountForSession(antigravitySessionKey);
|
|
2831
|
+
if (!selection.accountId) {
|
|
2832
|
+
return formatErrorResponse(401, "authentication_error", "Selected Antigravity OAuth account is unavailable");
|
|
2833
|
+
}
|
|
2834
|
+
if (selection.cooldownUntil !== undefined) {
|
|
2835
|
+
const retryAfter = Math.max(1, Math.ceil((selection.cooldownUntil - Date.now()) / 1000));
|
|
2836
|
+
if (selection.cooldownKind === "geoblock") {
|
|
2837
|
+
return formatErrorResponse(403, "permission_error", "Selected Antigravity OAuth account is in local cooldown after upstream location block");
|
|
2838
|
+
}
|
|
2839
|
+
return formatErrorResponse(429, "rate_limit_error", "Selected Antigravity OAuth account is in local cooldown after upstream rate limit", { retryAfter: String(retryAfter) });
|
|
2840
|
+
}
|
|
2841
|
+
if (selection.reason === "active-needs-reauth") {
|
|
2842
|
+
return formatErrorResponse(401, "authentication_error", "Selected Antigravity OAuth account needs reauthentication");
|
|
2843
|
+
}
|
|
2844
|
+
antigravityAccountId = selection.accountId;
|
|
2845
|
+
resolved = await getValidAccessTokenSnapshotForAccount(route.providerName, selection.accountId);
|
|
2846
|
+
bindAntigravitySessionAffinity(antigravitySessionKey, selection.accountId);
|
|
2847
|
+
} else {
|
|
2848
|
+
resolved = await getValidAccessTokenSnapshot(route.providerName);
|
|
2849
|
+
}
|
|
2800
2850
|
replayOAuthCredentialSnapshot = {
|
|
2801
2851
|
accountId: resolved.accountId,
|
|
2802
2852
|
generation: resolved.generation,
|
|
@@ -2808,6 +2858,14 @@ async function handleResponsesInner(
|
|
|
2808
2858
|
// Only genuinely accountless adapter calls leave the context undefined and use local/env fallback.
|
|
2809
2859
|
parsed._kiroAuthContext = { ...(resolved.kiro ?? {}) };
|
|
2810
2860
|
}
|
|
2861
|
+
// Antigravity (cloud-code-assist) must use the project paired with this exact token
|
|
2862
|
+
// snapshot. A configured project may belong to another account and is never a fallback.
|
|
2863
|
+
if (isAntigravityOAuth) {
|
|
2864
|
+
if (!resolved.projectId) {
|
|
2865
|
+
return formatErrorResponse(400, "invalid_request_error", "Antigravity project unavailable — re-run `ocx login google-antigravity`");
|
|
2866
|
+
}
|
|
2867
|
+
route.provider = { ...route.provider, project: resolved.projectId };
|
|
2868
|
+
}
|
|
2811
2869
|
}
|
|
2812
2870
|
} catch (err) {
|
|
2813
2871
|
if (err instanceof UnsupportedOAuthProviderError) {
|
|
@@ -2847,6 +2905,27 @@ async function handleResponsesInner(
|
|
|
2847
2905
|
delete logCtx.accountLogLabel;
|
|
2848
2906
|
}
|
|
2849
2907
|
const adapter = resolveAdapter(adapterProvider, config.cacheRetention);
|
|
2908
|
+
const googleOptionsError = googleProviderOptionsRouteError(parsed, {
|
|
2909
|
+
providerName: route.providerName,
|
|
2910
|
+
provider: adapterProvider,
|
|
2911
|
+
adapterName: adapter.name,
|
|
2912
|
+
});
|
|
2913
|
+
if (googleOptionsError) {
|
|
2914
|
+
return formatErrorResponse(400, "invalid_request_error", googleOptionsError);
|
|
2915
|
+
}
|
|
2916
|
+
const assertGoogleOptionsRoute = (
|
|
2917
|
+
candidate: Pick<ProviderAdapter, "name" | "validateRequest">,
|
|
2918
|
+
provider: OcxProviderConfig,
|
|
2919
|
+
requestParsed: OcxParsedRequest = parsed,
|
|
2920
|
+
): void => {
|
|
2921
|
+
const message = googleProviderOptionsRouteError(requestParsed, {
|
|
2922
|
+
providerName: route.providerName,
|
|
2923
|
+
provider,
|
|
2924
|
+
adapterName: candidate.name,
|
|
2925
|
+
});
|
|
2926
|
+
if (message) throw new OcxRequestValidationError(message);
|
|
2927
|
+
if (requestParsed.options.providerOptions?.google) candidate.validateRequest?.(requestParsed);
|
|
2928
|
+
};
|
|
2850
2929
|
bindRouteReasoningReplayScope({
|
|
2851
2930
|
parsed,
|
|
2852
2931
|
providerName: route.providerName,
|
|
@@ -2861,6 +2940,7 @@ async function handleResponsesInner(
|
|
|
2861
2940
|
}
|
|
2862
2941
|
logCtx.providerAdapter = adapter.name;
|
|
2863
2942
|
try {
|
|
2943
|
+
assertGoogleOptionsRoute(adapter, adapterProvider);
|
|
2864
2944
|
adapter.validateRequest?.(parsed);
|
|
2865
2945
|
} catch (err) {
|
|
2866
2946
|
return formatErrorResponse(
|
|
@@ -2901,6 +2981,23 @@ async function handleResponsesInner(
|
|
|
2901
2981
|
);
|
|
2902
2982
|
if (passiveSubjectId) logCtx.activeAttempt.labRouteSubjectId = passiveSubjectId;
|
|
2903
2983
|
}
|
|
2984
|
+
const diagnosticRequestId = isDebugEnabled() ? randomUUID() : undefined;
|
|
2985
|
+
const adapterDiagnosticState: BridgeDiagnosticSequence = { value: 0 };
|
|
2986
|
+
const diagnosticContext: BridgeDiagnosticContext | undefined = diagnosticRequestId
|
|
2987
|
+
? { requestId: diagnosticRequestId, adapterName: adapter.name, sequence: adapterDiagnosticState }
|
|
2988
|
+
: undefined;
|
|
2989
|
+
const noteDiagnosticAttempt = (
|
|
2990
|
+
attempt: RequestLogContext["activeAttempt"],
|
|
2991
|
+
inputEstimate: number | undefined,
|
|
2992
|
+
recovery?: AttemptRecoveryKind,
|
|
2993
|
+
adapterName?: string,
|
|
2994
|
+
): void => {
|
|
2995
|
+
noteAttemptSend(attempt, inputEstimate, recovery);
|
|
2996
|
+
if (!diagnosticContext) return;
|
|
2997
|
+
diagnosticContext.attempt = attempt?.ordinal;
|
|
2998
|
+
diagnosticContext.recovery = recovery;
|
|
2999
|
+
if (adapterName) diagnosticContext.adapterName = adapterName;
|
|
3000
|
+
};
|
|
2904
3001
|
const isPassthrough = "passthrough" in adapter && !!adapter.passthrough;
|
|
2905
3002
|
|
|
2906
3003
|
if (adapter.name === "kiro" && parsed.previousResponseId && !parsed._previousResponseInputExpanded) {
|
|
@@ -3070,8 +3167,14 @@ async function handleResponsesInner(
|
|
|
3070
3167
|
const clientDeclaredNamelessCallTypes = collectDeclaredNamelessClientCallTypes(
|
|
3071
3168
|
clientToolAuthorizationBody,
|
|
3072
3169
|
);
|
|
3170
|
+
// Hosted calls the PROVIDER runs itself. Gated on the destination actually being xAI, so a
|
|
3171
|
+
// declaration alone cannot buy the exemption on some other upstream that never serves it.
|
|
3172
|
+
const providerExecutedCallTypes = isXaiResponsesDestination(route.provider)
|
|
3173
|
+
? collectProviderExecutedCallTypes(clientToolAuthorizationBody)
|
|
3174
|
+
: new Set<ProviderExecutedCallType>();
|
|
3073
3175
|
let request: Awaited<ReturnType<typeof adapter.buildRequest>>;
|
|
3074
3176
|
try {
|
|
3177
|
+
assertGoogleOptionsRoute(adapter, adapterProvider);
|
|
3075
3178
|
request = await adapter.buildRequest(parsed, { headers: selectedForwardHeaders, translatorBudget });
|
|
3076
3179
|
} catch (error) {
|
|
3077
3180
|
releaseCodexAuthContextProbeLease(authCtx);
|
|
@@ -3181,6 +3284,9 @@ async function handleResponsesInner(
|
|
|
3181
3284
|
// rejection is sticky for the whole turn, set from every parsed payload on the inspection side.
|
|
3182
3285
|
let inspectionSawUndeclaredTool = false;
|
|
3183
3286
|
const noteInspectedPayload = (payload: unknown) => {
|
|
3287
|
+
if (isAntigravityOAuth && antigravityAccountId) {
|
|
3288
|
+
recordAntigravitySyntheticFailure(antigravityAccountId, payload);
|
|
3289
|
+
}
|
|
3184
3290
|
// Gated on the same flag as the guard itself: with no readable catalog (or a forward-auth
|
|
3185
3291
|
// provider) every name looks undeclared, and flipping this would stop recording continuation
|
|
3186
3292
|
// state for exactly the passthrough traffic the guard deliberately stands down for.
|
|
@@ -3189,6 +3295,7 @@ async function handleResponsesInner(
|
|
|
3189
3295
|
payload,
|
|
3190
3296
|
declaredWireToolNames,
|
|
3191
3297
|
declaredNamelessClientCallTypes,
|
|
3298
|
+
providerExecutedCallTypes,
|
|
3192
3299
|
) !== undefined) {
|
|
3193
3300
|
inspectionSawUndeclaredTool = true;
|
|
3194
3301
|
}
|
|
@@ -3202,6 +3309,7 @@ async function handleResponsesInner(
|
|
|
3202
3309
|
response,
|
|
3203
3310
|
declaredWireToolNames,
|
|
3204
3311
|
declaredNamelessClientCallTypes,
|
|
3312
|
+
providerExecutedCallTypes,
|
|
3205
3313
|
) !== undefined
|
|
3206
3314
|
) {
|
|
3207
3315
|
return;
|
|
@@ -3310,7 +3418,7 @@ async function handleResponsesInner(
|
|
|
3310
3418
|
// Body is a replayable string; nothing has streamed to the client yet.
|
|
3311
3419
|
upstreamResponse = await fetchWithTransientRetry(
|
|
3312
3420
|
recovery => {
|
|
3313
|
-
|
|
3421
|
+
noteDiagnosticAttempt(logCtx.activeAttempt, passthroughEstimate, recovery, route.provider.adapter);
|
|
3314
3422
|
return fetchWithHeaderTimeout(request.url, applyUpstreamRecoveryInit({
|
|
3315
3423
|
method: request.method,
|
|
3316
3424
|
headers: request.headers,
|
|
@@ -3351,10 +3459,17 @@ async function handleResponsesInner(
|
|
|
3351
3459
|
upstream.abort();
|
|
3352
3460
|
return { failed: formatErrorResponse(502, "upstream_error", "Recovery changed the provider wire unexpectedly") };
|
|
3353
3461
|
}
|
|
3462
|
+
try {
|
|
3463
|
+
assertGoogleOptionsRoute(retryAdapter, route.provider);
|
|
3464
|
+
} catch (err) {
|
|
3465
|
+
upstream.abort();
|
|
3466
|
+
return { failed: formatErrorResponse(400, "invalid_request_error", redactSecretString(err instanceof Error ? err.message : String(err))) };
|
|
3467
|
+
}
|
|
3354
3468
|
try {
|
|
3355
3469
|
request = await retryAdapter.buildRequest(parsed, {
|
|
3356
3470
|
headers: selectedForwardHeaders,
|
|
3357
3471
|
translatorBudget,
|
|
3472
|
+
...(observeAntigravityProviderError ? { onProviderError: observeAntigravityProviderError } : {}),
|
|
3358
3473
|
});
|
|
3359
3474
|
refreshRoutedNamespaceToolAliases(request);
|
|
3360
3475
|
recordAdapterReasoning(logCtx, request);
|
|
@@ -3380,7 +3495,7 @@ async function handleResponsesInner(
|
|
|
3380
3495
|
try {
|
|
3381
3496
|
return await fetchWithTransientRetry(
|
|
3382
3497
|
innerRecovery => {
|
|
3383
|
-
|
|
3498
|
+
noteDiagnosticAttempt(logCtx.activeAttempt, passthroughEstimate, innerRecovery ?? recovery, retryAdapter.name);
|
|
3384
3499
|
return fetchWithHeaderTimeout(request.url, applyUpstreamRecoveryInit({
|
|
3385
3500
|
method: request.method,
|
|
3386
3501
|
headers: request.headers,
|
|
@@ -3428,6 +3543,14 @@ async function handleResponsesInner(
|
|
|
3428
3543
|
releaseCodexAuthContextProbeLease(authCtx);
|
|
3429
3544
|
return formatErrorResponse(401, "authentication_error", publicOAuthAuthenticationErrorMessage(err));
|
|
3430
3545
|
}
|
|
3546
|
+
if (isAntigravityOAuth && refreshed.accountId !== antigravityAccountId) {
|
|
3547
|
+
upstream.abort();
|
|
3548
|
+
return formatErrorResponse(401, "authentication_error", "Antigravity OAuth account changed during refresh");
|
|
3549
|
+
}
|
|
3550
|
+
if (isAntigravityOAuth && !refreshed.projectId) {
|
|
3551
|
+
upstream.abort();
|
|
3552
|
+
return formatErrorResponse(400, "invalid_request_error", "Antigravity project unavailable — re-run `ocx login google-antigravity`");
|
|
3553
|
+
}
|
|
3431
3554
|
sentOAuthSnapshot = refreshed;
|
|
3432
3555
|
replayOAuthCredentialSnapshot = {
|
|
3433
3556
|
accountId: refreshed.accountId,
|
|
@@ -3436,6 +3559,9 @@ async function handleResponsesInner(
|
|
|
3436
3559
|
if (route.providerName === "kiro") {
|
|
3437
3560
|
parsed._kiroAuthContext = { ...(refreshed.kiro ?? {}) };
|
|
3438
3561
|
}
|
|
3562
|
+
if (isAntigravityOAuth) {
|
|
3563
|
+
route.provider = { ...route.provider, project: refreshed.projectId };
|
|
3564
|
+
}
|
|
3439
3565
|
const refreshedProvider = resolveProviderTransport(
|
|
3440
3566
|
route.providerName,
|
|
3441
3567
|
{ ...route.provider, apiKey: refreshed.accessToken },
|
|
@@ -3466,9 +3592,11 @@ async function handleResponsesInner(
|
|
|
3466
3592
|
logCtx.accountLogLabel,
|
|
3467
3593
|
);
|
|
3468
3594
|
try {
|
|
3595
|
+
assertGoogleOptionsRoute(refreshedAdapter, refreshedProvider);
|
|
3469
3596
|
request = await refreshedAdapter.buildRequest(parsed, {
|
|
3470
3597
|
headers: selectedForwardHeaders,
|
|
3471
3598
|
translatorBudget,
|
|
3599
|
+
...(observeAntigravityProviderError ? { onProviderError: observeAntigravityProviderError } : {}),
|
|
3472
3600
|
});
|
|
3473
3601
|
refreshRoutedNamespaceToolAliases(request);
|
|
3474
3602
|
recordAdapterReasoning(logCtx, request);
|
|
@@ -3483,7 +3611,7 @@ async function handleResponsesInner(
|
|
|
3483
3611
|
try {
|
|
3484
3612
|
upstreamResponse = await fetchWithTransientRetry(
|
|
3485
3613
|
recovery => {
|
|
3486
|
-
|
|
3614
|
+
noteDiagnosticAttempt(logCtx.activeAttempt, passthroughEstimate, recovery ?? "oauth-401", refreshedAdapter.name);
|
|
3487
3615
|
return fetchWithHeaderTimeout(request.url, applyUpstreamRecoveryInit({
|
|
3488
3616
|
method: request.method,
|
|
3489
3617
|
headers: request.headers,
|
|
@@ -3545,7 +3673,7 @@ async function handleResponsesInner(
|
|
|
3545
3673
|
recovery => {
|
|
3546
3674
|
// The first send of every replay is itself a rate-limit retry; inner transient-5xx
|
|
3547
3675
|
// recoveries keep their own label (recovery is provided for those).
|
|
3548
|
-
|
|
3676
|
+
noteDiagnosticAttempt(logCtx.activeAttempt, passthroughEstimate, recovery ?? "rate-limit-429", route.provider.adapter);
|
|
3549
3677
|
return fetchWithHeaderTimeout(request.url, applyUpstreamRecoveryInit({
|
|
3550
3678
|
method: request.method,
|
|
3551
3679
|
headers: request.headers,
|
|
@@ -3853,6 +3981,7 @@ async function handleResponsesInner(
|
|
|
3853
3981
|
? createUndeclaredToolCallGuardBlockRewrite(
|
|
3854
3982
|
declaredWireToolNames,
|
|
3855
3983
|
declaredNamelessClientCallTypes,
|
|
3984
|
+
providerExecutedCallTypes,
|
|
3856
3985
|
)
|
|
3857
3986
|
: undefined,
|
|
3858
3987
|
].filter((rewrite): rewrite is NonNullable<typeof rewrite> => rewrite !== undefined);
|
|
@@ -4074,6 +4203,7 @@ async function handleResponsesInner(
|
|
|
4074
4203
|
JSON.parse(clientJson),
|
|
4075
4204
|
declaredWireToolNames,
|
|
4076
4205
|
declaredNamelessClientCallTypes,
|
|
4206
|
+
providerExecutedCallTypes,
|
|
4077
4207
|
);
|
|
4078
4208
|
} catch {
|
|
4079
4209
|
return undefined;
|
|
@@ -4271,7 +4401,8 @@ async function handleResponsesInner(
|
|
|
4271
4401
|
...(vidPlan ? { videoPlan: vidPlan } : {}),
|
|
4272
4402
|
forwardHeaders: selectedForwardHeaders,
|
|
4273
4403
|
onAttemptSend: (recovery?: AttemptRecoveryKind) =>
|
|
4274
|
-
|
|
4404
|
+
noteDiagnosticAttempt(logCtx.activeAttempt, logCtx.usageLogInputTokens, recovery, adapter.name),
|
|
4405
|
+
...(diagnosticContext ? { diagnostic: diagnosticContext } : {}),
|
|
4275
4406
|
abortSignal: options.abortSignal,
|
|
4276
4407
|
maxRounds: imgPlan && vidPlan
|
|
4277
4408
|
? clampImageMaxRounds(Math.min(config.images?.maxRounds ?? 3, config.images?.videoMaxRounds ?? 2))
|
|
@@ -4286,6 +4417,7 @@ async function handleResponsesInner(
|
|
|
4286
4417
|
recordAdapterReasoning(logCtx, request);
|
|
4287
4418
|
recordAdapterTier(logCtx, request);
|
|
4288
4419
|
},
|
|
4420
|
+
validateAdapter: (requestParsed, candidate) => assertGoogleOptionsRoute(candidate, route.provider, requestParsed),
|
|
4289
4421
|
...(vidPlan?.timeoutMs ? { videoTimeoutMs: vidPlan.timeoutMs } : {}),
|
|
4290
4422
|
onUsage: usage => {
|
|
4291
4423
|
// Cursor may assign _cursorConversationId inside the image loop's first runTurn;
|
|
@@ -4375,8 +4507,10 @@ async function handleResponsesInner(
|
|
|
4375
4507
|
recordAdapterReasoning(logCtx, request);
|
|
4376
4508
|
recordAdapterTier(logCtx, request);
|
|
4377
4509
|
},
|
|
4510
|
+
validateAdapter: (requestParsed, candidate) => assertGoogleOptionsRoute(candidate, route.provider, requestParsed),
|
|
4378
4511
|
onAttemptSend: (recovery?: AttemptRecoveryKind) =>
|
|
4379
|
-
|
|
4512
|
+
noteDiagnosticAttempt(logCtx.activeAttempt, logCtx.usageLogInputTokens, recovery, adapter.name),
|
|
4513
|
+
...(diagnosticContext ? { diagnostic: diagnosticContext } : {}),
|
|
4380
4514
|
onUsage: usage => {
|
|
4381
4515
|
logCtx.usageFromBridge = true;
|
|
4382
4516
|
if (usage) {
|
|
@@ -4465,10 +4599,14 @@ async function handleResponsesInner(
|
|
|
4465
4599
|
pacingSlotAcquired = false,
|
|
4466
4600
|
): Promise<void> => {
|
|
4467
4601
|
try {
|
|
4602
|
+
if (diagnosticContext) {
|
|
4603
|
+
diagnosticContext.recovery = recovery;
|
|
4604
|
+
diagnosticContext.attempt = logCtx.activeAttempt?.ordinal;
|
|
4605
|
+
}
|
|
4468
4606
|
if (!pacingSlotAcquired) {
|
|
4469
4607
|
await waitForProviderRequestSlot(route.providerName, route.provider, route.modelId, runTurnAbort.signal);
|
|
4470
4608
|
}
|
|
4471
|
-
|
|
4609
|
+
noteDiagnosticAttempt(logCtx.activeAttempt, logCtx.usageLogInputTokens, recovery, adapter.name);
|
|
4472
4610
|
const runTurnProviderFetch = providerFetch(
|
|
4473
4611
|
route.provider,
|
|
4474
4612
|
options.codexWsRuntimeIdentity,
|
|
@@ -4522,13 +4660,15 @@ async function handleResponsesInner(
|
|
|
4522
4660
|
onBacklogExceeded: () => runTurnAbort.abort(),
|
|
4523
4661
|
});
|
|
4524
4662
|
void runTurnAttempt(retryQueue, "empty-completion");
|
|
4525
|
-
return retryQueue.stream();
|
|
4663
|
+
return diagnoseAdapterEvents(retryQueue.stream(), adapter.name, diagnosticRequestId, logCtx, adapterDiagnosticState);
|
|
4526
4664
|
};
|
|
4527
4665
|
|
|
4528
4666
|
const { toolNsMap, declaredToolNames, toolParameterSchemas, freeformToolNames, toolSearchToolNames } = toolBridgeMaps;
|
|
4529
4667
|
if (parsed.stream) {
|
|
4530
4668
|
void runTurn();
|
|
4531
|
-
let eventSource: AsyncIterable<AdapterEvent> =
|
|
4669
|
+
let eventSource: AsyncIterable<AdapterEvent> = diagnoseAdapterEvents(
|
|
4670
|
+
queue.stream(), adapter.name, diagnosticRequestId, logCtx, adapterDiagnosticState,
|
|
4671
|
+
);
|
|
4532
4672
|
if (options.comboAttempt) {
|
|
4533
4673
|
const preflight = await preflightAdapterEvents(eventSource);
|
|
4534
4674
|
if (preflight.error || preflight.empty) {
|
|
@@ -4566,6 +4706,7 @@ async function handleResponsesInner(
|
|
|
4566
4706
|
// grok-build's strict decoder dies on the typed response.heartbeat frame; its
|
|
4567
4707
|
// eventsource layer tolerates comment keep-alives. Codex needs the opposite.
|
|
4568
4708
|
...(logCtx.surface === "grok" ? { heartbeatStyle: "comment" as const } : {}),
|
|
4709
|
+
...(diagnosticContext ? { diagnostic: diagnosticContext } : {}),
|
|
4569
4710
|
onUsage: usage => {
|
|
4570
4711
|
// Raw adapter usage, pre wire-normalization: the bridged SSE now always carries
|
|
4571
4712
|
// zero-default detail objects, so provenance must come from here (cache_detail_missing).
|
|
@@ -4674,7 +4815,12 @@ async function handleResponsesInner(
|
|
|
4674
4815
|
let initialRequest: AdapterRequest | undefined;
|
|
4675
4816
|
let inputTokenEstimate: number | undefined;
|
|
4676
4817
|
try {
|
|
4677
|
-
|
|
4818
|
+
assertGoogleOptionsRoute(activeAdapter, route.provider);
|
|
4819
|
+
initialRequest = await activeAdapter.buildRequest(parsed, {
|
|
4820
|
+
headers: selectedForwardHeaders,
|
|
4821
|
+
translatorBudget,
|
|
4822
|
+
...(observeAntigravityProviderError ? { onProviderError: observeAntigravityProviderError } : {}),
|
|
4823
|
+
});
|
|
4678
4824
|
refreshRoutedNamespaceToolAliases(initialRequest);
|
|
4679
4825
|
recordAdapterReasoning(logCtx, initialRequest);
|
|
4680
4826
|
recordAdapterTier(logCtx, initialRequest);
|
|
@@ -4711,7 +4857,7 @@ async function handleResponsesInner(
|
|
|
4711
4857
|
let upstreamResponse: Response;
|
|
4712
4858
|
try {
|
|
4713
4859
|
if (activeAdapter.fetchResponse) {
|
|
4714
|
-
|
|
4860
|
+
noteDiagnosticAttempt(logCtx.activeAttempt, inputTokenEstimate, undefined, activeAdapter.name);
|
|
4715
4861
|
await waitForProviderRequestSlot(route.providerName, route.provider, route.modelId, upstream.signal);
|
|
4716
4862
|
upstreamResponse = await activeAdapter.fetchResponse(builtInitialRequest, {
|
|
4717
4863
|
abortSignal: upstream.signal,
|
|
@@ -4720,6 +4866,7 @@ async function handleResponsesInner(
|
|
|
4720
4866
|
executor: providerFetch(route.provider, options.codexWsRuntimeIdentity, {
|
|
4721
4867
|
providerName: route.providerName,
|
|
4722
4868
|
modelId: route.modelId,
|
|
4869
|
+
pacingSlotAcquired: true,
|
|
4723
4870
|
}),
|
|
4724
4871
|
...(antigravityAccountId ? { accountId: antigravityAccountId } : {}),
|
|
4725
4872
|
});
|
|
@@ -4731,7 +4878,7 @@ async function handleResponsesInner(
|
|
|
4731
4878
|
const fetchWithRetryPolicy = route.provider.adapter === "google" ? fetchWithTransientRetry : fetchWithResetRetry;
|
|
4732
4879
|
upstreamResponse = await fetchWithRetryPolicy(
|
|
4733
4880
|
recovery => {
|
|
4734
|
-
|
|
4881
|
+
noteDiagnosticAttempt(logCtx.activeAttempt, inputTokenEstimate, recovery, activeAdapter.name);
|
|
4735
4882
|
return fetchWithHeaderTimeout(builtInitialRequest.url, applyUpstreamRecoveryInit({
|
|
4736
4883
|
method: builtInitialRequest.method,
|
|
4737
4884
|
headers: builtInitialRequest.headers,
|
|
@@ -4782,6 +4929,13 @@ async function handleResponsesInner(
|
|
|
4782
4929
|
const rebuildAndRefetch = async (
|
|
4783
4930
|
recovery: AttemptRecoveryKind,
|
|
4784
4931
|
): Promise<Response | { failed: Response }> => {
|
|
4932
|
+
try {
|
|
4933
|
+
assertGoogleOptionsRoute(activeAdapter, route.provider);
|
|
4934
|
+
} catch (err) {
|
|
4935
|
+
cleanupUpstreamAbort();
|
|
4936
|
+
upstream.abort();
|
|
4937
|
+
return { failed: formatErrorResponse(400, "invalid_request_error", redactSecretString(err instanceof Error ? err.message : String(err))) };
|
|
4938
|
+
}
|
|
4785
4939
|
let retryRequest: AdapterRequest;
|
|
4786
4940
|
if (sameTargetRequest !== undefined && sameTargetParsed === parsed && sameTargetToken === transportToken) {
|
|
4787
4941
|
// Same target (key/adapter/parsed/tier unchanged): replay the exact cached request.
|
|
@@ -4792,6 +4946,7 @@ async function handleResponsesInner(
|
|
|
4792
4946
|
headers: selectedForwardHeaders,
|
|
4793
4947
|
translatorBudget,
|
|
4794
4948
|
...(imageTierBias > 0 ? { imageTierBias } : {}),
|
|
4949
|
+
...(observeAntigravityProviderError ? { onProviderError: observeAntigravityProviderError } : {}),
|
|
4795
4950
|
});
|
|
4796
4951
|
recordAdapterReasoning(logCtx, retryRequest);
|
|
4797
4952
|
recordAdapterTier(logCtx, retryRequest);
|
|
@@ -4816,7 +4971,7 @@ async function handleResponsesInner(
|
|
|
4816
4971
|
if (retryEstimate !== undefined) logCtx.usageLogInputTokens = retryEstimate;
|
|
4817
4972
|
logCtx.providerAdapter = activeAdapter.name;
|
|
4818
4973
|
sealRequestAttemptIdentity(logCtx.activeAttempt, logCtx.provider, activeAdapter.name, logCtx.accountLogLabel);
|
|
4819
|
-
|
|
4974
|
+
noteDiagnosticAttempt(logCtx.activeAttempt, retryEstimate, recovery, activeAdapter.name);
|
|
4820
4975
|
try {
|
|
4821
4976
|
try {
|
|
4822
4977
|
if (activeAdapter.fetchResponse) {
|
|
@@ -4828,6 +4983,7 @@ async function handleResponsesInner(
|
|
|
4828
4983
|
executor: providerFetch(route.provider, options.codexWsRuntimeIdentity, {
|
|
4829
4984
|
providerName: route.providerName,
|
|
4830
4985
|
modelId: route.modelId,
|
|
4986
|
+
pacingSlotAcquired: true,
|
|
4831
4987
|
}),
|
|
4832
4988
|
...(antigravityAccountId ? { accountId: antigravityAccountId } : {}),
|
|
4833
4989
|
});
|
|
@@ -4869,6 +5025,14 @@ async function handleResponsesInner(
|
|
|
4869
5025
|
cleanupUpstreamAbort();
|
|
4870
5026
|
return formatErrorResponse(401, "authentication_error", publicOAuthAuthenticationErrorMessage(err));
|
|
4871
5027
|
}
|
|
5028
|
+
if (isAntigravityOAuth && refreshed.accountId !== antigravityAccountId) {
|
|
5029
|
+
cleanupUpstreamAbort();
|
|
5030
|
+
return formatErrorResponse(401, "authentication_error", "Antigravity OAuth account changed during refresh");
|
|
5031
|
+
}
|
|
5032
|
+
if (isAntigravityOAuth && !refreshed.projectId) {
|
|
5033
|
+
cleanupUpstreamAbort();
|
|
5034
|
+
return formatErrorResponse(400, "invalid_request_error", "Antigravity project unavailable — re-run `ocx login google-antigravity`");
|
|
5035
|
+
}
|
|
4872
5036
|
sentOAuthSnapshot = refreshed;
|
|
4873
5037
|
replayOAuthCredentialSnapshot = {
|
|
4874
5038
|
accountId: refreshed.accountId,
|
|
@@ -4877,6 +5041,9 @@ async function handleResponsesInner(
|
|
|
4877
5041
|
if (route.providerName === "kiro") {
|
|
4878
5042
|
parsed._kiroAuthContext = { ...(refreshed.kiro ?? {}) };
|
|
4879
5043
|
}
|
|
5044
|
+
if (isAntigravityOAuth) {
|
|
5045
|
+
route.provider = { ...route.provider, project: refreshed.projectId };
|
|
5046
|
+
}
|
|
4880
5047
|
const refreshedProvider = resolveProviderTransport(
|
|
4881
5048
|
route.providerName,
|
|
4882
5049
|
{ ...route.provider, apiKey: refreshed.accessToken },
|
|
@@ -4972,6 +5139,37 @@ async function handleResponsesInner(
|
|
|
4972
5139
|
upstreamResponse = result;
|
|
4973
5140
|
}
|
|
4974
5141
|
|
|
5142
|
+
// Antigravity never rotates accounts. Record the account cooldown and allow only one
|
|
5143
|
+
// short, abort-aware replay on the same credential; longer Retry-After values surface to
|
|
5144
|
+
// the client so a conversation cannot churn through accounts or requests.
|
|
5145
|
+
if (upstreamResponse.status === 403 && isAntigravityOAuth && antigravityAccountId) {
|
|
5146
|
+
recordAntigravityCooldown(antigravityAccountId, upstreamResponse.headers.get("retry-after"), Date.now(), "geoblock");
|
|
5147
|
+
}
|
|
5148
|
+
if (upstreamResponse.status === 429 && isAntigravityOAuth && antigravityAccountId) {
|
|
5149
|
+
recordAntigravityCooldown(antigravityAccountId, upstreamResponse.headers.get("retry-after"));
|
|
5150
|
+
const retryAfter = retryableAntigravity429DelayMs(upstreamResponse.headers.get("retry-after"));
|
|
5151
|
+
if (!antigravity429RetryAttempted && retryAfter !== null) {
|
|
5152
|
+
antigravity429RetryAttempted = true;
|
|
5153
|
+
try { void upstreamResponse.body?.cancel().catch(() => {}); } catch { /* already closed */ }
|
|
5154
|
+
try {
|
|
5155
|
+
await sleepWithAbort(retryAfter, upstream.signal);
|
|
5156
|
+
} catch {
|
|
5157
|
+
cleanupUpstreamAbort();
|
|
5158
|
+
upstream.abort();
|
|
5159
|
+
return clientCancelledResponse();
|
|
5160
|
+
}
|
|
5161
|
+
if (options.abortSignal?.aborted || upstream.signal.aborted) {
|
|
5162
|
+
cleanupUpstreamAbort();
|
|
5163
|
+
upstream.abort();
|
|
5164
|
+
return clientCancelledResponse();
|
|
5165
|
+
}
|
|
5166
|
+
const result = await rebuildAndRefetch("rate-limit-429");
|
|
5167
|
+
if ("failed" in result) return result.failed;
|
|
5168
|
+
upstreamResponse = result;
|
|
5169
|
+
continue recovery;
|
|
5170
|
+
}
|
|
5171
|
+
}
|
|
5172
|
+
|
|
4975
5173
|
// Opt-in Anthropic OAuth account pool (#294): cool the failed account and retry
|
|
4976
5174
|
// with another eligible OAuth account (bounded per request). Disabled by default.
|
|
4977
5175
|
while (
|
|
@@ -5008,75 +5206,6 @@ async function handleResponsesInner(
|
|
|
5008
5206
|
break;
|
|
5009
5207
|
}
|
|
5010
5208
|
}
|
|
5011
|
-
// Antigravity OAuth accounts use the same bounded pre-stream carousel as Anthropic, but
|
|
5012
|
-
// their process-local routing module also excludes accounts cooled by quota/rate-limit
|
|
5013
|
-
// responses. Geoblocked 403s intentionally never enter this loop.
|
|
5014
|
-
while (
|
|
5015
|
-
upstreamResponse.status === 429
|
|
5016
|
-
&& route.providerName === "google-antigravity"
|
|
5017
|
-
&& route.provider.googleMode === "cloud-code-assist"
|
|
5018
|
-
&& antigravityAccountId
|
|
5019
|
-
&& antigravityFailovers < 3
|
|
5020
|
-
) {
|
|
5021
|
-
const stickWaitMs = antigravity429StickWaitMs(antigravityAccountId);
|
|
5022
|
-
if (stickWaitMs !== null) {
|
|
5023
|
-
await Bun.sleep(stickWaitMs);
|
|
5024
|
-
try { void upstreamResponse.body?.cancel().catch(() => {}); } catch { /* already consumed/closed */ }
|
|
5025
|
-
invalidateSameTargetRequest();
|
|
5026
|
-
activeAdapter = resolveAdapter(
|
|
5027
|
-
resolveWireProtocolOverride(route.providerName, route.modelId, route.provider, inboundWire),
|
|
5028
|
-
config.cacheRetention,
|
|
5029
|
-
);
|
|
5030
|
-
bindRouteReasoningReplayScope({
|
|
5031
|
-
parsed,
|
|
5032
|
-
providerName: route.providerName,
|
|
5033
|
-
provider: route.provider,
|
|
5034
|
-
adapterName: activeAdapter.name,
|
|
5035
|
-
codexAuthContext: authCtx,
|
|
5036
|
-
forwardHeaders: selectedForwardHeaders,
|
|
5037
|
-
});
|
|
5038
|
-
const result = await rebuildAndRefetch("rate-limit-429");
|
|
5039
|
-
if ("failed" in result) return result.failed;
|
|
5040
|
-
upstreamResponse = result;
|
|
5041
|
-
continue;
|
|
5042
|
-
}
|
|
5043
|
-
const nextAccountId = rotateAntigravityAccountOn429(antigravityAccountId, antigravitySessionKey);
|
|
5044
|
-
if (!nextAccountId) break;
|
|
5045
|
-
try { void upstreamResponse.body?.cancel().catch(() => {}); } catch { /* already consumed/closed */ }
|
|
5046
|
-
try {
|
|
5047
|
-
const accessToken = await getValidAccessTokenForAccount("google-antigravity", nextAccountId);
|
|
5048
|
-
const nextCredential = getAccountCredential("google-antigravity", nextAccountId);
|
|
5049
|
-
const bound = bindAntigravityProject(
|
|
5050
|
-
{ ...route.provider, apiKey: accessToken },
|
|
5051
|
-
nextCredential?.projectId,
|
|
5052
|
-
);
|
|
5053
|
-
if (!bound.ok) {
|
|
5054
|
-
return formatErrorResponse(bound.status, bound.type, bound.message);
|
|
5055
|
-
}
|
|
5056
|
-
antigravityAccountId = nextAccountId;
|
|
5057
|
-
antigravityFailovers += 1;
|
|
5058
|
-
route.provider = bound.provider;
|
|
5059
|
-
replayOAuthCredentialSnapshot = undefined;
|
|
5060
|
-
invalidateSameTargetRequest();
|
|
5061
|
-
activeAdapter = resolveAdapter(
|
|
5062
|
-
resolveWireProtocolOverride(route.providerName, route.modelId, route.provider, inboundWire),
|
|
5063
|
-
config.cacheRetention,
|
|
5064
|
-
);
|
|
5065
|
-
bindRouteReasoningReplayScope({
|
|
5066
|
-
parsed,
|
|
5067
|
-
providerName: route.providerName,
|
|
5068
|
-
provider: route.provider,
|
|
5069
|
-
adapterName: activeAdapter.name,
|
|
5070
|
-
codexAuthContext: authCtx,
|
|
5071
|
-
forwardHeaders: selectedForwardHeaders,
|
|
5072
|
-
});
|
|
5073
|
-
const result = await rebuildAndRefetch("rate-limit-429");
|
|
5074
|
-
if ("failed" in result) return result.failed;
|
|
5075
|
-
upstreamResponse = result;
|
|
5076
|
-
} catch {
|
|
5077
|
-
break;
|
|
5078
|
-
}
|
|
5079
|
-
}
|
|
5080
5209
|
if (
|
|
5081
5210
|
upstreamResponse.status === 402
|
|
5082
5211
|
&& cursorPoolAccountId
|
|
@@ -5296,6 +5425,16 @@ async function handleResponsesInner(
|
|
|
5296
5425
|
nextParsed: OcxParsedRequest,
|
|
5297
5426
|
initialRecoveryKind?: AttemptRecoveryKind,
|
|
5298
5427
|
): AsyncGenerator<AdapterEvent> {
|
|
5428
|
+
const requestValidationEvent = (error: unknown): AdapterEvent | undefined => {
|
|
5429
|
+
if (!(error instanceof OcxRequestValidationError)) return undefined;
|
|
5430
|
+
return {
|
|
5431
|
+
type: "error",
|
|
5432
|
+
status: error.status,
|
|
5433
|
+
errorType: "invalid_request_error",
|
|
5434
|
+
code: "invalid_request_error",
|
|
5435
|
+
message: error.message,
|
|
5436
|
+
};
|
|
5437
|
+
};
|
|
5299
5438
|
let response: Response | undefined;
|
|
5300
5439
|
// One-shot recovery label for the next top-of-loop continuation send after a failover rotation.
|
|
5301
5440
|
let nextContinuationRecoveryKind: AttemptRecoveryKind | undefined = initialRecoveryKind;
|
|
@@ -5308,6 +5447,7 @@ async function handleResponsesInner(
|
|
|
5308
5447
|
*/
|
|
5309
5448
|
const fetchContinuation = async (recoveryKind?: AttemptRecoveryKind): Promise<Response> => {
|
|
5310
5449
|
let continuationRequest: AdapterRequest | undefined;
|
|
5450
|
+
assertGoogleOptionsRoute(activeAdapter, route.provider, nextParsed);
|
|
5311
5451
|
if (sameTargetRequest !== undefined && sameTargetParsed === nextParsed && sameTargetToken === transportToken) {
|
|
5312
5452
|
// Same target (key/adapter/parsed/tier unchanged): replay the exact cached request.
|
|
5313
5453
|
continuationRequest = sameTargetRequest;
|
|
@@ -5317,6 +5457,7 @@ async function handleResponsesInner(
|
|
|
5317
5457
|
headers: selectedForwardHeaders,
|
|
5318
5458
|
translatorBudget,
|
|
5319
5459
|
...(imageTierBias > 0 ? { imageTierBias } : {}),
|
|
5460
|
+
...(observeAntigravityProviderError ? { onProviderError: observeAntigravityProviderError } : {}),
|
|
5320
5461
|
});
|
|
5321
5462
|
recordAdapterReasoning(logCtx, continuationRequest);
|
|
5322
5463
|
recordAdapterTier(logCtx, continuationRequest);
|
|
@@ -5342,8 +5483,13 @@ async function handleResponsesInner(
|
|
|
5342
5483
|
// Optional recovery label for same-target / failover continuation sends.
|
|
5343
5484
|
const replayKind: AttemptRecoveryKind | undefined = recoveryKind;
|
|
5344
5485
|
try {
|
|
5486
|
+
if (diagnosticContext) {
|
|
5487
|
+
diagnosticContext.recovery = replayKind;
|
|
5488
|
+
diagnosticContext.attempt = logCtx.activeAttempt?.ordinal;
|
|
5489
|
+
diagnosticContext.adapterName = activeAdapter.name;
|
|
5490
|
+
}
|
|
5345
5491
|
if (activeAdapter.fetchResponse) {
|
|
5346
|
-
|
|
5492
|
+
noteDiagnosticAttempt(logCtx.activeAttempt, continuationEstimate, replayKind, activeAdapter.name);
|
|
5347
5493
|
await waitForProviderRequestSlot(route.providerName, route.provider, nextParsed.modelId, upstream.signal);
|
|
5348
5494
|
return await activeAdapter.fetchResponse(builtContinuationRequest, {
|
|
5349
5495
|
abortSignal: upstream.signal,
|
|
@@ -5352,6 +5498,7 @@ async function handleResponsesInner(
|
|
|
5352
5498
|
executor: providerFetch(route.provider, options.codexWsRuntimeIdentity, {
|
|
5353
5499
|
providerName: route.providerName,
|
|
5354
5500
|
modelId: nextParsed.modelId,
|
|
5501
|
+
pacingSlotAcquired: true,
|
|
5355
5502
|
}),
|
|
5356
5503
|
...(antigravityAccountId ? { accountId: antigravityAccountId } : {}),
|
|
5357
5504
|
});
|
|
@@ -5361,7 +5508,7 @@ async function handleResponsesInner(
|
|
|
5361
5508
|
const fetchContinuationWithRetryPolicy = route.provider.adapter === "google" ? fetchWithTransientRetry : fetchWithResetRetry;
|
|
5362
5509
|
return await fetchContinuationWithRetryPolicy(
|
|
5363
5510
|
recovery => {
|
|
5364
|
-
|
|
5511
|
+
noteDiagnosticAttempt(logCtx.activeAttempt, continuationEstimate, recovery ?? replayKind, activeAdapter.name);
|
|
5365
5512
|
return fetchWithHeaderTimeout(
|
|
5366
5513
|
builtContinuationRequest.url,
|
|
5367
5514
|
applyUpstreamRecoveryInit({
|
|
@@ -5390,7 +5537,10 @@ async function handleResponsesInner(
|
|
|
5390
5537
|
nextContinuationRecoveryKind = undefined;
|
|
5391
5538
|
response = await fetchContinuation(recoveryKind);
|
|
5392
5539
|
} catch (error) {
|
|
5393
|
-
|
|
5540
|
+
const validationEvent = requestValidationEvent(error);
|
|
5541
|
+
if (validationEvent) {
|
|
5542
|
+
yield validationEvent;
|
|
5543
|
+
} else if (options.abortSignal?.aborted || upstream.signal.aborted) {
|
|
5394
5544
|
yield { type: "error", message: "client closed request during terminal continuation", status: 499 };
|
|
5395
5545
|
} else {
|
|
5396
5546
|
yield { type: "error", message: `Provider continuation failed: ${redactSecretString(error instanceof Error ? error.message : String(error))}` };
|
|
@@ -5436,7 +5586,10 @@ async function handleResponsesInner(
|
|
|
5436
5586
|
try {
|
|
5437
5587
|
response = await fetchContinuation("rate-limit-429");
|
|
5438
5588
|
} catch (error) {
|
|
5439
|
-
|
|
5589
|
+
const validationEvent = requestValidationEvent(error);
|
|
5590
|
+
if (validationEvent) {
|
|
5591
|
+
yield validationEvent;
|
|
5592
|
+
} else if (options.abortSignal?.aborted || upstream.signal.aborted) {
|
|
5440
5593
|
yield { type: "error", message: "client closed request during terminal continuation", status: 499 };
|
|
5441
5594
|
} else {
|
|
5442
5595
|
yield { type: "error", message: `Provider continuation failed: ${redactSecretString(error instanceof Error ? error.message : String(error))}` };
|
|
@@ -5445,6 +5598,42 @@ async function handleResponsesInner(
|
|
|
5445
5598
|
}
|
|
5446
5599
|
}
|
|
5447
5600
|
|
|
5601
|
+
if (response.status === 403 && isAntigravityOAuth && antigravityAccountId) {
|
|
5602
|
+
recordAntigravityCooldown(antigravityAccountId, response.headers.get("retry-after"), Date.now(), "geoblock");
|
|
5603
|
+
}
|
|
5604
|
+
if (response.status === 429 && isAntigravityOAuth && antigravityAccountId) {
|
|
5605
|
+
recordAntigravityCooldown(antigravityAccountId, response.headers.get("retry-after"));
|
|
5606
|
+
const retryAfter = retryableAntigravity429DelayMs(response.headers.get("retry-after"));
|
|
5607
|
+
if (!antigravity429RetryAttempted && retryAfter !== null) {
|
|
5608
|
+
antigravity429RetryAttempted = true;
|
|
5609
|
+
try { void response.body?.cancel().catch(() => {}); } catch { /* already closed */ }
|
|
5610
|
+
try {
|
|
5611
|
+
await sleepWithAbort(retryAfter, upstream.signal);
|
|
5612
|
+
} catch {
|
|
5613
|
+
if (options.abortSignal?.aborted || upstream.signal.aborted) {
|
|
5614
|
+
yield { type: "error", message: "client closed request during terminal continuation", status: 499 };
|
|
5615
|
+
} else {
|
|
5616
|
+
yield { type: "error", message: "Provider continuation failed: retry wait interrupted" };
|
|
5617
|
+
}
|
|
5618
|
+
return;
|
|
5619
|
+
}
|
|
5620
|
+
if (options.abortSignal?.aborted || upstream.signal.aborted) {
|
|
5621
|
+
yield { type: "error", message: "client closed request during terminal continuation", status: 499 };
|
|
5622
|
+
return;
|
|
5623
|
+
}
|
|
5624
|
+
try {
|
|
5625
|
+
response = await fetchContinuation("rate-limit-429");
|
|
5626
|
+
} catch (error) {
|
|
5627
|
+
if (options.abortSignal?.aborted || upstream.signal.aborted) {
|
|
5628
|
+
yield { type: "error", message: "client closed request during terminal continuation", status: 499 };
|
|
5629
|
+
} else {
|
|
5630
|
+
yield { type: "error", message: `Provider continuation failed: ${redactSecretString(error instanceof Error ? error.message : String(error))}` };
|
|
5631
|
+
}
|
|
5632
|
+
return;
|
|
5633
|
+
}
|
|
5634
|
+
}
|
|
5635
|
+
}
|
|
5636
|
+
|
|
5448
5637
|
if (response.status === 429 && hasKeyPoolFailover(route.provider)) {
|
|
5449
5638
|
const rotated = rotateProviderTransportOn429(config, route.providerName, route.provider, {
|
|
5450
5639
|
retryAfter: response.headers.get("retry-after"),
|
|
@@ -5651,7 +5840,13 @@ async function handleResponsesInner(
|
|
|
5651
5840
|
const detachContinuationBodyGuard = cancelBodyOnAbort(response.body, upstream.signal);
|
|
5652
5841
|
try {
|
|
5653
5842
|
if (nextParsed.stream) {
|
|
5654
|
-
yield*
|
|
5843
|
+
yield* diagnoseAdapterEvents(
|
|
5844
|
+
activeAdapter.parseStream(response, translatorBudget, logCtx.activeTierMetadata),
|
|
5845
|
+
activeAdapter.name,
|
|
5846
|
+
diagnosticRequestId,
|
|
5847
|
+
logCtx,
|
|
5848
|
+
adapterDiagnosticState,
|
|
5849
|
+
);
|
|
5655
5850
|
} else if (activeAdapter.parseResponse) {
|
|
5656
5851
|
yield* await activeAdapter.parseResponse(response, translatorBudget, logCtx.activeTierMetadata);
|
|
5657
5852
|
} else {
|
|
@@ -5661,7 +5856,10 @@ async function handleResponsesInner(
|
|
|
5661
5856
|
detachContinuationBodyGuard();
|
|
5662
5857
|
}
|
|
5663
5858
|
} catch (error) {
|
|
5664
|
-
|
|
5859
|
+
const validationEvent = requestValidationEvent(error);
|
|
5860
|
+
if (validationEvent) {
|
|
5861
|
+
yield validationEvent;
|
|
5862
|
+
} else if (options.abortSignal?.aborted) {
|
|
5665
5863
|
yield { type: "error", message: "client closed request during terminal continuation", status: 499 };
|
|
5666
5864
|
} else {
|
|
5667
5865
|
yield { type: "error", message: `Provider continuation parse failed: ${redactSecretString(error instanceof Error ? error.message : String(error))}` };
|
|
@@ -5683,11 +5881,18 @@ async function handleResponsesInner(
|
|
|
5683
5881
|
};
|
|
5684
5882
|
|
|
5685
5883
|
if (parsed.stream) {
|
|
5686
|
-
const initialEventStream =
|
|
5687
|
-
upstreamResponse,
|
|
5688
|
-
|
|
5689
|
-
|
|
5884
|
+
const initialEventStream = diagnoseAdapterEvents(
|
|
5885
|
+
activeAdapter.parseStream(upstreamResponse, translatorBudget, logCtx.activeTierMetadata),
|
|
5886
|
+
activeAdapter.name,
|
|
5887
|
+
diagnosticRequestId,
|
|
5888
|
+
logCtx,
|
|
5889
|
+
adapterDiagnosticState,
|
|
5690
5890
|
);
|
|
5891
|
+
if (diagnosticContext) {
|
|
5892
|
+
diagnosticContext.adapterName = activeAdapter.name;
|
|
5893
|
+
diagnosticContext.attempt = logCtx.activeAttempt?.ordinal;
|
|
5894
|
+
diagnosticContext.recovery = logCtx.activeAttempt?.recoveryKinds.at(-1);
|
|
5895
|
+
}
|
|
5691
5896
|
const eventStream = terminalGuardEnabled
|
|
5692
5897
|
? guardTerminalEventStream({
|
|
5693
5898
|
parsed,
|
|
@@ -5723,6 +5928,7 @@ async function handleResponsesInner(
|
|
|
5723
5928
|
...(routedCompaction ? { compaction: true } : {}),
|
|
5724
5929
|
// Same grok-surface split as the runTurn branch above.
|
|
5725
5930
|
...(logCtx.surface === "grok" ? { heartbeatStyle: "comment" as const } : {}),
|
|
5931
|
+
...(diagnosticContext ? { diagnostic: diagnosticContext } : {}),
|
|
5726
5932
|
onUsage: usage => {
|
|
5727
5933
|
// Raw adapter usage, pre wire-normalization (see the runTurn branch above).
|
|
5728
5934
|
logCtx.usageFromBridge = true;
|