mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-11 09:42:15 +03:00
fix(sse): move Antigravity client system content to first user message to avoid upstream 429 (#9030)
Closes #9030
This commit is contained in:
committed by
GitHub
parent
ebf151e057
commit
ff679ab86e
1
changelog.d/fixes/9030-antigravity-system-429s.md
Normal file
1
changelog.d/fixes/9030-antigravity-system-429s.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(sse): move Antigravity client system content to first user message to avoid upstream 429 RESOURCE_EXHAUSTED on oversized systemInstruction (#9030)
|
||||
@@ -734,11 +734,24 @@ function wrapInCloudCodeEnvelope(model, cloudCodeRequest, credentials = null) {
|
||||
envelope._toolNameMap = cloudCodeRequest._toolNameMap;
|
||||
}
|
||||
|
||||
// #9030 — Client system content must NOT be combined with default in systemInstruction
|
||||
//
|
||||
// The upstream Antigravity / Cloud Code endpoint rejects oversized systemInstruction
|
||||
// with 429 RESOURCE_EXHAUSTED. Keep only the lightweight ANTIGRAVITY_DEFAULT_SYSTEM
|
||||
// in systemInstruction and relocate any client system content (which can be very
|
||||
// large — Hermes ~125k tokens) to the first user message.
|
||||
const defaultPart: GeminiPart = { text: ANTIGRAVITY_DEFAULT_SYSTEM };
|
||||
if (envelope.request.systemInstruction?.parts) {
|
||||
envelope.request.systemInstruction.parts.unshift(defaultPart);
|
||||
} else {
|
||||
envelope.request.systemInstruction = { role: "system", parts: [defaultPart] };
|
||||
const clientParts = envelope.request.systemInstruction?.parts?.slice() ?? [];
|
||||
envelope.request.systemInstruction = { role: "system", parts: [defaultPart] };
|
||||
|
||||
if (clientParts.length > 0) {
|
||||
// Prepend client system parts to the first user message so they still guide
|
||||
// the model's behavior early in the conversation.
|
||||
if (envelope.request.contents && envelope.request.contents.length > 0) {
|
||||
envelope.request.contents[0].parts.unshift(...clientParts);
|
||||
} else {
|
||||
envelope.request.contents = [{ role: "user", parts: [...clientParts] }];
|
||||
}
|
||||
}
|
||||
|
||||
// Strip Gemini built-in tool *names* out of functionDeclarations: Antigravity's
|
||||
|
||||
131
tests/unit/repro-9030-antigravity-system-429s.test.ts
Normal file
131
tests/unit/repro-9030-antigravity-system-429s.test.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
const { openaiToAntigravityRequest } =
|
||||
await import("../../open-sse/translator/request/openai-to-gemini.ts");
|
||||
const { ANTIGRAVITY_DEFAULT_SYSTEM } = await import("../../open-sse/config/constants.ts");
|
||||
|
||||
type PartsArray = Array<{ text?: string; functionCall?: unknown; functionResponse?: unknown }>;
|
||||
|
||||
/**
|
||||
* #9030 — Hermes + Antigravity system messages cause 429s
|
||||
*
|
||||
* Root cause: openai-to-gemini.ts's wrapInCloudCodeEnvelope prepends
|
||||
* ANTIGRAVITY_DEFAULT_SYSTEM to systemInstruction.parts that already contain
|
||||
* the client's system message. This doubles the systemInstruction size well
|
||||
* beyond what the upstream Antigravity/Google Cloud Code endpoint accepts,
|
||||
* causing a 429 RESOURCE_EXHAUSTED.
|
||||
*
|
||||
* Fix: move client system content to the first user message and keep only the
|
||||
* default system in systemInstruction.
|
||||
*
|
||||
* This repro test asserts that the fix is in place — after translation, the
|
||||
* systemInstruction contains ONLY ANTIGRAVITY_DEFAULT_SYSTEM, and the client's
|
||||
* system text is in contents[0].
|
||||
*/
|
||||
test("OpenAI -> Antigravity: client system message must NOT be in systemInstruction with default (#9030)", () => {
|
||||
const result = openaiToAntigravityRequest(
|
||||
"gemini-2.5-flash",
|
||||
{
|
||||
messages: [
|
||||
{ role: "system", content: "You are a helpful assistant specialized in coding tasks." },
|
||||
{ role: "user", content: "Write a function to sort an array." },
|
||||
],
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
// systemInstruction must contain ONLY the ANTIGRAVITY_DEFAULT_SYSTEM
|
||||
assert.ok(result.request.systemInstruction, "systemInstruction must exist");
|
||||
assert.equal(
|
||||
result.request.systemInstruction.parts.length,
|
||||
1,
|
||||
"systemInstruction must have exactly 1 part (only ANTIGRAVITY_DEFAULT_SYSTEM)"
|
||||
);
|
||||
assert.equal(
|
||||
result.request.systemInstruction.parts[0].text,
|
||||
ANTIGRAVITY_DEFAULT_SYSTEM,
|
||||
"systemInstruction must contain only ANTIGRAVITY_DEFAULT_SYSTEM"
|
||||
);
|
||||
|
||||
// The client system message must be moved to the first user content
|
||||
const parts = result.request.contents[0]?.parts as PartsArray | undefined;
|
||||
assert.ok(parts, "contents[0] must exist");
|
||||
const firstUserText = parts.map((p) => p.text ?? "").join("");
|
||||
assert.ok(
|
||||
firstUserText.includes("You are a helpful assistant specialized in coding tasks."),
|
||||
"client system text must be in first user message contents[0]"
|
||||
);
|
||||
assert.ok(
|
||||
firstUserText.includes("Write a function to sort an array."),
|
||||
"user message must also be in contents[0]"
|
||||
);
|
||||
});
|
||||
|
||||
test("OpenAI -> Antigravity: systemInstruction with only ANTIGRAVITY_DEFAULT_SYSTEM when no client system (#9030)", () => {
|
||||
const result = openaiToAntigravityRequest(
|
||||
"gemini-2.5-flash",
|
||||
{
|
||||
messages: [
|
||||
{ role: "user", content: "Hello, how are you?" },
|
||||
],
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
// systemInstruction must still have only the ANTIGRAVITY_DEFAULT_SYSTEM
|
||||
assert.ok(result.request.systemInstruction, "systemInstruction must exist");
|
||||
assert.equal(
|
||||
result.request.systemInstruction.parts.length,
|
||||
1,
|
||||
"systemInstruction must have exactly 1 part"
|
||||
);
|
||||
assert.equal(
|
||||
result.request.systemInstruction.parts[0].text,
|
||||
ANTIGRAVITY_DEFAULT_SYSTEM,
|
||||
"systemInstruction must contain ANTIGRAVITY_DEFAULT_SYSTEM"
|
||||
);
|
||||
});
|
||||
|
||||
test("OpenAI -> Antigravity: multiple system messages all moved to first user content (#9030)", () => {
|
||||
const result = openaiToAntigravityRequest(
|
||||
"gemini-2.5-flash",
|
||||
{
|
||||
messages: [
|
||||
{ role: "system", content: "Rule one: be concise." },
|
||||
{ role: "system", content: "Rule two: use TypeScript." },
|
||||
{ role: "user", content: "Write code." },
|
||||
],
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
// systemInstruction must contain ONLY ANTIGRAVITY_DEFAULT_SYSTEM
|
||||
assert.equal(
|
||||
result.request.systemInstruction.parts.length,
|
||||
1,
|
||||
"systemInstruction must have exactly 1 part"
|
||||
);
|
||||
assert.equal(
|
||||
result.request.systemInstruction.parts[0].text,
|
||||
ANTIGRAVITY_DEFAULT_SYSTEM,
|
||||
"systemInstruction must contain only ANTIGRAVITY_DEFAULT_SYSTEM"
|
||||
);
|
||||
|
||||
// The combined system messages + user message must be in contents[0]
|
||||
const parts = result.request.contents[0]?.parts as PartsArray | undefined;
|
||||
assert.ok(parts, "contents[0] must exist");
|
||||
const firstUserText = parts.map((p) => p.text ?? "").join("");
|
||||
assert.ok(
|
||||
firstUserText.includes("Rule one: be concise."),
|
||||
"first system text must be in contents[0]"
|
||||
);
|
||||
assert.ok(
|
||||
firstUserText.includes("Rule two: use TypeScript."),
|
||||
"second system text must be in contents[0]"
|
||||
);
|
||||
assert.ok(
|
||||
firstUserText.includes("Write code."),
|
||||
"user message must be in contents[0]"
|
||||
);
|
||||
});
|
||||
@@ -863,7 +863,10 @@ test("OpenAI -> Antigravity maps Claude-family models to Gemini-compatible schem
|
||||
assert.match(result.requestId, /^agent\/\d+\/[0-9a-f]{8}$/);
|
||||
assert.equal(result.enabledCreditTypes, undefined);
|
||||
assert.equal(result.request.systemInstruction.parts[0].text, ANTIGRAVITY_DEFAULT_SYSTEM);
|
||||
assert.equal(result.request.systemInstruction.parts[1].text, "Project rules");
|
||||
assert.equal(result.request.systemInstruction.parts.length, 1, "systemInstruction must contain only ANTIGRAVITY_DEFAULT_SYSTEM (#9030)");
|
||||
// #9030 — Client system content moved to first user message to avoid upstream 429s
|
||||
assert.equal(result.request.contents[0].parts[0].text, "Project rules");
|
||||
assert.equal(result.request.contents[0].parts[1].text, "Read a file");
|
||||
assert.equal((result as any).request?.generationConfig.maxOutputTokens, undefined);
|
||||
assert.equal((result as any).request?.messages, undefined);
|
||||
assert.equal((result as any).request?.system, undefined);
|
||||
|
||||
Reference in New Issue
Block a user