@@ -562,3 +562,148 @@ describe('Output tracking integration', () => {
562562 ) . toBe ( true ) ;
563563 } ) ;
564564} ) ;
565+
566+ describe ( 'Workflow span statusCode propagation' , ( ) => {
567+ test ( 'test workflow span statusCode passed to addWorkflowSpan' , async ( ) => {
568+ const mockLogger = createMockLogger ( ) ;
569+ const processor = new GalileoTracingProcessor ( mockLogger as never , false ) ;
570+ const trace = makeTrace ( ) ;
571+
572+ await processor . onTraceStart ( trace ) ;
573+
574+ // Create a workflow span (handoff type maps to workflow nodeType)
575+ const workflow = makeSpan ( {
576+ spanId : 'workflow-001' ,
577+ parentId : 'trace-001' ,
578+ spanData : { type : 'handoff' , from_agent : 'Agent1' , to_agent : 'Agent2' }
579+ } ) ;
580+
581+ // Create a successful child LLM span
582+ const llm = makeSpan ( {
583+ spanId : 'llm-001' ,
584+ parentId : 'workflow-001' ,
585+ spanData : {
586+ type : 'generation' ,
587+ model : 'gpt-4' ,
588+ input : [ ] ,
589+ output : 'successful response'
590+ } ,
591+ error : null
592+ } ) ;
593+
594+ await processor . onSpanStart ( workflow ) ;
595+ await processor . onSpanStart ( llm ) ;
596+ await processor . onSpanEnd ( llm ) ;
597+ await processor . onSpanEnd ( workflow ) ;
598+ await processor . onTraceEnd ( trace ) ;
599+
600+ // Verify addWorkflowSpan was called (note: statusCode may be 200 by default)
601+ expect ( mockLogger . addWorkflowSpan ) . toHaveBeenCalledTimes ( 1 ) ;
602+ const workflowSpanCall = mockLogger . addWorkflowSpan . mock . calls [ 0 ] [ 0 ] ;
603+ // Verify statusCode parameter is being passed through (defaults to 200 for success)
604+ expect ( workflowSpanCall . statusCode ) . toBe ( 200 ) ;
605+ } ) ;
606+
607+ test ( 'test workflow span with direct error has statusCode 500' , async ( ) => {
608+ const mockLogger = createMockLogger ( ) ;
609+ const processor = new GalileoTracingProcessor ( mockLogger as never , false ) ;
610+ const trace = makeTrace ( ) ;
611+
612+ await processor . onTraceStart ( trace ) ;
613+
614+ // Create a workflow span that itself has an error
615+ const workflowWithError = makeSpan ( {
616+ spanId : 'workflow-001' ,
617+ parentId : 'trace-001' ,
618+ spanData : { type : 'handoff' , from_agent : 'Agent1' , to_agent : 'Agent2' } ,
619+ error : {
620+ message : 'Workflow execution failed' ,
621+ data : { reason : 'timeout' }
622+ }
623+ } ) ;
624+
625+ await processor . onSpanStart ( workflowWithError ) ;
626+ await processor . onSpanEnd ( workflowWithError ) ;
627+ await processor . onTraceEnd ( trace ) ;
628+
629+ // Verify addWorkflowSpan was called with statusCode 500
630+ expect ( mockLogger . addWorkflowSpan ) . toHaveBeenCalledTimes ( 1 ) ;
631+ const workflowSpanCall = mockLogger . addWorkflowSpan . mock . calls [ 0 ] [ 0 ] ;
632+ expect ( workflowSpanCall . statusCode ) . toBe ( 500 ) ;
633+ } ) ;
634+
635+ test ( 'test agent span statusCode passed to addAgentSpan' , async ( ) => {
636+ const mockLogger = createMockLogger ( ) ;
637+ const processor = new GalileoTracingProcessor ( mockLogger as never , false ) ;
638+ const trace = makeTrace ( ) ;
639+
640+ await processor . onTraceStart ( trace ) ;
641+
642+ // Create an agent span
643+ const agent = makeSpan ( {
644+ spanId : 'agent-001' ,
645+ parentId : 'trace-001' ,
646+ spanData : { type : 'agent' , name : 'TestAgent' }
647+ } ) ;
648+
649+ // Create a child LLM span
650+ const llm = makeSpan ( {
651+ spanId : 'llm-001' ,
652+ parentId : 'agent-001' ,
653+ spanData : {
654+ type : 'generation' ,
655+ model : 'gpt-4' ,
656+ input : [ ] ,
657+ output : 'test output'
658+ } ,
659+ error : null
660+ } ) ;
661+
662+ await processor . onSpanStart ( agent ) ;
663+ await processor . onSpanStart ( llm ) ;
664+ await processor . onSpanEnd ( llm ) ;
665+ await processor . onSpanEnd ( agent ) ;
666+ await processor . onTraceEnd ( trace ) ;
667+
668+ // Verify addAgentSpan was called with statusCode parameter
669+ expect ( mockLogger . addAgentSpan ) . toHaveBeenCalledTimes ( 1 ) ;
670+ const agentSpanCall = mockLogger . addAgentSpan . mock . calls [ 0 ] [ 0 ] ;
671+ expect ( agentSpanCall . statusCode ) . toBe ( 200 ) ;
672+ } ) ;
673+
674+ test ( 'test conclude called with statusCode for workflow spans' , async ( ) => {
675+ const mockLogger = createMockLogger ( ) ;
676+ const processor = new GalileoTracingProcessor ( mockLogger as never , false ) ;
677+ const trace = makeTrace ( ) ;
678+
679+ await processor . onTraceStart ( trace ) ;
680+
681+ // Create nested workflow spans to test conclude calls
682+ const outerWorkflow = makeSpan ( {
683+ spanId : 'workflow-001' ,
684+ parentId : 'trace-001' ,
685+ spanData : { type : 'handoff' , from_agent : 'Agent1' , to_agent : 'Agent2' }
686+ } ) ;
687+
688+ const innerWorkflow = makeSpan ( {
689+ spanId : 'workflow-002' ,
690+ parentId : 'workflow-001' ,
691+ spanData : { type : 'custom' , name : 'InnerWorkflow' }
692+ } ) ;
693+
694+ await processor . onSpanStart ( outerWorkflow ) ;
695+ await processor . onSpanStart ( innerWorkflow ) ;
696+ await processor . onSpanEnd ( innerWorkflow ) ;
697+ await processor . onSpanEnd ( outerWorkflow ) ;
698+ await processor . onTraceEnd ( trace ) ;
699+
700+ // Verify conclude was called for the workflow spans
701+ expect ( mockLogger . conclude ) . toHaveBeenCalled ( ) ;
702+ // Find calls that pass statusCode
703+ const concludeCalls = mockLogger . conclude . mock . calls ;
704+ const callsWithStatusCode = concludeCalls . filter (
705+ ( call ) => call [ 0 ] ?. statusCode !== undefined
706+ ) ;
707+ expect ( callsWithStatusCode . length ) . toBeGreaterThan ( 0 ) ;
708+ } ) ;
709+ } ) ;
0 commit comments