@@ -15,11 +15,9 @@ import { collectStreamedSpans, getSpanOp, SerializedStreamedSpan } from '@sentry
1515const APP = 'node-mastra' ;
1616const TICKET = 'My checkout page shows a blank screen after I click Pay.' ;
1717
18- const attrValue = ( span : SerializedStreamedSpan , key : string ) : unknown => span . attributes ?. [ key ] ?. value ;
19-
2018const isEvaluateSpan = ( span : SerializedStreamedSpan ) : boolean => getSpanOp ( span ) === GEN_AI_EVALUATE ;
2119const isClassifyServerSpan = ( span : SerializedStreamedSpan ) : boolean =>
22- getSpanOp ( span ) === HTTP_SERVER && String ( attrValue ( span , URL_FULL ) ?? '' ) . includes ( '/classify' ) ;
20+ getSpanOp ( span ) === HTTP_SERVER && String ( span . attributes ?. [ URL_FULL ] ?. value ?? '' ) . includes ( '/classify' ) ;
2321
2422test ( 'captures a Mastra classifier (Jev) evaluation as a gen_ai.evaluate span' , async ( { baseURL } ) => {
2523 const spansPromise = collectStreamedSpans (
@@ -41,17 +39,17 @@ test('captures a Mastra classifier (Jev) evaluation as a gen_ai.evaluate span',
4139 // Only the Mastra exporter reports the evaluation: `Classifier` calls `doEvaluate()` directly, so the
4240 // Vercel AI integration does not see it.
4341 const evaluateSpans = spans . filter ( isEvaluateSpan ) ;
44- expect ( evaluateSpans . map ( span => ( { name : span . name , origin : attrValue ( span , SENTRY_ORIGIN ) } ) ) ) . toEqual ( [
42+ expect ( evaluateSpans . map ( span => ( { name : span . name , origin : span . attributes ?. [ SENTRY_ORIGIN ] ?. value } ) ) ) . toEqual ( [
4543 { name : 'evaluate typesafe/jev-1.13' , origin : 'auto.ai.mastra' } ,
4644 ] ) ;
4745
4846 const evaluateSpan = evaluateSpans [ 0 ] ! ;
4947 expect ( evaluateSpan . parent_span_id ) . toBe ( serverSpan . span_id ) ;
50- expect ( attrValue ( evaluateSpan , GEN_AI_OPERATION_NAME ) ) . toBe ( 'evaluate' ) ;
51- expect ( attrValue ( evaluateSpan , GEN_AI_REQUEST_MODEL ) ) . toBe ( 'typesafe/jev-1.13' ) ;
52- expect ( attrValue ( evaluateSpan , GEN_AI_PROVIDER_NAME ) ) . toBe ( 'openrouter' ) ;
53- expect ( attrValue ( evaluateSpan , GEN_AI_USAGE_INPUT_TOKENS ) ) . toBeGreaterThan ( 0 ) ;
54- expect ( JSON . parse ( String ( attrValue ( evaluateSpan , GEN_AI_INPUT_MESSAGES ) ) ) ) . toEqual ( [
48+ expect ( evaluateSpan . attributes ?. [ GEN_AI_OPERATION_NAME ] ?. value ) . toBe ( 'evaluate' ) ;
49+ expect ( evaluateSpan . attributes ?. [ GEN_AI_REQUEST_MODEL ] ?. value ) . toBe ( 'typesafe/jev-1.13' ) ;
50+ expect ( evaluateSpan . attributes ?. [ GEN_AI_PROVIDER_NAME ] ?. value ) . toBe ( 'openrouter' ) ;
51+ expect ( evaluateSpan . attributes ?. [ GEN_AI_USAGE_INPUT_TOKENS ] ?. value ) . toBeGreaterThan ( 0 ) ;
52+ expect ( JSON . parse ( String ( evaluateSpan . attributes ?. [ GEN_AI_INPUT_MESSAGES ] ?. value ) ) ) . toEqual ( [
5553 {
5654 type : 'evaluation' ,
5755 state : { ticket : TICKET } ,
@@ -61,7 +59,7 @@ test('captures a Mastra classifier (Jev) evaluation as a gen_ai.evaluate span',
6159 } ,
6260 ] ) ;
6361 // The probability comes from the live model, so only its shape is stable.
64- expect ( JSON . parse ( String ( attrValue ( evaluateSpan , GEN_AI_OUTPUT_MESSAGES ) ) ) ) . toEqual ( [
62+ expect ( JSON . parse ( String ( evaluateSpan . attributes ?. [ GEN_AI_OUTPUT_MESSAGES ] ?. value ) ) ) . toEqual ( [
6563 { type : 'evaluation' , answers : { is_bug : { type : 'boolean' , probability : expect . any ( Number ) } } } ,
6664 ] ) ;
6765} ) ;
0 commit comments