Skip to content

Commit 849f8bf

Browse files
committed
Add tests
1 parent 4210819 commit 849f8bf

File tree

2 files changed

+302
-1
lines changed

2 files changed

+302
-1
lines changed
Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
// npx jest src/api/transform/__tests__/mistral-format.test.ts
2+
3+
import { Anthropic } from "@anthropic-ai/sdk"
4+
5+
import { convertToMistralMessages } from "../mistral-format"
6+
7+
describe("convertToMistralMessages", () => {
8+
it("should convert simple text messages for user and assistant roles", () => {
9+
const anthropicMessages: Anthropic.Messages.MessageParam[] = [
10+
{
11+
role: "user",
12+
content: "Hello",
13+
},
14+
{
15+
role: "assistant",
16+
content: "Hi there!",
17+
},
18+
]
19+
20+
const mistralMessages = convertToMistralMessages(anthropicMessages)
21+
expect(mistralMessages).toHaveLength(2)
22+
expect(mistralMessages[0]).toEqual({
23+
role: "user",
24+
content: "Hello",
25+
})
26+
expect(mistralMessages[1]).toEqual({
27+
role: "assistant",
28+
content: "Hi there!",
29+
})
30+
})
31+
32+
it("should handle user messages with image content", () => {
33+
const anthropicMessages: Anthropic.Messages.MessageParam[] = [
34+
{
35+
role: "user",
36+
content: [
37+
{
38+
type: "text",
39+
text: "What is in this image?",
40+
},
41+
{
42+
type: "image",
43+
source: {
44+
type: "base64",
45+
media_type: "image/jpeg",
46+
data: "base64data",
47+
},
48+
},
49+
],
50+
},
51+
]
52+
53+
const mistralMessages = convertToMistralMessages(anthropicMessages)
54+
expect(mistralMessages).toHaveLength(1)
55+
expect(mistralMessages[0].role).toBe("user")
56+
57+
const content = mistralMessages[0].content as Array<{
58+
type: string
59+
text?: string
60+
imageUrl?: { url: string }
61+
}>
62+
63+
expect(Array.isArray(content)).toBe(true)
64+
expect(content).toHaveLength(2)
65+
expect(content[0]).toEqual({ type: "text", text: "What is in this image?" })
66+
expect(content[1]).toEqual({
67+
type: "image_url",
68+
imageUrl: { url: "data:image/jpeg;base64,base64data" },
69+
})
70+
})
71+
72+
it("should handle user messages with only tool results", () => {
73+
const anthropicMessages: Anthropic.Messages.MessageParam[] = [
74+
{
75+
role: "user",
76+
content: [
77+
{
78+
type: "tool_result",
79+
tool_use_id: "weather-123",
80+
content: "Current temperature in London: 20°C",
81+
},
82+
],
83+
},
84+
]
85+
86+
// Based on the implementation, tool results without accompanying text/image
87+
// don't generate any messages
88+
const mistralMessages = convertToMistralMessages(anthropicMessages)
89+
expect(mistralMessages).toHaveLength(0)
90+
})
91+
92+
it("should handle user messages with mixed content (text, image, and tool results)", () => {
93+
const anthropicMessages: Anthropic.Messages.MessageParam[] = [
94+
{
95+
role: "user",
96+
content: [
97+
{
98+
type: "text",
99+
text: "Here's the weather data and an image:",
100+
},
101+
{
102+
type: "image",
103+
source: {
104+
type: "base64",
105+
media_type: "image/png",
106+
data: "imagedata123",
107+
},
108+
},
109+
{
110+
type: "tool_result",
111+
tool_use_id: "weather-123",
112+
content: "Current temperature in London: 20°C",
113+
},
114+
],
115+
},
116+
]
117+
118+
const mistralMessages = convertToMistralMessages(anthropicMessages)
119+
// Based on the implementation, only the text and image content is included
120+
// Tool results are not converted to separate messages
121+
expect(mistralMessages).toHaveLength(1)
122+
123+
// Message should be the user message with text and image
124+
expect(mistralMessages[0].role).toBe("user")
125+
const userContent = mistralMessages[0].content as Array<{
126+
type: string
127+
text?: string
128+
imageUrl?: { url: string }
129+
}>
130+
expect(Array.isArray(userContent)).toBe(true)
131+
expect(userContent).toHaveLength(2)
132+
expect(userContent[0]).toEqual({ type: "text", text: "Here's the weather data and an image:" })
133+
expect(userContent[1]).toEqual({
134+
type: "image_url",
135+
imageUrl: { url: "data:image/png;base64,imagedata123" },
136+
})
137+
})
138+
139+
it("should handle assistant messages with text content", () => {
140+
const anthropicMessages: Anthropic.Messages.MessageParam[] = [
141+
{
142+
role: "assistant",
143+
content: [
144+
{
145+
type: "text",
146+
text: "I'll help you with that question.",
147+
},
148+
],
149+
},
150+
]
151+
152+
const mistralMessages = convertToMistralMessages(anthropicMessages)
153+
expect(mistralMessages).toHaveLength(1)
154+
expect(mistralMessages[0].role).toBe("assistant")
155+
expect(mistralMessages[0].content).toBe("I'll help you with that question.")
156+
})
157+
158+
it("should handle assistant messages with tool use", () => {
159+
const anthropicMessages: Anthropic.Messages.MessageParam[] = [
160+
{
161+
role: "assistant",
162+
content: [
163+
{
164+
type: "text",
165+
text: "Let me check the weather for you.",
166+
},
167+
{
168+
type: "tool_use",
169+
id: "weather-123",
170+
name: "get_weather",
171+
input: { city: "London" },
172+
},
173+
],
174+
},
175+
]
176+
177+
const mistralMessages = convertToMistralMessages(anthropicMessages)
178+
expect(mistralMessages).toHaveLength(1)
179+
expect(mistralMessages[0].role).toBe("assistant")
180+
expect(mistralMessages[0].content).toBe("Let me check the weather for you.")
181+
})
182+
183+
it("should handle multiple text blocks in assistant messages", () => {
184+
const anthropicMessages: Anthropic.Messages.MessageParam[] = [
185+
{
186+
role: "assistant",
187+
content: [
188+
{
189+
type: "text",
190+
text: "First paragraph of information.",
191+
},
192+
{
193+
type: "text",
194+
text: "Second paragraph with more details.",
195+
},
196+
],
197+
},
198+
]
199+
200+
const mistralMessages = convertToMistralMessages(anthropicMessages)
201+
expect(mistralMessages).toHaveLength(1)
202+
expect(mistralMessages[0].role).toBe("assistant")
203+
expect(mistralMessages[0].content).toBe("First paragraph of information.\nSecond paragraph with more details.")
204+
})
205+
206+
it("should handle a conversation with mixed message types", () => {
207+
const anthropicMessages: Anthropic.Messages.MessageParam[] = [
208+
{
209+
role: "user",
210+
content: [
211+
{
212+
type: "text",
213+
text: "What's in this image?",
214+
},
215+
{
216+
type: "image",
217+
source: {
218+
type: "base64",
219+
media_type: "image/jpeg",
220+
data: "imagedata",
221+
},
222+
},
223+
],
224+
},
225+
{
226+
role: "assistant",
227+
content: [
228+
{
229+
type: "text",
230+
text: "This image shows a landscape with mountains.",
231+
},
232+
{
233+
type: "tool_use",
234+
id: "search-123",
235+
name: "search_info",
236+
input: { query: "mountain types" },
237+
},
238+
],
239+
},
240+
{
241+
role: "user",
242+
content: [
243+
{
244+
type: "tool_result",
245+
tool_use_id: "search-123",
246+
content: "Found information about different mountain types.",
247+
},
248+
],
249+
},
250+
{
251+
role: "assistant",
252+
content: "Based on the search results, I can tell you more about the mountains in the image.",
253+
},
254+
]
255+
256+
const mistralMessages = convertToMistralMessages(anthropicMessages)
257+
// Based on the implementation, user messages with only tool results don't generate messages
258+
expect(mistralMessages).toHaveLength(3)
259+
260+
// User message with image
261+
expect(mistralMessages[0].role).toBe("user")
262+
const userContent = mistralMessages[0].content as Array<{
263+
type: string
264+
text?: string
265+
imageUrl?: { url: string }
266+
}>
267+
expect(Array.isArray(userContent)).toBe(true)
268+
expect(userContent).toHaveLength(2)
269+
270+
// Assistant message with text (tool_use is not included in Mistral format)
271+
expect(mistralMessages[1].role).toBe("assistant")
272+
expect(mistralMessages[1].content).toBe("This image shows a landscape with mountains.")
273+
274+
// Final assistant message
275+
expect(mistralMessages[2]).toEqual({
276+
role: "assistant",
277+
content: "Based on the search results, I can tell you more about the mountains in the image.",
278+
})
279+
})
280+
281+
it("should handle empty content in assistant messages", () => {
282+
const anthropicMessages: Anthropic.Messages.MessageParam[] = [
283+
{
284+
role: "assistant",
285+
content: [
286+
{
287+
type: "tool_use",
288+
id: "search-123",
289+
name: "search_info",
290+
input: { query: "test query" },
291+
},
292+
],
293+
},
294+
]
295+
296+
const mistralMessages = convertToMistralMessages(anthropicMessages)
297+
expect(mistralMessages).toHaveLength(1)
298+
expect(mistralMessages[0].role).toBe("assistant")
299+
expect(mistralMessages[0].content).toBeUndefined()
300+
})
301+
})

src/api/transform/mistral-format.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { Anthropic } from "@anthropic-ai/sdk"
2-
import { Mistral } from "@mistralai/mistralai"
32
import { AssistantMessage } from "@mistralai/mistralai/models/components/assistantmessage"
43
import { SystemMessage } from "@mistralai/mistralai/models/components/systemmessage"
54
import { ToolMessage } from "@mistralai/mistralai/models/components/toolmessage"
@@ -13,6 +12,7 @@ export type MistralMessage =
1312

1413
export function convertToMistralMessages(anthropicMessages: Anthropic.Messages.MessageParam[]): MistralMessage[] {
1514
const mistralMessages: MistralMessage[] = []
15+
1616
for (const anthropicMessage of anthropicMessages) {
1717
if (typeof anthropicMessage.content === "string") {
1818
mistralMessages.push({

0 commit comments

Comments
 (0)