From 613f59535052945bc40459d9fd17a4ecda8d159a Mon Sep 17 00:00:00 2001 From: Santosh Sahu Date: Mon, 7 Sep 2026 21:25:56 +0530 Subject: [PATCH 1/2] DC-2871: Set gen_ai.request.streaming for Anthropic Messages.stream() Messages.stream() and AsyncMessages.stream() now stamp gen_ai.request.streaming=true on the span, matching create(stream=True). Co-authored-by: Cursor --- src/harness_sdk/instrumentation/anthropic/__init__.py | 2 ++ test/instrumentation/anthropic/test_anthropic.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/harness_sdk/instrumentation/anthropic/__init__.py b/src/harness_sdk/instrumentation/anthropic/__init__.py index 9f9e274..b4adabc 100644 --- a/src/harness_sdk/instrumentation/anthropic/__init__.py +++ b/src/harness_sdk/instrumentation/anthropic/__init__.py @@ -273,6 +273,7 @@ def _wrapper( merged_kwargs["stream"] = True params = extract_params(**merged_kwargs) invocation = _build_invocation(handler, params, instance, capture_content) + invocation.attributes["gen_ai.request.streaming"] = True try: _evaluate_invocation(invocation) except ControlEvaluationBlocked: @@ -306,6 +307,7 @@ def _wrapper( merged_kwargs["stream"] = True params = extract_params(**merged_kwargs) invocation = _build_invocation(handler, params, instance, capture_content) + invocation.attributes["gen_ai.request.streaming"] = True try: _evaluate_invocation(invocation) except ControlEvaluationBlocked: diff --git a/test/instrumentation/anthropic/test_anthropic.py b/test/instrumentation/anthropic/test_anthropic.py index cc604b8..2a992cf 100644 --- a/test/instrumentation/anthropic/test_anthropic.py +++ b/test/instrumentation/anthropic/test_anthropic.py @@ -368,6 +368,7 @@ def test_messages_stream_sync_span_after_consume(agent, exporter, anthropic_inst assert len(spans) == 1 attrs = spans[0].attributes assert attrs.get("gen_ai.system") == "anthropic" + assert attrs.get("gen_ai.request.streaming") is True assert attrs.get("gen_ai.usage.output_tokens") == 5 @@ -428,6 +429,7 @@ async def test_messages_stream_async_span_after_consume(agent, exporter, anthrop spans = exporter.get_finished_spans() exporter.clear() assert len(spans) == 1 + assert spans[0].attributes.get("gen_ai.request.streaming") is True assert spans[0].attributes.get("gen_ai.usage.output_tokens") == 5 From 44f5cd8d1fdd07f82a19b73a45cf766bff6936c0 Mon Sep 17 00:00:00 2001 From: Santosh Sahu Date: Mon, 7 Sep 2026 22:30:05 +0530 Subject: [PATCH 2/2] NO-TICKET: Fix Python 3.10 CI by rebuilding litellm pydantic models in pytest Co-authored-by: Cursor --- .github/workflows/pr_build.yaml | 4 ++-- scripts/litellm_pydantic_pytest_plugin.py | 25 +++++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 scripts/litellm_pydantic_pytest_plugin.py diff --git a/.github/workflows/pr_build.yaml b/.github/workflows/pr_build.yaml index 2c3bfff..758d541 100644 --- a/.github/workflows/pr_build.yaml +++ b/.github/workflows/pr_build.yaml @@ -75,7 +75,7 @@ jobs: - name: Unit tests run: | export RUN_SDK_INTEGRATION_TESTS=1 - python -m pytest --log-cli-level=INFO --tb=long + python -m pytest -p scripts.litellm_pydantic_pytest_plugin --log-cli-level=INFO --tb=long env: PYTHONUNBUFFERED: 1 HA_ENABLE_CONSOLE_SPAN_EXPORTER: "true" @@ -84,7 +84,7 @@ jobs: if: matrix.python-version == '3.12' run: | export RUN_SDK_INTEGRATION_TESTS=1 - python -m pytest --log-cli-level=INFO --tb=long \ + python -m pytest -p scripts.litellm_pydantic_pytest_plugin --log-cli-level=INFO --tb=long \ --cov=harness_sdk --cov-report=xml:coverage.xml --junitxml=pytest-report.xml env: PYTHONUNBUFFERED: 1 diff --git a/scripts/litellm_pydantic_pytest_plugin.py b/scripts/litellm_pydantic_pytest_plugin.py new file mode 100644 index 0000000..926079e --- /dev/null +++ b/scripts/litellm_pydantic_pytest_plugin.py @@ -0,0 +1,25 @@ +"""Pytest plugin to rebuild litellm pydantic models in the test process.""" + + +def pytest_configure(config): # pylint: disable=unused-argument + try: + from litellm.types.llms.openai import ( # noqa: F401 + ChatCompletionReasoningSummaryTextBlock, + ) + import litellm.types.utils as litellm_utils + from pydantic import BaseModel + except ImportError: + return + + for name in dir(litellm_utils): + obj = getattr(litellm_utils, name) + if ( + isinstance(obj, type) + and issubclass(obj, BaseModel) + and obj is not BaseModel + and hasattr(obj, "model_rebuild") + ): + try: + obj.model_rebuild() + except Exception: + pass