@@ -82,6 +82,7 @@ type _DMessageFragmentWrapper<TFragment, TPart extends { pt: string }> = {
8282 ft : TFragment ;
8383 fId : DMessageFragmentId ;
8484 part : TPart ;
85+ originId ?: string ; // optional, for multi-model, identifies which actor produced this fragment
8586}
8687
8788
@@ -362,6 +363,9 @@ export function duplicateDMessageFragments(fragments: Readonly<DMessageFragment[
362363 : fragments . map ( _duplicateFragment ) . filter ( f => f . ft !== 'void' ) ;
363364}
364365
366+ /**
367+ * NOTE: a duplicate fragment gets a new ID, and also loses any originId, if set (not sure why, but it's the way it is now)
368+ */
365369function _duplicateFragment ( fragment : DMessageFragment ) : DMessageFragment {
366370 switch ( fragment . ft ) {
367371 case 'content' :
@@ -554,6 +558,16 @@ function _duplicate_DataReference(ref: DMessageDataRef): DMessageDataRef {
554558
555559/// Editor Helpers - Fragment Editing
556560
561+ /** Creates a new array of fragments with a specific originId assigned to each. */
562+ export function fragmentsSetOriginId ( fragments : ReadonlyArray < Readonly < DMessageFragment > > , originId : string ) : Readonly < DMessageFragment > [ ] {
563+
564+ // shallow copy if empty or no originId
565+ if ( ! fragments . length || ! originId ) return [ ...fragments ] ;
566+
567+ // shallow-copy + set origin
568+ return fragments . map ( fragment => ( { ...fragment , originId : originId } ) ) ;
569+ }
570+
557571export function splitFragmentsByType ( fragments : DMessageFragment [ ] ) {
558572 // also see `useFragmentBuckets.ts` which inspired this function
559573 return fragments . reduce ( ( acc , frag ) => {
@@ -596,15 +610,16 @@ export function updateFragmentWithEditedText(
596610 // }
597611
598612 if ( isContentFragment ( fragment ) ) {
599- const { fId, part } = fragment ;
613+ const { fId, part, originId } = fragment ;
614+ const preserveId = { fId, ...( originId && { originId } ) } as const ;
600615
601616 if ( isTextPart ( part ) ) {
602617 // Create a new text content fragment with the same fId and the edited text
603618 const newFragment = createTextContentFragment ( editedText ) ;
604- return { ...newFragment , fId } ; // Preserve original fId
619+ return { ...newFragment , ... preserveId } ;
605620 } else if ( part . pt === 'error' ) {
606621 const newFragment = createErrorContentFragment ( editedText ) ;
607- return { ...newFragment , fId } ; // Preserve original fId
622+ return { ...newFragment , ... preserveId } ;
608623 } else if ( part . pt === 'tool_invocation' ) {
609624 if ( part . invocation . type === 'function_call' ) {
610625 // Create a new tool invocation fragment with the edited args
@@ -613,15 +628,15 @@ export function updateFragmentWithEditedText(
613628 part . invocation . name ,
614629 editedText , // args (if empty, it calls the funciton without params)
615630 ) ;
616- return { ...newFragment , fId } ; // Preserve original fId
631+ return { ...newFragment , ... preserveId } ;
617632 } else if ( part . invocation . type === 'code_execution' ) {
618633 const newFragment = create_CodeExecutionInvocation_ContentFragment (
619634 part . id , // Keep same id
620635 part . invocation . language ,
621636 editedText , // code
622637 part . invocation . author ,
623638 ) ;
624- return { ...newFragment , fId } ;
639+ return { ...newFragment , ... preserveId } ;
625640 }
626641 } else if ( part . pt === 'tool_response' ) {
627642 if ( part . error ) {
@@ -642,7 +657,7 @@ export function updateFragmentWithEditedText(
642657 editedText , // result
643658 part . environment ,
644659 ) ;
645- return { ...newFragment , fId } ;
660+ return { ...newFragment , ... preserveId } ;
646661 } else if ( response . type === 'code_execution' ) {
647662 const newFragment = create_CodeExecutionResponse_ContentFragment (
648663 part . id ,
@@ -651,12 +666,13 @@ export function updateFragmentWithEditedText(
651666 response . executor ,
652667 part . environment ,
653668 ) ;
654- return { ...newFragment , fId } ;
669+ return { ...newFragment , ... preserveId } ;
655670 }
656671 }
657672 }
658673 } else if ( isAttachmentFragment ( fragment ) ) {
659- const { fId, part, title, caption, liveFileId } = fragment ;
674+ const { fId, part, title, caption, liveFileId, originId } = fragment ;
675+ const preserveId = { fId, ...( originId && { originId } ) } as const ;
660676
661677 if ( isDocPart ( part ) ) {
662678 // Create a new doc attachment fragment with the edited text
@@ -674,7 +690,7 @@ export function updateFragmentWithEditedText(
674690 part . meta ,
675691 liveFileId ,
676692 ) ;
677- return { ...newFragment , fId } ; // Preserve original fId
693+ return { ...newFragment , ... preserveId } ;
678694 }
679695 // Handle other attachment parts if needed
680696 }
0 commit comments