Bidirectional Streaming Session Management
Session management for BidiAgent provides a mechanism for persisting conversation history and agent state across bidirectional streaming sessions. This enables voice assistants and interactive applications to maintain context and continuity even when connections are restarted or the application is redeployed.
Overview
Section titled “Overview”A bidirectional streaming session represents all stateful information needed by the agent to function, including:
- Conversation history (messages with audio transcripts)
- Agent state (key-value storage)
- Connection state and configuration
- Tool execution history
Built-in session persistence captures and restores this information automatically, so BidiAgent continues conversations where they left off, even after connection restarts or application restarts.
For an introduction to session management concepts and general patterns, see the Session Management documentation. This guide focuses on considerations specific to bidirectional streaming.
Basic Usage
Section titled “Basic Usage”Create a BidiAgent with a session manager and use it:
from strands.experimental.bidi.agent import BidiAgentfrom strands.experimental.bidi.io import BidiAudioIOfrom strands.experimental.bidi.models import BedrockNovaSonicModelfrom strands.session.file_session_manager import FileSessionManager
# Create a session manager with a unique session IDsession_manager = FileSessionManager(session_id="user_123_voice_session")
# Create the agent with session managementmodel = BedrockNovaSonicModel()agent = BidiAgent( model=model, session_manager=session_manager)
# Use the agent - all messages are automatically persistedaudio_io = BidiAudioIO()await agent.run( inputs=[audio_io.input()], outputs=[audio_io.output()])The conversation history is automatically persisted and will be restored on the next session.
Provider-Specific Considerations
Section titled “Provider-Specific Considerations”Bedrock Nova Sonic
Section titled “Bedrock Nova Sonic”Google Gemini Live
Section titled “Google Gemini Live”When using Gemini Live with connection restarts, the model leverages Google’s built-in session handler mechanism to maintain context during reconnections within the same session lifecycle.
Built-in Session Managers
Section titled “Built-in Session Managers”Strands offers two built-in session managers for persisting bidirectional streaming sessions:
- FileSessionManager: Stores sessions in the local filesystem
- S3SessionManager: Stores sessions in Amazon S3 buckets
Both inherit the shared RepositorySessionManager implementation. For a custom backend,
implement a
session repository.
SnapshotSessionManager does not support BidiAgent.
FileSessionManager
Section titled “FileSessionManager”The FileSessionManager provides a simple way to persist sessions to the local filesystem:
from strands.experimental.bidi.agent import BidiAgentfrom strands.session.file_session_manager import FileSessionManager
# Create a session managersession_manager = FileSessionManager( session_id="user_123_session", storage_dir="/path/to/sessions" # Optional, defaults to temp directory)
agent = BidiAgent( model=model, session_manager=session_manager)Use cases:
- Development and testing
- Single-server deployments
- Local voice assistants
- Prototyping
S3SessionManager
Section titled “S3SessionManager”The S3SessionManager stores sessions in Amazon S3 for distributed deployments:
from strands.experimental.bidi.agent import BidiAgentfrom strands.session.s3_session_manager import S3SessionManager
# Create an S3 session managersession_manager = S3SessionManager( session_id="user_123_session", bucket="my-voice-sessions", prefix="sessions/" # Optional prefix for organization)
agent = BidiAgent( model=model, session_manager=session_manager)Use cases:
- Production deployments
- Multi-server environments
- Serverless applications
- High availability requirements
Session Lifecycle
Section titled “Session Lifecycle”Session Creation
Section titled “Session Creation”Create the session by constructing a session manager. Passing it to BidiAgent
initializes the agent’s session data during construction:
from strands.experimental.bidi.agent import BidiAgentfrom strands.experimental.bidi.models import BedrockNovaSonicModelfrom strands.session import FileSessionManager
session_manager = FileSessionManager(session_id="user_123", storage_dir="./sessions/")agent = BidiAgent( model=BedrockNovaSonicModel(), agent_id="voice-assistant", session_manager=session_manager,)Session Restoration
Section titled “Session Restoration”To reload saved messages and application state, construct a new session manager over the
same storage and pass it to BidiAgent with the same session ID and agent ID. Restoration
happens during construction, before await agent.start() opens the model connection.
from strands.experimental.bidi.agent import BidiAgentfrom strands.experimental.bidi.models import BedrockNovaSonicModelfrom strands.session import FileSessionManager
# First conversationsession_manager = FileSessionManager(session_id="user_123", storage_dir="./sessions/")agent = BidiAgent( model=BedrockNovaSonicModel(), agent_id="voice-assistant", session_manager=session_manager,)await agent.start()await agent.send("My name is Alice")# ... conversation continues ...await agent.stop()
# Later: constructing a new agent restores the saved messages and state.session_manager = FileSessionManager(session_id="user_123", storage_dir="./sessions/")agent = BidiAgent( model=BedrockNovaSonicModel(), agent_id="voice-assistant", session_manager=session_manager,)await agent.start()await agent.send("What's my name?")await agent.stop()Session Updates
Section titled “Session Updates”Messages are persisted automatically as they’re added:
agent = BidiAgent(model=model, session_manager=session_manager)await agent.start()
# Each message automatically savedawait agent.send("Hello") # Saved# Model response received and saved# Tool execution saved# All transcripts savedConnection Restart Behavior
Section titled “Connection Restart Behavior”BidiAgent reconnects both proactively (a timer fires ahead of the provider’s connection limit) and reactively (after a timeout). On either path the session manager keeps the conversation intact:
agent = BidiAgent(model=model, session_manager=session_manager)await agent.start()
async for event in agent.receive(): if isinstance(event, BidiConnectionRestartEvent): # On restart (reason "scheduled" or "timeout") the session manager: # 1. Persists every message up to this point # 2. Sends the full history into the restarted connection # 3. Lets the conversation continue print(f"Reconnecting (reason={event.reason}) with full history preserved")For the reconnect timing and how to tune it with BidiConnectionConfig, see Connection Restart.
Integration with Hooks
Section titled “Integration with Hooks”Register a message hook after constructing the agent to run it after the session manager’s persistence hooks at the default hook order:
from strands import LocalAgentfrom strands.experimental.bidi.agent import BidiAgentfrom strands.hooks import MessageAddedEventfrom strands.session import FileSessionManager
agent = BidiAgent( session_manager=FileSessionManager(session_id="user_123", storage_dir="./sessions/"))
async def log_message(event: MessageAddedEvent[LocalAgent]) -> None: print(f"Message persisted: {event.message['role']}")
agent.add_hook(log_message)The session manager also syncs state when BidiAgentStopEvent fires during shutdown.
For best practices on session ID management, session cleanup, error handling, storage considerations, and troubleshooting, see the Session Management documentation.
Next Steps
Section titled “Next Steps”- Agent - Learn about BidiAgent configuration and lifecycle
- Hooks - Extend agent functionality with hooks
- Events - Complete guide to bidirectional streaming events
- Python API Reference - Complete API documentation