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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 14 additions & 10 deletions src/adapters/client-fingerprint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,24 @@ export function claudeCodeSessionId(token: string | undefined): string {
return `${h.slice(0, 8)}-${h.slice(8, 12)}-4${h.slice(13, 16)}-${variant}${h.slice(17, 20)}-${h.slice(20, 32)}`;
}

// ── Antigravity CLI ──
/** Pinned fallback Antigravity CLI version (real client fetches a manifest; we pin to avoid the network dependency). */
export const ANTIGRAVITY_CLI_VERSION = "1.1.12";
const ANTIGRAVITY_CLI_CLIENT_NAME = "aidev_client";
const ANTIGRAVITY_CLI_PLATFORM = "darwin/arm64";
// ── Antigravity IDE ──
/** Pinned fallback Antigravity IDE language-server version (matches the bundled LS 2.5.5). */
export const ANTIGRAVITY_IDE_VERSION = "2.5.5";
const ANTIGRAVITY_IDE_CLIENT_NAME = "aidev_client";
const ANTIGRAVITY_IDE_PLATFORM = "windows/amd64";
/** Secondary Google API client UA the Antigravity client library reports. */
export const ANTIGRAVITY_GOOG_API_CLIENT_UA = "google-api-nodejs-client/10.3.0";

/**
* The real Antigravity CLI User-Agent, e.g.
* `antigravity/cli/1.1.12 (aidev_client; os_type=darwin; arch=arm64)`.
* The real Antigravity IDE User-Agent, e.g.
* `antigravity/ide/2.5.5 (aidev_client; os_type=windows; arch=amd64)`.
*
* Must be the IDE client family, NOT `antigravity/cli/...`: the Cloud Code Assist backend gates
* newer agent models (e.g. `gemini-3.7-flash`) by User-Agent and answers 404 NOT_FOUND to
* CLI-shaped UAs even with a valid OAuth token. Only `antigravity/ide/<ver>` unlocks them.
* A `GOOGLE_ANTIGRAVITY_USER_AGENT` override (set by the caller) takes precedence upstream.
*/
export function antigravityUserAgent(version = ANTIGRAVITY_CLI_VERSION): string {
const [osType, arch] = ANTIGRAVITY_CLI_PLATFORM.split("/");
return `antigravity/cli/${version} (${ANTIGRAVITY_CLI_CLIENT_NAME}; os_type=${osType}; arch=${arch})`;
export function antigravityUserAgent(version = ANTIGRAVITY_IDE_VERSION): string {
const [osType, arch] = ANTIGRAVITY_IDE_PLATFORM.split("/");
return `antigravity/ide/${version} (${ANTIGRAVITY_IDE_CLIENT_NAME}; os_type=${osType}; arch=${arch})`;
}
7 changes: 4 additions & 3 deletions src/adapters/google-antigravity-wire.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ import type { OcxContentPart, OcxParsedRequest } from "../types";
import { antigravityUserAgent } from "./client-fingerprint";

/**
* Antigravity request User-Agent. Mirrors the real Antigravity CLI UA
* (`antigravity/cli/{ver} (aidev_client; os_type=darwin; arch=arm64)`) so the request fingerprint
* Antigravity request User-Agent. Mirrors the real Antigravity IDE UA
* (`antigravity/ide/{ver} (aidev_client; os_type=windows; arch=amd64)`) so the request fingerprint
* matches the OAuth credential — the prior literal `"antigravity"` was a giveaway no real client
* sends. A `GOOGLE_ANTIGRAVITY_USER_AGENT` override still wins.
* sends. The IDE client family is also required to unlock newer agent models (the backend 404s
* CLI-shaped UAs for `gemini-3.7-*`). A `GOOGLE_ANTIGRAVITY_USER_AGENT` override still wins.
*/
export const ANTIGRAVITY_REQUEST_UA = process.env.GOOGLE_ANTIGRAVITY_USER_AGENT || antigravityUserAgent();

Expand Down
2 changes: 1 addition & 1 deletion src/adapters/google.ts
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ export function createGoogleAdapter(provider: OcxProviderConfig): ProviderAdapte
const envelope = {
model: wireModelId,
// The envelope's `userAgent` field is a protocol constant ("antigravity"), distinct from
// the HTTP `User-Agent` header (the real CLI UA). CLIProxyAPI `geminiToAntigravity` hardcodes
// the HTTP `User-Agent` header (the real IDE UA). CLIProxyAPI `geminiToAntigravity` hardcodes
// the body field; only the header carries the versioned client string.
userAgent: "antigravity",
requestType: "agent",
Expand Down
8 changes: 4 additions & 4 deletions tests/client-fingerprint.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, expect, test } from "bun:test";
import {
ANTIGRAVITY_CLI_VERSION,
ANTIGRAVITY_IDE_VERSION,
ANTIGRAVITY_GOOG_API_CLIENT_UA,
CLAUDE_CODE_HEADERS,
antigravityUserAgent,
Expand All @@ -19,14 +19,14 @@ function parsed(): OcxParsedRequest {
}

describe("client fingerprint — helpers", () => {
test("antigravity UA has the real CLI shape, never the literal giveaway", async () => {
test("antigravity UA has the real IDE shape, never the literal giveaway", async () => {
const ua = antigravityUserAgent();
expect(ua).toBe("antigravity/cli/1.1.12 (aidev_client; os_type=darwin; arch=arm64)");
expect(ua).toBe(`antigravity/ide/${ANTIGRAVITY_IDE_VERSION} (aidev_client; os_type=windows; arch=amd64)`);
expect(ua).not.toBe("antigravity");
});

test("antigravity UA honors an explicit version override", async () => {
expect(antigravityUserAgent("9.9.9")).toBe("antigravity/cli/9.9.9 (aidev_client; os_type=darwin; arch=arm64)");
expect(antigravityUserAgent("9.9.9")).toBe("antigravity/ide/9.9.9 (aidev_client; os_type=windows; arch=amd64)");
});

test("GOOGLE_ANTIGRAVITY_USER_AGENT env override wins over the default UA", async () => {
Expand Down
6 changes: 5 additions & 1 deletion tests/google-antigravity-wire.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,11 @@ describe("antigravity CCA envelope", () => {
expect(env.request.model).toBeUndefined();
expect(env.request.safetySettings).toBeUndefined();
expect(req.headers["Authorization"]).toBe("Bearer ya29.token");
expect(req.headers["User-Agent"]).toMatch(/^antigravity\/cli\/[\d.]+ \(aidev_client; os_type=\w+; arch=\w+\)$/);
// The exact default must not drift: Google gates models by family AND version,
// so any change to version/platform could silently re-lock gemini-3.7-flash.
expect(req.headers["User-Agent"]).toBe(
"antigravity/ide/2.5.5 (aidev_client; os_type=windows; arch=amd64)",
);
// The literal "antigravity" giveaway UA must no longer be sent.
expect(req.headers["User-Agent"]).not.toBe("antigravity");
// x-goog-api-client is NOT sent on runtime requests (CLIProxyAPI only uses it during onboarding).
Expand Down
Loading