7
7
from typing import Any , Callable , Dict , List , Literal , Optional
8
8
9
9
from langchain_core .callbacks import dispatch_custom_event
10
- from uipath .tracing import TracingManager
10
+ from uipath .tracing import TracingManager , traced
11
11
12
12
from ._events import CustomTraceEvents , FunctionCallEventData
13
13
@@ -387,12 +387,112 @@ def register_uipath_tracing():
387
387
388
388
389
389
# Apply the patch
390
- def _instrument_traceable_attributes ():
390
+ def _map_traceable_to_traced_args (
391
+ run_type : Optional [str ] = None ,
392
+ name : Optional [str ] = None ,
393
+ tags : Optional [List [str ]] = None ,
394
+ metadata : Optional [Dict [str , Any ]] = None ,
395
+ ** kwargs : Any ,
396
+ ) -> Dict [str , Any ]:
397
+ """
398
+ Map LangSmith @traceable arguments to UiPath @traced() arguments.
399
+
400
+ Args:
401
+ run_type: Function type (tool, chain, llm, retriever, etc.)
402
+ name: Custom name for the traced function
403
+ tags: List of tags for categorization
404
+ metadata: Additional metadata dictionary
405
+ **kwargs: Additional arguments (ignored)
406
+
407
+ Returns:
408
+ Dict containing mapped arguments for @traced()
409
+ """
410
+ traced_args = {}
411
+
412
+ # Direct mappings
413
+ if name is not None :
414
+ traced_args ["name" ] = name
415
+
416
+ # Pass through run_type directly to UiPath @traced()
417
+ if run_type :
418
+ traced_args ["run_type" ] = run_type
419
+
420
+ # For span_type, we can derive from run_type or use a default
421
+ if run_type :
422
+ # Map run_type to appropriate span_type for OpenTelemetry
423
+ span_type_mapping = {
424
+ "tool" : "tool_call" ,
425
+ "chain" : "chain_execution" ,
426
+ "llm" : "llm_call" ,
427
+ "retriever" : "retrieval" ,
428
+ "embedding" : "embedding" ,
429
+ "prompt" : "prompt_template" ,
430
+ "parser" : "output_parser"
431
+ }
432
+ traced_args ["span_type" ] = span_type_mapping .get (run_type , run_type )
433
+
434
+ # Note: UiPath @traced() doesn't support custom attributes directly
435
+ # Tags and metadata information is lost in the current mapping
436
+ # This could be enhanced in future versions
437
+
438
+ return traced_args
439
+
440
+
441
+ def otel_traceable_adapter (
442
+ func : Optional [Callable ] = None ,
443
+ * ,
444
+ run_type : Optional [str ] = None ,
445
+ name : Optional [str ] = None ,
446
+ tags : Optional [List [str ]] = None ,
447
+ metadata : Optional [Dict [str , Any ]] = None ,
448
+ ** kwargs : Any ,
449
+ ):
450
+ """
451
+ OTEL-based adapter that converts LangSmith @traceable decorator calls to UiPath @traced().
452
+
453
+ This function maintains the same interface as LangSmith's @traceable but uses
454
+ UiPath's OpenTelemetry-based tracing system underneath.
455
+
456
+ Args:
457
+ func: Function to be decorated (when used without parentheses)
458
+ run_type: Type of function (tool, chain, llm, etc.)
459
+ name: Custom name for tracing
460
+ tags: List of tags for categorization
461
+ metadata: Additional metadata dictionary
462
+ **kwargs: Additional arguments (for future compatibility)
463
+
464
+ Returns:
465
+ Decorated function or decorator function
466
+ """
467
+ def decorator (f : Callable ) -> Callable :
468
+ # Map arguments to @traced() format
469
+ traced_args = _map_traceable_to_traced_args (
470
+ run_type = run_type ,
471
+ name = name ,
472
+ tags = tags ,
473
+ metadata = metadata ,
474
+ ** kwargs
475
+ )
476
+
477
+ # Apply UiPath @traced() decorator
478
+ return traced (** traced_args )(f )
479
+
480
+ # Handle both @traceable and @traceable(...) usage patterns
481
+ if func is None :
482
+ # Called as @traceable(...) - return decorator
483
+ return decorator
484
+ else :
485
+ # Called as @traceable - apply decorator directly
486
+ return decorator (func )
487
+
488
+
489
+ def _instrument_traceable_attributes (useOtel : bool = False ):
391
490
"""Apply the patch to langsmith module at import time."""
392
491
global original_langsmith , original_traceable
393
492
394
- # Register our custom tracing decorator
395
- register_uipath_tracing ()
493
+ if not useOtel :
494
+ # Register our custom tracing decorator when not using opentelemetry
495
+ register_uipath_tracing ()
396
496
397
497
# Import the original module if not already done
398
498
if original_langsmith is None :
@@ -408,7 +508,12 @@ def _instrument_traceable_attributes():
408
508
original_traceable = original_langsmith .traceable
409
509
410
510
# Replace the traceable function with our patched version
411
- original_langsmith .traceable = patched_traceable
511
+ if useOtel :
512
+ # Use OTEL-based adapter when OTEL is enabled
513
+ original_langsmith .traceable = otel_traceable_adapter
514
+ else :
515
+ # Use existing dispatch_event-based adapter
516
+ original_langsmith .traceable = patched_traceable
412
517
413
518
# Put our modified module back
414
519
sys .modules ["langsmith" ] = original_langsmith
0 commit comments