22
33from __future__ import annotations
44
5+ import random
6+ import uuid
57from contextlib import contextmanager
6- from typing import Any , Mapping , Protocol , Type , cast
8+ from typing import Any , Mapping , Protocol , Type
79
810from agents import CustomSpanData , custom_span , get_current_span , trace
911from agents .tracing import (
1012 get_trace_provider ,
1113)
12- from agents .tracing .provider import DefaultTraceProvider
1314from agents .tracing .scope import Scope
14- from agents .tracing .spans import NoOpSpan , SpanImpl
15+ from agents .tracing .spans import NoOpSpan
1516
1617import temporalio .activity
1718import temporalio .api .common .v1
@@ -283,6 +284,35 @@ async def execute_activity(
283284 return await self .next .execute_activity (input )
284285
285286
287+ class RunIdRandom :
288+ """Random uuid generator seeded by the run id of the workflow.
289+ Doesn't currently support replay over reset correctly.
290+ """
291+
292+ def __init__ (self ):
293+ """Create a new random UUID generator."""
294+ self ._random = random .Random ("OpenAIPlugin" + workflow .info ().run_id )
295+
296+ def uuid4 (self ) -> str :
297+ """Generate a random UUID."""
298+ return uuid .UUID (
299+ bytes = random .getrandbits (16 * 8 ).to_bytes (16 , "big" ), version = 4
300+ ).hex [:24 ]
301+
302+
303+ def _ensure_tracing_random () -> None :
304+ """We use a custom uuid generator for spans to ensure that changes to user code workflow.random usage
305+ do not affect tracing and vice versa.
306+ """
307+ instance = workflow .instance ()
308+ if not hasattr (instance , "__temporal_openai_tracing_random" ):
309+ setattr (
310+ workflow .instance (),
311+ "__temporal_openai_tracing_random" ,
312+ RunIdRandom (),
313+ )
314+
315+
286316class _ContextPropagationWorkflowInboundInterceptor (
287317 temporalio .worker .WorkflowInboundInterceptor
288318):
@@ -292,18 +322,21 @@ def init(self, outbound: temporalio.worker.WorkflowOutboundInterceptor) -> None:
292322 async def execute_workflow (
293323 self , input : temporalio .worker .ExecuteWorkflowInput
294324 ) -> Any :
325+ _ensure_tracing_random ()
295326 with context_from_header (
296327 "temporal:executeWorkflow" , input , temporalio .workflow .payload_converter ()
297328 ):
298329 return await self .next .execute_workflow (input )
299330
300331 async def handle_signal (self , input : temporalio .worker .HandleSignalInput ) -> None :
332+ _ensure_tracing_random ()
301333 with context_from_header (
302334 "temporal:handleSignal" , input , temporalio .workflow .payload_converter ()
303335 ):
304336 return await self .next .handle_signal (input )
305337
306338 async def handle_query (self , input : temporalio .worker .HandleQueryInput ) -> Any :
339+ _ensure_tracing_random ()
307340 with context_from_header (
308341 "temporal:handleQuery" , input , temporalio .workflow .payload_converter ()
309342 ):
@@ -322,6 +355,7 @@ def handle_update_validator(
322355 async def handle_update_handler (
323356 self , input : temporalio .worker .HandleUpdateInput
324357 ) -> Any :
358+ _ensure_tracing_random ()
325359 with context_from_header (
326360 "temporal:handleUpdateHandler" ,
327361 input ,
0 commit comments