Skip to content

Commit c954409

Browse files
Merge pull request #104 from GetStream/bedrock
[AI-192] - Bedrock, AWS & Nova
2 parents ab27e48 + c71da10 commit c954409

File tree

43 files changed

+11732
-6761
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+11732
-6761
lines changed

.github/actions/python-uv-setup/action.yml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,20 @@ runs:
1717
using: composite
1818
steps:
1919
- name: Install the latest version of uv
20-
uses: astral-sh/setup-uv@v6
20+
uses: astral-sh/setup-uv@v7
2121
with:
2222
python-version: "3.13"
2323
version: "latest"
2424
enable-cache: true
25-
cache-dependency-glob: "uv.lock"
25+
cache-dependency-glob: |
26+
**/pyproject.toml
27+
**/uv.lock
28+
- name: Log cache status
29+
shell: bash
30+
env:
31+
UV_CACHE_HIT: "${{ steps.setup_uv.outputs['cache-hit'] }}"
32+
run: |
33+
echo "setup-uv cache hit: ${UV_CACHE_HIT}"
2634
2735
- name: Install the project
2836
shell: bash

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
uses: ./.github/workflows/run_tests.yml
1111
with:
1212
marker: 'not integration'
13-
13+
secrets: inherit
1414

1515
# Cancel in-flight runs for the same branch/PR when new commits arrive
1616
concurrency:

.github/workflows/run_tests.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ jobs:
2424
run: uv run mypy --install-types --non-interactive agents-core/vision_agents
2525
- name: Mypy plugins
2626
run: uv run mypy --install-types --non-interactive --exclude 'plugins/.*/tests/.*' plugins
27+
- name: Show environment name
28+
run: |
29+
echo "Environment: ${{ job.environment }}"
2730
2831
test:
2932
name: Test "${{ inputs.marker }}"
@@ -40,11 +43,24 @@ jobs:
4043
STREAM_API_KEY: ${{ secrets.STREAM_API_KEY }}
4144
STREAM_API_SECRET: ${{ secrets.STREAM_API_SECRET }}
4245
XAI_API_KEY: ${{ secrets.XAI_API_KEY }}
46+
AWS_BEARER_TOKEN_BEDROCK: "${{ secrets.AWS_BEARER_TOKEN_BEDROCK }}"
47+
_BEARER_TOKEN_BEDROCK: "${{ secrets.AWS_BEARER_TOKEN_BEDROCK }}"
4348
timeout-minutes: 30
4449
steps:
4550
- name: Checkout
4651
uses: actions/checkout@v5
4752
- uses: ./.github/actions/python-uv-setup
53+
- name: Export AWS_BEARER_TOKEN_BEDROCK (heredoc)
54+
shell: bash
55+
run: |
56+
{
57+
echo 'AWS_BEARER_TOKEN_BEDROCK<<EOF'
58+
echo "${{ secrets.AWS_BEARER_TOKEN_BEDROCK }}"
59+
echo 'EOF'
60+
} >> "$GITHUB_ENV"
61+
62+
- name: Verify presence
63+
run: uv run python -c "import os; v=os.getenv('AWS_BEARER_TOKEN_BEDROCK'); print('exists', v is not None, 'len', 0 if v is None else len(v))"
4864
- name: Run test
4965
run: uv run pytest -n auto -m "${{ inputs.marker }}"
5066
- name: Run plugin test

agents-core/vision_agents/core/events/manager.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -536,11 +536,10 @@ async def _run_handler(self, handler, event):
536536
async def _process_single_event(self, event):
537537
"""Process a single event."""
538538
for handler in self._handlers.get(event.type, []):
539-
module_name = getattr(handler, "__module__", "unknown")
539+
#module_name = getattr(handler, '__module__', 'unknown')
540540
if event.type not in self._silent_events:
541-
logger.info(
542-
f"Called handler {handler.__name__} from {module_name} for event {event.type}"
543-
)
541+
pass
542+
#logger.info(f"Called handler {handler.__name__} from {module_name} for event {event.type}")
544543

545544
loop = asyncio.get_running_loop()
546545
handler_task = loop.create_task(self._run_handler(handler, event))

agents-core/vision_agents/core/llm/llm.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@
2323

2424

2525
class LLMResponseEvent(Generic[T]):
26-
def __init__(self, original: T, text: str):
26+
def __init__(self, original: T, text: str, exception: Optional[Exception] = None):
2727
self.original = original
2828
self.text = text
29+
self.exception = exception
2930

3031

3132
BeforeCb = Callable[[List[Any]], None]
@@ -157,10 +158,14 @@ def _attach_agent(self, agent: Agent):
157158
"""
158159
self.agent = agent
159160
self._conversation = agent.conversation
160-
self.instructions = agent.instructions
161-
161+
self._set_instructions(agent.instructions)
162+
163+
164+
def _set_instructions(self, instructions: str):
165+
self.instructions = instructions
166+
162167
# Parse instructions to extract @ mentioned markdown files
163-
self.parsed_instructions = parse_instructions(agent.instructions)
168+
self.parsed_instructions = parse_instructions(instructions)
164169

165170
def register_function(self,
166171
name: Optional[str] = None,

agents-core/vision_agents/core/llm/realtime.py

Lines changed: 9 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
import logging
1414
import uuid
1515

16-
from vision_agents.core.events import PluginClosedEvent
1716

1817
from . import events, LLM
1918

@@ -38,32 +37,26 @@ class Realtime(LLM, abc.ABC):
3837
- Transcript outgoing audio
3938
4039
"""
41-
42-
fps: int = 1
40+
fps : int = 1
41+
session_id : str # UUID to identify this session
4342

4443
def __init__(
4544
self,
4645
fps: int = 1, # the number of video frames per second to send (for implementations that support setting fps)
4746
):
4847
super().__init__()
49-
self._is_connected = False
48+
self.connected = False
5049

5150
self.provider_name = "realtime_base"
5251
self.session_id = str(uuid.uuid4())
5352
self.fps = fps
5453
# The most common style output track (webrtc)
55-
# TODO: do we like the output track here, or do we want to do an event, and have the agent manage the output track
5654
self.output_track: AudioStreamTrack = AudioStreamTrack(
5755
framerate=48000, stereo=True, format="s16"
5856
)
5957
# Store current participant for user speech transcription events
6058
self._current_participant: Optional[Participant] = None
6159

62-
@property
63-
def is_connected(self) -> bool:
64-
"""Return True if the realtime session is currently active."""
65-
return self._is_connected
66-
6760
@abc.abstractmethod
6861
async def connect(self): ...
6962

@@ -82,7 +75,7 @@ async def _stop_watching_video_track(self) -> None:
8275

8376
def _emit_connected_event(self, session_config=None, capabilities=None):
8477
"""Emit a structured connected event."""
85-
self._is_connected = True
78+
self.connected = True
8679
# Mark ready when connected if provider uses base emitter
8780
try:
8881
self._ready_event.set() # type: ignore[attr-defined]
@@ -98,7 +91,7 @@ def _emit_connected_event(self, session_config=None, capabilities=None):
9891

9992
def _emit_disconnected_event(self, reason=None, was_clean=True):
10093
"""Emit a structured disconnected event."""
101-
self._is_connected = False
94+
self.connected = False
10295
event = events.RealtimeDisconnectedEvent(
10396
session_id=self.session_id,
10497
plugin_name=self.provider_name,
@@ -182,6 +175,10 @@ def _emit_error_event(self, error, context="", user_metadata=None):
182175
)
183176
self.events.send(event)
184177

178+
@abc.abstractmethod
179+
async def close(self):
180+
raise NotImplementedError("llm.close isn't implemented")
181+
185182
def _emit_user_speech_transcription(self, text: str, original=None):
186183
"""Emit a user speech transcription event with participant info."""
187184
event = events.RealtimeUserSpeechTranscriptionEvent(
@@ -202,19 +199,3 @@ def _emit_agent_speech_transcription(self, text: str, original=None):
202199
original=original,
203200
)
204201
self.events.send(event)
205-
206-
async def close(self):
207-
"""Close the Realtime service and release any resources."""
208-
if self._is_connected:
209-
await self._close_impl()
210-
self._emit_disconnected_event("service_closed", True)
211-
212-
close_event = PluginClosedEvent(
213-
session_id=self.session_id,
214-
plugin_name=self.provider_name,
215-
cleanup_successful=True,
216-
)
217-
self.events.send(close_event)
218-
219-
@abc.abstractmethod
220-
async def _close_impl(self): ...

conftest.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,17 @@ def mia_audio_16khz():
7777
return pcm
7878

7979

80+
@pytest.fixture
81+
def golf_swing_image():
82+
"""Load golf_swing.png image and return as bytes."""
83+
image_file_path = os.path.join(get_assets_dir(), "golf_swing.png")
84+
85+
with open(image_file_path, "rb") as f:
86+
image_bytes = f.read()
87+
88+
return image_bytes
89+
90+
8091
@pytest.fixture
8192
async def bunny_video_track():
8293
"""Create RealVideoTrack from video file."""

docs/ai/ai-overview.md

Lines changed: 0 additions & 59 deletions
This file was deleted.

0 commit comments

Comments
 (0)