@@ -268,30 +268,119 @@ describe("Test Associations API", () => {
268268 assert . ok ( result ) ;
269269 assert . ok ( chatSpan ) ;
270270
271- // Check all property types are set
272- assert . strictEqual (
273- chatSpan . attributes [
274- `${ SpanAttributes . TRACELOOP_ASSOCIATION_PROPERTIES } .conversation_id`
275- ] ,
276- "conv-abc" ,
271+ // Check all property types are set (standard properties without prefix)
272+ assert . strictEqual ( chatSpan . attributes [ "conversation_id" ] , "conv-abc" ) ;
273+ assert . strictEqual ( chatSpan . attributes [ "customer_id" ] , "customer-def" ) ;
274+ assert . strictEqual ( chatSpan . attributes [ "user_id" ] , "user-ghi" ) ;
275+ assert . strictEqual ( chatSpan . attributes [ "session_id" ] , "session-jkl" ) ;
276+ } ) ;
277+
278+ it ( "should propagate associations to all child spans" , async ( ) => {
279+ @traceloop . task ( { name : "subtask" } )
280+ async function subtask ( ) {
281+ const chatCompletion = await openai . chat . completions . create ( {
282+ messages : [ { role : "user" , content : "Child task message" } ] ,
283+ model : "gpt-3.5-turbo" ,
284+ } ) ;
285+ return chatCompletion . choices [ 0 ] . message . content ;
286+ }
287+
288+ const result = await traceloop . withWorkflow (
289+ { name : "test_child_propagation" } ,
290+ async ( ) => {
291+ // Set associations at the workflow level
292+ traceloop . Associations . set ( [
293+ [ traceloop . AssociationProperty . CONVERSATION_ID , "conv-propagate" ] ,
294+ [ traceloop . AssociationProperty . USER_ID , "user-propagate" ] ,
295+ ] ) ;
296+
297+ // Call a child task
298+ const taskResult = await subtask ( ) ;
299+
300+ return taskResult ;
301+ } ,
277302 ) ;
278- assert . strictEqual (
279- chatSpan . attributes [
280- `${ SpanAttributes . TRACELOOP_ASSOCIATION_PROPERTIES } .customer_id`
281- ] ,
282- "customer-def" ,
303+
304+ await traceloop . forceFlush ( ) ;
305+ const spans = memoryExporter . getFinishedSpans ( ) ;
306+
307+ const workflowSpan = spans . find (
308+ ( span ) => span . name === "test_child_propagation.workflow" ,
283309 ) ;
310+ const taskSpan = spans . find ( ( span ) => span . name === "subtask.task" ) ;
311+ const chatSpan = spans . find (
312+ ( span ) =>
313+ span . name === "openai.chat" &&
314+ span . attributes [ `${ SpanAttributes . ATTR_GEN_AI_PROMPT } .0.content` ] ===
315+ "Child task message" ,
316+ ) ;
317+
318+ assert . ok ( result ) ;
319+ assert . ok ( workflowSpan ) ;
320+ assert . ok ( taskSpan ) ;
321+ assert . ok ( chatSpan ) ;
322+
323+ // All spans should have the associations (standard properties without prefix)
284324 assert . strictEqual (
285- chatSpan . attributes [
286- `${ SpanAttributes . TRACELOOP_ASSOCIATION_PROPERTIES } .user_id`
287- ] ,
288- "user-ghi" ,
325+ workflowSpan . attributes [ "conversation_id" ] ,
326+ "conv-propagate" ,
327+ ) ;
328+ assert . strictEqual ( workflowSpan . attributes [ "user_id" ] , "user-propagate" ) ;
329+
330+ assert . strictEqual ( taskSpan . attributes [ "conversation_id" ] , "conv-propagate" ) ;
331+ assert . strictEqual ( taskSpan . attributes [ "user_id" ] , "user-propagate" ) ;
332+
333+ assert . strictEqual ( chatSpan . attributes [ "conversation_id" ] , "conv-propagate" ) ;
334+ assert . strictEqual ( chatSpan . attributes [ "user_id" ] , "user-propagate" ) ;
335+ } ) ;
336+
337+ it ( "should merge associations from Associations.set() and withAssociationProperties()" , async ( ) => {
338+ const result = await traceloop . withWorkflow (
339+ { name : "test_merge_associations" } ,
340+ async ( ) => {
341+ // Set standard associations
342+ traceloop . Associations . set ( [
343+ [ traceloop . AssociationProperty . CONVERSATION_ID , "conv-merge" ] ,
344+ [ traceloop . AssociationProperty . USER_ID , "user-merge" ] ,
345+ ] ) ;
346+
347+ // Add custom properties via withAssociationProperties
348+ return await traceloop . withAssociationProperties (
349+ { custom_field : "custom-value" } ,
350+ async ( ) => {
351+ const chatCompletion = await openai . chat . completions . create ( {
352+ messages : [ { role : "user" , content : "Test merge" } ] ,
353+ model : "gpt-3.5-turbo" ,
354+ } ) ;
355+ return chatCompletion . choices [ 0 ] . message . content ;
356+ } ,
357+ ) ;
358+ } ,
289359 ) ;
360+
361+ await traceloop . forceFlush ( ) ;
362+ const spans = memoryExporter . getFinishedSpans ( ) ;
363+
364+ const chatSpan = spans . find (
365+ ( span ) =>
366+ span . name === "openai.chat" &&
367+ span . attributes [ `${ SpanAttributes . ATTR_GEN_AI_PROMPT } .0.content` ] ===
368+ "Test merge" ,
369+ ) ;
370+
371+ assert . ok ( result ) ;
372+ assert . ok ( chatSpan ) ;
373+
374+ // Standard properties should be without prefix
375+ assert . strictEqual ( chatSpan . attributes [ "conversation_id" ] , "conv-merge" ) ;
376+ assert . strictEqual ( chatSpan . attributes [ "user_id" ] , "user-merge" ) ;
377+
378+ // Custom property should have prefix
290379 assert . strictEqual (
291380 chatSpan . attributes [
292- `${ SpanAttributes . TRACELOOP_ASSOCIATION_PROPERTIES } .session_id `
381+ `${ SpanAttributes . TRACELOOP_ASSOCIATION_PROPERTIES } .custom_field `
293382 ] ,
294- "session-jkl " ,
383+ "custom-value " ,
295384 ) ;
296385 } ) ;
297386} ) ;
0 commit comments