diff --git a/packages/ai/src/providers/google-antigravity-forced-tool.md b/packages/ai/src/providers/google-antigravity-forced-tool.md new file mode 100644 index 000000000..4b95cd331 --- /dev/null +++ b/packages/ai/src/providers/google-antigravity-forced-tool.md @@ -0,0 +1 @@ +TOOL-ONLY TURN. This turn accepts a tool call and nothing else; a text reply here is discarded unread and you will be re-prompted. Emit the tool call now. diff --git a/packages/ai/src/providers/google-gemini-cli.ts b/packages/ai/src/providers/google-gemini-cli.ts index 3071e2846..47cb48efc 100644 --- a/packages/ai/src/providers/google-gemini-cli.ts +++ b/packages/ai/src/providers/google-gemini-cli.ts @@ -14,6 +14,7 @@ import { getGeminiCliHeaders, } from "@oh-my-pi/pi-catalog/wire/gemini-headers"; import { extractHttpStatusFromError, fetchWithRetry, readSseJson } from "@oh-my-pi/pi-utils"; +import forcedToolDirective from "./google-antigravity-forced-tool.md" with { type: "text" }; import * as AIError from "../error"; import type { Api, @@ -1347,6 +1348,13 @@ export function buildRequest( }, }; } + // Cloud Code Assist drops `toolConfig` on Antigravity's Gemini routes: + // the backend answers in text under `mode: "ANY"` and still emits calls + // under `"NONE"`. Claude routes implement it, so only Gemini needs the + // forced choice restated in the transcript. + if (isAntigravity && !isClaudeModel(model.id) && request.toolConfig?.functionCallingConfig.mode === "ANY") { + contents.push({ role: "user", parts: [{ text: forcedToolDirective }] }); + } } // Antigravity's default tool mode is VALIDATED (verified for Gemini and // Claude); an explicit non-auto tool choice above wins.