fix(ai): keep tools when Gemini tool choice is none (#38556)

This commit is contained in:
Aiden Cline 2026-07-23 14:09:25 -05:00 committed by GitHub
commit 193f6be99c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 8 additions and 6 deletions

View file

@ -313,7 +313,7 @@ const thinkingConfig = (request: LLMRequest) => {
} }
const fromRequest = Effect.fn("Gemini.fromRequest")(function* (request: LLMRequest) { const fromRequest = Effect.fn("Gemini.fromRequest")(function* (request: LLMRequest) {
const toolsEnabled = request.tools.length > 0 && request.toolChoice?.type !== "none" const hasTools = request.tools.length > 0
const generation = request.generation const generation = request.generation
const toolSchemaCompatibility = request.model.compatibility?.toolSchema const toolSchemaCompatibility = request.model.compatibility?.toolSchema
const generationConfig = { const generationConfig = {
@ -329,7 +329,7 @@ const fromRequest = Effect.fn("Gemini.fromRequest")(function* (request: LLMReque
contents: yield* lowerMessages(request), contents: yield* lowerMessages(request),
systemInstruction: systemInstruction:
request.system.length === 0 ? undefined : { parts: [{ text: ProviderShared.joinText(request.system) }] }, request.system.length === 0 ? undefined : { parts: [{ text: ProviderShared.joinText(request.system) }] },
tools: toolsEnabled tools: hasTools
? [ ? [
{ {
functionDeclarations: request.tools.map((tool) => functionDeclarations: request.tools.map((tool) =>
@ -338,7 +338,7 @@ const fromRequest = Effect.fn("Gemini.fromRequest")(function* (request: LLMReque
}, },
] ]
: undefined, : undefined,
toolConfig: toolsEnabled && request.toolChoice ? yield* lowerToolConfig(request.toolChoice) : undefined, toolConfig: hasTools && request.toolChoice ? yield* lowerToolConfig(request.toolChoice) : undefined,
generationConfig: Object.values(generationConfig).some((value) => value !== undefined) generationConfig: Object.values(generationConfig).some((value) => value !== undefined)
? generationConfig ? generationConfig
: undefined, : undefined,

View file

@ -233,11 +233,11 @@ describe("Gemini route", () => {
}), }),
) )
it.effect("omits tools when tool choice is none", () => it.effect("keeps tools and sends function calling mode NONE", () =>
Effect.gen(function* () { Effect.gen(function* () {
const prepared = yield* LLMClient.prepare( const prepared = yield* LLMClient.prepare(
LLM.request({ LLM.request({
id: "req_no_tools", id: "req_tool_choice_none",
model, model,
prompt: "Say hello.", prompt: "Say hello.",
tools: [{ name: "lookup", description: "Lookup data", inputSchema: { type: "object" } }], tools: [{ name: "lookup", description: "Lookup data", inputSchema: { type: "object" } }],
@ -245,8 +245,10 @@ describe("Gemini route", () => {
}), }),
) )
expect(prepared.body).toEqual({ expect(prepared.body).toMatchObject({
contents: [{ role: "user", parts: [{ text: "Say hello." }] }], contents: [{ role: "user", parts: [{ text: "Say hello." }] }],
tools: [{ functionDeclarations: [{ name: "lookup", description: "Lookup data" }] }],
toolConfig: { functionCallingConfig: { mode: "NONE" } },
}) })
}), }),
) )