Gemini 3: function calls require thought_signature (400 error)
Hi! 👋
Firstly, thanks for your work on this project! 🙂
Today I used patch-package to patch @inngest/agent-kit@0.13.2 for the project I'm working on.
Problem: When using the Gemini adapter with Gemini 3 models (e.g. gemini-3-flash-preview), the API returns a 400 error:
Function call is missing a thought_signature in functionCall parts. This is required for tools to work correctly, and missing thought_signature may lead to degraded model performance.
Google’s docs: Thought Signatures | Gemini API. For Gemini 3, every functionCall part in conversation history must include a thoughtSignature. The adapter was neither capturing it from responses nor sending it on subsequent requests, so validation failed.
Fix (summary):
- Response parser – When the API returns a
functionCall part, read thoughtSignature / thought_signature from that part and store it on the tool-call message (e.g. as thought_signature on the first tool).
- Request builder – When building Gemini
contents, include thoughtSignature on every functionCall part: use the stored value when present, otherwise the documented dummy "skip_thought_signature_validator" so the request is accepted (e.g. first turn or history without signatures).
Here is the diff that solved my problem:
diff --git a/node_modules/@inngest/agent-kit/dist/chunk-BSWKEFTT.js b/node_modules/@inngest/agent-kit/dist/chunk-BSWKEFTT.js
index 50538d4..20cbda1 100644
--- a/node_modules/@inngest/agent-kit/dist/chunk-BSWKEFTT.js
+++ b/node_modules/@inngest/agent-kit/dist/chunk-BSWKEFTT.js
@@ -658,6 +658,7 @@ var responseParser4 = (input) => {
content: content.text
});
} else if (candidate.content.role === "model" && "functionCall" in content) {
+ const thoughtSignature = content.thoughtSignature ?? content.thought_signature;
messages.push({
role: "assistant",
type: "tool_call",
@@ -667,7 +668,8 @@ var responseParser4 = (input) => {
name: content.functionCall.name,
input: content.functionCall.args,
type: "tool",
- id: content.functionCall.name
+ id: content.functionCall.name,
+ ...(thoughtSignature != null && { thought_signature: thoughtSignature })
}
]
});
@@ -711,7 +713,10 @@ var messageToContent = (m) => {
functionCall: {
name: m.tools[0].name,
args: m.tools[0].input
- }
+ },
+ ...(m.tools[0].thought_signature != null
+ ? { thoughtSignature: m.tools[0].thought_signature }
+ : { thoughtSignature: "skip_thought_signature_validator" })
}
]
};
@@ -735,7 +740,10 @@ var messageToContent = (m) => {
functionCall: {
name: m.tools[0].name,
args: m.tools[0].input
- }
+ },
+ ...(m.tools[0].thought_signature != null
+ ? { thoughtSignature: m.tools[0].thought_signature }
+ : { thoughtSignature: "skip_thought_signature_validator" })
}
]
};
diff --git a/node_modules/@inngest/agent-kit/dist/index.cjs b/node_modules/@inngest/agent-kit/dist/index.cjs
index 2ecaa90..805ddf3 100644
--- a/node_modules/@inngest/agent-kit/dist/index.cjs
+++ b/node_modules/@inngest/agent-kit/dist/index.cjs
@@ -1476,6 +1476,7 @@ var responseParser4 = (input) => {
content: content.text
});
} else if (candidate.content.role === "model" && "functionCall" in content) {
+ const thoughtSignature = content.thoughtSignature ?? content.thought_signature;
messages.push({
role: "assistant",
type: "tool_call",
@@ -1485,7 +1486,8 @@ var responseParser4 = (input) => {
name: content.functionCall.name,
input: content.functionCall.args,
type: "tool",
- id: content.functionCall.name
+ id: content.functionCall.name,
+ ...(thoughtSignature != null && { thought_signature: thoughtSignature })
}
]
});
@@ -1529,7 +1531,10 @@ var messageToContent = (m) => {
functionCall: {
name: m.tools[0].name,
args: m.tools[0].input
- }
+ },
+ ...(m.tools[0].thought_signature != null
+ ? { thoughtSignature: m.tools[0].thought_signature }
+ : { thoughtSignature: "skip_thought_signature_validator" })
}
]
};
@@ -1553,7 +1558,10 @@ var messageToContent = (m) => {
functionCall: {
name: m.tools[0].name,
args: m.tools[0].input
- }
+ },
+ ...(m.tools[0].thought_signature != null
+ ? { thoughtSignature: m.tools[0].thought_signature }
+ : { thoughtSignature: "skip_thought_signature_validator" })
}
]
};
This issue body was partially generated by patch-package.
Gemini 3: function calls require
thought_signature(400 error)Hi! 👋
Firstly, thanks for your work on this project! 🙂
Today I used patch-package to patch
@inngest/agent-kit@0.13.2for the project I'm working on.Problem: When using the Gemini adapter with Gemini 3 models (e.g.
gemini-3-flash-preview), the API returns a 400 error:Google’s docs: Thought Signatures | Gemini API. For Gemini 3, every
functionCallpart in conversation history must include athoughtSignature. The adapter was neither capturing it from responses nor sending it on subsequent requests, so validation failed.Fix (summary):
functionCallpart, readthoughtSignature/thought_signaturefrom that part and store it on the tool-call message (e.g. asthought_signatureon the first tool).contents, includethoughtSignatureon everyfunctionCallpart: use the stored value when present, otherwise the documented dummy"skip_thought_signature_validator"so the request is accepted (e.g. first turn or history without signatures).Here is the diff that solved my problem:
This issue body was partially generated by patch-package.