From df097d69beedf4744f7c08a762164330d94959f7 Mon Sep 17 00:00:00 2001 From: bhumikadangayach Date: Sun, 19 Jul 2026 13:05:54 +0530 Subject: [PATCH 1/2] wip(util-genai): remove 9 deprecated TelemetryHandler methods, rename stale tests, add changelog Still waiting on lmolkova's deprecation-window policy answer on #246 before opening a PR. --- .../+remove-deprecated-methods.removed | 1 + .../util/genai/_inference_invocation.py | 6 +- .../src/opentelemetry/util/genai/handler.py | 205 ------------------ .../tests/test_handler_metrics.py | 6 +- .../tests/test_handler_workflow.py | 12 +- .../tests/test_toolcall.py | 2 +- .../tests/test_utils.py | 6 +- 7 files changed, 17 insertions(+), 221 deletions(-) create mode 100644 util/opentelemetry-util-genai/.changelog/+remove-deprecated-methods.removed diff --git a/util/opentelemetry-util-genai/.changelog/+remove-deprecated-methods.removed b/util/opentelemetry-util-genai/.changelog/+remove-deprecated-methods.removed new file mode 100644 index 000000000..85ea3df73 --- /dev/null +++ b/util/opentelemetry-util-genai/.changelog/+remove-deprecated-methods.removed @@ -0,0 +1 @@ +Remove deprecated ``start_inference``, ``start_llm``, ``start_embedding``, ``start_tool``, ``start_workflow``, ``stop_llm``, ``fail_llm``, ``start_invoke_local_agent``, and ``start_invoke_remote_agent`` methods from ``TelemetryHandler``. Use ``inference()``, ``embedding()``, ``tool()``, ``workflow()``, ``invoke_local_agent()``, and ``invoke_remote_agent()`` instead. \ No newline at end of file diff --git a/util/opentelemetry-util-genai/src/opentelemetry/util/genai/_inference_invocation.py b/util/opentelemetry-util-genai/src/opentelemetry/util/genai/_inference_invocation.py index 8701e78a9..d6acad654 100644 --- a/util/opentelemetry-util-genai/src/opentelemetry/util/genai/_inference_invocation.py +++ b/util/opentelemetry-util-genai/src/opentelemetry/util/genai/_inference_invocation.py @@ -222,8 +222,8 @@ def _maybe_create_event(self) -> LogRecord | None: class LLMInvocation: """Deprecated. Use InferenceInvocation instead. - Data container for an LLM invocation. Pass to handler.llm() to start - the span, then update fields and call handler.stop_llm() or handler.fail_llm(). + Data container for an LLM invocation. Pass to handler.inference() to start + the span, then update fields and call invocation.stop() or invocation.fail(). """ request_model: str | None = None @@ -261,7 +261,7 @@ def _start_with_handler( logger: Logger, completion_hook: CompletionHook, ) -> None: - """Create and start an InferenceInvocation from this data container. Called by handler.start_llm().""" + """Create and start an InferenceInvocation from this data container. Called by handler.inference().""" inv = InferenceInvocation( tracer, metrics_recorder, diff --git a/util/opentelemetry-util-genai/src/opentelemetry/util/genai/handler.py b/util/opentelemetry-util-genai/src/opentelemetry/util/genai/handler.py index e28d0e8dd..34b69d7c2 100644 --- a/util/opentelemetry-util-genai/src/opentelemetry/util/genai/handler.py +++ b/util/opentelemetry-util-genai/src/opentelemetry/util/genai/handler.py @@ -49,8 +49,6 @@ get_tracer, ) from opentelemetry.util.genai._agent_invocation import AgentInvocation -from opentelemetry.util.genai._inference_invocation import LLMInvocation -from opentelemetry.util.genai._invocation import Error from opentelemetry.util.genai.completion_hook import ( CompletionHook, _NoOpCompletionHook, @@ -126,77 +124,6 @@ def should_capture_content(self) -> bool: """ return self._capture_content - # New-style factory methods: construct + start in one call, handler stored on invocation - def start_inference( - self, - provider: str, - *, - request_model: str | None = None, - server_address: str | None = None, - server_port: int | None = None, - operation_name: str | None = None, - ) -> InferenceInvocation: - """Create and start an LLM inference invocation. - - .. deprecated:: 1.0b0 - Use ``handler.inference()`` instead. - - Set remaining attributes (input_messages, temperature, etc.) on the - returned invocation, then call invocation.stop() or invocation.fail(). - """ - return InferenceInvocation( - self._tracer, - self._metrics_recorder, - self._logger, - self._completion_hook, - provider, - request_model=request_model, - server_address=server_address, - server_port=server_port, - operation_name=operation_name, - ) - - def start_llm(self, invocation: LLMInvocation) -> LLMInvocation: - """Start an LLM invocation. - - .. deprecated:: - Use ``handler.inference()`` instead. - """ - invocation._start_with_handler( - self._tracer, - self._metrics_recorder, - self._logger, - self._completion_hook, - ) - return invocation - - def start_embedding( - self, - provider: str, - *, - request_model: str | None = None, - server_address: str | None = None, - server_port: int | None = None, - ) -> EmbeddingInvocation: - """Create and start an Embedding invocation. - - .. deprecated:: 1.0b0 - Use ``handler.embedding()`` instead. - - Set remaining attributes (encoding_formats, etc.) on the returned - invocation, then call invocation.stop() or invocation.fail(). - """ - return EmbeddingInvocation( - self._tracer, - self._metrics_recorder, - self._logger, - self._completion_hook, - provider, - request_model=request_model, - server_address=server_address, - server_port=server_port, - ) - def retrieval( self, *, @@ -226,80 +153,6 @@ def retrieval( server_port=server_port, ) - def start_tool( - self, - name: str, - *, - tool_call_id: str | None = None, - tool_type: str | None = None, - tool_description: str | None = None, - ) -> ToolInvocation: - """Create and start a tool invocation. - - .. deprecated:: 1.0b0 - Use ``handler.tool()`` instead. - - Set tool_result on the returned invocation when done, then call - invocation.stop() or invocation.fail(). - """ - return ToolInvocation( - self._tracer, - self._metrics_recorder, - self._logger, - self._completion_hook, - name, - tool_call_id=tool_call_id, - tool_type=tool_type, - tool_description=tool_description, - ) - - def start_workflow( - self, - *, - name: str | None = None, - ) -> WorkflowInvocation: - """Create and start a workflow invocation. - - .. deprecated:: 1.0b0 - Use ``handler.workflow()`` instead. - - Set remaining attributes on the returned invocation, then call - invocation.stop() or invocation.fail(). - """ - return WorkflowInvocation( - self._tracer, - self._metrics_recorder, - self._logger, - self._completion_hook, - name, - ) - - def stop_llm(self, invocation: LLMInvocation) -> LLMInvocation: # pylint: disable=no-self-use - """Finalize an LLM invocation successfully and end its span. - - .. deprecated:: - Use ``handler.inference()`` and then ``inference.stop()`` instead. - """ - invocation._sync_to_invocation() - if invocation._inference_invocation is not None: - invocation._inference_invocation.stop() - return invocation - - def fail_llm( # pylint: disable=no-self-use - self, - invocation: LLMInvocation, - error: Error, - ) -> LLMInvocation: - """Fail an LLM invocation and end its span with error status. - - .. deprecated:: - Use ``handler.inference()`` and then ``inference.fail()`` instead. - """ - invocation._sync_to_invocation() - if invocation._inference_invocation is not None: - invocation._inference_invocation.fail(error) - return invocation - # New-style factory methods: construct + start in one call, handler stored on invocation def inference( @@ -387,64 +240,6 @@ def tool( tool_description=tool_description, ) - def start_invoke_local_agent( - self, - *, - request_model: str | None = None, - agent_name: str | None = None, - ) -> AgentInvocation: - """Create and start a local agent invocation (INTERNAL span kind). - - .. deprecated:: 1.0b0 - Use ``handler.invoke_local_agent()`` instead. - - Use for agents running within the same process (e.g. LangChain, CrewAI). - - Set remaining attributes (agent_name, etc.) on the returned invocation, - then call invocation.stop() or invocation.fail(). - """ - return AgentInvocation( - self._tracer, - self._metrics_recorder, - self._logger, - self._completion_hook, - span_kind=SpanKind.INTERNAL, - request_model=request_model, - agent_name=agent_name, - ) - - def start_invoke_remote_agent( - self, - provider: str, - *, - request_model: str | None = None, - server_address: str | None = None, - server_port: int | None = None, - agent_name: str | None = None, - ) -> AgentInvocation: - """Create and start a remote agent invocation (CLIENT span kind). - - .. deprecated:: 1.0b0 - Use ``handler.invoke_remote_agent()`` instead. - - Use for agents invoked over a remote service (e.g. OpenAI Assistants, AWS Bedrock). - - Set remaining attributes (agent_name, etc.) on the returned invocation, - then call invocation.stop() or invocation.fail(). - """ - return AgentInvocation( - self._tracer, - self._metrics_recorder, - self._logger, - self._completion_hook, - provider=provider, - span_kind=SpanKind.CLIENT, - request_model=request_model, - agent_name=agent_name, - server_address=server_address, - server_port=server_port, - ) - def invoke_local_agent( self, *, diff --git a/util/opentelemetry-util-genai/tests/test_handler_metrics.py b/util/opentelemetry-util-genai/tests/test_handler_metrics.py index d5eaa9b04..f0481edc7 100644 --- a/util/opentelemetry-util-genai/tests/test_handler_metrics.py +++ b/util/opentelemetry-util-genai/tests/test_handler_metrics.py @@ -20,7 +20,7 @@ class TelemetryHandlerMetricsTest(TestBase): - def test_stop_llm_records_duration_and_tokens(self) -> None: + def test_inference_stop_records_duration_and_tokens(self) -> None: handler = TelemetryHandler( tracer_provider=self.tracer_provider, meter_provider=self.meter_provider, @@ -74,7 +74,7 @@ def test_stop_llm_records_duration_and_tokens(self) -> None: places=3, ) - def test_stop_llm_records_duration_and_tokens_with_additional_attributes( + def test_inference_stop_records_duration_and_tokens_with_additional_attributes( self, ) -> None: handler = TelemetryHandler( @@ -114,7 +114,7 @@ def test_stop_llm_records_duration_and_tokens_with_additional_attributes( ) self.assertIsNone(point.attributes.get("should not be on metrics")) - def test_fail_llm_records_error_and_available_tokens(self) -> None: + def test_inference_fail_records_error_and_available_tokens(self) -> None: handler = TelemetryHandler( tracer_provider=self.tracer_provider, meter_provider=self.meter_provider, diff --git a/util/opentelemetry-util-genai/tests/test_handler_workflow.py b/util/opentelemetry-util-genai/tests/test_handler_workflow.py index 5e75507ea..98d0c604f 100644 --- a/util/opentelemetry-util-genai/tests/test_handler_workflow.py +++ b/util/opentelemetry-util-genai/tests/test_handler_workflow.py @@ -51,12 +51,12 @@ class TelemetryHandlerWorkflowTest(_WorkflowTestBase): # start_workflow # ------------------------------------------------------------------ - def test_start_workflow_creates_span(self) -> None: + def test_workflow_creates_span(self) -> None: invocation = self.handler.workflow(name="my_workflow") self.assertIsNot(invocation.span, INVALID_SPAN) invocation.stop() - def test_start_workflow_span_name(self) -> None: + def test_workflow_span_name(self) -> None: invocation = self.handler.workflow(name="my_pipeline") invocation.stop() @@ -64,7 +64,7 @@ def test_start_workflow_span_name(self) -> None: self.assertEqual(len(spans), 1) self.assertEqual(spans[0].name, "invoke_workflow my_pipeline") - def test_start_workflow_span_name_without_name(self) -> None: + def test_workflow_span_name_without_name(self) -> None: invocation = self.handler.workflow(name=None) invocation.stop() @@ -72,7 +72,7 @@ def test_start_workflow_span_name_without_name(self) -> None: self.assertEqual(len(spans), 1) self.assertEqual(spans[0].name, "invoke_workflow") - def test_start_workflow_span_kind_is_internal(self) -> None: + def test_workflow_span_kind_is_internal(self) -> None: invocation = self.handler.workflow(name="wf") invocation.stop() @@ -80,7 +80,7 @@ def test_start_workflow_span_kind_is_internal(self) -> None: self.assertEqual(len(spans), 1) self.assertEqual(spans[0].kind, SpanKind.INTERNAL) - def test_start_workflow_records_monotonic_start(self) -> None: + def test_workflow_records_monotonic_start(self) -> None: with patch("timeit.default_timer", return_value=500.0): invocation = self.handler.workflow(name="wf") self.assertEqual(invocation._monotonic_start_s, 500.0) @@ -183,7 +183,7 @@ def test_workflow_context_manager_default_invocation(self) -> None: class TelemetryHandlerWorkflowSamplingTest(_WorkflowTestBase): - def test_start_workflow_passes_sampling_attributes_at_span_creation( + def test_workflow_passes_sampling_attributes_at_span_creation( self, ) -> None: """Verify that sampling-relevant attributes are available at start_span() time for workflows.""" diff --git a/util/opentelemetry-util-genai/tests/test_toolcall.py b/util/opentelemetry-util-genai/tests/test_toolcall.py index 47b3c6de3..566540e52 100644 --- a/util/opentelemetry-util-genai/tests/test_toolcall.py +++ b/util/opentelemetry-util-genai/tests/test_toolcall.py @@ -167,7 +167,7 @@ def test_tool_span_is_internal_kind(): assert span_exporter.get_finished_spans()[0].kind == SpanKind.INTERNAL -def test_start_tool_passes_sampling_attributes_at_span_creation(): +def test_tool_passes_sampling_attributes_at_span_creation(): """Verify that sampling-relevant attributes are available at start_span() time for tools.""" captured_attributes = {} diff --git a/util/opentelemetry-util-genai/tests/test_utils.py b/util/opentelemetry-util-genai/tests/test_utils.py index ec7efad11..551f4adbb 100644 --- a/util/opentelemetry-util-genai/tests/test_utils.py +++ b/util/opentelemetry-util-genai/tests/test_utils.py @@ -410,7 +410,7 @@ def test_llm_manual_start_and_stop_creates_span(self): }, ) - def test_start_inference_passes_sampling_attributes_at_span_creation(self): + def test_inference_passes_sampling_attributes_at_span_creation(self): """Verify that sampling-relevant attributes are available at start_span() time.""" captured_attributes = {} @@ -461,7 +461,7 @@ def get_description(self): ) assert captured_attributes[server_attributes.SERVER_PORT] == 8080 - def test_start_inference_sampler_can_drop_span_based_on_attributes(self): + def test_inference_sampler_can_drop_span_based_on_attributes(self): """Verify that a sampler can reject spans based on attributes passed at creation time.""" class ModelRejectingSampler: # pylint: disable=no-self-use @@ -512,7 +512,7 @@ def get_description(self): assert len(spans) == 1 assert spans[0].name == "chat accepted-model" - def test_start_embedding_passes_sampling_attributes_at_span_creation(self): + def test_embedding_passes_sampling_attributes_at_span_creation(self): """Verify that sampling-relevant attributes are available at start_span() time for embeddings.""" captured_attributes = {} From e5007320e8ed97a2bc547d21b63b7d7cbbb96a47 Mon Sep 17 00:00:00 2001 From: bhumikadangayach Date: Wed, 22 Jul 2026 11:53:25 +0530 Subject: [PATCH 2/2] fix: rename changelog fragment to match PR number --- .../{+remove-deprecated-methods.removed => 300.removed} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename util/opentelemetry-util-genai/.changelog/{+remove-deprecated-methods.removed => 300.removed} (100%) diff --git a/util/opentelemetry-util-genai/.changelog/+remove-deprecated-methods.removed b/util/opentelemetry-util-genai/.changelog/300.removed similarity index 100% rename from util/opentelemetry-util-genai/.changelog/+remove-deprecated-methods.removed rename to util/opentelemetry-util-genai/.changelog/300.removed