Skip to content

Commit 130efef

Browse files
authored
Merge pull request #195 from wirjo/feat/agentcore-webrtc-kvs
Add AgentCore WebRTC example with KVS managed TURN
2 parents 24b6834 + fd140e7 commit 130efef

14 files changed

Lines changed: 1953 additions & 0 deletions

File tree

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# AgentCore configuration (account-specific)
2+
.bedrock_agentcore.yaml
3+
.bedrock_agentcore/
4+
.dockerignore
5+
agent/Dockerfile
6+
7+
# VPC configuration (generated by setup-vpc.sh)
8+
vpc-config.env
9+
10+
# Environment files (contain API keys)
11+
**/.env
12+
13+
# Keep template files (should be committed)
14+
!env.example
15+
!.env.example
16+
17+
# Backup files
18+
*.backup
19+
*.bak
Lines changed: 357 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,357 @@
1+
# Amazon Bedrock AgentCore Runtime WebRTC Example (KVS Managed TURN)
2+
3+
This example demonstrates how to deploy a Pipecat voice agent to **Amazon Bedrock AgentCore Runtime** using SmallWebRTC as a lightweight transport mechanism, with **Amazon Kinesis Video Streams (KVS)** providing managed TURN infrastructure entirely within AWS. The example pipeline orchestrates Deepgram (speech-to-text), Amazon Nova (LLM), and Cartesia (text-to-speech).
4+
5+
> **Note:** This example focuses on illustrating how to get a Pipecat bot running as an agent in AgentCore Runtime. In the interest of staying focused on that goal, it does not address various production-readiness concerns, including but not limited to: authentication with the server that launches the agent, sanitized logging, rate limiting, CORS tightening, and input validation. Be sure to address these before deploying to production.
6+
7+
## How KVS Managed TURN Works
8+
9+
Instead of configuring non-AWS TURN providers, this example uses [Amazon Kinesis Video Streams (KVS)](https://docs.aws.amazon.com/kinesisvideostreams/latest/dg/what-is-amazon-kinesis-video-streams.html) for managed TURN infrastructure. KVS provides temporary, auto-rotating TURN credentials through the [GetIceServerConfig](https://docs.aws.amazon.com/kinesisvideostreams/latest/dg/API_signaling_GetIceServerConfig.html) API, eliminating non-AWS dependencies for NAT traversal.
10+
11+
The flow works as follows:
12+
13+
1. **One-time setup:** A KVS signaling channel is created (automatically on first connection, or via CLI). The channel is used only for TURN credential provisioning -- your agent continues to use Pipecat's WebRTC transport for all signaling and media.
14+
2. **At connection time:** Your agent calls `GetSignalingChannelEndpoint` to get the HTTPS endpoint, then calls `GetIceServerConfig` to retrieve temporary TURN credentials (URIs, username, password).
15+
3. **Configure the peer connection:** The returned credentials are passed to the WebRTC peer connection as ICE servers. TURN traffic flows through KVS-managed infrastructure.
16+
17+
### Choosing Between KVS and Non-AWS TURN
18+
19+
| Factor | KVS Managed TURN (this example) | Non-AWS TURN |
20+
|---|---|---|
21+
| AWS-native | Yes -- no external dependency | No -- requires external account |
22+
| Credential management | Automatic rotation | Manual or provider-managed |
23+
| Setup | Create signaling channel + API calls | Configure environment variables |
24+
| Best for | AWS-centric deployments | Simplicity or existing provider relationships |
25+
26+
> For the non-AWS TURN variant, see the [`aws-agentcore-webrtc`](../aws-agentcore-webrtc) example.
27+
28+
## Prerequisites
29+
30+
- Accounts with:
31+
- AWS
32+
- Deepgram
33+
- Cartesia
34+
- Python 3.10 or higher
35+
- `uv` package manager
36+
37+
## Set Up the Environment
38+
39+
### IAM Configuration
40+
41+
Configure your IAM user with the necessary policies for AgentCore deployment and management:
42+
43+
- `BedrockAgentCoreFullAccess`
44+
- A new policy (maybe named `BedrockAgentCoreCLI`) configured [like this](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-permissions.html#runtime-permissions-starter-toolkit), with the following additional statements:
45+
46+
**EC2 access** (for VPC setup and teardown):
47+
```json
48+
{
49+
"Sid": "EC2Access",
50+
"Effect": "Allow",
51+
"Action": [
52+
"ec2:CreateVpc",
53+
"ec2:CreateTags",
54+
"ec2:ModifyVpcAttribute",
55+
"ec2:CreateInternetGateway",
56+
"ec2:AttachInternetGateway",
57+
"ec2:DescribeAvailabilityZones",
58+
"ec2:CreateSubnet",
59+
"ec2:AllocateAddress",
60+
"ec2:CreateNatGateway",
61+
"ec2:DescribeNatGateways",
62+
"ec2:CreateRouteTable",
63+
"ec2:CreateRoute",
64+
"ec2:AssociateRouteTable",
65+
"ec2:CreateSecurityGroup",
66+
"ec2:AuthorizeSecurityGroupEgress",
67+
"ec2:DeleteNatGateway",
68+
"ec2:ReleaseAddress",
69+
"ec2:DetachInternetGateway",
70+
"ec2:DeleteInternetGateway",
71+
"ec2:DeleteSubnet",
72+
"ec2:DeleteRouteTable",
73+
"ec2:DeleteSecurityGroup",
74+
"ec2:DeleteVpc"
75+
],
76+
"Resource": "*"
77+
}
78+
```
79+
80+
**KVS access** (for signaling channel creation):
81+
```json
82+
{
83+
"Sid": "KVSAccess",
84+
"Effect": "Allow",
85+
"Action": [
86+
"kinesisvideo:CreateSignalingChannel",
87+
"kinesisvideo:DescribeSignalingChannel",
88+
"kinesisvideo:DeleteSignalingChannel",
89+
"kinesisvideo:GetSignalingChannelEndpoint",
90+
"kinesisvideo:GetIceServerConfig"
91+
],
92+
"Resource": "*"
93+
}
94+
```
95+
96+
You can also choose to specify more granular permissions; see [Amazon Bedrock AgentCore docs](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-permissions.html) for more information.
97+
98+
To authenticate with AWS, you have two options:
99+
100+
1. Export environment variables:
101+
102+
```bash
103+
export AWS_SECRET_ACCESS_KEY=your_secret_key
104+
export AWS_ACCESS_KEY_ID=your_access_key
105+
export AWS_REGION=your_region
106+
export AWS_DEFAULT_REGION=your_default_region
107+
export AWS_SESSION_TOKEN=your_session_token # Optional: only for temporary credentials (e.g. AWS SSO, STS AssumeRole)
108+
```
109+
110+
2. Or use AWS CLI configuration:
111+
```bash
112+
aws configure
113+
```
114+
This will create/update your AWS credentials file (~/.aws/credentials).
115+
116+
### Virtual Environment Setup
117+
118+
Create and activate a virtual environment:
119+
120+
```bash
121+
uv sync
122+
```
123+
124+
### Environment Variables Configuration
125+
126+
1. For the agent:
127+
128+
```bash
129+
cd agent
130+
cp env.example .env
131+
```
132+
133+
Add your API keys:
134+
- `DEEPGRAM_API_KEY`: Your Deepgram API key
135+
- `CARTESIA_API_KEY`: Your Cartesia API key
136+
- `KVS_CHANNEL_NAME`: Name of the KVS signaling channel for TURN credentials (default: `voice-agent-turn`)
137+
138+
> No TURN server URLs or credentials are needed -- KVS provides these automatically.
139+
140+
2. For the server:
141+
142+
```bash
143+
cd server
144+
cp env.example .env
145+
```
146+
147+
Add your AWS credentials and configuration:
148+
149+
- `AWS_ACCESS_KEY_ID`
150+
- `AWS_SECRET_ACCESS_KEY`
151+
- `AWS_REGION`
152+
- `AWS_SESSION_TOKEN` (optional -- only needed for temporary credentials, e.g. AWS SSO or STS AssumeRole)
153+
154+
Also configure:
155+
156+
- `AGENT_RUNTIME_ARN`: Automatically set during agent deployment
157+
- `KVS_CHANNEL_NAME`: Must match the agent configuration
158+
159+
> **KVS permissions:** The AWS account running the server also needs KVS permissions (`kinesisvideo:DescribeSignalingChannel`, `GetSignalingChannelEndpoint`, `GetIceServerConfig`) to fetch TURN credentials for the browser client. The same KVS IAM policy listed above applies here.
160+
161+
### KVS Signaling Channel Setup (Optional)
162+
163+
The signaling channel is auto-created on first connection. To create it ahead of time:
164+
165+
```bash
166+
aws kinesisvideo create-signaling-channel \
167+
--channel-name voice-agent-turn \
168+
--channel-type SINGLE_MASTER \
169+
--region us-west-2
170+
```
171+
172+
## Agent Configuration
173+
174+
Configure your bot as an AgentCore agent:
175+
176+
```bash
177+
./scripts/configure.sh
178+
```
179+
180+
This script automatically:
181+
182+
1. Creates IAM execution role (if needed) with Bedrock and KVS permissions
183+
2. Configures container deployment with docker runtime
184+
3. Patches Dockerfile to add SmallWebRTC dependencies (`libgl1` and `libglib2.0-0`)
185+
186+
> Technical Note:
187+
> Direct Code Deploy isn't used because some dependencies (like `numba`) lack `aarch64_manylinux2014` wheels.
188+
189+
## Before Proceeding
190+
191+
Just in case you've previously deployed other agents to AgentCore, ensure that you have the desired agent selected as "default" in the `agentcore` tool:
192+
193+
```
194+
# Check
195+
uv run agentcore configure list
196+
# Set
197+
uv run agentcore configure set-default <agent-name>
198+
```
199+
200+
The following steps act on `agentcore`'s default agent.
201+
202+
## Deployment to AgentCore Runtime
203+
204+
**VPC Mode (recommended) - TCP and UDP TURN support:**
205+
206+
```bash
207+
# First time: Create VPC infrastructure (NAT Gateway costs ~$32/month)
208+
# Note that this creates various Elastic IP addresses; ensure you have sufficient quota (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html#using-instance-addressing-limit)
209+
./scripts/setup-vpc.sh
210+
211+
# Deploy agent
212+
# (This is the only command you need to run after an incremental change to your agent's code)
213+
./scripts/launch.sh
214+
```
215+
216+
This deploys AgentCore Runtime in private subnets with NAT Gateway for outbound internet access, enabling UDP TURN relay (blocked in PUBLIC mode) for better WebRTC connection reliability, lower latency, and enhanced security with private subnet isolation.
217+
218+
**Infrastructure overview:**
219+
220+
- VPC with public and private subnets across 2 availability zones
221+
- Internet Gateway for public subnet connectivity
222+
- NAT Gateway in public subnet for private subnet outbound traffic
223+
- Route tables directing private subnet traffic through NAT Gateway
224+
- Security groups allowing outbound HTTPS and UDP connections
225+
226+
**PUBLIC Mode - TCP TURN only:**
227+
228+
For development/testing without UDP TURN:
229+
230+
```bash
231+
./scripts/launch.sh
232+
```
233+
234+
The launch script:
235+
236+
1. Reads environment variables from `agent/.env`
237+
2. Deploys to AgentCore
238+
3. Updates the server's configuration with the agent ARN
239+
4. Displays log-tailing commands for monitoring
240+
241+
> **Note on KVS and VPC:** KVS TURN endpoints do not support PrivateLink, so the VPC still requires internet egress (via NAT Gateway) to reach KVS TURN endpoints.
242+
243+
## Running on AgentCore Runtime
244+
245+
1. Start the server:
246+
247+
```bash
248+
cd server
249+
uv run server.py
250+
```
251+
252+
2. Access the UI:
253+
- Open http://localhost:7860 in your browser
254+
- Or use your configured custom port
255+
256+
3. Test WebRTC connectivity:
257+
- Click "Connect" in the UI
258+
- Allow microphone permissions when prompted
259+
- Speak to the agent - you should hear a voice response
260+
- Verify connection type:
261+
- Open browser DevTools (F12 -> Console tab)
262+
- Type `chrome://webrtc-internals` in address bar (Chrome) or `about:webrtc` (Firefox) for detailed stats
263+
- Look for "Selected candidate pair" showing protocol (`udp` for VPC, `tcp` for PUBLIC) and type (`relay` for TURN)
264+
- For log monitoring, see the next section below
265+
266+
## KVS Considerations
267+
268+
- **Cost:** Each active signaling channel costs $0.03/month. At low to moderate volume, this is negligible.
269+
- **Rate limit:** `GetIceServerConfig` is limited to 5 transactions per second (TPS) per channel. For high-volume deployments exceeding 100,000 sessions per month, implement a channel pooling strategy where you distribute requests across multiple channels: `channels_needed = ceil(peak_new_sessions_per_second / 5)`.
270+
- **No PrivateLink:** The VPC still requires internet egress (via NAT Gateway) to reach KVS TURN endpoints.
271+
- **Credential lifetime:** KVS TURN credentials are temporary and auto-rotated, so you do not need to manage credential rotation.
272+
273+
## Monitoring and Troubleshooting
274+
275+
### View Intermediary Server Logs
276+
277+
The intermediary server (`server.py`) proxies WebRTC signaling between the browser client and AgentCore Runtime. Check the terminal where the server is already running (from step 1 above).
278+
279+
Look for:
280+
281+
- WebRTC SDP offers and answers
282+
- ICE candidate exchanges showing protocol (`udp`/`tcp`) and type (`relay`/`host`)
283+
- KVS TURN credential retrieval logs
284+
- Connection events and errors
285+
286+
### View Agent Logs
287+
288+
Use the log-tailing command provided during deployment:
289+
290+
```bash
291+
# Replace with your actual command
292+
aws logs tail /aws/bedrock-agentcore/runtimes/bot1-0uJkkT7QHC-DEFAULT --log-stream-name-prefix "2025/11/19/[runtime-logs]" --follow
293+
```
294+
295+
If you don't have that command handy, no worries. Just run:
296+
297+
```bash
298+
uv run agentcore status
299+
```
300+
301+
## Test Agent Manually
302+
303+
Test the agent using the AWS CLI:
304+
305+
```bash
306+
uv run agentcore invoke \
307+
--session-id user-123456-conversation-12345679 \
308+
'{
309+
"sdp": "YOUR_OFFER",
310+
"type": "offer"
311+
}'
312+
```
313+
314+
> This will only allow you to see that the Pipecat agent has started, but you won't be able to hear or send audio. So it is only useful for troubleshooting.
315+
316+
## Cleanup
317+
318+
Remove your agent:
319+
320+
```bash
321+
./scripts/destroy.sh
322+
```
323+
324+
If using VPC mode, remove VPC resources:
325+
326+
```bash
327+
./scripts/cleanup-vpc.sh
328+
```
329+
330+
Optionally, delete the KVS signaling channel:
331+
332+
```bash
333+
aws kinesisvideo delete-signaling-channel \
334+
--channel-arn $(aws kinesisvideo describe-signaling-channel \
335+
--channel-name voice-agent-turn \
336+
--query 'ChannelInfo.ChannelARN' \
337+
--output text) \
338+
--region us-west-2
339+
```
340+
341+
## Local Development
342+
343+
For testing, it may be helpful to run your bot locally without having to deploy to AgentCore.
344+
345+
First, ensure that your agent's `.env` file specifies the necessary variables for local development (placeholders should already be there, from env.example).
346+
347+
Then, run your bot in local dev mode:
348+
349+
```bash
350+
PIPECAT_LOCAL_DEV=1 uv run pipecat-agent.py
351+
```
352+
353+
## Additional Resources
354+
355+
- [Amazon Bedrock AgentCore Developer Guide](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/what-is-bedrock-agentcore.html)
356+
- [Amazon Kinesis Video Streams Developer Guide](https://docs.aws.amazon.com/kinesisvideostreams/latest/dg/what-is-amazon-kinesis-video-streams.html)
357+
- [GetIceServerConfig API Reference](https://docs.aws.amazon.com/kinesisvideostreams/latest/dg/API_signaling_GetIceServerConfig.html)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
DEEPGRAM_API_KEY=
2+
CARTESIA_API_KEY=
3+
4+
# KVS signaling channel name for managed TURN credential provisioning
5+
# The channel will be auto-created if it doesn't exist
6+
KVS_CHANNEL_NAME=voice-agent-turn
7+
8+
# AWS credentials.
9+
# Only needed for local development (PIPECAT_LOCAL_DEV=1).
10+
# When running on AgentCore, credentials come from assumed IAM role.
11+
# AWS_ACCESS_KEY_ID=
12+
# AWS_SECRET_ACCESS_KEY=
13+
# AWS_REGION=

0 commit comments

Comments
 (0)