diff --git a/api/core/ops/langsmith_trace/entities/langsmith_trace_entity.py b/api/core/ops/langsmith_trace/entities/langsmith_trace_entity.py index 05c932fb99..16c76f363c 100644 --- a/api/core/ops/langsmith_trace/entities/langsmith_trace_entity.py +++ b/api/core/ops/langsmith_trace/entities/langsmith_trace_entity.py @@ -49,6 +49,7 @@ class LangSmithRunModel(LangSmithTokenUsage, LangSmithMultiModel): reference_example_id: Optional[str] = Field(None, description="Reference example ID associated with the run") input_attachments: Optional[dict[str, Any]] = Field(None, description="Input attachments of the run") output_attachments: Optional[dict[str, Any]] = Field(None, description="Output attachments of the run") + dotted_order: Optional[str] = Field(None, description="Dotted order of the run") @field_validator("inputs", "outputs") @classmethod diff --git a/api/core/ops/langsmith_trace/langsmith_trace.py b/api/core/ops/langsmith_trace/langsmith_trace.py index ad45050405..c15b132abd 100644 --- a/api/core/ops/langsmith_trace/langsmith_trace.py +++ b/api/core/ops/langsmith_trace/langsmith_trace.py @@ -25,7 +25,7 @@ from core.ops.langsmith_trace.entities.langsmith_trace_entity import ( LangSmithRunType, LangSmithRunUpdateModel, ) -from core.ops.utils import filter_none_values +from core.ops.utils import filter_none_values, generate_dotted_order from extensions.ext_database import db from models.model import EndUser, MessageFile from models.workflow import WorkflowNodeExecution @@ -62,6 +62,16 @@ class LangSmithDataTrace(BaseTraceInstance): self.generate_name_trace(trace_info) def workflow_trace(self, trace_info: WorkflowTraceInfo): + trace_id = trace_info.message_id or trace_info.workflow_app_log_id or trace_info.workflow_run_id + message_dotted_order = ( + generate_dotted_order(trace_info.message_id, trace_info.start_time) if trace_info.message_id else None + ) + workflow_dotted_order = generate_dotted_order( + trace_info.workflow_app_log_id or trace_info.workflow_run_id, + trace_info.workflow_data.created_at, + message_dotted_order, + ) + if trace_info.message_id: message_run = LangSmithRunModel( id=trace_info.message_id, @@ -76,6 +86,8 @@ class LangSmithDataTrace(BaseTraceInstance): }, tags=["message", "workflow"], error=trace_info.error, + trace_id=trace_id, + dotted_order=message_dotted_order, ) self.add_run(message_run) @@ -95,6 +107,8 @@ class LangSmithDataTrace(BaseTraceInstance): error=trace_info.error, tags=["workflow"], parent_run_id=trace_info.message_id or None, + trace_id=trace_id, + dotted_order=workflow_dotted_order, ) self.add_run(langsmith_run) @@ -177,6 +191,7 @@ class LangSmithDataTrace(BaseTraceInstance): else: run_type = LangSmithRunType.tool + node_dotted_order = generate_dotted_order(node_execution_id, created_at, workflow_dotted_order) langsmith_run = LangSmithRunModel( total_tokens=node_total_tokens, name=node_type, @@ -191,6 +206,9 @@ class LangSmithDataTrace(BaseTraceInstance): }, parent_run_id=trace_info.workflow_app_log_id or trace_info.workflow_run_id, tags=["node_execution"], + id=node_execution_id, + trace_id=trace_id, + dotted_order=node_dotted_order, ) self.add_run(langsmith_run) diff --git a/api/core/ops/utils.py b/api/core/ops/utils.py index 3cd3fb5756..998eba9ea9 100644 --- a/api/core/ops/utils.py +++ b/api/core/ops/utils.py @@ -1,5 +1,6 @@ from contextlib import contextmanager from datetime import datetime +from typing import Optional, Union from extensions.ext_database import db from models.model import Message @@ -43,3 +44,19 @@ def replace_text_with_content(data): return [replace_text_with_content(item) for item in data] else: return data + + +def generate_dotted_order( + run_id: str, start_time: Union[str, datetime], parent_dotted_order: Optional[str] = None +) -> str: + """ + generate dotted_order for langsmith + """ + start_time = datetime.fromisoformat(start_time) if isinstance(start_time, str) else start_time + timestamp = start_time.strftime("%Y%m%dT%H%M%S%f")[:-3] + "Z" + current_segment = f"{timestamp}{run_id}" + + if parent_dotted_order is None: + return current_segment + + return f"{parent_dotted_order}.{current_segment}"