@@ -53,6 +53,17 @@ const model: Provider.Model = {
5353 release_date : "2026-01-01" ,
5454}
5555
56+ const model2 : Provider . Model = {
57+ ...model ,
58+ id : "other-model" ,
59+ providerID : "other" ,
60+ api : {
61+ ...model . api ,
62+ id : "other-model" ,
63+ } ,
64+ name : "Other Model" ,
65+ }
66+
5667function userInfo ( id : string ) : MessageV2 . User {
5768 return {
5869 id,
@@ -355,7 +366,90 @@ describe("session.message-v2.toModelMessage", () => {
355366 ] )
356367 } )
357368
358- test ( "omits provider metadata when assistant model differs" , ( ) => {
369+ test ( "preserves reasoning providerMetadata when model matches" , ( ) => {
370+ const assistantID = "m-assistant"
371+
372+ const input : MessageV2 . WithParts [ ] = [
373+ {
374+ info : assistantInfo ( assistantID , "m-parent" ) ,
375+ parts : [
376+ {
377+ ...basePart ( assistantID , "a1" ) ,
378+ type : "reasoning" ,
379+ text : "thinking" ,
380+ metadata : { openai : { signature : "sig-match" } } ,
381+ time : { start : 0 } ,
382+ } ,
383+ ] as MessageV2 . Part [ ] ,
384+ } ,
385+ ]
386+
387+ expect ( MessageV2 . toModelMessages ( input , model ) ) . toStrictEqual ( [
388+ {
389+ role : "assistant" ,
390+ content : [ { type : "reasoning" , text : "thinking" , providerOptions : { openai : { signature : "sig-match" } } } ] ,
391+ } ,
392+ ] )
393+ } )
394+
395+ test ( "preserves reasoning providerMetadata when model differs" , ( ) => {
396+ const assistantID = "m-assistant"
397+
398+ const input : MessageV2 . WithParts [ ] = [
399+ {
400+ info : assistantInfo ( assistantID , "m-parent" , undefined , {
401+ providerID : model2 . providerID ,
402+ modelID : model2 . api . id ,
403+ } ) ,
404+ parts : [
405+ {
406+ ...basePart ( assistantID , "a1" ) ,
407+ type : "reasoning" ,
408+ text : "thinking" ,
409+ metadata : { openai : { signature : "sig-different" } } ,
410+ time : { start : 0 } ,
411+ } ,
412+ ] as MessageV2 . Part [ ] ,
413+ } ,
414+ ]
415+
416+ expect ( MessageV2 . toModelMessages ( input , model ) ) . toStrictEqual ( [
417+ {
418+ role : "assistant" ,
419+ content : [ { type : "reasoning" , text : "thinking" , providerOptions : { openai : { signature : "sig-different" } } } ] ,
420+ } ,
421+ ] )
422+ } )
423+
424+ test ( "preserves text providerMetadata when model differs" , ( ) => {
425+ const assistantID = "m-assistant"
426+
427+ const input : MessageV2 . WithParts [ ] = [
428+ {
429+ info : assistantInfo ( assistantID , "m-parent" , undefined , {
430+ providerID : model2 . providerID ,
431+ modelID : model2 . api . id ,
432+ } ) ,
433+ parts : [
434+ {
435+ ...basePart ( assistantID , "a1" ) ,
436+ type : "text" ,
437+ text : "done" ,
438+ metadata : { openai : { assistant : "meta" } } ,
439+ } ,
440+ ] as MessageV2 . Part [ ] ,
441+ } ,
442+ ]
443+
444+ expect ( MessageV2 . toModelMessages ( input , model ) ) . toStrictEqual ( [
445+ {
446+ role : "assistant" ,
447+ content : [ { type : "text" , text : "done" , providerOptions : { openai : { assistant : "meta" } } } ] ,
448+ } ,
449+ ] )
450+ } )
451+
452+ test ( "preserves tool callProviderMetadata when model differs" , ( ) => {
359453 const userID = "m-user"
360454 const assistantID = "m-assistant"
361455
@@ -371,16 +465,97 @@ describe("session.message-v2.toModelMessage", () => {
371465 ] as MessageV2 . Part [ ] ,
372466 } ,
373467 {
374- info : assistantInfo ( assistantID , userID , undefined , { providerID : "other" , modelID : "other" } ) ,
468+ info : assistantInfo ( assistantID , userID , undefined , {
469+ providerID : model2 . providerID ,
470+ modelID : model2 . api . id ,
471+ } ) ,
472+ parts : [
473+ {
474+ ...basePart ( assistantID , "a1" ) ,
475+ type : "tool" ,
476+ callID : "call-1" ,
477+ tool : "bash" ,
478+ state : {
479+ status : "completed" ,
480+ input : { cmd : "ls" } ,
481+ output : "ok" ,
482+ title : "Bash" ,
483+ metadata : { } ,
484+ time : { start : 0 , end : 1 } ,
485+ } ,
486+ metadata : { openai : { tool : "meta" } } ,
487+ } ,
488+ ] as MessageV2 . Part [ ] ,
489+ } ,
490+ ]
491+
492+ expect ( MessageV2 . toModelMessages ( input , model ) ) . toStrictEqual ( [
493+ {
494+ role : "user" ,
495+ content : [ { type : "text" , text : "run tool" } ] ,
496+ } ,
497+ {
498+ role : "assistant" ,
499+ content : [
500+ {
501+ type : "tool-call" ,
502+ toolCallId : "call-1" ,
503+ toolName : "bash" ,
504+ input : { cmd : "ls" } ,
505+ providerExecuted : undefined ,
506+ providerOptions : { openai : { tool : "meta" } } ,
507+ } ,
508+ ] ,
509+ } ,
510+ {
511+ role : "tool" ,
512+ content : [
513+ {
514+ type : "tool-result" ,
515+ toolCallId : "call-1" ,
516+ toolName : "bash" ,
517+ output : { type : "text" , value : "ok" } ,
518+ providerOptions : { openai : { tool : "meta" } } ,
519+ } ,
520+ ] ,
521+ } ,
522+ ] )
523+ } )
524+
525+ test ( "handles undefined metadata gracefully" , ( ) => {
526+ const userID = "m-user"
527+ const assistantID = "m-assistant"
528+
529+ const input : MessageV2 . WithParts [ ] = [
530+ {
531+ info : userInfo ( userID ) ,
532+ parts : [
533+ {
534+ ...basePart ( userID , "u1" ) ,
535+ type : "text" ,
536+ text : "run tool" ,
537+ } ,
538+ ] as MessageV2 . Part [ ] ,
539+ } ,
540+ {
541+ info : assistantInfo ( assistantID , userID , undefined , {
542+ providerID : model2 . providerID ,
543+ modelID : model2 . api . id ,
544+ } ) ,
375545 parts : [
376546 {
377547 ...basePart ( assistantID , "a1" ) ,
378548 type : "text" ,
379549 text : "done" ,
380- metadata : { openai : { assistant : "meta" } } ,
381550 } ,
382551 {
383552 ...basePart ( assistantID , "a2" ) ,
553+ type : "reasoning" ,
554+ text : "thinking" ,
555+ time : { start : 0 } ,
556+ } ,
557+ {
558+ ...basePart ( assistantID , "a3" ) ,
384559 type : "tool" ,
385560 callID : "call-1" ,
386561 tool : "bash" ,
@@ -392,7 +567,6 @@ describe("session.message-v2.toModelMessage", () => {
392567 metadata : { } ,
393568 time : { start : 0 , end : 1 } ,
394569 } ,
395- metadata : { openai : { tool : "meta" } } ,
396570 } ,
397571 ] as MessageV2 . Part [ ] ,
398572 } ,
@@ -407,6 +581,7 @@ describe("session.message-v2.toModelMessage", () => {
407581 role : "assistant" ,
408582 content : [
409583 { type : "text" , text : "done" } ,
584+ { type : "reasoning" , text : "thinking" , providerOptions : undefined } ,
410585 {
411586 type : "tool-call" ,
412587 toolCallId : "call-1" ,
0 commit comments