Skip to content

Commit 29abcb2

Browse files
authored
Add Claude Agent SDK Integration with Streaming Support (#505)
* Add Claude Agent SDK Integration with Streaming Support This commit adds a new integration example demonstrating how to use the Claude Agent SDK with Amazon Bedrock AgentCore. The example showcases: - Asynchronous streaming support for real-time responses - Three operational modes: basic queries, custom options, and tool usage - Integration with BedrockAgentCoreApp for managed deployment - File system tools (Read/Write) support - Custom Dockerfile with Node.js and Claude Code CLI setup Also updates .gitignore to exclude AgentCore deployment artifacts (.bedrock_agentcore/ and .bedrock_agentcore.yaml). * Fix ruff linting errors and add API key documentation - Remove unused anyio import - Move all imports to top of file before app initialization - Add note about ANTHROPIC_API_KEY or Bedrock access requirements - Include link to Claude Agent SDK documentation * Format code with ruff * Fix ASH security scan findings - Add HEALTHCHECK to Dockerfile to verify agent.py exists (fixes CKV_DOCKER_2) - Wrap app.run() in if __name__ == '__main__' guard (fixes semgrep finding) * Update README with environment variables and cleanup section - Add --disable-memory flag to configure command - Document both CLAUDE_CODE_USE_BEDROCK and AWS_BEARER_TOKEN_BEDROCK env vars - Add Clean Up section explaining memory (not needed) and agent runtime destruction - Show example output of agentcore destroy command * Added starter toolkit to reqmts
1 parent 7657c2a commit 29abcb2

File tree

6 files changed

+388
-0
lines changed

6 files changed

+388
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,3 +225,7 @@ pyrightconfig.json
225225
### Zip file for prereq infa deployment
226226
lambda.zip
227227
.kiro/
228+
229+
### Bedrock AgentCore ###
230+
.bedrock_agentcore/
231+
.bedrock_agentcore.yaml
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Build artifacts
2+
build/
3+
dist/
4+
*.egg-info/
5+
*.egg
6+
7+
# Python cache
8+
__pycache__/
9+
__pycache__*
10+
*.py[cod]
11+
*$py.class
12+
*.so
13+
.Python
14+
15+
# Virtual environments
16+
.venv/
17+
.env
18+
venv/
19+
env/
20+
ENV/
21+
22+
# Testing
23+
.pytest_cache/
24+
.coverage
25+
.coverage*
26+
htmlcov/
27+
.tox/
28+
*.cover
29+
.hypothesis/
30+
.mypy_cache/
31+
.ruff_cache/
32+
33+
# Development
34+
*.log
35+
*.bak
36+
*.swp
37+
*.swo
38+
*~
39+
.DS_Store
40+
41+
# IDEs
42+
.vscode/
43+
.idea/
44+
45+
# Version control
46+
.git/
47+
.gitignore
48+
.gitattributes
49+
50+
# Documentation
51+
docs/
52+
*.md
53+
!README.md
54+
55+
# CI/CD
56+
.github/
57+
.gitlab-ci.yml
58+
.travis.yml
59+
60+
# Project specific
61+
tests/
62+
63+
# Bedrock AgentCore specific - keep config but exclude runtime files
64+
.bedrock_agentcore.yaml
65+
.dockerignore
66+
.bedrock_agentcore/
67+
68+
# Keep wheelhouse for offline installations
69+
# wheelhouse/
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
FROM ghcr.io/astral-sh/uv:python3.11-bookworm-slim
2+
WORKDIR /app
3+
4+
# All environment variables in one layer
5+
ENV UV_SYSTEM_PYTHON=1 \
6+
UV_COMPILE_BYTECODE=1 \
7+
UV_NO_PROGRESS=1 \
8+
PYTHONUNBUFFERED=1 \
9+
DOCKER_CONTAINER=1 \
10+
AWS_REGION=us-east-1 \
11+
AWS_DEFAULT_REGION=us-east-1
12+
13+
14+
15+
COPY requirements.txt requirements.txt
16+
# Install from requirements file
17+
RUN uv pip install -r requirements.txt
18+
19+
RUN apt-get update && \
20+
apt-get install -y curl && \
21+
curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - && \
22+
apt-get install -y nodejs
23+
24+
# Verify installation (optional)
25+
RUN node -v && npm -v
26+
27+
RUN npm install -g @anthropic-ai/claude-code
28+
29+
30+
RUN uv pip install aws-opentelemetry-distro>=0.10.1
31+
32+
33+
# For using Claude on Bedrock, you also need to either add the AWS_BEARER_TOKEN_BEDROCK here, or inline with starter toolkit with --env option
34+
ENV CLAUDE_CODE_USE_BEDROCK=1
35+
36+
# Create non-root user
37+
RUN useradd -m -u 1000 bedrock_agentcore
38+
USER bedrock_agentcore
39+
40+
EXPOSE 9000
41+
EXPOSE 8000
42+
EXPOSE 8080
43+
44+
# Copy entire project (respecting .dockerignore)
45+
COPY . .
46+
47+
# Health check to verify container setup
48+
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
49+
CMD test -f agent.py || exit 1
50+
51+
# Use the full module path
52+
53+
CMD ["opentelemetry-instrument", "python", "-m", "agent"]
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
# Claude Agent SDK with Bedrock AgentCore Integration
2+
3+
| Information | Details |
4+
|---------------------|------------------------------------------------------------------------------|
5+
| Agent type | Asynchronous with Streaming |
6+
| Agentic Framework | Claude Agent SDK |
7+
| LLM model | Anthropic Claude (via Bedrock) |
8+
| Components | AgentCore Runtime |
9+
| Example complexity | Easy |
10+
| SDK used | Amazon BedrockAgentCore Python SDK, Claude Agent SDK |
11+
12+
This example demonstrates how to integrate Claude Agent SDK with AWS Bedrock AgentCore, enabling you to deploy your Claude-powered agent as a managed service with streaming support. You can use the `agentcore` CLI to configure and launch this agent.
13+
14+
## Prerequisites
15+
16+
- Python 3.10+
17+
- [uv](https://github.com/astral-sh/uv) - Fast Python package installer and resolver
18+
- AWS account with Bedrock AgentCore access
19+
- Node.js and npm (for Claude Code CLI)
20+
21+
## Setup Instructions
22+
23+
### 1. Create a Python Environment with uv
24+
25+
```bash
26+
# Install uv if you don't have it already
27+
28+
# Create and activate a virtual environment
29+
uv venv
30+
source .venv/bin/activate # On Windows: .venv\Scripts\activate
31+
```
32+
33+
### 2. Install Requirements
34+
35+
```bash
36+
uv pip install -r requirements.txt
37+
```
38+
39+
### 3. Understanding the Agent Code
40+
41+
The `agent.py` file contains a Claude Agent SDK implementation with streaming support, integrated with Bedrock AgentCore:
42+
43+
```python
44+
from claude_agent_sdk import (
45+
AssistantMessage,
46+
ClaudeAgentOptions,
47+
ResultMessage,
48+
TextBlock,
49+
query,
50+
)
51+
from bedrock_agentcore.runtime import BedrockAgentCoreApp
52+
53+
app = BedrockAgentCoreApp()
54+
55+
async def basic_example(prompt):
56+
"""Basic example with streaming."""
57+
async for message in query(prompt=prompt):
58+
if isinstance(message, AssistantMessage):
59+
for block in message.content:
60+
if isinstance(block, TextBlock):
61+
print(f"Claude: {block.text}")
62+
yield message
63+
64+
@app.entrypoint
65+
async def run_main(payload):
66+
"""Handler for agent invocation with streaming support"""
67+
async for message in basic_example(payload["prompt"]):
68+
yield message
69+
70+
app.run()
71+
```
72+
73+
The agent supports three modes:
74+
- **Mode 1**: Basic example - simple question answering
75+
- **Mode 2**: With custom options - customized system prompt and max turns
76+
- **Mode 3**: With tools - file reading and writing capabilities
77+
78+
### 4. Configure and Launch with Bedrock AgentCore Toolkit
79+
80+
```bash
81+
# Configure your agent for deployment (without memory)
82+
agentcore configure -e agent.py --disable-memory
83+
84+
# Deploy your agent with environment variables
85+
agentcore launch --env CLAUDE_CODE_USE_BEDROCK=1 --env AWS_BEARER_TOKEN_BEDROCK=<your-token>
86+
```
87+
88+
**Note**: The Claude Agent SDK requires either `ANTHROPIC_API_KEY` or AWS Bedrock access configured as environment variables. This example uses:
89+
- `CLAUDE_CODE_USE_BEDROCK=1` to enable Bedrock integration
90+
- `AWS_BEARER_TOKEN_BEDROCK` for authentication with Bedrock
91+
92+
You can provide these environment variables either in the Dockerfile or inline with the `--env` option as shown above. For more details on configuration options, see the [Claude Agent SDK documentation](https://docs.claude.com/en/api/agent-sdk/overview#core-concepts).
93+
94+
### 5. Testing Your Agent
95+
96+
Once deployed, you can test your agent using:
97+
98+
```bash
99+
# Basic query (mode 1)
100+
agentcore invoke '{"prompt":"What is the capital of France?", "mode":1}'
101+
102+
# With custom options (mode 2)
103+
agentcore invoke '{"prompt":"Explain quantum computing", "mode":2}'
104+
105+
# With tools (mode 3)
106+
agentcore invoke '{"prompt":"Read the contents of test.txt", "mode":3}'
107+
```
108+
109+
## Key Features
110+
111+
- **Streaming Support**: Real-time response streaming for better user experience
112+
- **Multiple Modes**: Three operational modes for different use cases
113+
- **Tool Integration**: Built-in support for Read and Write tools
114+
- **Async/Await**: Full asynchronous processing for optimal performance
115+
- **BedrockAgentCore Integration**: Seamless deployment as a managed AWS service
116+
117+
## Architecture
118+
119+
The agent uses a layered architecture:
120+
1. **Claude Agent SDK**: Handles LLM interactions via `query()` function
121+
2. **Example Functions**: Process messages and yield them for streaming
122+
3. **Main Function**: Routes requests based on mode parameter
123+
4. **BedrockAgentCoreApp**: Provides runtime environment and handles deployment
124+
125+
## Customization
126+
127+
You can customize the agent by:
128+
- Adding more tools to the `allowed_tools` list
129+
- Modifying the `system_prompt` in `ClaudeAgentOptions`
130+
- Adjusting `max_turns` for conversation length
131+
- Creating new example functions for additional use cases
132+
133+
## Clean Up
134+
135+
When you're done with the agent, you can clean up the deployed resources.
136+
137+
### Memory
138+
Since this example is configured with `--disable-memory`, no memory resources were created, so there's nothing to remove for memory.
139+
140+
### Agent Runtime
141+
To destroy the agent and all its associated AWS resources, use the `agentcore destroy` command:
142+
143+
```bash
144+
agentcore destroy
145+
```
146+
147+
You'll see output similar to:
148+
149+
```
150+
⚠️ About to destroy resources for agent 'claudesdkagent'
151+
152+
Current deployment:
153+
• Agent ARN: arn:aws:bedrock-agentcore:us-east-1:XXXXXXXXXXXX:runtime/claudesdkagent-XXXXXXXXXX
154+
• Agent ID: claudesdkagent-XXXXXXXXXX
155+
• ECR Repository: XXXXXXXXXXXX.dkr.ecr.us-east-1.amazonaws.com/bedrock-agentcore-claudesdkagent
156+
• Execution Role: arn:aws:iam::XXXXXXXXXXXX:role/AmazonBedrockAgentCoreSDKRuntime-us-east-1-XXXXXXXXXX
157+
158+
This will permanently delete AWS resources and cannot be undone!
159+
Are you sure you want to destroy the agent 'claudesdkagent' and all its resources? [y/N]:
160+
```
161+
162+
Type `y` to confirm and permanently delete the agent and all its associated resources including the ECR repository and execution role.
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
#!/usr/bin/env python3
2+
"""Quick start example for Claude Code SDK."""
3+
4+
from bedrock_agentcore.runtime import BedrockAgentCoreApp
5+
from claude_agent_sdk import (
6+
AssistantMessage,
7+
ClaudeAgentOptions,
8+
ResultMessage,
9+
TextBlock,
10+
query,
11+
)
12+
13+
app = BedrockAgentCoreApp()
14+
15+
16+
async def basic_example(prompt):
17+
"""Basic example - simple question."""
18+
print("=== Basic Example ===")
19+
20+
async for message in query(prompt=prompt):
21+
if isinstance(message, AssistantMessage):
22+
for block in message.content:
23+
if isinstance(block, TextBlock):
24+
print(f"Claude: {block.text}")
25+
yield message
26+
print()
27+
28+
29+
async def with_options_example(prompt):
30+
"""Example with custom options."""
31+
print("=== With Options Example ===")
32+
33+
options = ClaudeAgentOptions(
34+
system_prompt="You are a helpful assistant that explains things simply.",
35+
max_turns=1,
36+
)
37+
38+
async for message in query(prompt=prompt, options=options):
39+
if isinstance(message, AssistantMessage):
40+
for block in message.content:
41+
if isinstance(block, TextBlock):
42+
print(f"Claude: {block.text}")
43+
yield message
44+
print()
45+
46+
47+
async def with_tools_example(prompt):
48+
"""Example using tools."""
49+
print("=== With Tools Example ===")
50+
51+
options = ClaudeAgentOptions(
52+
allowed_tools=["Read", "Write"],
53+
system_prompt="You are a helpful file assistant.",
54+
)
55+
56+
async for message in query(
57+
prompt=prompt,
58+
options=options,
59+
):
60+
if isinstance(message, AssistantMessage):
61+
for block in message.content:
62+
if isinstance(block, TextBlock):
63+
print(f"Claude: {block.text}")
64+
elif isinstance(message, ResultMessage) and message.total_cost_usd > 0:
65+
print(f"\nCost: ${message.total_cost_usd:.4f}")
66+
yield message
67+
print()
68+
69+
70+
async def main(prompt, mode):
71+
"""Run the right example based on mode."""
72+
73+
if mode == 1:
74+
async for message in basic_example(prompt):
75+
yield message
76+
elif mode == 2:
77+
async for message in with_options_example(prompt):
78+
yield message
79+
elif mode == 3:
80+
async for message in with_tools_example(prompt):
81+
yield message
82+
else:
83+
yield "Input prompt and mode in [1,2,3]"
84+
85+
86+
@app.entrypoint
87+
async def run_main(payload):
88+
print("received payload")
89+
print(payload)
90+
91+
print("sending to agent:")
92+
async for message in main(payload["prompt"], payload["mode"]):
93+
yield message
94+
95+
96+
if __name__ == "__main__":
97+
app.run()
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
claude-agent-sdk
2+
bedrock-agentcore
3+
bedrock-agentcore-starter-toolkit

0 commit comments

Comments
 (0)