@@ -376,14 +376,18 @@ describe("buildSessionOptions", () => {
376376 name : "omits the team_id header when POSTHOG_PROJECT_ID is unset" ,
377377 projectId : undefined ,
378378 existingHeaders : undefined ,
379- expected : "x-posthog-use-bedrock-fallback: true" ,
379+ expected : [
380+ "x-posthog-property-$ai_session_id: test-session" ,
381+ "x-posthog-use-bedrock-fallback: true" ,
382+ ] . join ( "\n" ) ,
380383 } ,
381384 {
382385 name : "forwards POSTHOG_PROJECT_ID as the team_id attribution header" ,
383386 projectId : "42" ,
384387 existingHeaders : undefined ,
385388 expected : [
386389 "x-posthog-property-team_id: 42" ,
390+ "x-posthog-property-$ai_session_id: test-session" ,
387391 "x-posthog-use-bedrock-fallback: true" ,
388392 ] . join ( "\n" ) ,
389393 } ,
@@ -394,6 +398,7 @@ describe("buildSessionOptions", () => {
394398 expected : [
395399 "x-posthog-property-task_id: task-abc" ,
396400 "x-posthog-property-team_id: 42" ,
401+ "x-posthog-property-$ai_session_id: test-session" ,
397402 "x-posthog-use-bedrock-fallback: true" ,
398403 ] . join ( "\n" ) ,
399404 } ,
@@ -411,6 +416,101 @@ describe("buildSessionOptions", () => {
411416 expect ( headers ) . toBe ( expected ) ;
412417 } ) ;
413418 } ) ;
419+
420+ describe ( "gateway turn tracing env" , ( ) => {
421+ const KEYS = [
422+ "CLAUDE_CODE_ENABLE_TELEMETRY" ,
423+ "CLAUDE_CODE_ENHANCED_TELEMETRY_BETA" ,
424+ "CLAUDE_CODE_PROPAGATE_TRACEPARENT" ,
425+ "OTEL_TRACES_EXPORTER" ,
426+ "OTEL_EXPORTER_OTLP_PROTOCOL" ,
427+ "OTEL_EXPORTER_OTLP_ENDPOINT" ,
428+ "TRACEPARENT" ,
429+ "TRACESTATE" ,
430+ ] as const ;
431+ const original : Partial < Record < string , string | undefined > > = { } ;
432+
433+ beforeEach ( ( ) => {
434+ for ( const key of KEYS ) {
435+ original [ key ] = process . env [ key ] ;
436+ delete process . env [ key ] ;
437+ }
438+ } ) ;
439+
440+ afterEach ( ( ) => {
441+ for ( const key of KEYS ) {
442+ const value = original [ key ] ;
443+ if ( value === undefined ) {
444+ delete process . env [ key ] ;
445+ } else {
446+ process . env [ key ] = value ;
447+ }
448+ }
449+ } ) ;
450+
451+ const gatewayEnv = {
452+ anthropicBaseUrl : "https://gateway.example" ,
453+ anthropicAuthToken : "tok" ,
454+ openaiBaseUrl : "https://gateway.example/v1" ,
455+ openaiApiKey : "tok" ,
456+ } ;
457+
458+ it ( "enables per-turn traceparent when routed through the gateway" , ( ) => {
459+ const env = buildSessionOptions ( { ...makeParams ( ) , gatewayEnv } ) . env ;
460+
461+ expect ( env ?. CLAUDE_CODE_ENABLE_TELEMETRY ) . toBe ( "1" ) ;
462+ expect ( env ?. CLAUDE_CODE_ENHANCED_TELEMETRY_BETA ) . toBe ( "1" ) ;
463+ expect ( env ?. CLAUDE_CODE_PROPAGATE_TRACEPARENT ) . toBe ( "1" ) ;
464+ expect ( env ?. OTEL_TRACES_EXPORTER ) . toBe ( "otlp" ) ;
465+ expect ( env ?. OTEL_EXPORTER_OTLP_PROTOCOL ) . toBe ( "http/json" ) ;
466+ expect ( env ?. OTEL_EXPORTER_OTLP_ENDPOINT ) . toBe ( "http://127.0.0.1:9" ) ;
467+ } ) ;
468+
469+ it ( "honors a caller-supplied OTLP endpoint" , ( ) => {
470+ process . env . OTEL_EXPORTER_OTLP_ENDPOINT =
471+ "http://collector.internal:4318" ;
472+
473+ const env = buildSessionOptions ( { ...makeParams ( ) , gatewayEnv } ) . env ;
474+
475+ expect ( env ?. OTEL_EXPORTER_OTLP_ENDPOINT ) . toBe (
476+ "http://collector.internal:4318" ,
477+ ) ;
478+ } ) ;
479+
480+ it ( "pins exporter and protocol so an inherited none can't disable tracing" , ( ) => {
481+ process . env . OTEL_TRACES_EXPORTER = "none" ;
482+ process . env . OTEL_EXPORTER_OTLP_PROTOCOL = "grpc" ;
483+
484+ const env = buildSessionOptions ( { ...makeParams ( ) , gatewayEnv } ) . env ;
485+
486+ expect ( env ?. OTEL_TRACES_EXPORTER ) . toBe ( "otlp" ) ;
487+ expect ( env ?. OTEL_EXPORTER_OTLP_PROTOCOL ) . toBe ( "http/json" ) ;
488+ } ) ;
489+
490+ it ( "strips inherited TRACEPARENT so turns keep distinct trace ids" , ( ) => {
491+ process . env . TRACEPARENT =
492+ "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01" ;
493+ process . env . TRACESTATE = "vendor=x" ;
494+
495+ const env = buildSessionOptions ( { ...makeParams ( ) , gatewayEnv } ) . env ;
496+
497+ expect ( env ?. TRACEPARENT ) . toBeUndefined ( ) ;
498+ expect ( env ?. TRACESTATE ) . toBeUndefined ( ) ;
499+ } ) ;
500+
501+ it ( "leaves BYOK sessions untouched" , ( ) => {
502+ process . env . TRACEPARENT =
503+ "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01" ;
504+
505+ const env = buildSessionOptions ( makeParams ( ) ) . env ;
506+
507+ expect ( env ?. CLAUDE_CODE_ENABLE_TELEMETRY ) . toBeUndefined ( ) ;
508+ expect ( env ?. CLAUDE_CODE_PROPAGATE_TRACEPARENT ) . toBeUndefined ( ) ;
509+ expect ( env ?. TRACEPARENT ) . toBe (
510+ "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01" ,
511+ ) ;
512+ } ) ;
513+ } ) ;
414514} ) ;
415515
416516describe ( "buildSystemPrompt" , ( ) => {
0 commit comments