diff --git a/src/google/adk/agents/invocation_context.py b/src/google/adk/agents/invocation_context.py index 5dac20f6..6afa0d35 100644 --- a/src/google/adk/agents/invocation_context.py +++ b/src/google/adk/agents/invocation_context.py @@ -18,7 +18,6 @@ import asyncio from typing import Any from typing import cast from typing import Optional -from typing import TYPE_CHECKING from google.adk.platform import uuid as platform_uuid from google.genai import types @@ -48,9 +47,6 @@ from .live_request_queue import LiveRequestQueue from .run_config import RunConfig from .transcription_entry import TranscriptionEntry -if TYPE_CHECKING: - from google.adk.telemetry._instrumentation import TelemetryContext - class LlmCallsLimitExceededError(Exception): """Error thrown when the number of LLM calls exceed the limit.""" @@ -274,12 +270,6 @@ class InvocationContext(BaseModel): of this invocation. """ - _invoke_agent_telemetry_context: Optional[TelemetryContext] = PrivateAttr( - default=None - ) - """TelemetryContext of the active ``invoke_agent`` span, if any. - """ - @property def is_resumable(self) -> bool: """Returns whether the current invocation is resumable.""" diff --git a/src/google/adk/telemetry/_instrumentation.py b/src/google/adk/telemetry/_instrumentation.py index e12b7c9b..2284fb83 100644 --- a/src/google/adk/telemetry/_instrumentation.py +++ b/src/google/adk/telemetry/_instrumentation.py @@ -27,11 +27,11 @@ import opentelemetry.context as context_api from . import _metrics from . import tracing +from ..events import event as event_lib if TYPE_CHECKING: from ..agents.base_agent import BaseAgent from ..agents.invocation_context import InvocationContext - from ..events import event as event_lib from ..models.llm_request import LlmRequest from ..models.llm_response import LlmResponse from ..tools.base_tool import BaseTool @@ -78,31 +78,11 @@ class TelemetryContext: error_type: str | None = None span: tracing.GenerateContentSpan | trace.Span | None = None _llm_responses: list[LlmResponse] = dataclasses.field(default_factory=list) - _inference_call_count: int = 0 - _tool_call_count: int = 0 @property def llm_responses(self) -> list[LlmResponse]: return self._llm_responses - @property - def inference_call_count(self) -> int: - """Number of model calls counted against this invoke_agent span.""" - return self._inference_call_count - - def increment_inference_calls(self) -> None: - """Counts one model call against this span (including calls that raised).""" - self._inference_call_count += 1 - - def increment_tool_calls(self) -> None: - """Counts one tool call against this invoke_agent span.""" - self._tool_call_count += 1 - - @property - def tool_call_count(self) -> int: - """Number of tool calls counted against this invoke_agent span.""" - return self._tool_call_count - def record_llm_response( self, invocation_context: InvocationContext, response: LlmResponse ) -> None: @@ -130,30 +110,6 @@ def _record_agent_metrics( logger.exception("Failed to record agent metrics for agent %s", agent_name) -def _flush_invoke_agent_metrics( - tel_ctx: TelemetryContext, agent_name: str -) -> None: - """Flushes this span's accumulated inference/tool-call metrics.""" - _metrics.record_invoke_agent_inference_calls( - agent_name, tel_ctx.inference_call_count - ) - _metrics.record_invoke_agent_tool_calls(agent_name, tel_ctx.tool_call_count) - - -def _accumulate_invoke_agent_tool_call(ctx: InvocationContext) -> None: - """Counts one tool call against the active invoke_agent span.""" - span_tel_ctx = ctx._invoke_agent_telemetry_context # pylint: disable=protected-access - if span_tel_ctx is not None: - span_tel_ctx.increment_tool_calls() - - -def _accumulate_invoke_agent_inference_call(ctx: InvocationContext) -> None: - """Counts one model call against the active invoke_agent span.""" - span_tel_ctx = ctx._invoke_agent_telemetry_context # pylint: disable=protected-access - if span_tel_ctx is not None: - span_tel_ctx.increment_inference_calls() - - @contextlib.asynccontextmanager async def record_agent_invocation( ctx: InvocationContext, agent: BaseAgent @@ -163,13 +119,11 @@ async def record_agent_invocation( caught_error: Exception | None = None span: trace.Span | None = None span_name = f"invoke_agent {agent.name}" - tel_ctx = TelemetryContext() try: with tracing.tracer.start_as_current_span(span_name) as s: span = s tracing.trace_agent_invocation(span, agent, ctx) - tel_ctx.otel_context = context_api.get_current() - ctx._invoke_agent_telemetry_context = tel_ctx # pylint: disable=protected-access + tel_ctx = TelemetryContext(otel_context=context_api.get_current()) yield tel_ctx except Exception as e: caught_error = e @@ -182,7 +136,6 @@ async def record_agent_invocation( getattr(getattr(ctx, "session", None), "events", []), caught_error, ) - _flush_invoke_agent_metrics(tel_ctx, agent.name) @contextlib.asynccontextmanager @@ -190,7 +143,7 @@ async def record_tool_execution( tool: BaseTool, agent: BaseAgent, function_args: dict[str, object], - invocation_context: InvocationContext, + invocation_context: InvocationContext | None = None, ) -> AsyncIterator[TelemetryContext]: """Unified context manager for consolidated tool execution telemetry.""" start_time = time.monotonic() @@ -218,7 +171,6 @@ async def record_tool_execution( invocation_context=invocation_context, error_type=tel_ctx.error_type, ) - _accumulate_invoke_agent_tool_call(invocation_context) finally: try: _metrics.record_tool_execution_duration( @@ -253,7 +205,6 @@ async def record_inference_telemetry( yield tel_ctx finally: inference_error = sys.exc_info()[1] - _accumulate_invoke_agent_inference_call(invocation_context) agent = invocation_context.agent elapsed_s = _get_elapsed_s(tel_ctx.span, start_time) try: diff --git a/src/google/adk/telemetry/_metrics.py b/src/google/adk/telemetry/_metrics.py index 7be66bc7..eac65b48 100644 --- a/src/google/adk/telemetry/_metrics.py +++ b/src/google/adk/telemetry/_metrics.py @@ -146,44 +146,6 @@ _client_operation_duration = ( gen_ai_metrics.create_gen_ai_client_operation_duration(meter) ) _client_token_usage = gen_ai_metrics.create_gen_ai_client_token_usage(meter) -_invoke_agent_inference_calls = meter.create_histogram( - "gen_ai.invoke_agent.inference_calls", - unit="1", - description="Number of inference (model) calls per agent invocation.", - explicit_bucket_boundaries_advisory=[ - 1, - 2, - 3, - 4, - 5, - 6, - 8, - 12, - 16, - 24, - 32, - 64, - ], -) -_invoke_agent_tool_calls = meter.create_histogram( - "gen_ai.invoke_agent.tool_calls", - unit="1", - description="Number of tool calls per agent invocation.", - explicit_bucket_boundaries_advisory=[ - 1, - 2, - 3, - 4, - 5, - 6, - 8, - 12, - 16, - 24, - 32, - 64, - ], -) def record_agent_invocation_duration( @@ -198,18 +160,6 @@ def record_agent_invocation_duration( _agent_invocation_duration.record(elapsed_s, attributes=attrs) -def record_invoke_agent_inference_calls(agent_name: str, count: int): - """Records the number of inference (model) calls in an agent invocation.""" - attrs = {gen_ai_attributes.GEN_AI_AGENT_NAME: agent_name} - _invoke_agent_inference_calls.record(count, attributes=attrs) - - -def record_invoke_agent_tool_calls(agent_name: str, count: int): - """Records the number of tool calls in an agent invocation.""" - attrs = {gen_ai_attributes.GEN_AI_AGENT_NAME: agent_name} - _invoke_agent_tool_calls.record(count, attributes=attrs) - - def record_agent_request_size( agent_name: str, user_content: types.Content | None ): diff --git a/tests/unittests/telemetry/functional_node_test_cases.py b/tests/unittests/telemetry/functional_node_test_cases.py index 67774235..56e58a7f 100644 --- a/tests/unittests/telemetry/functional_node_test_cases.py +++ b/tests/unittests/telemetry/functional_node_test_cases.py @@ -2900,12 +2900,6 @@ EXPECTED_NODE_METRICS_V1: dict[str, frozenset[MetricPoint]] = { value=NON_DETERMINISTIC, ), }), - "gen_ai.invoke_agent.inference_calls": frozenset({ - MetricPoint(attributes={"gen_ai.agent.name": AGENT_NAME}, value=2), - }), - "gen_ai.invoke_agent.tool_calls": frozenset({ - MetricPoint(attributes={"gen_ai.agent.name": AGENT_NAME}, value=1), - }), } @@ -2953,12 +2947,6 @@ EXPECTED_NODE_METRICS_V2: dict[str, frozenset[MetricPoint]] = { value=NON_DETERMINISTIC, ), }), - "gen_ai.invoke_agent.inference_calls": frozenset({ - MetricPoint(attributes={"gen_ai.agent.name": AGENT_NAME}, value=2), - }), - "gen_ai.invoke_agent.tool_calls": frozenset({ - MetricPoint(attributes={"gen_ai.agent.name": AGENT_NAME}, value=1), - }), } diff --git a/tests/unittests/telemetry/functional_test_cases.py b/tests/unittests/telemetry/functional_test_cases.py index 0bb7b9b3..44c352a4 100644 --- a/tests/unittests/telemetry/functional_test_cases.py +++ b/tests/unittests/telemetry/functional_test_cases.py @@ -2294,12 +2294,6 @@ EXPECTED_METRICS_V1: dict[str, frozenset[MetricPoint]] = { value=NON_DETERMINISTIC, ), }), - "gen_ai.invoke_agent.inference_calls": frozenset({ - MetricPoint(attributes={"gen_ai.agent.name": AGENT_NAME}, value=2), - }), - "gen_ai.invoke_agent.tool_calls": frozenset({ - MetricPoint(attributes={"gen_ai.agent.name": AGENT_NAME}, value=1), - }), } @@ -2347,12 +2341,6 @@ EXPECTED_METRICS_V2: dict[str, frozenset[MetricPoint]] = { value=NON_DETERMINISTIC, ), }), - "gen_ai.invoke_agent.inference_calls": frozenset({ - MetricPoint(attributes={"gen_ai.agent.name": AGENT_NAME}, value=2), - }), - "gen_ai.invoke_agent.tool_calls": frozenset({ - MetricPoint(attributes={"gen_ai.agent.name": AGENT_NAME}, value=1), - }), } diff --git a/tests/unittests/telemetry/functional_test_helpers.py b/tests/unittests/telemetry/functional_test_helpers.py index 82f997b6..e4ae30a3 100644 --- a/tests/unittests/telemetry/functional_test_helpers.py +++ b/tests/unittests/telemetry/functional_test_helpers.py @@ -339,16 +339,6 @@ _PATCHED_HISTOGRAMS: tuple[HistogramSpec, ...] = ( attr="_client_token_usage", metric_name="gen_ai.client.token.usage", ), - HistogramSpec( - module=_metrics, - attr="_invoke_agent_inference_calls", - metric_name="gen_ai.invoke_agent.inference_calls", - ), - HistogramSpec( - module=_metrics, - attr="_invoke_agent_tool_calls", - metric_name="gen_ai.invoke_agent.tool_calls", - ), ) diff --git a/tests/unittests/telemetry/test_instrumentation.py b/tests/unittests/telemetry/test_instrumentation.py index 92fc33b0..8711aa97 100644 --- a/tests/unittests/telemetry/test_instrumentation.py +++ b/tests/unittests/telemetry/test_instrumentation.py @@ -15,7 +15,6 @@ # pylint: disable=protected-access import time -import types from unittest import mock from google.adk.telemetry import _instrumentation @@ -95,8 +94,8 @@ async def test_record_agent_invocation_tolerates_minimal_context(): """ agent = mock.MagicMock() agent.name = "test_agent" - # Context-like without `user_content` and without `session`. - bare_ctx = types.SimpleNamespace() + # Bare object without `user_content` and without `session`. + bare_ctx = object() with ( mock.patch.object(