@@ -552,4 +552,87 @@ describe('TestLLOHandlerEvents', () => {
552552 expect ( outputMessages [ 0 ] . content ) . toBe ( 'Quantum computing is...' ) ;
553553 expect ( outputMessages [ 0 ] . role ) . toBe ( 'assistant' ) ;
554554 } ) ;
555+
556+ /**
557+ * Verify session.id attribute from span is copied to event attributes when present.
558+ */
559+ it ( 'emitLloAttributes should copy session.id to event attributes when present' , ( ) => {
560+ const attributes = {
561+ 'session.id' : 'test-session-123' ,
562+ 'gen_ai.prompt' : 'Hello, AI' ,
563+ 'gen_ai.completion' : 'Hello! How can I help you?' ,
564+ } ;
565+
566+ const span = testBase . createMockSpan ( attributes ) ;
567+ testBase . updateMockSpanKey ( span , 'endTime' , [ 1234567899 , 0 ] ) ;
568+ testBase . updateMockSpanKey ( span , 'instrumentationLibrary' , { name : 'test.scope' , version : '1.0.0' } ) ;
569+
570+ testBase . lloHandler [ 'emitLloAttributes' ] ( span , attributes ) ;
571+
572+ sinon . assert . calledOnce ( testBase . eventLoggerMock . emit as any ) ;
573+ const emittedEvent = ( testBase . eventLoggerMock . emit as any ) . getCall ( 0 ) . args [ 0 ] as Event ;
574+
575+ // Verify session.id was copied to event attributes
576+ expect ( emittedEvent . attributes ) . toBeDefined ( ) ;
577+ expect ( emittedEvent . attributes ?. [ 'session.id' ] ) . toBe ( 'test-session-123' ) ;
578+
579+ // Verify event body still contains LLO data
580+ const eventBody = emittedEvent . data as any ;
581+ expect ( eventBody . input ) . toBeDefined ( ) ;
582+ expect ( eventBody . output ) . toBeDefined ( ) ;
583+ } ) ;
584+
585+ /**
586+ * Verify event attributes do not contain session.id when not present in span attributes.
587+ */
588+ it ( 'emitLloAttributes should not include session.id in event attributes when not present' , ( ) => {
589+ const attributes = {
590+ 'gen_ai.prompt' : 'Hello, AI' ,
591+ 'gen_ai.completion' : 'Hello! How can I help you?' ,
592+ } ;
593+
594+ const span = testBase . createMockSpan ( attributes ) ;
595+ testBase . updateMockSpanKey ( span , 'endTime' , [ 1234567899 , 0 ] ) ;
596+ testBase . updateMockSpanKey ( span , 'instrumentationLibrary' , { name : 'test.scope' , version : '1.0.0' } ) ;
597+
598+ testBase . lloHandler [ 'emitLloAttributes' ] ( span , attributes ) ;
599+
600+ sinon . assert . calledOnce ( testBase . eventLoggerMock . emit as any ) ;
601+ const emittedEvent = ( testBase . eventLoggerMock . emit as any ) . getCall ( 0 ) . args [ 0 ] as Event ;
602+
603+ // Verify session.id is not in event attributes (because the event doesn't have attributes)
604+ expect ( emittedEvent . attributes ) . toBeUndefined ( ) ;
605+ expect ( emittedEvent ) . not . toHaveProperty ( 'attributes' ) ;
606+ } ) ;
607+
608+ /**
609+ * Verify only session.id is copied from span attributes when mixed with other attributes.
610+ */
611+ it ( 'emitLloAttributes should only copy session.id when mixed with other attributes' , ( ) => {
612+ const attributes = {
613+ 'session.id' : 'session-456' ,
614+ 'user.id' : 'user-789' ,
615+ 'gen_ai.prompt' : "What's the weather?" ,
616+ 'gen_ai.completion' : "I can't check the weather." ,
617+ 'other.attribute' : 'some-value' ,
618+ } ;
619+
620+ const span = testBase . createMockSpan ( attributes ) ;
621+ testBase . updateMockSpanKey ( span , 'endTime' , [ 1234567899 , 0 ] ) ;
622+ testBase . updateMockSpanKey ( span , 'instrumentationLibrary' , { name : 'test.scope' , version : '1.0.0' } ) ;
623+
624+ testBase . lloHandler [ 'emitLloAttributes' ] ( span , attributes ) ;
625+
626+ sinon . assert . calledOnce ( testBase . eventLoggerMock . emit as any ) ;
627+ const emittedEvent = ( testBase . eventLoggerMock . emit as any ) . getCall ( 0 ) . args [ 0 ] as Event ;
628+
629+ // Verify only session.id was copied to event attributes (plus event.name from Event class)
630+ expect ( emittedEvent . attributes ) . toBeDefined ( ) ;
631+ expect ( emittedEvent . attributes ?. [ 'session.id' ] ) . toBe ( 'session-456' ) ;
632+ // Verify other span attributes were not copied
633+ expect ( emittedEvent . attributes ) . not . toHaveProperty ( 'user.id' ) ;
634+ expect ( emittedEvent . attributes ) . not . toHaveProperty ( 'other.attribute' ) ;
635+ expect ( emittedEvent . attributes ) . not . toHaveProperty ( 'gen_ai.prompt' ) ;
636+ expect ( emittedEvent . attributes ) . not . toHaveProperty ( 'gen_ai.completion' ) ;
637+ } ) ;
555638} ) ;
0 commit comments