feat(antigravity): expose physical send telemetry (#13659)

Co-authored-by: ginettododo <117327638+ginettododo@users.noreply.github.com>
This commit is contained in:
Domenico Massafra
2026-09-19 05:04:10 +02:00
committed by GitHub
parent d715190bb0
commit c8434436af
4 changed files with 75 additions and 11 deletions

View File

@@ -508,6 +508,7 @@ function isAntigravityGeminiChatModel(upstreamModel: string): boolean {
export const __test_stripTrailingAntigravityAssistantTurn = stripTrailingAntigravityAssistantTurn;
type AntigravityCreditsRetryState = { attempted: boolean };
type AntigravityPhysicalSendCounter = { value: number };
/** Base per-url-index attempt context, before the request has been sent. */
type AntigravityAttemptContext = {
@@ -527,6 +528,8 @@ type AntigravityAttemptContext = {
urlIndex: number;
retryAttemptsByUrl: Record<number, number>;
fallbackCount: number;
physicalSendCounter: AntigravityPhysicalSendCounter;
correlationId: string | null;
};
/** Context threaded through the 429/503 handling helpers — adds the sent response. */
@@ -1169,6 +1172,7 @@ export class AntigravityExecutor extends BaseExecutor {
* exactly the same single call as before (zero extra upstream requests).
*/
async execute(input: ExecuteInput) {
const physicalSendCounter: AntigravityPhysicalSendCounter = { value: 0 };
await resolveAntigravityClientVersion(getAntigravityClientProfile(input.credentials));
// Look up the chain by the NORMALLY-resolved upstream id (honours MITM/static aliases).
@@ -1178,7 +1182,7 @@ export class AntigravityExecutor extends BaseExecutor {
if (chain.length <= 1) {
// No fallback chain (flash, claude, plain pro, unknown) → single attempt, unchanged.
return this.executeOnce(input);
return this.executeOnce(input, undefined, physicalSendCounter);
}
let firstResult: Awaited<ReturnType<AntigravityExecutor["executeOnce"]>> | null = null;
@@ -1186,7 +1190,7 @@ export class AntigravityExecutor extends BaseExecutor {
const candidate = chain[i];
let result: Awaited<ReturnType<AntigravityExecutor["executeOnce"]>>;
try {
result = await this.executeOnce(input, candidate);
result = await this.executeOnce(input, candidate, physicalSendCounter);
} catch (error) {
const outcome = handleAntigravityFallbackChainError(
input,
@@ -1228,7 +1232,7 @@ export class AntigravityExecutor extends BaseExecutor {
}
// Unreachable (loop always returns), but keeps the type checker happy.
return firstResult ?? this.executeOnce(input);
return firstResult ?? this.executeOnce(input, undefined, physicalSendCounter);
}
/**
@@ -1239,8 +1243,18 @@ export class AntigravityExecutor extends BaseExecutor {
* status of the first response so `execute()` can decide whether to fall through. @internal
*/
private async executeOnce(
{ model, body, stream, credentials, signal, log, upstreamExtraHeaders }: ExecuteInput,
modelIdOverride?: string
{
model,
body,
stream,
credentials,
signal,
log,
upstreamExtraHeaders,
correlationId = null,
}: ExecuteInput,
modelIdOverride?: string,
physicalSendCounter: AntigravityPhysicalSendCounter = { value: 0 }
) {
await resolveAntigravityClientVersion(getAntigravityClientProfile(credentials));
const fallbackCount = this.getFallbackCount();
@@ -1307,6 +1321,8 @@ export class AntigravityExecutor extends BaseExecutor {
urlIndex,
retryAttemptsByUrl,
fallbackCount,
physicalSendCounter,
correlationId,
});
if (outcome.action === "return") return outcome.result;
@@ -1356,6 +1372,8 @@ export class AntigravityExecutor extends BaseExecutor {
urlIndex,
retryAttemptsByUrl,
fallbackCount,
physicalSendCounter,
correlationId,
} = ctx;
const { response, finalHeaders } = await sendAntigravityRequest(
@@ -1368,7 +1386,9 @@ export class AntigravityExecutor extends BaseExecutor {
stream,
signal,
log,
retryAttemptsByUrl[urlIndex]
retryAttemptsByUrl[urlIndex],
physicalSendCounter,
correlationId
);
let retryMs: number | null = null;
@@ -1619,7 +1639,9 @@ export class AntigravityExecutor extends BaseExecutor {
signal,
log,
accountId,
updateAntigravityRemainingCredits
updateAntigravityRemainingCredits,
ctx.physicalSendCounter,
ctx.correlationId
);
if (creditsResult) return { kind: "return", result: creditsResult };
if (retryMs) markConnectionQuotaExhausted(accountId, retryMs, ctx.model);

View File

@@ -333,7 +333,9 @@ export async function sendAntigravityRequest(
stream: boolean,
signal: AbortSignal | null | undefined,
log: SafeAntigravityLog,
retryAttempt: number
retryAttempt: number,
physicalSendCounter: { value: number },
correlationId: string | null
): Promise<{ response: Response; finalHeaders: Record<string, string> }> {
const serializedRequest = serializeAntigravityRequest(provider, headers, transformedBody);
let finalHeaders = serializedRequest.headers;
@@ -356,6 +358,11 @@ export async function sendAntigravityRequest(
}
await prl.captureCurrentProviderBody(url, finalHeaders, serializedRequest.bodyString, log);
const physicalSendOrdinal = ++physicalSendCounter.value;
log.debug(
"TELEMETRY",
`[Antigravity] PhysicalSend - RequestId: ${correlationId ?? "none"}, URL: ${url}, Model: ${model}, PhysicalSend: ${physicalSendOrdinal}, RetryAttempt: ${retryAttempt}`
);
let response = await fetchAntigravityWithReadinessTimeout(url, {
method: "POST",
headers: finalHeaders,
@@ -369,6 +376,11 @@ export async function sendAntigravityRequest(
removeHeaderCaseInsensitive(retryHeaders, "x-goog-user-project");
log.debug("RETRY", "403 with x-goog-user-project, retrying once without it");
await prl.captureCurrentProviderBody(url, retryHeaders, serializedRequest.bodyString, log);
const retryPhysicalSendOrdinal = ++physicalSendCounter.value;
log.debug(
"TELEMETRY",
`[Antigravity] PhysicalSend - RequestId: ${correlationId ?? "none"}, URL: ${url}, Model: ${model}, PhysicalSend: ${retryPhysicalSendOrdinal}, RetryAttempt: ${retryAttempt}, Cause: x-goog-user-project-403`
);
response = await fetchAntigravityWithReadinessTimeout(url, {
method: "POST",
headers: retryHeaders,
@@ -416,7 +428,9 @@ export async function tryCreditsRetry(
signal: AbortSignal | null | undefined,
log: SafeAntigravityLog,
accountId: string,
onCreditsUpdate: OnAntigravityCreditsUpdate
onCreditsUpdate: OnAntigravityCreditsUpdate,
physicalSendCounter: { value: number },
correlationId: string | null
): Promise<SsePassthroughResult | null> {
log.info("AG_CREDITS", "Retrying with Google One AI credits");
const creditsBody = attachToolNameMap(
@@ -433,6 +447,11 @@ export async function tryCreditsRetry(
serializedCreditsRequest.bodyString,
log
);
const creditsPhysicalSendOrdinal = ++physicalSendCounter.value;
log.debug(
"TELEMETRY",
`[Antigravity] PhysicalSend - RequestId: ${correlationId ?? "none"}, URL: ${url}, PhysicalSend: ${creditsPhysicalSendOrdinal}, Cause: google-one-ai-credits-retry`
);
const creditsResp = await fetchAntigravityWithReadinessTimeout(url, {
method: "POST",
headers: finalCreditsHeaders,

View File

@@ -36,6 +36,7 @@ test("AntigravityExecutor.execute auto-retries short 429 responses and collects
const originalFetch = globalThis.fetch;
const originalSetTimeout = globalThis.setTimeout;
const calls = [];
const telemetry: string[] = [];
seedAntigravityIdeVersionCache("2026.04.17-test");
seedAntigravityCliVersionCache("2026.04.17-test");
@@ -71,7 +72,13 @@ test("AntigravityExecutor.execute auto-retries short 429 responses and collects
body: { request: { contents: [] } },
stream: false,
credentials: { accessToken: "token", projectId: "project-1" },
log: { debug() {}, warn() {} },
log: {
debug(_scope, message) {
telemetry.push(String(message));
},
warn() {},
},
correlationId: "prompt194-native-retry-test",
});
// Non-streaming collects the upstream SSE and returns the already-converted
// OpenAI chat.completion payload — no further SSE parsing on the caller side.
@@ -79,6 +86,10 @@ test("AntigravityExecutor.execute auto-retries short 429 responses and collects
assert.equal(payload.object, "chat.completion");
assert.equal(calls.length, 2);
const physicalSends = telemetry.filter((line) => line.includes("[Antigravity] PhysicalSend"));
assert.equal(physicalSends.length, calls.length);
assert.match(physicalSends[0] ?? "", /RequestId: prompt194-native-retry-test/);
assert.match(physicalSends[1] ?? "", /PhysicalSend: 2/);
assert.equal(result.response.status, 200);
assert.equal(payload.choices[0].message.content, "Hello again");
assert.deepEqual(payload.usage, {

View File

@@ -871,6 +871,7 @@ test("AntigravityExecutor.execute bounds a persistent short-retry 429 instead of
const originalFetch = globalThis.fetch;
const originalSetTimeout = globalThis.setTimeout;
const calls: string[] = [];
const telemetry: string[] = [];
seedAntigravityIdeVersionCache("2.1.1");
// "rate limited" with no parseable retry hint classifies as rate_limited →
@@ -897,7 +898,13 @@ test("AntigravityExecutor.execute bounds a persistent short-retry 429 instead of
body: { request: { contents: [] } },
stream: true,
credentials: { accessToken: "token", projectId: "project-1" },
log: { debug() {}, warn() {} },
log: {
debug(_scope, message) {
telemetry.push(String(message));
},
warn() {},
},
correlationId: "prompt194-physical-send-test",
});
// Returns the 429 rather than hanging.
@@ -906,6 +913,11 @@ test("AntigravityExecutor.execute bounds a persistent short-retry 429 instead of
// Bounded: switchAuth declines same-URL retries → 2 live runtime endpoints
// × 1 attempt each = 2 attempts total (#9351).
assert.equal(calls.length, 2);
const physicalSends = telemetry.filter((line) => line.includes("[Antigravity] PhysicalSend"));
assert.equal(physicalSends.length, calls.length);
assert.match(physicalSends[0] ?? "", /RequestId: prompt194-physical-send-test/);
assert.match(physicalSends[0] ?? "", /PhysicalSend: 1/);
assert.match(physicalSends[1] ?? "", /PhysicalSend: 2/);
// Tried every distinct live runtime base URL before giving up.
const distinctHosts = new Set(calls.map((u) => new URL(u).host));