diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-google-genai/CHANGELOG.md b/instrumentation-loongsuite/loongsuite-instrumentation-google-genai/CHANGELOG.md index eaf43047e..161172dd7 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-google-genai/CHANGELOG.md +++ b/instrumentation-loongsuite/loongsuite-instrumentation-google-genai/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Fixed + +- Keep the Interactions test mocks working with google-genai 2.34, which + copies the interaction that `interactions.create` returns with + `model_copy` to merge automatic continuation hops. + ## Version 0.9.0 (2026-09-07) ### Added diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-google-genai/tests/interactions/util.py b/instrumentation-loongsuite/loongsuite-instrumentation-google-genai/tests/interactions/util.py index 29a66f8da..17d93879b 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-google-genai/tests/interactions/util.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-google-genai/tests/interactions/util.py @@ -21,6 +21,24 @@ from typing import Any +def create_mock_model(**fields: Any) -> Any: + """Mock a pydantic model of the Interactions API with these fields. + + Since google-genai 2.34, ``interactions.create`` copies the interaction + it returns, and its usage, with ``model_copy(update=...)`` (to merge + automatic continuation hops, even for a single hop). On a plain + ``MagicMock`` that copy would be a new mock without these fields. + """ + mock = unittest.mock.MagicMock() + mock.configure_mock(**fields) + + def model_copy(update: Any = None, **kwargs: Any) -> Any: + return create_mock_model(**{**fields, **(update or {})}) + + mock.model_copy.side_effect = model_copy + return mock + + def create_mock_interaction( interaction_id: str = "test-id", model_name: str = "test-model", @@ -29,11 +47,12 @@ def create_mock_interaction( input_tokens: int = 10, output_tokens: int = 20, ) -> Any: - mock_usage = unittest.mock.MagicMock() - mock_usage.total_input_tokens = input_tokens - mock_usage.total_output_tokens = output_tokens - mock_usage.total_thought_tokens = 0 - mock_usage.total_cached_tokens = 0 + mock_usage = create_mock_model( + total_input_tokens=input_tokens, + total_output_tokens=output_tokens, + total_thought_tokens=0, + total_cached_tokens=0, + ) mock_user_step = unittest.mock.MagicMock() mock_user_step.type = "user_input" @@ -47,14 +66,13 @@ def create_mock_interaction( mock_model_part.text = output_text mock_model_step.content = [mock_model_part] - mock_interaction = unittest.mock.MagicMock() - mock_interaction.id = interaction_id - mock_interaction.model = model_name - mock_interaction.usage = mock_usage - mock_interaction.steps = [mock_user_step, mock_model_step] - mock_interaction.output_text = output_text - - return mock_interaction + return create_mock_model( + id=interaction_id, + model=model_name, + usage=mock_usage, + steps=[mock_user_step, mock_model_step], + output_text=output_text, + ) def create_mock_completed_event(interaction: Any) -> Any: diff --git a/util/opentelemetry-util-genai/CHANGELOG-loongsuite.md b/util/opentelemetry-util-genai/CHANGELOG-loongsuite.md index 6a392610a..bb48072eb 100644 --- a/util/opentelemetry-util-genai/CHANGELOG-loongsuite.md +++ b/util/opentelemetry-util-genai/CHANGELOG-loongsuite.md @@ -14,6 +14,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 event coverage, Provider setup, context lifetimes, and version troubleshooting. Present GenAI Utils as a standalone library configured through the OpenTelemetry SDK, with optional storage backends separate from the setup guide. +- Fix the API docs build: Sphinx read the "Streaming:" prefix of the + `InvokeAgentInvocation.monotonic_first_token_s` docstring as a type and + failed on the missing `Streaming` class. ## Version 0.9.0 (2026-09-07) diff --git a/util/opentelemetry-util-genai/src/opentelemetry/util/genai/extended_types.py b/util/opentelemetry-util-genai/src/opentelemetry/util/genai/extended_types.py index d74131cf9..b488dd997 100644 --- a/util/opentelemetry-util-genai/src/opentelemetry/util/genai/extended_types.py +++ b/util/opentelemetry-util-genai/src/opentelemetry/util/genai/extended_types.py @@ -206,7 +206,9 @@ class InvokeAgentInvocation: monotonic_start_s: float | None = None monotonic_end_s: float | None = None monotonic_first_token_s: float | None = None - """Streaming: first-token time; TTFT attribute derived like ``LLMInvocation``.""" + """Monotonic time when the first token of a streaming response arrived. + The time-to-first-token attribute is derived from it as for + ``LLMInvocation``.""" @dataclass