mirror of
https://github.com/Nezumi-2711/9router.git
synced 2026-09-22 13:38:31 +00:00
fix(antigravity): align provider fingerprint with IDE Desktop 2.1.1 (#2389)
Match captured official Antigravity IDE traffic: cloudcode-pa host, antigravity/ide/2.1.1 User-Agent, IDE-shaped agent requestId, and drop router-only stream/usage headers plus the legacy double system prompt. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
committed by
decolua
co-authored by
Cursor
parent
b10b807063
commit
71cd5b2f23
@@ -1,5 +1,6 @@
|
|||||||
import { platform, arch } from "os";
|
import { platform, arch } from "os";
|
||||||
import { PROVIDERS, PROVIDER_OAUTH } from "./providers.js";
|
import { PROVIDERS, PROVIDER_OAUTH } from "./providers.js";
|
||||||
|
import { ANTIGRAVITY_IDE_USER_AGENT } from "../providers/shared.js";
|
||||||
|
|
||||||
// === Gemini CLI === derive từ registry gemini-cli.transport
|
// === Gemini CLI === derive từ registry gemini-cli.transport
|
||||||
export const GEMINI_CLI_VERSION = PROVIDERS["gemini-cli"]?.cliVersion;
|
export const GEMINI_CLI_VERSION = PROVIDERS["gemini-cli"]?.cliVersion;
|
||||||
@@ -59,7 +60,7 @@ export function getPlatformEnum() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getPlatformUserAgent() {
|
export function getPlatformUserAgent() {
|
||||||
return `antigravity/1.104.0 ${platform()}/${arch()}`;
|
return ANTIGRAVITY_IDE_USER_AGENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CLIENT_METADATA = {
|
export const CLIENT_METADATA = {
|
||||||
@@ -129,7 +130,7 @@ export const AG_DEFAULT_TOOLS = new Set([
|
|||||||
|
|
||||||
// Antigravity chat/stream headers
|
// Antigravity chat/stream headers
|
||||||
export const ANTIGRAVITY_HEADERS = {
|
export const ANTIGRAVITY_HEADERS = {
|
||||||
"User-Agent": `antigravity/1.107.0 ${platform()}/${arch()}`
|
"User-Agent": ANTIGRAVITY_IDE_USER_AGENT
|
||||||
};
|
};
|
||||||
|
|
||||||
// Cloud Code Assist API
|
// Cloud Code Assist API
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import crypto from "crypto";
|
import crypto from "crypto";
|
||||||
import { BaseExecutor } from "./base.js";
|
import { BaseExecutor } from "./base.js";
|
||||||
import { PROVIDERS } from "../config/providers.js";
|
import { PROVIDERS } from "../config/providers.js";
|
||||||
import { OAUTH_ENDPOINTS, ANTIGRAVITY_HEADERS, INTERNAL_REQUEST_HEADER, AG_DEFAULT_TOOLS, AG_TOOL_SUFFIX } from "../config/appConstants.js";
|
import { OAUTH_ENDPOINTS, ANTIGRAVITY_HEADERS, AG_DEFAULT_TOOLS, AG_TOOL_SUFFIX } from "../config/appConstants.js";
|
||||||
import { HTTP_STATUS } from "../config/runtimeConfig.js";
|
import { HTTP_STATUS } from "../config/runtimeConfig.js";
|
||||||
import { resolveSessionId } from "../utils/sessionManager.js";
|
import { resolveSessionId } from "../utils/sessionManager.js";
|
||||||
import { proxyAwareFetch } from "../utils/proxyFetch.js";
|
import { proxyAwareFetch } from "../utils/proxyFetch.js";
|
||||||
@@ -18,7 +18,8 @@ function sanitizeFunctionName(name) {
|
|||||||
|
|
||||||
const MAX_RETRY_AFTER_MS = 10000;
|
const MAX_RETRY_AFTER_MS = 10000;
|
||||||
const ANTIGRAVITY_TRANSIENT_RETRY_MAX_MS = 15000;
|
const ANTIGRAVITY_TRANSIENT_RETRY_MAX_MS = 15000;
|
||||||
const MAX_ANTIGRAVITY_OUTPUT_TOKENS = 16384;
|
const MAX_ANTIGRAVITY_OUTPUT_TOKENS = 64000;
|
||||||
|
const ANTIGRAVITY_IDE_REQUEST_ID_RE = /^agent\/[^/]+\/\d+\/[^/]+\/\d+$/;
|
||||||
|
|
||||||
const ANTIGRAVITY_TRANSIENT_ERROR_PATTERNS = [
|
const ANTIGRAVITY_TRANSIENT_ERROR_PATTERNS = [
|
||||||
/high\s+traffic/i,
|
/high\s+traffic/i,
|
||||||
@@ -87,6 +88,27 @@ function parseImageConfig(model) {
|
|||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function uuidFromSeed(seed) {
|
||||||
|
const bytes = crypto.createHash("sha256").update(String(seed || "antigravity")).digest().subarray(0, 16);
|
||||||
|
bytes[6] = (bytes[6] & 0x0f) | 0x50;
|
||||||
|
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
||||||
|
const hex = bytes.toString("hex");
|
||||||
|
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildIdeRequestId({ body, request, credentials, model, requestType }) {
|
||||||
|
if (ANTIGRAVITY_IDE_REQUEST_ID_RE.test(body?.requestId || "")) {
|
||||||
|
return body.requestId;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sessionId = request?.sessionId || body?.request?.sessionId || credentials?._clientSessionId || credentials?.connectionId || credentials?.email || "anonymous";
|
||||||
|
const conversationId = uuidFromSeed(`antigravity:conversation:${sessionId}`);
|
||||||
|
const trajectoryId = uuidFromSeed(`antigravity:trajectory:${sessionId}:${model}:${requestType}`);
|
||||||
|
const contentCount = Array.isArray(request?.contents) ? request.contents.length : 1;
|
||||||
|
const step = Math.max(1, contentCount * 2 - 1);
|
||||||
|
return `agent/${conversationId}/${Date.now()}/${trajectoryId}/${step}`;
|
||||||
|
}
|
||||||
|
|
||||||
export class AntigravityExecutor extends BaseExecutor {
|
export class AntigravityExecutor extends BaseExecutor {
|
||||||
constructor() {
|
constructor() {
|
||||||
super("antigravity", PROVIDERS.antigravity);
|
super("antigravity", PROVIDERS.antigravity);
|
||||||
@@ -104,14 +126,10 @@ export class AntigravityExecutor extends BaseExecutor {
|
|||||||
// sessionId comes from transformRequest output; base.execute runs transformRequest before
|
// sessionId comes from transformRequest output; base.execute runs transformRequest before
|
||||||
// buildHeaders, so we read it from instance state cached there (fallback: explicit arg).
|
// buildHeaders, so we read it from instance state cached there (fallback: explicit arg).
|
||||||
buildHeaders(credentials, stream = true, sessionId = null) {
|
buildHeaders(credentials, stream = true, sessionId = null) {
|
||||||
const sid = sessionId || this._lastSessionId;
|
|
||||||
return {
|
return {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"Authorization": `Bearer ${credentials.accessToken}`,
|
"Authorization": `Bearer ${credentials.accessToken}`,
|
||||||
"User-Agent": this.config.headers?.["User-Agent"] || ANTIGRAVITY_HEADERS["User-Agent"],
|
"User-Agent": this.config.headers?.["User-Agent"] || ANTIGRAVITY_HEADERS["User-Agent"],
|
||||||
[INTERNAL_REQUEST_HEADER.name]: INTERNAL_REQUEST_HEADER.value,
|
|
||||||
...(sid && { "X-Machine-Session-Id": sid }),
|
|
||||||
"Accept": stream ? "text/event-stream" : "application/json"
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,25 +160,26 @@ export class AntigravityExecutor extends BaseExecutor {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this._lastSessionId = sessionId;
|
this._lastSessionId = sessionId;
|
||||||
|
const request = {
|
||||||
|
contents,
|
||||||
|
generationConfig: {
|
||||||
|
temperature: 1.0,
|
||||||
|
topP: 0.95,
|
||||||
|
topK: 40,
|
||||||
|
maxOutputTokens: 8192,
|
||||||
|
imageConfig,
|
||||||
|
},
|
||||||
|
sessionId,
|
||||||
|
// No tools, no systemInstruction, no safetySettings for image gen
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
project: projectId,
|
project: projectId,
|
||||||
model: cleanModel,
|
model: cleanModel,
|
||||||
userAgent: "antigravity",
|
userAgent: "antigravity",
|
||||||
requestType: "image_gen",
|
requestType: "image_gen",
|
||||||
requestId: `agent-${crypto.randomUUID()}`,
|
requestId: buildIdeRequestId({ body, request, credentials, model: cleanModel, requestType: "image_gen" }),
|
||||||
request: {
|
request,
|
||||||
contents,
|
|
||||||
generationConfig: {
|
|
||||||
temperature: 1.0,
|
|
||||||
topP: 0.95,
|
|
||||||
topK: 40,
|
|
||||||
maxOutputTokens: 8192,
|
|
||||||
imageConfig,
|
|
||||||
},
|
|
||||||
sessionId,
|
|
||||||
// No tools, no systemInstruction, no safetySettings for image gen
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,7 +267,7 @@ export class AntigravityExecutor extends BaseExecutor {
|
|||||||
model: model,
|
model: model,
|
||||||
userAgent: "antigravity",
|
userAgent: "antigravity",
|
||||||
requestType: "agent",
|
requestType: "agent",
|
||||||
requestId: `agent-${crypto.randomUUID()}`,
|
requestId: buildIdeRequestId({ body, request: transformedRequest, credentials, model, requestType: "agent" }),
|
||||||
request: transformedRequest
|
request: transformedRequest
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { platform, arch } from "os";
|
import { ANTIGRAVITY_IDE_BASE_URL, ANTIGRAVITY_IDE_USER_AGENT, ANTIGRAVITY_OAUTH_CLIENT } from "../shared.js";
|
||||||
import { ANTIGRAVITY_OAUTH_CLIENT } from "../shared.js";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
id: "antigravity",
|
id: "antigravity",
|
||||||
@@ -20,13 +19,10 @@ export default {
|
|||||||
category: "oauth",
|
category: "oauth",
|
||||||
serviceKinds: ["llm", "image"],
|
serviceKinds: ["llm", "image"],
|
||||||
transport: {
|
transport: {
|
||||||
baseUrls: [
|
baseUrls: [ANTIGRAVITY_IDE_BASE_URL],
|
||||||
"https://daily-cloudcode-pa.googleapis.com",
|
|
||||||
"https://daily-cloudcode-pa.sandbox.googleapis.com",
|
|
||||||
],
|
|
||||||
format: "antigravity",
|
format: "antigravity",
|
||||||
headers: {
|
headers: {
|
||||||
"User-Agent": "antigravity/1.107.0 darwin/arm64",
|
"User-Agent": ANTIGRAVITY_IDE_USER_AGENT,
|
||||||
},
|
},
|
||||||
retry: {
|
retry: {
|
||||||
"429": {
|
"429": {
|
||||||
|
|||||||
@@ -54,6 +54,13 @@ export const KIMI_CODING_BASE_URL = "https://api.kimi.com/coding/v1/messages";
|
|||||||
export const OPENAI_COMPAT_BASE = "https://api.openai.com/v1";
|
export const OPENAI_COMPAT_BASE = "https://api.openai.com/v1";
|
||||||
export const ANTHROPIC_COMPAT_BASE = "https://api.anthropic.com/v1";
|
export const ANTHROPIC_COMPAT_BASE = "https://api.anthropic.com/v1";
|
||||||
|
|
||||||
|
// Official Antigravity IDE Desktop 2.1.1 fingerprint captured from macOS arm64.
|
||||||
|
// Keep this static even when 9router runs on Linux: the provider profile is
|
||||||
|
// intentionally matching the IDE client, not the server host.
|
||||||
|
export const ANTIGRAVITY_IDE_VERSION = "2.1.1";
|
||||||
|
export const ANTIGRAVITY_IDE_BASE_URL = "https://cloudcode-pa.googleapis.com";
|
||||||
|
export const ANTIGRAVITY_IDE_USER_AGENT = `antigravity/ide/${ANTIGRAVITY_IDE_VERSION} darwin/arm64`;
|
||||||
|
|
||||||
// Antigravity OAuth client credentials (public CLI client — duplicated in usage.js + src/lib/oauth)
|
// Antigravity OAuth client credentials (public CLI client — duplicated in usage.js + src/lib/oauth)
|
||||||
export const ANTIGRAVITY_OAUTH_CLIENT = {
|
export const ANTIGRAVITY_OAUTH_CLIENT = {
|
||||||
clientId: "1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com",
|
clientId: "1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com",
|
||||||
|
|||||||
@@ -2,15 +2,15 @@
|
|||||||
* Google usage handlers (Gemini CLI + Antigravity)
|
* Google usage handlers (Gemini CLI + Antigravity)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { CLIENT_METADATA, getPlatformUserAgent } from "../../config/appConstants.js";
|
import { CLIENT_METADATA } from "../../config/appConstants.js";
|
||||||
import { ANTIGRAVITY_OAUTH_CLIENT } from "../../providers/shared.js";
|
import { ANTIGRAVITY_IDE_USER_AGENT, ANTIGRAVITY_IDE_VERSION, ANTIGRAVITY_OAUTH_CLIENT } from "../../providers/shared.js";
|
||||||
import { U, parseResetTime, normalizeCloudCodeProjectId, fetchWithTimeout } from "./shared.js";
|
import { U, parseResetTime, normalizeCloudCodeProjectId, fetchWithTimeout } from "./shared.js";
|
||||||
|
|
||||||
// Antigravity API config (from Quotio) — urls from registry, oauth client + dynamic UA kept here
|
// Antigravity API config (from Quotio) — urls from registry, oauth client + dynamic UA kept here
|
||||||
const ANTIGRAVITY_CONFIG = {
|
const ANTIGRAVITY_CONFIG = {
|
||||||
...U("antigravity"),
|
...U("antigravity"),
|
||||||
...ANTIGRAVITY_OAUTH_CLIENT,
|
...ANTIGRAVITY_OAUTH_CLIENT,
|
||||||
userAgent: getPlatformUserAgent(),
|
userAgent: ANTIGRAVITY_IDE_USER_AGENT,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -129,8 +129,7 @@ export async function getAntigravityUsage(accessToken, providerSpecificData, pro
|
|||||||
"User-Agent": ANTIGRAVITY_CONFIG.userAgent,
|
"User-Agent": ANTIGRAVITY_CONFIG.userAgent,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"X-Client-Name": "antigravity",
|
"X-Client-Name": "antigravity",
|
||||||
"X-Client-Version": "1.107.0",
|
"X-Client-Version": ANTIGRAVITY_IDE_VERSION,
|
||||||
"x-request-source": "local", // MITM bypass
|
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
...(projectId ? { project: projectId } : {})
|
...(projectId ? { project: projectId } : {})
|
||||||
@@ -229,7 +228,6 @@ async function getAntigravitySubscriptionInfo(accessToken, proxyOptions = null)
|
|||||||
"Authorization": `Bearer ${accessToken}`,
|
"Authorization": `Bearer ${accessToken}`,
|
||||||
"User-Agent": ANTIGRAVITY_CONFIG.userAgent,
|
"User-Agent": ANTIGRAVITY_CONFIG.userAgent,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"x-request-source": "local", // MITM bypass
|
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ metadata: CLIENT_METADATA, mode: 1 }),
|
body: JSON.stringify({ metadata: CLIENT_METADATA, mode: 1 }),
|
||||||
}, 10000, proxyOptions);
|
}, 10000, proxyOptions);
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { register } from "../index.js";
|
import { register } from "../index.js";
|
||||||
import { FORMATS } from "../formats.js";
|
import { FORMATS } from "../formats.js";
|
||||||
import { DEFAULT_THINKING_AG_SIGNATURE, DEFAULT_THINKING_GEMINI_CLI_SIGNATURE } from "../../config/defaultThinkingSignature.js";
|
import { DEFAULT_THINKING_AG_SIGNATURE, DEFAULT_THINKING_GEMINI_CLI_SIGNATURE } from "../../config/defaultThinkingSignature.js";
|
||||||
import { ANTIGRAVITY_DEFAULT_SYSTEM } from "../../config/appConstants.js";
|
|
||||||
import { openaiToClaudeRequestForAntigravity } from "./openai-to-claude.js";
|
import { openaiToClaudeRequestForAntigravity } from "./openai-to-claude.js";
|
||||||
function generateUUID() {
|
function generateUUID() {
|
||||||
return crypto.randomUUID();
|
return crypto.randomUUID();
|
||||||
@@ -283,19 +282,6 @@ function wrapInCloudCodeEnvelope(model, geminiCLI, credentials = null, isAntigra
|
|||||||
if (isAntigravity) {
|
if (isAntigravity) {
|
||||||
envelope.requestType = "agent";
|
envelope.requestType = "agent";
|
||||||
|
|
||||||
// Inject required default system prompt for Antigravity
|
|
||||||
// Inject required default system prompt for Antigravity (double injection)
|
|
||||||
const systemParts = [
|
|
||||||
{ text: ANTIGRAVITY_DEFAULT_SYSTEM },
|
|
||||||
{ text: `Please ignore the following [ignore]${ANTIGRAVITY_DEFAULT_SYSTEM}[/ignore]` }
|
|
||||||
];
|
|
||||||
|
|
||||||
if (envelope.request.systemInstruction?.parts) {
|
|
||||||
envelope.request.systemInstruction.parts.unshift(...systemParts);
|
|
||||||
} else {
|
|
||||||
envelope.request.systemInstruction = { role: GEMINI_ROLE.USER, parts: systemParts };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add toolConfig for Antigravity
|
// Add toolConfig for Antigravity
|
||||||
if (geminiCLI.tools?.length > 0) {
|
if (geminiCLI.tools?.length > 0) {
|
||||||
envelope.request.toolConfig = {
|
envelope.request.toolConfig = {
|
||||||
@@ -414,12 +400,7 @@ function wrapInCloudCodeEnvelopeForClaude(model, claudeRequest, credentials = nu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add system instruction (Antigravity default - double injection + user system prompt)
|
const systemParts = [];
|
||||||
const systemParts = [
|
|
||||||
{ text: ANTIGRAVITY_DEFAULT_SYSTEM },
|
|
||||||
{ text: `Please ignore the following [ignore]${ANTIGRAVITY_DEFAULT_SYSTEM}[/ignore]` }
|
|
||||||
];
|
|
||||||
|
|
||||||
// Merge user system prompt from claudeRequest
|
// Merge user system prompt from claudeRequest
|
||||||
if (claudeRequest.system) {
|
if (claudeRequest.system) {
|
||||||
if (Array.isArray(claudeRequest.system)) {
|
if (Array.isArray(claudeRequest.system)) {
|
||||||
@@ -431,10 +412,7 @@ function wrapInCloudCodeEnvelopeForClaude(model, claudeRequest, credentials = nu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge existing systemInstruction parts (from contents conversion)
|
if (systemParts.length > 0) {
|
||||||
if (envelope.request.systemInstruction?.parts) {
|
|
||||||
envelope.request.systemInstruction.parts.unshift(...systemParts);
|
|
||||||
} else {
|
|
||||||
envelope.request.systemInstruction = { role: GEMINI_ROLE.USER, parts: systemParts };
|
envelope.request.systemInstruction = { role: GEMINI_ROLE.USER, parts: systemParts };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -463,4 +441,3 @@ export function openaiToAntigravityRequest(model, body, stream, credentials = nu
|
|||||||
register(FORMATS.OPENAI, FORMATS.GEMINI, openaiToGeminiRequest, null);
|
register(FORMATS.OPENAI, FORMATS.GEMINI, openaiToGeminiRequest, null);
|
||||||
register(FORMATS.OPENAI, FORMATS.GEMINI_CLI, (model, body, stream, credentials) => wrapInCloudCodeEnvelope(model, openaiToGeminiCLIRequest(model, body, stream), credentials), null);
|
register(FORMATS.OPENAI, FORMATS.GEMINI_CLI, (model, body, stream, credentials) => wrapInCloudCodeEnvelope(model, openaiToGeminiCLIRequest(model, body, stream), credentials), null);
|
||||||
register(FORMATS.OPENAI, FORMATS.ANTIGRAVITY, openaiToAntigravityRequest, null);
|
register(FORMATS.OPENAI, FORMATS.ANTIGRAVITY, openaiToAntigravityRequest, null);
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import "./registerAll.js";
|
|||||||
import { translateRequest, translateResponse, initState } from "../../open-sse/translator/index.js";
|
import { translateRequest, translateResponse, initState } from "../../open-sse/translator/index.js";
|
||||||
import { FORMATS } from "../../open-sse/translator/formats.js";
|
import { FORMATS } from "../../open-sse/translator/formats.js";
|
||||||
import { AntigravityExecutor } from "../../open-sse/executors/antigravity.js";
|
import { AntigravityExecutor } from "../../open-sse/executors/antigravity.js";
|
||||||
|
import { openaiToAntigravityRequest } from "../../open-sse/translator/request/openai-to-gemini.js";
|
||||||
|
import { ANTIGRAVITY_DEFAULT_SYSTEM } from "../../open-sse/config/appConstants.js";
|
||||||
|
|
||||||
const AG2O = (req) =>
|
const AG2O = (req) =>
|
||||||
translateRequest(FORMATS.ANTIGRAVITY, FORMATS.OPENAI, "m", { request: req }, true, null, null);
|
translateRequest(FORMATS.ANTIGRAVITY, FORMATS.OPENAI, "m", { request: req }, true, null, null);
|
||||||
@@ -106,4 +108,32 @@ describe("Antigravity executor", () => {
|
|||||||
const query = out.request.tools[0].functionDeclarations[0].parameters.properties.query;
|
const query = out.request.tools[0].functionDeclarations[0].parameters.properties.query;
|
||||||
expect(query).toEqual({ type: "string", description: "Search query" });
|
expect(query).toEqual({ type: "string", description: "Search query" });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("does not inject the legacy Antigravity default system prompt for Gemini-backed models", () => {
|
||||||
|
const out = openaiToAntigravityRequest("gemini-3.5-flash-low", {
|
||||||
|
messages: [
|
||||||
|
{ role: "system", content: "USER_SYSTEM_PROMPT" },
|
||||||
|
{ role: "user", content: "hello" },
|
||||||
|
],
|
||||||
|
}, true, { projectId: "project-1", connectionId: "conn-1" });
|
||||||
|
|
||||||
|
const system = JSON.stringify(out.request.systemInstruction);
|
||||||
|
expect(system).toContain("USER_SYSTEM_PROMPT");
|
||||||
|
expect(system).not.toContain(ANTIGRAVITY_DEFAULT_SYSTEM);
|
||||||
|
expect(system).not.toContain("Please ignore the following [ignore]");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not inject the legacy Antigravity default system prompt for Claude-backed models", () => {
|
||||||
|
const out = openaiToAntigravityRequest("claude-opus-4-6-thinking", {
|
||||||
|
messages: [
|
||||||
|
{ role: "system", content: "USER_SYSTEM_PROMPT" },
|
||||||
|
{ role: "user", content: "hello" },
|
||||||
|
],
|
||||||
|
}, true, { projectId: "project-1", connectionId: "conn-1" });
|
||||||
|
|
||||||
|
const system = JSON.stringify(out.request.systemInstruction);
|
||||||
|
expect(system).toContain("USER_SYSTEM_PROMPT");
|
||||||
|
expect(system).not.toContain(ANTIGRAVITY_DEFAULT_SYSTEM);
|
||||||
|
expect(system).not.toContain("Please ignore the following [ignore]");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Guards D3: antigravity 429/503 retry merged into base via computeRetryDelay hook.
|
// Guards D3: antigravity 429/503 retry merged into base via computeRetryDelay hook.
|
||||||
import { describe, it, expect } from "vitest";
|
import { describe, it, expect } from "vitest";
|
||||||
import { AntigravityExecutor } from "../../open-sse/executors/antigravity.js";
|
import { AntigravityExecutor } from "../../open-sse/executors/antigravity.js";
|
||||||
|
import antigravity from "../../open-sse/providers/registry/antigravity.js";
|
||||||
|
|
||||||
const MAX = 10000;
|
const MAX = 10000;
|
||||||
function res(status, headers = {}, body = null) {
|
function res(status, headers = {}, body = null) {
|
||||||
@@ -66,9 +67,35 @@ describe("antigravity computeRetryDelay hook (D3)", () => {
|
|||||||
expect(out.request.tools[0].functionDeclarations.map(fn => fn.name)).toEqual(["read_file"]);
|
expect(out.request.tools[0].functionDeclarations.map(fn => fn.name)).toEqual(["read_file"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("buildHeaders includes cached session id after transformRequest", () => {
|
it("registry uses the official IDE cloudcode host and user agent", () => {
|
||||||
|
expect(antigravity.transport.baseUrls).toEqual(["https://cloudcode-pa.googleapis.com"]);
|
||||||
|
expect(antigravity.transport.headers["User-Agent"]).toBe("antigravity/ide/2.1.1 darwin/arm64");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("buildHeaders matches official IDE stream headers", () => {
|
||||||
ag._lastSessionId = "sess-123";
|
ag._lastSessionId = "sess-123";
|
||||||
const h = ag.buildHeaders({ accessToken: "tok" }, true);
|
const h = ag.buildHeaders({ accessToken: "tok" }, true);
|
||||||
expect(h["X-Machine-Session-Id"]).toBe("sess-123");
|
expect(h["User-Agent"]).toBe("antigravity/ide/2.1.1 darwin/arm64");
|
||||||
|
expect(h["Content-Type"]).toBe("application/json");
|
||||||
|
expect(h["Authorization"]).toBe("Bearer tok");
|
||||||
|
expect(h).not.toHaveProperty("X-Machine-Session-Id");
|
||||||
|
expect(h).not.toHaveProperty("x-request-source");
|
||||||
|
expect(h).not.toHaveProperty("Accept");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("transforms chat requests with official IDE requestId shape and 64000 token cap", () => {
|
||||||
|
const out = ag.transformRequest("claude-opus-4-6-thinking", {
|
||||||
|
request: {
|
||||||
|
contents: [
|
||||||
|
{ role: "user", parts: [{ text: "hi" }] },
|
||||||
|
{ role: "model", parts: [{ text: "hello" }] },
|
||||||
|
],
|
||||||
|
generationConfig: { maxOutputTokens: 90000 },
|
||||||
|
sessionId: "-3750763034362895579",
|
||||||
|
},
|
||||||
|
}, true, { projectId: "project-1", connectionId: "conn-1" });
|
||||||
|
|
||||||
|
expect(out.requestId).toMatch(/^agent\/[0-9a-f-]{36}\/\d{13}\/[0-9a-f-]{36}\/\d+$/);
|
||||||
|
expect(out.request.generationConfig.maxOutputTokens).toBe(64000);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||||
|
|
||||||
|
const proxyAwareFetch = vi.fn(async (url) => ({
|
||||||
|
ok: true,
|
||||||
|
status: 200,
|
||||||
|
json: async () => url.includes(":loadCodeAssist")
|
||||||
|
? { cloudaicompanionProject: "project-1", currentTier: { name: "Pro" } }
|
||||||
|
: { models: {} },
|
||||||
|
text: async () => "{}",
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("../../open-sse/utils/proxyFetch.js", () => ({
|
||||||
|
proxyAwareFetch,
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe("Antigravity usage headers", () => {
|
||||||
|
beforeEach(() => proxyAwareFetch.mockClear());
|
||||||
|
|
||||||
|
it("uses the official IDE user agent and omits router-only source headers", async () => {
|
||||||
|
const { getAntigravityUsage } = await import("../../open-sse/services/usage/google.js");
|
||||||
|
|
||||||
|
await getAntigravityUsage("access-token", {});
|
||||||
|
|
||||||
|
expect(proxyAwareFetch).toHaveBeenCalledTimes(2);
|
||||||
|
for (const [, options] of proxyAwareFetch.mock.calls) {
|
||||||
|
expect(options.headers["User-Agent"]).toBe("antigravity/ide/2.1.1 darwin/arm64");
|
||||||
|
expect(options.headers).not.toHaveProperty("x-request-source");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user