@@ -224,4 +224,181 @@ describe("convertToOpenAiMessages", () => {
224224 const assistantMessage = openAiMessages [ 0 ] as OpenAI . Chat . ChatCompletionAssistantMessageParam
225225 expect ( assistantMessage . tool_calls ! [ 0 ] . id ) . toBe ( "custom_toolu_123" )
226226 } )
227+
228+ describe ( "mergeToolResultText option" , ( ) => {
229+ it ( "should merge text content into last tool message when mergeToolResultText is true" , ( ) => {
230+ const anthropicMessages : Anthropic . Messages . MessageParam [ ] = [
231+ {
232+ role : "user" ,
233+ content : [
234+ {
235+ type : "tool_result" ,
236+ tool_use_id : "tool-123" ,
237+ content : "Tool result content" ,
238+ } ,
239+ {
240+ type : "text" ,
241+ text : "<environment_details>\nSome context\n</environment_details>" ,
242+ } ,
243+ ] ,
244+ } ,
245+ ]
246+
247+ const openAiMessages = convertToOpenAiMessages ( anthropicMessages , { mergeToolResultText : true } )
248+
249+ // Should produce only one tool message with merged content
250+ expect ( openAiMessages ) . toHaveLength ( 1 )
251+ const toolMessage = openAiMessages [ 0 ] as OpenAI . Chat . ChatCompletionToolMessageParam
252+ expect ( toolMessage . role ) . toBe ( "tool" )
253+ expect ( toolMessage . tool_call_id ) . toBe ( "tool-123" )
254+ expect ( toolMessage . content ) . toBe (
255+ "Tool result content\n\n<environment_details>\nSome context\n</environment_details>" ,
256+ )
257+ } )
258+
259+ it ( "should merge text into last tool message when multiple tool results exist" , ( ) => {
260+ const anthropicMessages : Anthropic . Messages . MessageParam [ ] = [
261+ {
262+ role : "user" ,
263+ content : [
264+ {
265+ type : "tool_result" ,
266+ tool_use_id : "call_1" ,
267+ content : "First result" ,
268+ } ,
269+ {
270+ type : "tool_result" ,
271+ tool_use_id : "call_2" ,
272+ content : "Second result" ,
273+ } ,
274+ {
275+ type : "text" ,
276+ text : "<environment_details>Context</environment_details>" ,
277+ } ,
278+ ] ,
279+ } ,
280+ ]
281+
282+ const openAiMessages = convertToOpenAiMessages ( anthropicMessages , { mergeToolResultText : true } )
283+
284+ // Should produce two tool messages, with text merged into the last one
285+ expect ( openAiMessages ) . toHaveLength ( 2 )
286+ expect ( ( openAiMessages [ 0 ] as OpenAI . Chat . ChatCompletionToolMessageParam ) . content ) . toBe ( "First result" )
287+ expect ( ( openAiMessages [ 1 ] as OpenAI . Chat . ChatCompletionToolMessageParam ) . content ) . toBe (
288+ "Second result\n\n<environment_details>Context</environment_details>" ,
289+ )
290+ } )
291+
292+ it ( "should NOT merge text when images are present (fall back to user message)" , ( ) => {
293+ const anthropicMessages : Anthropic . Messages . MessageParam [ ] = [
294+ {
295+ role : "user" ,
296+ content : [
297+ {
298+ type : "tool_result" ,
299+ tool_use_id : "tool-123" ,
300+ content : "Tool result content" ,
301+ } ,
302+ {
303+ type : "image" ,
304+ source : {
305+ type : "base64" ,
306+ media_type : "image/png" ,
307+ data : "base64data" ,
308+ } ,
309+ } ,
310+ ] ,
311+ } ,
312+ ]
313+
314+ const openAiMessages = convertToOpenAiMessages ( anthropicMessages , { mergeToolResultText : true } )
315+
316+ // Should produce a tool message AND a user message (because image is present)
317+ expect ( openAiMessages ) . toHaveLength ( 2 )
318+ expect ( ( openAiMessages [ 0 ] as OpenAI . Chat . ChatCompletionToolMessageParam ) . role ) . toBe ( "tool" )
319+ expect ( openAiMessages [ 1 ] . role ) . toBe ( "user" )
320+ } )
321+
322+ it ( "should create separate user message when mergeToolResultText is false" , ( ) => {
323+ const anthropicMessages : Anthropic . Messages . MessageParam [ ] = [
324+ {
325+ role : "user" ,
326+ content : [
327+ {
328+ type : "tool_result" ,
329+ tool_use_id : "tool-123" ,
330+ content : "Tool result content" ,
331+ } ,
332+ {
333+ type : "text" ,
334+ text : "<environment_details>\nSome context\n</environment_details>" ,
335+ } ,
336+ ] ,
337+ } ,
338+ ]
339+
340+ const openAiMessages = convertToOpenAiMessages ( anthropicMessages , { mergeToolResultText : false } )
341+
342+ // Should produce a tool message AND a separate user message (default behavior)
343+ expect ( openAiMessages ) . toHaveLength ( 2 )
344+ expect ( ( openAiMessages [ 0 ] as OpenAI . Chat . ChatCompletionToolMessageParam ) . role ) . toBe ( "tool" )
345+ expect ( ( openAiMessages [ 0 ] as OpenAI . Chat . ChatCompletionToolMessageParam ) . content ) . toBe (
346+ "Tool result content" ,
347+ )
348+ expect ( openAiMessages [ 1 ] . role ) . toBe ( "user" )
349+ } )
350+
351+ it ( "should work with normalizeToolCallId when mergeToolResultText is true" , ( ) => {
352+ const anthropicMessages : Anthropic . Messages . MessageParam [ ] = [
353+ {
354+ role : "user" ,
355+ content : [
356+ {
357+ type : "tool_result" ,
358+ tool_use_id : "call_5019f900a247472bacde0b82" ,
359+ content : "Tool result content" ,
360+ } ,
361+ {
362+ type : "text" ,
363+ text : "<environment_details>Context</environment_details>" ,
364+ } ,
365+ ] ,
366+ } ,
367+ ]
368+
369+ const openAiMessages = convertToOpenAiMessages ( anthropicMessages , {
370+ mergeToolResultText : true ,
371+ normalizeToolCallId : normalizeMistralToolCallId ,
372+ } )
373+
374+ // Should merge AND normalize the ID
375+ expect ( openAiMessages ) . toHaveLength ( 1 )
376+ const toolMessage = openAiMessages [ 0 ] as OpenAI . Chat . ChatCompletionToolMessageParam
377+ expect ( toolMessage . role ) . toBe ( "tool" )
378+ expect ( toolMessage . tool_call_id ) . toBe ( normalizeMistralToolCallId ( "call_5019f900a247472bacde0b82" ) )
379+ expect ( toolMessage . content ) . toBe (
380+ "Tool result content\n\n<environment_details>Context</environment_details>" ,
381+ )
382+ } )
383+
384+ it ( "should handle user messages with only text content (no tool results)" , ( ) => {
385+ const anthropicMessages : Anthropic . Messages . MessageParam [ ] = [
386+ {
387+ role : "user" ,
388+ content : [
389+ {
390+ type : "text" ,
391+ text : "Hello, how are you?" ,
392+ } ,
393+ ] ,
394+ } ,
395+ ]
396+
397+ const openAiMessages = convertToOpenAiMessages ( anthropicMessages , { mergeToolResultText : true } )
398+
399+ // Should produce a normal user message
400+ expect ( openAiMessages ) . toHaveLength ( 1 )
401+ expect ( openAiMessages [ 0 ] . role ) . toBe ( "user" )
402+ } )
403+ } )
227404} )
0 commit comments