diff --git a/lib/ai/gemini-chat.ts b/lib/ai/gemini-chat.ts index 0ccb3f3b..d693e9c5 100644 --- a/lib/ai/gemini-chat.ts +++ b/lib/ai/gemini-chat.ts @@ -55,20 +55,22 @@ function toGeminiContents(messages: ChatMessage[]) { if (msg.content) parts.push({ text: msg.content }); if (msg.toolCalls?.length) { for (const tc of msg.toolCalls) { - const fc: any = { name: tc.name, args: tc.args, id: tc.id }; - if (tc.thoughtSignature) fc.thought_signature = tc.thoughtSignature; - parts.push({ functionCall: fc }); + // thoughtSignature is a SIBLING of functionCall in the part object, + // not nested inside it. See: ai.google.dev/gemini-api/docs/thought-signatures + const part: any = { functionCall: { name: tc.name, args: tc.args, id: tc.id } }; + if (tc.thoughtSignature) part.thoughtSignature = tc.thoughtSignature; + parts.push(part); } } if (parts.length) contents.push({ role: 'model', parts }); } else if (msg.role === 'tool') { - const fr: any = { - name: msg.toolName || 'unknown', - id: msg.toolCallId, - response: { content: msg.content }, + const part = { + functionResponse: { + name: msg.toolName || 'unknown', + id: msg.toolCallId, + response: { content: msg.content }, + }, }; - if (msg.thoughtSignature) fr.thought_signature = msg.thoughtSignature; - const part = { functionResponse: fr }; const last = contents[contents.length - 1]; if (last?.role === 'user') { last.parts.push(part); @@ -147,7 +149,8 @@ export async function callGeminiChat(opts: { id: part.functionCall.id || `tc-${Date.now()}-${Math.random().toString(36).slice(2)}`, name: part.functionCall.name, args: part.functionCall.args ?? {}, - thoughtSignature: part.functionCall.thought_signature, + // thoughtSignature is a SIBLING of functionCall in the part, not inside it + thoughtSignature: part.thoughtSignature, }); } }