mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-05-22 18:45:19 +02:00
fix: merge consecutive tool results for Anthropic API compatibility
When the Anthropic API returns multiple parallel tool calls in a single assistant message, all tool_result blocks must be sent together in the next message. Previously, each tool result was sent as a separate message, causing Anthropic's API to reject the request with: "tool_use ids were found without tool_result blocks immediately after" This change modifies convertFromMessages() to merge consecutive tool messages into a single message containing all tool_result content blocks. Fixes #375
This commit is contained in:
parent
6244ea19fb
commit
793a07904f
1 changed files with 41 additions and 13 deletions
|
|
@ -354,7 +354,8 @@ export async function loadAgent(id: string): Promise<z.infer<typeof Agent>> {
|
||||||
|
|
||||||
export function convertFromMessages(messages: z.infer<typeof Message>[]): ModelMessage[] {
|
export function convertFromMessages(messages: z.infer<typeof Message>[]): ModelMessage[] {
|
||||||
const result: ModelMessage[] = [];
|
const result: ModelMessage[] = [];
|
||||||
for (const msg of messages) {
|
for (let i = 0; i < messages.length; i++) {
|
||||||
|
const msg = messages[i];
|
||||||
const { providerOptions } = msg;
|
const { providerOptions } = msg;
|
||||||
switch (msg.role) {
|
switch (msg.role) {
|
||||||
case "assistant":
|
case "assistant":
|
||||||
|
|
@ -401,11 +402,19 @@ export function convertFromMessages(messages: z.infer<typeof Message>[]): ModelM
|
||||||
providerOptions,
|
providerOptions,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "tool":
|
case "tool": {
|
||||||
result.push({
|
// Collect all consecutive tool messages into a single message
|
||||||
role: "tool",
|
// This is required by Anthropic's API which expects all tool_result blocks
|
||||||
content: [
|
// for parallel tool calls to be in a single message
|
||||||
{
|
const toolResults: Array<{
|
||||||
|
type: "tool-result";
|
||||||
|
toolCallId: string;
|
||||||
|
toolName: string;
|
||||||
|
output: { type: "text"; value: string };
|
||||||
|
}> = [];
|
||||||
|
|
||||||
|
// Add current tool message
|
||||||
|
toolResults.push({
|
||||||
type: "tool-result",
|
type: "tool-result",
|
||||||
toolCallId: msg.toolCallId,
|
toolCallId: msg.toolCallId,
|
||||||
toolName: msg.toolName,
|
toolName: msg.toolName,
|
||||||
|
|
@ -413,13 +422,32 @@ export function convertFromMessages(messages: z.infer<typeof Message>[]): ModelM
|
||||||
type: "text",
|
type: "text",
|
||||||
value: msg.content,
|
value: msg.content,
|
||||||
},
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Collect any consecutive tool messages
|
||||||
|
while (i + 1 < messages.length && messages[i + 1].role === "tool") {
|
||||||
|
i++;
|
||||||
|
const nextMsg = messages[i] as z.infer<typeof ToolMessage>;
|
||||||
|
toolResults.push({
|
||||||
|
type: "tool-result",
|
||||||
|
toolCallId: nextMsg.toolCallId,
|
||||||
|
toolName: nextMsg.toolName,
|
||||||
|
output: {
|
||||||
|
type: "text",
|
||||||
|
value: nextMsg.content,
|
||||||
},
|
},
|
||||||
],
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push({
|
||||||
|
role: "tool",
|
||||||
|
content: toolResults,
|
||||||
providerOptions,
|
providerOptions,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// doing this because: https://github.com/OpenRouterTeam/ai-sdk-provider/issues/262
|
// doing this because: https://github.com/OpenRouterTeam/ai-sdk-provider/issues/262
|
||||||
return JSON.parse(JSON.stringify(result));
|
return JSON.parse(JSON.stringify(result));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue