pull/14641/merge
粒粒橙 2026-04-08 05:21:13 +00:00 committed by GitHub
commit 9dce870ca4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 136 additions and 26 deletions

View File

@ -153,36 +153,30 @@ export namespace ProviderTransform {
if (typeof model.capabilities.interleaved === "object" && model.capabilities.interleaved.field) {
const field = model.capabilities.interleaved.field
const key =
model.api.npm === "@ai-sdk/anthropic" || model.api.npm === "@ai-sdk/google-vertex/anthropic"
? "anthropic"
: "openaiCompatible"
return msgs.map((msg) => {
if (msg.role === "assistant" && Array.isArray(msg.content)) {
const reasoningParts = msg.content.filter((part: any) => part.type === "reasoning")
const reasoningText = reasoningParts.map((part: any) => part.text).join("")
if (msg.role !== "assistant" || !Array.isArray(msg.content)) return msg
// Filter out reasoning parts from content
const filteredContent = msg.content.filter((part: any) => part.type !== "reasoning")
const reasoningText = msg.content
.filter((part: any) => part.type === "reasoning")
.map((part: any) => part.text)
.join("")
if (!reasoningText) return msg
// Include reasoning_content | reasoning_details directly on the message for all assistant messages
if (reasoningText) {
return {
...msg,
content: filteredContent,
providerOptions: {
...msg.providerOptions,
openaiCompatible: {
...(msg.providerOptions as any)?.openaiCompatible,
[field]: reasoningText,
},
},
}
}
return {
...msg,
content: filteredContent,
}
return {
...msg,
content: msg.content.filter((part: any) => part.type !== "reasoning"),
providerOptions: {
...msg.providerOptions,
[key]: {
...(msg.providerOptions as any)?.[key],
[field]: reasoningText,
},
},
}
return msg
})
}

View File

@ -911,6 +911,122 @@ describe("ProviderTransform.message - DeepSeek reasoning content", () => {
})
})
describe("ProviderTransform.message - kimi-k2.5 anthropic interleaved reasoning", () => {
const kimiModel = {
id: "anthropic/kimi-k2.5",
providerID: "anthropic",
api: {
id: "kimi-k2.5",
url: "https://api.anthropic.com",
npm: "@ai-sdk/anthropic",
},
name: "Kimi K2.5",
capabilities: {
temperature: true,
reasoning: true,
attachment: false,
toolcall: true,
input: { text: true, audio: false, image: false, video: false, pdf: false },
output: { text: true, audio: false, image: false, video: false, pdf: false },
interleaved: { field: "reasoning_content" },
},
cost: { input: 0.001, output: 0.002, cache: { read: 0.0001, write: 0.0002 } },
limit: { context: 128000, output: 8192 },
status: "active",
options: {},
headers: {},
release_date: "2025-01-01",
} as any
test("injects reasoning_content into providerOptions.anthropic", () => {
const msgs = [
{
role: "assistant",
content: [
{ type: "reasoning", text: "Let me think..." },
{ type: "text", text: "The answer is 42" },
],
},
] as any[]
const result = ProviderTransform.message(msgs, kimiModel, {})
expect(result).toHaveLength(1)
expect(result[0].providerOptions?.anthropic?.reasoning_content).toBe("Let me think...")
expect(result[0].content).toEqual([{ type: "text", text: "The answer is 42" }])
})
test("does not inject when no reasoning parts exist", () => {
const msgs = [
{
role: "assistant",
content: [{ type: "text", text: "No reasoning here" }],
},
] as any[]
const result = ProviderTransform.message(msgs, kimiModel, {})
expect(result[0].providerOptions?.anthropic?.reasoning_content).toBeUndefined()
expect(result[0].content).toEqual([{ type: "text", text: "No reasoning here" }])
})
test("concatenates multiple reasoning parts", () => {
const msgs = [
{
role: "assistant",
content: [
{ type: "reasoning", text: "First thought. " },
{ type: "reasoning", text: "Second thought." },
{ type: "text", text: "Result" },
],
},
] as any[]
const result = ProviderTransform.message(msgs, kimiModel, {})
expect(result[0].providerOptions?.anthropic?.reasoning_content).toBe("First thought. Second thought.")
expect(result[0].content).toEqual([{ type: "text", text: "Result" }])
})
test("works with google-vertex/anthropic SDK", () => {
const vertexModel = {
...kimiModel,
api: { ...kimiModel.api, npm: "@ai-sdk/google-vertex/anthropic" },
}
const msgs = [
{
role: "assistant",
content: [
{ type: "reasoning", text: "Thinking via vertex..." },
{ type: "text", text: "Done" },
],
},
] as any[]
const result = ProviderTransform.message(msgs, vertexModel, {})
expect(result[0].providerOptions?.anthropic?.reasoning_content).toBe("Thinking via vertex...")
})
test("leaves non-assistant messages unchanged", () => {
const msgs = [
{ role: "user", content: "Hello" },
{
role: "assistant",
content: [
{ type: "reasoning", text: "Thinking..." },
{ type: "text", text: "Hi" },
],
},
] as any[]
const result = ProviderTransform.message(msgs, kimiModel, {})
expect(result[0].content).toBe("Hello")
expect(result[1].providerOptions?.anthropic?.reasoning_content).toBe("Thinking...")
})
})
describe("ProviderTransform.message - empty image handling", () => {
const mockModel = {
id: "anthropic/claude-3-5-sonnet",