Files
OmniRoute/open-sse/executors/antigravityUpstreamError.ts
Diego Rodrigues de Sa e Souza 0ba661ed97 fix(providers): surface real Antigravity upstream error detail (#13591) (#13801)
Merged in the 2026-09-16 sweep of the maintainer's own open PRs, at the owner's explicit instruction. No push was made to the PR branch: the merge took the head as the owning session left it (verified OPEN, non-draft and MERGEABLE against the release tip immediately before merging).
2026-09-16 06:11:41 -03:00

59 lines
2.8 KiB
TypeScript

/**
* Build a sanitized OpenAI-style error body for a non-ok Antigravity/agy upstream
* response (#3229).
*
* The non-streaming executor path previously fed 4xx/5xx responses into the SSE
* collector, which produced a synthetic `{"object":"chat.completion","content":""}`
* success envelope — masking the real error. Route non-ok responses through
* `buildErrorBody` instead so the client sees a proper error (hard rule #12).
*/
import { buildErrorBody } from "../utils/error.ts";
import { isGeoBlockedError } from "../services/errorClassifier.ts";
// The dashboard "Test Connection" for antigravity only probes the OAuth userinfo
// endpoint (https://www.googleapis.com/oauth2/v1/userinfo), which is NOT
// geo-restricted — so a green tick does not prove the model path works. Spell
// this out in the geo-block message so operators stop chasing accounts.
const GEO_BLOCKED_HINT =
"The Cloud Code API is not offered from this server's current egress location " +
'("User location is not supported for the API use."). This is not an account ' +
"problem: the connection test only validates the Google OAuth token and does not " +
"call the model API. Route antigravity/agy egress through a proxy in a " +
"supported region (e.g. US/EU) or use a different provider.";
/**
* Extract the real upstream error message (e.g. Google's Gemini-dialect field-path
* rejection) from a parsed Antigravity `upstream_details`-shaped body, so callers can
* surface it directly in `error.message` instead of only nesting it under
* `upstream_details` — the generic `parseUpstreamError()` re-parser used by the shared
* chatCore failure path only reads the outer `error.message` (#13591).
*/
function extractUpstreamMessage(details: unknown): string | null {
if (!details || typeof details !== "object") return null;
const err = (details as { error?: { message?: unknown } }).error;
const msg = err && typeof err.message === "string" ? err.message : null;
return msg && msg.trim() ? msg.trim() : null;
}
export function buildAntigravityUpstreamError(status: number, statusText: string, rawBody: string) {
let upstreamDetails: unknown;
try {
upstreamDetails = JSON.parse(rawBody);
} catch {
// upstream body is not JSON (e.g. HTML error page) — omit structured details
}
const suffix = statusText ? `: ${statusText}` : "";
if (isGeoBlockedError(rawBody)) {
return buildErrorBody(
status,
`Antigravity upstream error (${status})${suffix}. ${GEO_BLOCKED_HINT}`,
upstreamDetails
);
}
const upstreamMessage = extractUpstreamMessage(upstreamDetails);
const message = upstreamMessage
? `Antigravity upstream error (${status}): ${upstreamMessage}`
: `Antigravity upstream error (${status})${suffix}`;
return buildErrorBody(status, message, upstreamDetails);
}