Skip to content
This repository was archived by the owner on May 15, 2026. It is now read-only.

Commit 3b31b37

Browse files
committed
fix: resolve AI_InvalidPromptError in OpenRouter AI SDK tool results
- Fixed tool result output format to use typed object { type: 'text', value: string } instead of plain string to satisfy AI SDK validation schema - Added tool name resolution by building a map of tool call IDs to names - Updated tests to reflect new output format
1 parent 0d2db24 commit 3b31b37

3 files changed

Lines changed: 69 additions & 6 deletions

File tree

src/api/providers/openrouter.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import {
66
type ModelRecord,
77
openRouterDefaultModelId,
88
openRouterDefaultModelInfo,
9-
NATIVE_TOOL_DEFAULTS,
109
OPENROUTER_DEFAULT_PROVIDER_NAME,
1110
DEEP_SEEK_DEFAULT_TEMPERATURE,
1211
} from "@roo-code/types"
@@ -183,7 +182,7 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH
183182
}
184183

185184
// Apply tool preferences for models accessed through routers
186-
info = applyRouterToolPreferences(id, { ...NATIVE_TOOL_DEFAULTS, ...info })
185+
info = applyRouterToolPreferences(id, info)
187186

188187
const isDeepSeekR1 = id.startsWith("deepseek/deepseek-r1") || id === "perplexity/sonar-reasoning"
189188

src/api/transform/__tests__/ai-sdk.spec.ts

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,19 @@ describe("AI SDK conversion utilities", () => {
8181
})
8282
})
8383

84-
it("converts tool results into separate tool messages", () => {
84+
it("converts tool results into separate tool messages with resolved tool names", () => {
8585
const messages: Anthropic.Messages.MessageParam[] = [
86+
{
87+
role: "assistant",
88+
content: [
89+
{
90+
type: "tool_use",
91+
id: "call_123",
92+
name: "read_file",
93+
input: { path: "test.ts" },
94+
},
95+
],
96+
},
8697
{
8798
role: "user",
8899
content: [
@@ -97,15 +108,56 @@ describe("AI SDK conversion utilities", () => {
97108

98109
const result = convertToAiSdkMessages(messages)
99110

100-
expect(result).toHaveLength(1)
111+
expect(result).toHaveLength(2)
101112
expect(result[0]).toEqual({
113+
role: "assistant",
114+
content: [
115+
{
116+
type: "tool-call",
117+
toolCallId: "call_123",
118+
toolName: "read_file",
119+
args: { path: "test.ts" },
120+
},
121+
],
122+
})
123+
expect(result[1]).toEqual({
102124
role: "tool",
103125
content: [
104126
{
105127
type: "tool-result",
106128
toolCallId: "call_123",
107-
toolName: "",
108-
output: "Tool result content",
129+
toolName: "read_file",
130+
output: { type: "text", value: "Tool result content" },
131+
},
132+
],
133+
})
134+
})
135+
136+
it("uses unknown_tool for tool results without matching tool call", () => {
137+
const messages: Anthropic.Messages.MessageParam[] = [
138+
{
139+
role: "user",
140+
content: [
141+
{
142+
type: "tool_result",
143+
tool_use_id: "call_orphan",
144+
content: "Orphan result",
145+
},
146+
],
147+
},
148+
]
149+
150+
const result = convertToAiSdkMessages(messages)
151+
152+
expect(result).toHaveLength(1)
153+
expect(result[0]).toEqual({
154+
role: "tool",
155+
content: [
156+
{
157+
type: "tool-result",
158+
toolCallId: "call_orphan",
159+
toolName: "unknown_tool",
160+
output: { type: "text", value: "Orphan result" },
109161
},
110162
],
111163
})

src/api/transform/ai-sdk.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,18 @@ export function convertToAiSdkMessages(
4545
}
4646
}
4747

48+
// First pass: build a map of tool call IDs to tool names from assistant messages
49+
const toolCallIdToName = new Map<string, string>()
50+
for (const message of messages) {
51+
if (message.role === "assistant" && typeof message.content !== "string") {
52+
for (const part of message.content) {
53+
if (part.type === "tool_use") {
54+
toolCallIdToName.set(part.id, part.name)
55+
}
56+
}
57+
}
58+
}
59+
4860
for (const message of messages) {
4961
if (typeof message.content === "string") {
5062
modelMessages.push({

0 commit comments

Comments
 (0)