Skip to content

Commit 8f45a0e

Browse files
authored
feat(models): enable Kimi k2 ⇄ Claude trajectory handoff (anomalyco#1525)
1 parent 6581741 commit 8f45a0e

1 file changed

Lines changed: 61 additions & 38 deletions

File tree

Lines changed: 61 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,81 @@
11
import type { ModelMessage } from "ai"
22
import { unique } from "remeda"
33

4+
45
export namespace ProviderTransform {
5-
export function message(msgs: ModelMessage[], providerID: string, modelID: string) {
6-
if (providerID === "anthropic" || modelID.includes("anthropic") || modelID.includes("claude")) {
7-
const system = msgs.filter((msg) => msg.role === "system").slice(0, 2)
8-
const final = msgs.filter((msg) => msg.role !== "system").slice(-2)
9-
10-
const providerOptions = {
11-
anthropic: {
12-
cacheControl: { type: "ephemeral" },
13-
},
14-
openrouter: {
15-
cache_control: { type: "ephemeral" },
16-
},
17-
bedrock: {
18-
cachePoint: { type: "ephemeral" },
19-
},
20-
openaiCompatible: {
21-
cache_control: { type: "ephemeral" },
22-
},
6+
function normalizeToolCallIds(msgs: ModelMessage[]): ModelMessage[] {
7+
return msgs.map((msg) => {
8+
if ((msg.role === "assistant" || msg.role === "tool") && Array.isArray(msg.content)) {
9+
msg.content = msg.content.map((part) => {
10+
if ((part.type === "tool-call" || part.type === "tool-result") && "toolCallId" in part) {
11+
return {
12+
...part,
13+
toolCallId: part.toolCallId.replace(/[^a-zA-Z0-9_-]/g, '_')
14+
}
15+
}
16+
return part
17+
})
2318
}
19+
return msg
20+
})
21+
}
2422

25-
for (const msg of unique([...system, ...final])) {
26-
const shouldUseContentOptions =
27-
providerID !== "anthropic" && Array.isArray(msg.content) && msg.content.length > 0
23+
function applyCaching(msgs: ModelMessage[], providerID: string): ModelMessage[] {
24+
const system = msgs.filter((msg) => msg.role === "system").slice(0, 2)
25+
const final = msgs.filter((msg) => msg.role !== "system").slice(-2)
2826

29-
if (shouldUseContentOptions) {
30-
const lastContent = msg.content[msg.content.length - 1]
31-
if (lastContent && typeof lastContent === "object") {
32-
lastContent.providerOptions = {
33-
...lastContent.providerOptions,
34-
...providerOptions,
35-
}
36-
continue
27+
const providerOptions = {
28+
anthropic: {
29+
cacheControl: { type: "ephemeral" },
30+
},
31+
openrouter: {
32+
cache_control: { type: "ephemeral" },
33+
},
34+
bedrock: {
35+
cachePoint: { type: "ephemeral" },
36+
},
37+
openaiCompatible: {
38+
cache_control: { type: "ephemeral" },
39+
},
40+
}
41+
42+
for (const msg of unique([...system, ...final])) {
43+
const shouldUseContentOptions =
44+
providerID !== "anthropic" && Array.isArray(msg.content) && msg.content.length > 0
45+
46+
if (shouldUseContentOptions) {
47+
const lastContent = msg.content[msg.content.length - 1]
48+
if (lastContent && typeof lastContent === "object") {
49+
lastContent.providerOptions = {
50+
...lastContent.providerOptions,
51+
...providerOptions,
3752
}
53+
continue
3854
}
55+
}
3956

40-
msg.providerOptions = {
41-
...msg.providerOptions,
42-
...providerOptions,
43-
}
57+
msg.providerOptions = {
58+
...msg.providerOptions,
59+
...providerOptions,
4460
}
4561
}
62+
63+
return msgs
64+
}
65+
66+
export function message(msgs: ModelMessage[], providerID: string, modelID: string) {
67+
if (modelID.includes("claude")) {
68+
msgs = normalizeToolCallIds(msgs)
69+
}
70+
if (providerID === "anthropic" || modelID.includes("anthropic") || modelID.includes("claude")) {
71+
msgs = applyCaching(msgs, providerID)
72+
}
73+
4674
return msgs
4775
}
4876

4977
export function temperature(_providerID: string, modelID: string) {
5078
if (modelID.toLowerCase().includes("qwen")) return 0.55
5179
return 0
5280
}
53-
54-
export function topP(_providerID: string, modelID: string) {
55-
if (modelID.toLowerCase().includes("qwen")) return 1
56-
return undefined
57-
}
5881
}

0 commit comments

Comments
 (0)