fix: rm tool reorder logic from old bug (#30483)
This commit is contained in:
@@ -212,31 +212,7 @@ function normalizeMessages(
|
|||||||
return msg
|
return msg
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (["@ai-sdk/anthropic", "@ai-sdk/google-vertex/anthropic"].includes(model.api.npm)) {
|
|
||||||
// Anthropic rejects assistant turns where tool_use blocks are followed by non-tool
|
|
||||||
// content, e.g. [tool_use, tool_use, text], with:
|
|
||||||
// `tool_use` ids were found without `tool_result` blocks immediately after...
|
|
||||||
//
|
|
||||||
// Reorder that invalid shape into [text] + [tool_use, tool_use]. Consecutive
|
|
||||||
// assistant messages are later merged by the provider/SDK, so preserving the
|
|
||||||
// original [tool_use...] then [text] order still produces the invalid payload.
|
|
||||||
//
|
|
||||||
// The root cause appears to be somewhere upstream where the stream is originally
|
|
||||||
// processed. We were unable to locate an exact narrower reproduction elsewhere,
|
|
||||||
// so we keep this transform in place for the time being.
|
|
||||||
msgs = msgs.flatMap((msg) => {
|
|
||||||
if (msg.role !== "assistant" || !Array.isArray(msg.content)) return [msg]
|
|
||||||
|
|
||||||
const parts = msg.content
|
|
||||||
const first = parts.findIndex((part) => part.type === "tool-call")
|
|
||||||
if (first === -1) return [msg]
|
|
||||||
if (!parts.slice(first).some((part) => part.type !== "tool-call")) return [msg]
|
|
||||||
return [
|
|
||||||
{ ...msg, content: parts.filter((part) => part.type !== "tool-call") },
|
|
||||||
{ ...msg, content: parts.filter((part) => part.type === "tool-call") },
|
|
||||||
]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (
|
if (
|
||||||
model.providerID === "mistral" ||
|
model.providerID === "mistral" ||
|
||||||
model.api.id.toLowerCase().includes("mistral") ||
|
model.api.id.toLowerCase().includes("mistral") ||
|
||||||
|
|||||||
@@ -1614,50 +1614,6 @@ describe("ProviderTransform.message - anthropic empty content filtering", () =>
|
|||||||
expect(result[1].content).toHaveLength(1)
|
expect(result[1].content).toHaveLength(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("splits anthropic assistant messages when text trails tool calls", () => {
|
|
||||||
const msgs = [
|
|
||||||
{
|
|
||||||
role: "user",
|
|
||||||
content: [{ type: "text", text: "Check my home directory for PDFs" }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
role: "assistant",
|
|
||||||
content: [
|
|
||||||
{ type: "tool-call", toolCallId: "toolu_1", toolName: "read", input: { filePath: "/root" } },
|
|
||||||
{ type: "tool-call", toolCallId: "toolu_2", toolName: "glob", input: { pattern: "**/*.pdf" } },
|
|
||||||
{ type: "text", text: "I checked your home directory and looked for PDF files." },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
role: "tool",
|
|
||||||
content: [
|
|
||||||
{ type: "tool-result", toolCallId: "toolu_1", toolName: "read", output: { type: "text", value: "ok" } },
|
|
||||||
{
|
|
||||||
type: "tool-result",
|
|
||||||
toolCallId: "toolu_2",
|
|
||||||
toolName: "glob",
|
|
||||||
output: { type: "text", value: "No files found" },
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
] as any[]
|
|
||||||
|
|
||||||
const result = ProviderTransform.message(msgs, anthropicModel, {}) as any[]
|
|
||||||
|
|
||||||
expect(result).toHaveLength(4)
|
|
||||||
expect(result[1]).toMatchObject({
|
|
||||||
role: "assistant",
|
|
||||||
content: [{ type: "text", text: "I checked your home directory and looked for PDF files." }],
|
|
||||||
})
|
|
||||||
expect(result[2]).toMatchObject({
|
|
||||||
role: "assistant",
|
|
||||||
content: [
|
|
||||||
{ type: "tool-call", toolCallId: "toolu_1", toolName: "read", input: { filePath: "/root" } },
|
|
||||||
{ type: "tool-call", toolCallId: "toolu_2", toolName: "glob", input: { pattern: "**/*.pdf" } },
|
|
||||||
],
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
test("leaves valid anthropic assistant tool ordering unchanged", () => {
|
test("leaves valid anthropic assistant tool ordering unchanged", () => {
|
||||||
const msgs = [
|
const msgs = [
|
||||||
{
|
{
|
||||||
@@ -1680,43 +1636,6 @@ describe("ProviderTransform.message - anthropic empty content filtering", () =>
|
|||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
test("splits vertex anthropic assistant messages when text trails tool calls", () => {
|
|
||||||
const model = {
|
|
||||||
...anthropicModel,
|
|
||||||
providerID: "google-vertex-anthropic",
|
|
||||||
api: {
|
|
||||||
id: "claude-sonnet-4@20250514",
|
|
||||||
url: "https://us-central1-aiplatform.googleapis.com",
|
|
||||||
npm: "@ai-sdk/google-vertex/anthropic",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const msgs = [
|
|
||||||
{
|
|
||||||
role: "assistant",
|
|
||||||
content: [
|
|
||||||
{ type: "tool-call", toolCallId: "toolu_1", toolName: "read", input: { filePath: "/root" } },
|
|
||||||
{ type: "tool-call", toolCallId: "toolu_2", toolName: "glob", input: { pattern: "**/*.pdf" } },
|
|
||||||
{ type: "text", text: "I checked your home directory and looked for PDF files." },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
] as any[]
|
|
||||||
|
|
||||||
const result = ProviderTransform.message(msgs, model, {}) as any[]
|
|
||||||
|
|
||||||
expect(result).toHaveLength(2)
|
|
||||||
expect(result[0]).toMatchObject({
|
|
||||||
role: "assistant",
|
|
||||||
content: [{ type: "text", text: "I checked your home directory and looked for PDF files." }],
|
|
||||||
})
|
|
||||||
expect(result[1]).toMatchObject({
|
|
||||||
role: "assistant",
|
|
||||||
content: [
|
|
||||||
{ type: "tool-call", toolCallId: "toolu_1", toolName: "read", input: { filePath: "/root" } },
|
|
||||||
{ type: "tool-call", toolCallId: "toolu_2", toolName: "glob", input: { pattern: "**/*.pdf" } },
|
|
||||||
],
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("ProviderTransform.message - strip openai metadata when store=false", () => {
|
describe("ProviderTransform.message - strip openai metadata when store=false", () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user