From 4ba072b6710289e9a864ccc7535f42e5567fb861 Mon Sep 17 00:00:00 2001 From: Jagdeep Soni Date: Wed, 11 Mar 2026 11:32:23 +0100 Subject: [PATCH 1/3] feat(aws): Add AWS profile support and improve credential resolution - Add aws_profile parameter to BedrockLLM for profile-based credential selection - Replace environment variable credential resolution with boto3.Session for full credential chain support - Implement Boto3CredentialsResolver class to delegate credential resolution to boto3 - Support AWS profiles, SSO, EC2 instance profiles, and shared credentials files - Remove hardcoded AWS_BEDROCK_API_KEY environment variable handling - Remove unused os import from aws_llm.py - Update BedrockLLM client initialization to use boto3.Session - Add aws_profile parameter to Realtime class constructor - Improve type hints for session_kwargs in BedrockLLM --- plugins/aws/example/.env.example | 8 +++- .../aws/vision_agents/plugins/aws/aws_llm.py | 15 +++--- .../vision_agents/plugins/aws/aws_realtime.py | 48 ++++++++++++++++++- 3 files changed, 60 insertions(+), 11 deletions(-) diff --git a/plugins/aws/example/.env.example b/plugins/aws/example/.env.example index 0ff6a087e..3d825e4cb 100644 --- a/plugins/aws/example/.env.example +++ b/plugins/aws/example/.env.example @@ -1,10 +1,14 @@ STREAM_API_KEY=your_stream_api_key_here STREAM_API_SECRET=your_stream_api_secret_here -AWS_BEARER_TOKEN_BEDROCK= +# AWS authentication (choose one approach): +# Option 1: AWS Profile (recommended for SSO/local dev) +AWS_PROFILE= + +# Option 2: Explicit credentials AWS_ACCESS_KEY_ID= AWS_SECRET_ACCESS_KEY= FAL_KEY= CARTESIA_API_KEY= -DEEPGRAM_API_KEY= \ No newline at end of file +DEEPGRAM_API_KEY= diff --git a/plugins/aws/vision_agents/plugins/aws/aws_llm.py b/plugins/aws/vision_agents/plugins/aws/aws_llm.py index 54395c1a9..c8e8d13d1 100644 --- a/plugins/aws/vision_agents/plugins/aws/aws_llm.py +++ b/plugins/aws/vision_agents/plugins/aws/aws_llm.py @@ -1,5 +1,4 @@ import asyncio -import os import logging import time from typing import Optional, List, TYPE_CHECKING, Any, Dict, cast @@ -48,6 +47,7 @@ def __init__( aws_access_key_id: Optional[str] = None, aws_secret_access_key: Optional[str] = None, aws_session_token: Optional[str] = None, + aws_profile: Optional[str] = None, ): """ Initialize the BedrockLLM class. @@ -58,14 +58,17 @@ def __init__( aws_access_key_id: Optional AWS access key ID aws_secret_access_key: Optional AWS secret access key aws_session_token: Optional AWS session token + aws_profile: Optional AWS profile name (from ~/.aws/credentials or ~/.aws/config) """ super().__init__() self.events.register_events_from_module(events) self.model = model self._pending_tool_uses_by_index: Dict[int, Dict[str, Any]] = {} - # Initialize boto3 bedrock-runtime client - session_kwargs = {"region_name": region_name} + # Build boto3 Session kwargs + session_kwargs: Dict[str, Any] = {"region_name": region_name} + if aws_profile: + session_kwargs["profile_name"] = aws_profile if aws_access_key_id: session_kwargs["aws_access_key_id"] = aws_access_key_id if aws_secret_access_key: @@ -73,9 +76,6 @@ def __init__( if aws_session_token: session_kwargs["aws_session_token"] = aws_session_token - if os.environ.get("AWS_BEDROCK_API_KEY"): - session_kwargs["aws_session_token"] = os.environ["AWS_BEDROCK_API_KEY"] - self._client = None self._session_kwargs = session_kwargs self.region_name = region_name @@ -86,7 +86,8 @@ async def client(self) -> Any: if self._client is None: def _create_client(): - self._client = boto3.client("bedrock-runtime", **self._session_kwargs) + session = boto3.Session(**self._session_kwargs) + self._client = session.client("bedrock-runtime") await asyncio.to_thread(_create_client) return self._client diff --git a/plugins/aws/vision_agents/plugins/aws/aws_realtime.py b/plugins/aws/vision_agents/plugins/aws/aws_realtime.py index 94d91365e..2fffbe81e 100644 --- a/plugins/aws/vision_agents/plugins/aws/aws_realtime.py +++ b/plugins/aws/vision_agents/plugins/aws/aws_realtime.py @@ -18,7 +18,12 @@ ) from getstream.video.rtc import PcmData from getstream.video.rtc.audio_track import AudioStreamTrack -from smithy_aws_core.identity.environment import EnvironmentCredentialsResolver +import boto3 +from smithy_aws_core.identity.components import ( + AWSCredentialsIdentity, + AWSIdentityProperties, +) +from smithy_core.aio.interfaces.identity import IdentityResolver from vision_agents.core.agents.agent_types import AgentOptions from vision_agents.core.edge.types import Participant from vision_agents.core.llm import realtime @@ -34,6 +39,44 @@ FORCE_RECONNECT_IN_MINUTES = 7.0 +class Boto3CredentialsResolver( + IdentityResolver[AWSCredentialsIdentity, AWSIdentityProperties] +): + """IdentityResolver that delegates to boto3.Session for credential resolution. + + Supports the full boto3 credential chain: env vars, shared credentials files, + AWS profiles, SSO, EC2 instance profiles, etc. + """ + + def __init__(self, profile_name: Optional[str] = None) -> None: + self._session = boto3.Session(profile_name=profile_name) + self._cached: Optional[AWSCredentialsIdentity] = None + + async def get_identity( + self, *, properties: AWSIdentityProperties, **kwargs: Any + ) -> AWSCredentialsIdentity: + if self._cached is not None: + return self._cached + + credentials = self._session.get_credentials() + if not credentials: + raise ValueError("Unable to load AWS credentials via boto3") + + creds = credentials.get_frozen_credentials() + if not creds.access_key or not creds.secret_key: + raise ValueError("AWS credentials are incomplete") + + expiry = getattr(credentials, "_expiry_time", None) + + self._cached = AWSCredentialsIdentity( + access_key_id=creds.access_key, + secret_access_key=creds.secret_key, + session_token=creds.token or None, + expiration=expiry, + ) + return self._cached + + class RealtimeConnection: """Encapsulates a single AWS Bedrock bidirectional stream connection. @@ -154,6 +197,7 @@ def __init__( region_name: str = "us-east-1", voice_id: str = "matthew", reconnect_after_minutes=5.0, # Attempt to reconnect during silence after 5 minutes. Reconnect is forced after 7 minutes + aws_profile: Optional[str] = None, **kwargs, ) -> None: """ """ @@ -173,7 +217,7 @@ def __init__( config = Config( endpoint_uri=f"https://bedrock-runtime.{region_name}.amazonaws.com", region=region_name, - aws_credentials_identity_resolver=EnvironmentCredentialsResolver(), + aws_credentials_identity_resolver=Boto3CredentialsResolver(profile_name=aws_profile), ) self.client = BedrockRuntimeClient(config=config) self.logger = logging.getLogger(__name__) From dbeb4575fcb47e7279a54807d20a2ca0c17b79d6 Mon Sep 17 00:00:00 2001 From: Jagdeep Soni Date: Thu, 12 Mar 2026 16:58:26 +0100 Subject: [PATCH 2/3] feat(aws): Add AWS_BEDROCK_API_KEY environment variable support - Import os module for environment variable access - Add support for AWS_BEDROCK_API_KEY environment variable in BedrockLLM initialization - Set aws_session_token from environment variable when AWS_BEDROCK_API_KEY is present - Enables credential resolution through environment variables for improved flexibility --- plugins/aws/vision_agents/plugins/aws/aws_llm.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/aws/vision_agents/plugins/aws/aws_llm.py b/plugins/aws/vision_agents/plugins/aws/aws_llm.py index c8e8d13d1..5a146ef2c 100644 --- a/plugins/aws/vision_agents/plugins/aws/aws_llm.py +++ b/plugins/aws/vision_agents/plugins/aws/aws_llm.py @@ -1,5 +1,6 @@ import asyncio import logging +import os import time from typing import Optional, List, TYPE_CHECKING, Any, Dict, cast import json @@ -76,6 +77,9 @@ def __init__( if aws_session_token: session_kwargs["aws_session_token"] = aws_session_token + if os.environ.get("AWS_BEDROCK_API_KEY"): + session_kwargs["aws_session_token"] = os.environ["AWS_BEDROCK_API_KEY"] + self._client = None self._session_kwargs = session_kwargs self.region_name = region_name From f295abc30d68df7fd06f7ee7bdac8f0d500ecede Mon Sep 17 00:00:00 2001 From: "Neevash Ramdial (Nash)" Date: Thu, 19 Mar 2026 09:34:16 -0700 Subject: [PATCH 3/3] adjust ruff and mypy formatting --- plugins/aws/vision_agents/plugins/aws/aws_realtime.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/aws/vision_agents/plugins/aws/aws_realtime.py b/plugins/aws/vision_agents/plugins/aws/aws_realtime.py index 2fffbe81e..883bcfd4a 100644 --- a/plugins/aws/vision_agents/plugins/aws/aws_realtime.py +++ b/plugins/aws/vision_agents/plugins/aws/aws_realtime.py @@ -217,7 +217,9 @@ def __init__( config = Config( endpoint_uri=f"https://bedrock-runtime.{region_name}.amazonaws.com", region=region_name, - aws_credentials_identity_resolver=Boto3CredentialsResolver(profile_name=aws_profile), + aws_credentials_identity_resolver=Boto3CredentialsResolver( + profile_name=aws_profile + ), ) self.client = BedrockRuntimeClient(config=config) self.logger = logging.getLogger(__name__)