diff --git a/.changeset/fix-google-thought-signature.md b/.changeset/fix-google-thought-signature.md new file mode 100644 index 00000000..15be3f53 --- /dev/null +++ b/.changeset/fix-google-thought-signature.md @@ -0,0 +1,5 @@ +--- +"perstack": patch +--- + +fix: support Google/Vertex thought_signature in multi-turn conversations with Gemini 3 models diff --git a/packages/core/src/schemas/message-part.ts b/packages/core/src/schemas/message-part.ts index 2dffd2d9..7c57eed5 100644 --- a/packages/core/src/schemas/message-part.ts +++ b/packages/core/src/schemas/message-part.ts @@ -129,6 +129,8 @@ export interface ToolCallPart extends BasePart { toolName: string /** Arguments to pass to the tool */ args: Record + /** Provider-specific metadata for this tool call (e.g., Google thought_signature) */ + providerMetadata?: Record> } export const toolCallPartSchema = basePartSchema.extend({ @@ -136,6 +138,7 @@ export const toolCallPartSchema = basePartSchema.extend({ toolCallId: z.string(), toolName: z.string(), args: z.record(z.string(), z.unknown()), + providerMetadata: z.record(z.string(), z.record(z.string(), z.unknown())).optional(), }) toolCallPartSchema satisfies z.ZodType diff --git a/packages/runtime/src/messages/message.ts b/packages/runtime/src/messages/message.ts index 3877e352..64206248 100644 --- a/packages/runtime/src/messages/message.ts +++ b/packages/runtime/src/messages/message.ts @@ -237,6 +237,7 @@ function toolCallPartToCoreToolCallPart(part: ToolCallPart): ToolCallModelPart { toolCallId: part.toolCallId, toolName: part.toolName, input: part.args, + providerOptions: part.providerMetadata as ToolCallModelPart["providerOptions"], } } function thinkingPartToCoreThinkingPart(part: ThinkingPart): { diff --git a/packages/runtime/src/state-machine/states/generating-tool-call.ts b/packages/runtime/src/state-machine/states/generating-tool-call.ts index 42eedaee..6e74c8b3 100644 --- a/packages/runtime/src/state-machine/states/generating-tool-call.ts +++ b/packages/runtime/src/state-machine/states/generating-tool-call.ts @@ -34,10 +34,16 @@ type ClassifiedToolCall = { toolName: string input: Record adapter: SkillAdapter + providerMetadata?: Record> } function classifyToolCalls( - toolCalls: Array<{ toolCallId: string; toolName: string; input: unknown }>, + toolCalls: Array<{ + toolCallId: string + toolName: string + input: unknown + providerMetadata?: Record> + }>, skillManager: SkillManager, ): ClassifiedToolCall[] { return toolCalls.map((tc) => { @@ -47,6 +53,7 @@ function classifyToolCalls( toolName: tc.toolName, input: tc.input as Record, adapter, + providerMetadata: tc.providerMetadata, } }) } @@ -64,6 +71,7 @@ function buildToolCallParts(toolCalls: ClassifiedToolCall[]): Array