|
48 | 48 | from ddtrace.llmobs._constants import ANNOTATIONS_CONTEXT_ID |
49 | 49 | from ddtrace.llmobs._constants import DECORATOR |
50 | 50 | from ddtrace.llmobs._constants import DEFAULT_PROJECT_NAME |
| 51 | +from ddtrace.llmobs._constants import DISPATCH_ON_GUARDRAIL_SPAN_START |
| 52 | +from ddtrace.llmobs._constants import DISPATCH_ON_LLM_SPAN_FINISH |
51 | 53 | from ddtrace.llmobs._constants import DISPATCH_ON_LLM_TOOL_CHOICE |
| 54 | +from ddtrace.llmobs._constants import DISPATCH_ON_OPENAI_AGENT_SPAN_FINISH |
52 | 55 | from ddtrace.llmobs._constants import DISPATCH_ON_TOOL_CALL |
53 | 56 | from ddtrace.llmobs._constants import DISPATCH_ON_TOOL_CALL_OUTPUT_USED |
54 | 57 | from ddtrace.llmobs._constants import EXPERIMENT_CSV_FIELD_MAX_SIZE |
|
91 | 94 | from ddtrace.llmobs._experiment import JSONType |
92 | 95 | from ddtrace.llmobs._utils import AnnotationContext |
93 | 96 | from ddtrace.llmobs._utils import LinkTracker |
94 | | -from ddtrace.llmobs._utils import ToolCallTracker |
95 | 97 | from ddtrace.llmobs._utils import _get_ml_app |
96 | 98 | from ddtrace.llmobs._utils import _get_nearest_llmobs_ancestor |
97 | 99 | from ddtrace.llmobs._utils import _get_session_id |
@@ -219,8 +221,6 @@ def __init__( |
219 | 221 | self._annotations: List[Tuple[str, str, Dict[str, Any]]] = [] |
220 | 222 | self._annotation_context_lock = forksafe.RLock() |
221 | 223 |
|
222 | | - self._tool_call_tracker = ToolCallTracker() |
223 | | - |
224 | 224 | def _on_span_start(self, span: Span) -> None: |
225 | 225 | if self.enabled and span.span_type == SpanTypes.LLM: |
226 | 226 | self._activate_llmobs_span(span) |
@@ -256,6 +256,9 @@ def _llmobs_span_event(self, span: Span) -> Optional[LLMObsSpanEvent]: |
256 | 256 | if not span_kind: |
257 | 257 | raise KeyError("Span kind not found in span context") |
258 | 258 |
|
| 259 | + if span_kind == "llm": |
| 260 | + core.dispatch(DISPATCH_ON_LLM_SPAN_FINISH, (span,)) |
| 261 | + |
259 | 262 | llmobs_span = LLMObsSpan() |
260 | 263 | _dd_attrs = { |
261 | 264 | "span_id": str(span.span_id), |
@@ -501,9 +504,13 @@ def _stop_service(self) -> None: |
501 | 504 | core.reset_listeners("threading.submit", self._current_trace_context) |
502 | 505 | core.reset_listeners("threading.execution", self._llmobs_context_provider.activate) |
503 | 506 |
|
504 | | - core.reset_listeners(DISPATCH_ON_LLM_TOOL_CHOICE, self._tool_call_tracker.on_llm_tool_choice) |
505 | | - core.reset_listeners(DISPATCH_ON_TOOL_CALL, self._tool_call_tracker.on_tool_call) |
506 | | - core.reset_listeners(DISPATCH_ON_TOOL_CALL_OUTPUT_USED, self._tool_call_tracker.on_tool_call_output_used) |
| 507 | + core.reset_listeners(DISPATCH_ON_LLM_TOOL_CHOICE, self._link_tracker.on_llm_tool_choice) |
| 508 | + core.reset_listeners(DISPATCH_ON_TOOL_CALL, self._link_tracker.on_tool_call) |
| 509 | + core.reset_listeners(DISPATCH_ON_TOOL_CALL_OUTPUT_USED, self._link_tracker.on_tool_call_output_used) |
| 510 | + |
| 511 | + core.reset_listeners(DISPATCH_ON_GUARDRAIL_SPAN_START, self._link_tracker.on_guardrail_span_start) |
| 512 | + core.reset_listeners(DISPATCH_ON_LLM_SPAN_FINISH, self._link_tracker.on_llm_span_finish) |
| 513 | + core.reset_listeners(DISPATCH_ON_OPENAI_AGENT_SPAN_FINISH, self._link_tracker.on_openai_agent_span_finish) |
507 | 514 |
|
508 | 515 | forksafe.unregister(self._child_after_fork) |
509 | 516 |
|
@@ -614,9 +621,13 @@ def enable( |
614 | 621 | core.on("threading.submit", cls._instance._current_trace_context, "llmobs_ctx") |
615 | 622 | core.on("threading.execution", cls._instance._llmobs_context_provider.activate) |
616 | 623 |
|
617 | | - core.on(DISPATCH_ON_LLM_TOOL_CHOICE, cls._instance._tool_call_tracker.on_llm_tool_choice) |
618 | | - core.on(DISPATCH_ON_TOOL_CALL, cls._instance._tool_call_tracker.on_tool_call) |
619 | | - core.on(DISPATCH_ON_TOOL_CALL_OUTPUT_USED, cls._instance._tool_call_tracker.on_tool_call_output_used) |
| 624 | + core.on(DISPATCH_ON_LLM_TOOL_CHOICE, cls._instance._link_tracker.on_llm_tool_choice) |
| 625 | + core.on(DISPATCH_ON_TOOL_CALL, cls._instance._link_tracker.on_tool_call) |
| 626 | + core.on(DISPATCH_ON_TOOL_CALL_OUTPUT_USED, cls._instance._link_tracker.on_tool_call_output_used) |
| 627 | + |
| 628 | + core.on(DISPATCH_ON_GUARDRAIL_SPAN_START, cls._instance._link_tracker.on_guardrail_span_start) |
| 629 | + core.on(DISPATCH_ON_LLM_SPAN_FINISH, cls._instance._link_tracker.on_llm_span_finish) |
| 630 | + core.on(DISPATCH_ON_OPENAI_AGENT_SPAN_FINISH, cls._instance._link_tracker.on_openai_agent_span_finish) |
620 | 631 |
|
621 | 632 | atexit.register(cls.disable) |
622 | 633 | telemetry_writer.product_activated(TELEMETRY_APM_PRODUCT.LLMOBS, True) |
@@ -811,41 +822,6 @@ def disable(cls) -> None: |
811 | 822 |
|
812 | 823 | log.debug("%s disabled", cls.__name__) |
813 | 824 |
|
814 | | - def _record_object(self, span, obj, input_or_output): |
815 | | - if obj is None: |
816 | | - return |
817 | | - span_links = [] |
818 | | - for span_link in self._link_tracker.get_span_links_from_object(obj): |
819 | | - try: |
820 | | - if span_link["attributes"]["from"] == "input" and input_or_output == "output": |
821 | | - continue |
822 | | - except KeyError: |
823 | | - log.debug("failed to read span link: ", span_link) |
824 | | - continue |
825 | | - span_links.append( |
826 | | - { |
827 | | - "trace_id": span_link["trace_id"], |
828 | | - "span_id": span_link["span_id"], |
829 | | - "attributes": { |
830 | | - "from": span_link["attributes"]["from"], |
831 | | - "to": input_or_output, |
832 | | - }, |
833 | | - } |
834 | | - ) |
835 | | - self._tag_span_links(span, span_links) |
836 | | - self._link_tracker.add_span_links_to_object( |
837 | | - obj, |
838 | | - [ |
839 | | - { |
840 | | - "trace_id": self.export_span(span)["trace_id"], |
841 | | - "span_id": self.export_span(span)["span_id"], |
842 | | - "attributes": { |
843 | | - "from": input_or_output, |
844 | | - }, |
845 | | - } |
846 | | - ], |
847 | | - ) |
848 | | - |
849 | 825 | def _tag_span_links(self, span, span_links): |
850 | 826 | if not span_links: |
851 | 827 | return |
|
0 commit comments