Fix thought_signature: it's a sibling of functionCall, not nested inside it

The Gemini REST API returns thoughtSignature as a sibling part field:
  { "functionCall": {...}, "thoughtSignature": "..." }
not inside functionCall. We were reading part.functionCall.thought_signature
(always undefined) and writing fc.thought_signature inside the functionCall
object (also wrong). Now correctly reads part.thoughtSignature and writes
part.thoughtSignature when building history.

Made-with: Cursor
This commit is contained in:
2026-04-27 17:28:49 -07:00
parent 8872ab606b
commit e08405ffbf

View File

@@ -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,
});
}
}