From 09474aa7efe0254f8e591c48fc6cfedf9d19cec1 Mon Sep 17 00:00:00 2001 From: jonathan343 Date: Wed, 15 Apr 2026 18:18:00 -0400 Subject: [PATCH] fix(bidi): set Strands user agent for Nova Sonic client --- .../experimental/bidi/models/nova_sonic.py | 10 ++++++++-- .../experimental/bidi/models/test_nova_sonic.py | 17 +++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/strands/experimental/bidi/models/nova_sonic.py b/src/strands/experimental/bidi/models/nova_sonic.py index 8ad5b2a83..bdd9a097b 100644 --- a/src/strands/experimental/bidi/models/nova_sonic.py +++ b/src/strands/experimental/bidi/models/nova_sonic.py @@ -25,6 +25,7 @@ import json import logging import uuid +from importlib.metadata import PackageNotFoundError, version from typing import Any, AsyncGenerator, cast import boto3 @@ -99,6 +100,11 @@ _MAX_HISTORY_MESSAGE_BYTES = 50 * 1024 # 50KB per message _MAX_HISTORY_TOTAL_BYTES = 200 * 1024 # 200KB total history +try: + _STRANDS_USER_AGENT_EXTRA = f"lib/strands-agents#{version('strands-agents')}" +except PackageNotFoundError: + _STRANDS_USER_AGENT_EXTRA = "lib/strands-agents" + class BidiNovaSonicModel(BidiModel): """Nova Sonic implementation for bidirectional streaming. @@ -262,13 +268,13 @@ async def start( aws_access_key_id=credentials.access_key, aws_secret_access_key=credentials.secret_key, aws_session_token=credentials.token, + user_agent_extra=_STRANDS_USER_AGENT_EXTRA, ) self.client = BedrockRuntimeClient(config=config) logger.debug("region=<%s> | nova sonic client initialized", self.region) - client = BedrockRuntimeClient(config=config) - self._stream = await client.invoke_model_with_bidirectional_stream( + self._stream = await self.client.invoke_model_with_bidirectional_stream( InvokeModelWithBidirectionalStreamOperationInput(model_id=self.model_id) ) logger.debug("region=<%s> | nova sonic client initialized", self.region) diff --git a/tests/strands/experimental/bidi/models/test_nova_sonic.py b/tests/strands/experimental/bidi/models/test_nova_sonic.py index 14630875b..9d2887663 100644 --- a/tests/strands/experimental/bidi/models/test_nova_sonic.py +++ b/tests/strands/experimental/bidi/models/test_nova_sonic.py @@ -96,6 +96,23 @@ async def test_model_initialization(model_id, boto_session): assert model._connection_id is None +@pytest.mark.asyncio +async def test_start_sets_strands_user_agent_on_bedrock_runtime_client(model_id, boto_session, mock_stream): + """Always set the Strands user agent marker on the generated Bedrock Runtime client.""" + with patch("strands.experimental.bidi.models.nova_sonic.BedrockRuntimeClient") as mock_cls: + mock_instance = AsyncMock() + mock_instance.invoke_model_with_bidirectional_stream = AsyncMock(return_value=mock_stream) + mock_cls.return_value = mock_instance + + model = BidiNovaSonicModel(model_id=model_id, client_config={"boto_session": boto_session}) + + await model.start() + + assert mock_cls.call_count == 1 + config = mock_cls.call_args.kwargs["config"] + assert config.user_agent_extra.startswith("lib/strands-agents") + + # Audio Configuration Tests