Skip to content

Commit a5d26e7

Browse files
authored
feat: make pyaudio an optional dependency by lazy loading (#1731)
1 parent 2456b71 commit a5d26e7

3 files changed

Lines changed: 35 additions & 8 deletions

File tree

README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,16 @@ Build real-time voice and audio conversations with persistent streaming connecti
208208
- Google Gemini Live
209209
- OpenAI Realtime API
210210

211+
**Installation:**
212+
213+
```bash
214+
# Server-side only (no audio I/O dependencies)
215+
pip install strands-agents[bidi]
216+
217+
# With audio I/O support (includes PyAudio dependency)
218+
pip install strands-agents[bidi,bidi-io]
219+
```
220+
211221
**Quick Example:**
212222

213223
```python
@@ -223,7 +233,7 @@ async def main():
223233
model = BidiNovaSonicModel()
224234
agent = BidiAgent(model=model, tools=[calculator, stop_conversation])
225235

226-
# Setup audio and text I/O
236+
# Setup audio and text I/O (requires bidi-io extra)
227237
audio_io = BidiAudioIO()
228238
text_io = BidiTextIO()
229239

@@ -238,6 +248,8 @@ if __name__ == "__main__":
238248
asyncio.run(main())
239249
```
240250

251+
> **Note**: `BidiAudioIO` and `BidiTextIO` require the `bidi-io` extra. For server-side deployments where audio I/O is handled by clients (browsers, mobile apps), install only `strands-agents[bidi]` and implement custom input/output handlers using the `BidiInput` and `BidiOutput` protocols.
252+
241253
**Configuration Options:**
242254

243255
```python

pyproject.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,17 @@ a2a = [
7373

7474
bidi = [
7575
"aws_sdk_bedrock_runtime; python_version>='3.12'",
76+
"smithy-aws-core>=0.0.1; python_version>='3.12'",
77+
]
78+
bidi-io = [
7679
"prompt_toolkit>=3.0.0,<4.0.0",
7780
"pyaudio>=0.2.13,<1.0.0",
78-
"smithy-aws-core>=0.0.1; python_version>='3.12'",
7981
]
8082
bidi-gemini = ["google-genai>=1.32.0,<2.0.0"]
8183
bidi-openai = ["websockets>=15.0.0,<17.0.0"]
8284

8385
all = ["strands-agents[a2a,anthropic,docs,gemini,litellm,llamaapi,mistral,ollama,openai,writer,sagemaker,otel]"]
84-
bidi-all = ["strands-agents[a2a,bidi,bidi-gemini,bidi-openai,docs,otel]"]
86+
bidi-all = ["strands-agents[a2a,bidi,bidi-io,bidi-gemini,bidi-openai,docs,otel]"]
8587

8688
dev = [
8789
"commitizen>=4.4.0,<5.0.0",

src/strands/experimental/bidi/__init__.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
"""Bidirectional streaming package."""
22

3+
from typing import Any
4+
35
# Main components - Primary user interface
46
# Re-export standard agent events for tool handling
57
from ...types._events import (
@@ -9,9 +11,6 @@
911
)
1012
from .agent.agent import BidiAgent
1113

12-
# IO channels - Hardware abstraction
13-
from .io.audio import BidiAudioIO
14-
1514
# Model interface (for custom implementations)
1615
from .models.model import BidiModel
1716

@@ -40,8 +39,6 @@
4039
__all__ = [
4140
# Main interface
4241
"BidiAgent",
43-
# IO channels
44-
"BidiAudioIO",
4542
# Built-in tools
4643
"stop_conversation",
4744
# Input Event types
@@ -68,3 +65,19 @@
6865
# Model interface
6966
"BidiModel",
7067
]
68+
69+
70+
def __getattr__(name: str) -> Any:
71+
"""Lazy load IO implementations only when accessed.
72+
73+
This defers the import of optional dependencies until actually needed.
74+
"""
75+
if name == "BidiAudioIO":
76+
from .io.audio import BidiAudioIO
77+
78+
return BidiAudioIO
79+
if name == "BidiTextIO":
80+
from .io.text import BidiTextIO
81+
82+
return BidiTextIO
83+
raise AttributeError(f"cannot import name '{name}' from '{__name__}' ({__file__})")

0 commit comments

Comments
 (0)