fix: strip x-goog-user-project header to enable opus 4.6 on Daily endpoint

- Strip x-goog-user-project header ONLY for antigravity headerStyle (Daily endpoint)
- Keep the header for gemini-cli style (Prod endpoint) where it may be needed for billing/quota
- Add test coverage for both headerStyle behaviors

Root cause:
The x-goog-user-project header (added by OpenCode/AI SDK) causes 403 Forbidden
errors on the Daily sandbox endpoint. This triggers fallback to Prod endpoint,
but claude-opus-4-6-thinking is only available on Daily, resulting in 404 errors.

By stripping this header only for antigravity requests, Daily endpoint works
while preserving potential billing/quota functionality for gemini-cli requests.

Fixes #410
This commit is contained in:
Chirag Panwar
2026-02-10 15:52:53 +05:30
parent e7c12d7523
commit 53e3efdfc4
2 changed files with 34 additions and 1 deletions

View File

@@ -572,7 +572,7 @@ describe("request.ts", () => {
expect(headers.get("Authorization")).toBe("Bearer test-token");
});
it("removes x-api-key header", () => {
it("removes x-api-key header", () => {
const result = prepareAntigravityRequest(
"https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent",
{ method: "POST", body: JSON.stringify({ contents: [] }), headers: { "x-api-key": "old-key" } },
@@ -583,6 +583,32 @@ describe("request.ts", () => {
expect(headers.get("x-api-key")).toBeNull();
});
it("removes x-goog-user-project header for antigravity headerStyle", () => {
const result = prepareAntigravityRequest(
"https://generativelanguage.googleapis.com/v1beta/models/claude-opus-4-6-thinking:generateContent",
{ method: "POST", body: JSON.stringify({ contents: [] }), headers: { "x-goog-user-project": "my-project" } },
mockAccessToken,
mockProjectId,
undefined,
"antigravity"
);
const headers = result.init.headers as Headers;
expect(headers.get("x-goog-user-project")).toBeNull();
});
it("preserves x-goog-user-project header for gemini-cli headerStyle", () => {
const result = prepareAntigravityRequest(
"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent",
{ method: "POST", body: JSON.stringify({ contents: [] }), headers: { "x-goog-user-project": "my-project" } },
mockAccessToken,
mockProjectId,
undefined,
"gemini-cli"
);
const headers = result.init.headers as Headers;
expect(headers.get("x-goog-user-project")).toBe("my-project");
});
it("identifies Claude models correctly", () => {
const result = prepareAntigravityRequest(
"https://generativelanguage.googleapis.com/v1beta/models/claude-sonnet-4-20250514:generateContent",

View File

@@ -655,6 +655,13 @@ export function prepareAntigravityRequest(
headers.set("Authorization", `Bearer ${accessToken}`);
headers.delete("x-api-key");
// Strip x-goog-user-project for antigravity headerStyle (Daily endpoint) to prevent 403 errors.
// This header is added by OpenCode/AI SDK but causes auth conflicts on sandbox endpoints.
// Models like claude-opus-4-6-thinking are only available on Daily, so this enables them to work.
// Keep the header for gemini-cli style (Prod endpoint) where it may be needed for billing/quota.
if (headerStyle === "antigravity") {
headers.delete("x-goog-user-project");
}
const match = input.match(/\/models\/([^:]+):(\w+)/);
if (!match) {