Skip to content
This repository was archived by the owner on Feb 28, 2026. It is now read-only.

Commit ff2552e

Browse files
authored
fix(antigravity): update handling for new Antigravity API structure (#25)
1 parent 8314ac6 commit ff2552e

7 files changed

Lines changed: 115 additions & 6 deletions

File tree

bun.lock

Lines changed: 3 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/plugin/request-helpers.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,43 @@ export function generateRequestId(): string {
1111
return `agent-${randomUUID()}`;
1212
}
1313

14+
export const ANTIGRAVITY_BASE_SYSTEM_INSTRUCTION =
15+
"You are Antigravity, a powerful agentic AI coding assistant designed by the Google Deepmind team working on Advanced Agentic Coding.You are pair programming with a USER to solve their coding task. The task may require creating a new codebase, modifying or debugging an existing codebase, or simply answering a question.**Absolute paths only****Proactiveness**";
16+
17+
export function applyAntigravitySystemInstruction(payload: Record<string, unknown>, model: string): void {
18+
const normalizedModel = model.toLowerCase();
19+
const needsInjection = normalizedModel.includes("claude")
20+
|| normalizedModel.includes("gemini-3-pro")
21+
|| normalizedModel.includes("gemini-3-flash");
22+
if (!needsInjection) {
23+
return;
24+
}
25+
26+
const existing = payload.systemInstruction;
27+
let existingParts: Array<Record<string, unknown>> = [];
28+
let existingRecord: Record<string, unknown> | undefined;
29+
30+
if (typeof existing === "string") {
31+
if (existing.length > 0) {
32+
existingParts = [{ text: existing }];
33+
}
34+
} else if (existing && typeof existing === "object") {
35+
existingRecord = existing as Record<string, unknown>;
36+
const parts = existingRecord.parts;
37+
if (Array.isArray(parts)) {
38+
existingParts = parts.filter(
39+
(part): part is Record<string, unknown> => typeof part === "object" && part !== null,
40+
);
41+
}
42+
}
43+
44+
const nextParts = [{ text: ANTIGRAVITY_BASE_SYSTEM_INSTRUCTION }, ...existingParts];
45+
46+
payload.systemInstruction = existingRecord
47+
? { ...existingRecord, role: "user", parts: nextParts }
48+
: { role: "user", parts: nextParts };
49+
}
50+
1451
const GEMINI_PREVIEW_LINK = "https://goo.gle/enable-preview-features";
1552

1653
export interface GeminiApiError {

src/plugin/request.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,20 @@ describe("URL Transformation", () => {
132132

133133
expect(result.requestedModel).toBe("gemini-3-flash");
134134
});
135+
136+
test("aliases gemini-3-flash-preview to gemini-3-flash", async () => {
137+
const url = "https://generativelanguage.googleapis.com/v1beta/models/gemini-3-flash-preview:generateContent";
138+
139+
const result = await prepareAntigravityRequest(
140+
url,
141+
{ method: "POST", body: JSON.stringify({ contents: [] }) },
142+
"dummy-token",
143+
"dummy-project"
144+
);
145+
146+
const body = JSON.parse(result.init.body as string);
147+
expect(body.model).toBe("gemini-3-flash");
148+
});
135149
});
136150

137151
describe("Endpoint Fallback Override", () => {

src/plugin/request.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ const MODEL_ALIASES: Record<string, string> = {
2929
"gemini-2.5-computer-use-preview-10-2025": "rev19-uic3-1p",
3030
"gemini-3-pro-image-preview": "gemini-3-pro-image",
3131
"gemini-3-pro-preview": "gemini-3-pro-high",
32+
"gemini-3-flash-preview": "gemini-3-flash",
3233
"gemini-claude-sonnet-4-5": "claude-sonnet-4-5",
3334
"gemini-claude-sonnet-4-5-thinking": "claude-sonnet-4-5-thinking",
3435
"gemini-claude-opus-4-5-thinking": "claude-opus-4-5-thinking",

src/plugin/transform/claude.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { randomUUID } from "node:crypto";
22
import { cacheSignature, getCachedSignature } from "../cache";
33
import { createLogger } from "../logger";
4-
import { normalizeThinkingConfig } from "../request-helpers";
4+
import { applyAntigravitySystemInstruction, normalizeThinkingConfig } from "../request-helpers";
55
import { cacheToolSchemas } from "../tool-schema-cache";
66
import type { RequestPayload, TransformContext, TransformResult } from "./types";
77

@@ -161,6 +161,8 @@ export function transformClaudeRequest(
161161
delete requestPayload.system_instruction;
162162
}
163163

164+
applyAntigravitySystemInstruction(requestPayload, context.model);
165+
164166
const cachedContentFromExtra =
165167
typeof requestPayload.extra_body === "object" && requestPayload.extra_body
166168
? (requestPayload.extra_body as Record<string, unknown>).cached_content ??
@@ -316,6 +318,7 @@ export function transformClaudeRequest(
316318
project: context.projectId,
317319
model: context.model,
318320
userAgent: "antigravity",
321+
requestType: "agent",
319322
requestId: context.requestId,
320323
request: requestPayload,
321324
};

src/plugin/transform/gemini.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { getCachedSignature } from "../cache";
22
import { createLogger } from "../logger";
3-
import { normalizeThinkingConfig } from "../request-helpers";
3+
import { applyAntigravitySystemInstruction, normalizeThinkingConfig } from "../request-helpers";
44
import { cacheToolSchemas } from "../tool-schema-cache";
55
import type { RequestPayload, TransformContext, TransformResult } from "./types";
66

@@ -531,6 +531,7 @@ export function transformGeminiRequest(
531531
augmentToolDescriptionsWithStrictParams(requestPayload);
532532
injectSystemInstructionIfNeeded(requestPayload);
533533
scrubConversationArtifactsFromModelHistory(requestPayload);
534+
applyAntigravitySystemInstruction(requestPayload, context.model);
534535

535536
const contents = requestPayload.contents as Array<Record<string, unknown>> | undefined;
536537
if (Array.isArray(contents)) {
@@ -638,6 +639,7 @@ export function transformGeminiRequest(
638639
project: context.projectId,
639640
model: context.model,
640641
userAgent: "antigravity",
642+
requestType: "agent",
641643
requestId: context.requestId,
642644
request: requestPayload,
643645
};

src/plugin/transform/signature.test.ts

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { describe, expect, it } from "bun:test";
22

33
import { cacheSignature } from "../cache";
4-
import { normalizeToolCallArgs, recursivelyParseJsonStrings } from "../request-helpers";
4+
import { ANTIGRAVITY_BASE_SYSTEM_INSTRUCTION, normalizeToolCallArgs, recursivelyParseJsonStrings } from "../request-helpers";
55
import { cacheToolSchemas, clearToolSchemaCache } from "../tool-schema-cache";
66
import { transformClaudeRequest } from "./claude";
77
import { transformGeminiRequest } from "./gemini";
@@ -139,6 +139,38 @@ describe("thoughtSignature handling", () => {
139139
const userParts = contents[0].parts;
140140
expect(userParts[0].thoughtSignature).toBe("user-sig-should-stay");
141141
});
142+
143+
it("prepends Antigravity systemInstruction and requestType for gemini-3-pro", () => {
144+
const payload: RequestPayload = {
145+
systemInstruction: { parts: [{ text: "Existing instruction" }] },
146+
contents: [{ role: "user", parts: [{ text: "hi" }] }],
147+
};
148+
149+
const context = createContext("gemini-3-pro-high");
150+
const result = transformGeminiRequest(context, payload);
151+
const parsed = JSON.parse(result.body);
152+
153+
expect(parsed.requestType).toBe("agent");
154+
expect(parsed.request.systemInstruction.role).toBe("user");
155+
expect(parsed.request.systemInstruction.parts[0].text).toBe(ANTIGRAVITY_BASE_SYSTEM_INSTRUCTION);
156+
expect(parsed.request.systemInstruction.parts[1].text).toBe("Existing instruction");
157+
});
158+
159+
it("prepends Antigravity systemInstruction and requestType for gemini-3-flash-preview", () => {
160+
const payload: RequestPayload = {
161+
systemInstruction: { parts: [{ text: "Existing instruction" }] },
162+
contents: [{ role: "user", parts: [{ text: "hi" }] }],
163+
};
164+
165+
const context = createContext("gemini-3-flash-preview");
166+
const result = transformGeminiRequest(context, payload);
167+
const parsed = JSON.parse(result.body);
168+
169+
expect(parsed.requestType).toBe("agent");
170+
expect(parsed.request.systemInstruction.role).toBe("user");
171+
expect(parsed.request.systemInstruction.parts[0].text).toBe(ANTIGRAVITY_BASE_SYSTEM_INSTRUCTION);
172+
expect(parsed.request.systemInstruction.parts[1].text).toBe("Existing instruction");
173+
});
142174
});
143175

144176
describe("tool schema mitigations", () => {
@@ -177,7 +209,10 @@ describe("thoughtSignature handling", () => {
177209
const result = transformGeminiRequest(context, payload);
178210
const parsed = JSON.parse(result.body);
179211

180-
expect(parsed.request.systemInstruction.parts[0].text).toContain("<CRITICAL_TOOL_USAGE_INSTRUCTIONS>");
212+
const instructionText = parsed.request.systemInstruction.parts
213+
.map((part: any) => part.text ?? "")
214+
.join("\n");
215+
expect(instructionText).toContain("<CRITICAL_TOOL_USAGE_INSTRUCTIONS>");
181216
const funcDecl = parsed.request.tools[0].functionDeclarations[0];
182217
expect(funcDecl.description).toContain("STRICT PARAMETERS:");
183218
expect(funcDecl.description).toContain("filePath");
@@ -306,6 +341,22 @@ describe("thoughtSignature handling", () => {
306341
});
307342

308343
describe("claude transformer", () => {
344+
it("prepends Antigravity systemInstruction and requestType for claude models", () => {
345+
const payload: RequestPayload = {
346+
systemInstruction: "Existing instruction",
347+
contents: [{ role: "user", parts: [{ text: "Hello" }] }],
348+
};
349+
350+
const context = createContext("gemini-claude-sonnet-4-5");
351+
const result = transformClaudeRequest(context, payload);
352+
const parsed = JSON.parse(result.body);
353+
354+
expect(parsed.requestType).toBe("agent");
355+
expect(parsed.request.systemInstruction.role).toBe("user");
356+
expect(parsed.request.systemInstruction.parts[0].text).toBe(ANTIGRAVITY_BASE_SYSTEM_INSTRUCTION);
357+
expect(parsed.request.systemInstruction.parts[1].text).toBe("Existing instruction");
358+
});
359+
309360
it("keeps thinking blocks with valid signatures (length > 50)", () => {
310361
const payload: RequestPayload = {
311362
contents: [

0 commit comments

Comments
 (0)