Skip to content

Commit 09c965f

Browse files
michaelraskanskyMichael Raskansky
andauthored
feat: Add Amazon Bedrock AgentCore integration (#681)
* agentcore working metadata recived in interface and mwKwwords for configureing agent streaming working * basic history working - no history after 8 hours save history metadata send history Improve error handling and logging in session history management Enhance agent ID validation and improve error logging for session history fix: address critical security and code quality issues in bedrock-agents handler - Add input validation for agent IDs to prevent injection attacks - Implement specific exception handling with sanitized error messages - Simplify session management by removing unused expiration logic - Consolidate session saving into single consistent function - Add conversation history support for AgentCore context continuity Security improvements: - Validate agent ID format with regex patterns - Sanitize error messages to prevent information disclosure - Handle AWS service errors, JSON parsing errors, and validation errors separately Code quality improvements: - Remove complex unused session expiration checking - Eliminate potential race conditions in session updates - Ensure consistent session management across all code paths fix: add transaction safety and error recovery to session history operations - Implement state tracking for DynamoDB session save operations - Add error recovery mechanism for partial save failures - Prevent orphaned user messages by adding recovery AI messages - Maintain session integrity during database operation failures - Add comprehensive logging for recovery scenarios Ensures conversation history remains consistent even when partial DynamoDB operations fail, preventing incomplete conversation states. > fix: add specific exception handling to agents.py list_agents function - Replace generic exception handling with specific error types - Add ClientError handling for AWS API failures with error codes - Add BotoCoreError handling for AWS service-level errors - Add KeyError/AttributeError handling for malformed API responses - Maintain safe fallback behavior while improving error diagnostics Provides better debugging information and handles different failure scenarios appropriately without changing function behavior. fix: enhance agent ID validation and improve conversation history retrieval fix: add missing imports and update session activity handling in request handler fix: implement agent listing tests and enhance agent ID validation * add tests vet-all rfctr + remove unused fix regressions * rfctr + use agentRuntimeArn * update model to haiku update snap update tests * thinking basic * docs * vet-all * Refactor thinking steps handling and update related UI components * update doc + vet-all * limit steps * linkt thinking steps * update agentcore doc --------- Co-authored-by: Michael Raskansky <[email protected]>
1 parent 42118f8 commit 09c965f

File tree

44 files changed

+2903
-105
lines changed

Some content is hidden

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

44 files changed

+2903
-105
lines changed

docs/.vitepress/config.mts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export default defineConfig({
5353
text: 'Documentation',
5454
items: [
5555
{ text: 'Access Control', link: '/documentation/access-control' },
56+
{ text: 'AgentCore Integration', link: '/documentation/agentcore' },
5657
{ text: 'Applications', link: '/documentation/applications' },
5758
{ text: 'AppSync', link: '/documentation/appsync' },
5859
{ text: 'CloudFront Geo Restriction', link: '/documentation/cf-geo-restriction' },

docs/documentation/agentcore.md

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
# AgentCore Integration
2+
3+
Amazon Bedrock AgentCore enables you to deploy and operate highly capable AI agents securely, at scale. It offers infrastructure purpose-built for dynamic agent workloads, powerful tools to enhance agents, and essential controls for real-world deployment. AgentCore services can be used together or independently and work with any framework including CrewAI, LangGraph, LlamaIndex, and Strands Agents, as well as any foundation model in or outside of Amazon Bedrock, giving you ultimate flexibility. AgentCore eliminates the undifferentiated heavy lifting of building specialized agent infrastructure, so you can accelerate agents to production.
4+
5+
![AgentCore Demo](assets/agent-demo.gif)
6+
7+
## Prerequisites
8+
9+
1. **Deploy Amazon Bedrock AgentCore Agent Runtime** in your AWS account
10+
11+
The CDK deployment automatically configures the required IAM permissions (`bedrock-agentcore:InvokeAgentRuntime` and `bedrock-agentcore:ListAgentRuntimes`).
12+
13+
## Using AgentCore
14+
15+
### 1. Agent Discovery
16+
17+
Agents are automatically discovered using the `listAgents` GraphQL query, which calls `list_agent_runtimes()` on the bedrock-agentcore-control client. Only users with `admin` or `workspace_manager` roles can access this query.
18+
19+
### 2. Agent Selection
20+
21+
In the chat interface:
22+
23+
- Agents appear in a separate dropdown labeled "Select an agent (optional)"
24+
- Agents display using `agentRuntimeName` as the label
25+
- The `agentRuntimeArn` is used as the value
26+
- Agent selection is optional - you can use regular models instead
27+
28+
### 3. Conversation
29+
30+
- When an agent is selected, the system uses `modelInterface: "agent"`
31+
- **Thinking Steps**: The agent's reasoning process is displayed in a collapsible section with:
32+
- Compact vertical timeline layout with connecting lines
33+
- Real-time updates during streaming responses
34+
- Visual indicators (emojis) for different agent actions
35+
- Click to expand/collapse the full thinking process
36+
- **Streaming**: Both thinking steps and response content stream in real-time
37+
- **Tool Usage**: When agents use tools, thinking steps show tool invocation and execution
38+
39+
## Interface Between Agent and Chatbot
40+
41+
### Request Format
42+
43+
The chatbot sends the complete request record as JSON payload to the agent's `@app.entrypoint` function:
44+
45+
```python
46+
{
47+
"userId": "user-id",
48+
"userGroups": ["group1", "group2"],
49+
"data": {
50+
"text": "User message",
51+
"agentRuntimeArn": "arn:aws:bedrock-agentcore:region:account:runtime/agent-id",
52+
"sessionId": "session-uuid",
53+
"conversation_history": [
54+
{"role": "user", "content": "Previous user message"},
55+
{"role": "assistant", "content": "Previous assistant response"}
56+
],
57+
# Additional fields from original request...
58+
"modelName": "anthropic.claude-3-5-sonnet-20241022-v2:0",
59+
"modelKwargs": {
60+
"temperature": 0.7,
61+
"topP": 0.9,
62+
"maxTokens": 4000,
63+
"streaming": true
64+
}
65+
}
66+
}
67+
```
68+
69+
**Key Fields:**
70+
71+
- `userId`: User identifier from the chatbot session
72+
- `userGroups`: User's group memberships for authorization
73+
- `data.text`: The user's current message
74+
- `data.agentRuntimeArn`: The selected agent's ARN
75+
- `data.sessionId`: Session identifier for conversation continuity
76+
- `data.conversation_history`: Array of previous messages with `role` and `content` fields (up to 20 recent messages)
77+
- `data.modelName`: Bedrock model identifier (if provided)
78+
- `data.modelKwargs`: Model configuration including streaming preference
79+
80+
**Important Notes:**
81+
82+
- The `conversation_history` is automatically added by the handler from DynamoDB
83+
- Messages are converted to simple `{role, content}` objects
84+
- The entire original request record is passed through, so agents receive all original fields
85+
86+
### Response Format
87+
88+
The agent returns Server-Sent Events (SSE) streaming data that the chatbot processes:
89+
90+
**Streaming SSE Format:**
91+
92+
```python
93+
# Thinking steps (agent reasoning)
94+
data: {"type": "thinking", "content": "💭 Assistant starting..."}
95+
data: {"type": "thinking", "content": "🔧 Calling calculator..."}
96+
data: {"type": "thinking", "content": "🧠 Analyzing the calculation..."}
97+
data: {"type": "thinking", "content": "✅ Block complete"}
98+
99+
# Response content (actual answer)
100+
data: {"type": "content", "content": "The result is "}
101+
data: {"type": "content", "content": "42"}
102+
```
103+
104+
**Non-streaming Response:**
105+
106+
```python
107+
{
108+
"result": "Agent's complete response text"
109+
}
110+
```
111+
112+
**Event Processing:**
113+
114+
- **Thinking Events**: `type: "thinking"` events are displayed in the expandable thinking steps section
115+
- **Content Events**: `type: "content"` events are accumulated to build the final response
116+
- **Visual Indicators**: Thinking steps support emoji indicators for different agent actions (needs to be sent by the agent):
117+
- 💭 Message start/thinking
118+
- 🔧 Tool usage
119+
- 🧠 Reasoning content
120+
- 📚 Citations
121+
- ✅ Completion markers
122+
- ⏸️ Tool execution
123+
- 🏁 Response complete
124+
125+
The above are CoverseStream events sent by a Amazon Bedrock [more info here](https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_ConverseStream.html#API_runtime_ConverseStream_ResponseSyntax)
126+
127+
### Security
128+
129+
- **Session Isolation**: Each conversation maintains separate session state (Handled by AgentCore)
130+
- **Error Handling**: Graceful fallback with error recovery for session history
131+
132+
## Getting Started
133+
134+
[QuickStart: Your First Agent in 5 Minutes! 🚀](https://aws.github.io/bedrock-agentcore-starter-toolkit/user-guide/runtime/quickstart.html)
135+
136+
### Simple Agent Example
137+
138+
Here's a minimal agent implementation that demonstrates the core concepts:
139+
140+
```python
141+
import boto3
142+
import json
143+
from bedrock_agentcore import BedrockAgentCoreApp
144+
from strands import Agent
145+
from strands.models import BedrockModel
146+
from strands_tools import calculator, current_time
147+
148+
app = BedrockAgentCoreApp()
149+
session = boto3.Session(region_name='il-central-1')
150+
bedrock_model = BedrockModel(boto_session=session)
151+
152+
agent = Agent(
153+
system_prompt="You are a helpful AI assistant that can use tools to answer questions.",
154+
model=bedrock_model,
155+
tools=[calculator, current_time],
156+
)
157+
158+
@app.entrypoint
159+
async def invoke(payload, context):
160+
"""Main agent function with streaming support"""
161+
# Extract request data
162+
user_message = payload["data"]["text"]
163+
conversation_history = payload["data"].get("conversation_history", [])
164+
is_streaming = payload["data"].get("modelKwargs", {}).get("streaming", False)
165+
166+
# Configure model from payload (if provided)
167+
if "modelName" in payload["data"]:
168+
bedrock_model.update_config(
169+
model_id=payload["data"]["modelName"],
170+
temperature=payload["data"]["modelKwargs"].get("temperature", 0.7),
171+
streaming=is_streaming,
172+
)
173+
174+
if is_streaming:
175+
async def generate_sse():
176+
async for event in agent.stream_async(user_message):
177+
if "event" in event:
178+
bedrock_event = event["event"]
179+
180+
# Handle different event types
181+
if "contentBlockDelta" in bedrock_event:
182+
delta = bedrock_event["contentBlockDelta"]["delta"]
183+
184+
if "text" in delta:
185+
# Stream response content
186+
sse_data = json.dumps({"type": "content", "content": delta["text"]})
187+
yield f"data: {sse_data}\n\n"
188+
189+
elif "reasoningContent" in delta:
190+
# Stream thinking steps
191+
reasoning = delta["reasoningContent"]["text"]
192+
sse_data = json.dumps({"type": "thinking", "content": f"🧠 {reasoning}"})
193+
yield f"data: {sse_data}\n\n"
194+
195+
elif "contentBlockStart" in bedrock_event:
196+
start_data = bedrock_event["contentBlockStart"]["start"]
197+
if "toolUse" in start_data:
198+
tool_name = start_data["toolUse"]["name"]
199+
sse_data = json.dumps({"type": "thinking", "content": f"🔧 Using {tool_name}"})
200+
yield f"data: {sse_data}\n\n"
201+
202+
return generate_sse()
203+
else:
204+
# Non-streaming response
205+
result = agent(user_message)
206+
return {"result": result.message}
207+
208+
if __name__ == "__main__":
209+
app.run()
210+
```
211+
212+
**Key Components:**
213+
214+
- `BedrockAgentCoreApp()`: Main application wrapper
215+
- `Agent()`: Core agent with system prompt, model, and tools
216+
- `@app.entrypoint`: Decorator for the main handler function
217+
- **Streaming**: Uses `agent.stream_async()` for real-time responses
218+
- **Event Processing**: Handles Bedrock events to extract thinking and content
219+
- **SSE Format**: Returns properly formatted Server-Sent Events
220+
221+
## Troubleshooting
222+
223+
### Agent Not Available
224+
225+
- Verify agent is deployed and active in Bedrock
226+
- Confirm agent ARN matches the exact pattern required
227+
- Check that your user has `admin` or `workspace_manager` role
228+
229+
### Streaming Issues
230+
231+
- Check WebSocket connection in browser developer tools
232+
- Verify session management in CloudWatch logs
233+
- Ensure agent provides data in expected `thinking`/`event` format
234+
235+
### Performance
236+
237+
- Agents may take longer than standard models due to reasoning complexity
238+
- Monitor CloudWatch metrics for agent invocation times
239+
- Conversation history is limited to prevent payload size issues
6.8 MB
Loading
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from clients.appsync_client import AppSyncClient
2+
3+
4+
def test_list_agents(client: AppSyncClient):
5+
agents = client.list_agents()
6+
assert isinstance(agents, list)

integtests/chatbot-api/application_test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def test_create_application(client: AppSyncClient):
1616
pytest.application = client.create_application(
1717
input={
1818
"name": "INTEG_TEST_APP",
19-
"model": "bedrock::anthropic.claude-instant-v1",
19+
"model": "bedrock::anthropic.claude-3-haiku-20240307-v1:0",
2020
"roles": ["user"],
2121
"allowImageInput": True,
2222
"allowVideoInput": True,
@@ -103,7 +103,7 @@ def test_update_application(client: AppSyncClient):
103103
input={
104104
"id": pytest.application.get("id"),
105105
"name": "INTEG_TEST_APP",
106-
"model": "bedrock::anthropic.claude-instant-v1",
106+
"model": "bedrock::anthropic.claude-3-haiku-20240307-v1:0",
107107
"roles": ["user", "admin"],
108108
"allowImageInput": False,
109109
"allowVideoInput": False,

integtests/chatbot-api/model_test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ def test_list_models(client: AppSyncClient, default_model):
66
assert len(models) > 10
77
model = next(i for i in models if i.get("name") == default_model)
88
assert model == {
9-
"name": "anthropic.claude-instant-v1",
9+
"name": "anthropic.claude-3-haiku-20240307-v1:0",
1010
"provider": "bedrock",
1111
"interface": "langchain",
1212
"ragSupported": True,
13-
"inputModalities": ["TEXT", "DOCUMENT"],
13+
"inputModalities": ["TEXT", "IMAGE", "DOCUMENT"],
1414
"outputModalities": ["TEXT"],
1515
"streaming": True,
1616
}

0 commit comments

Comments
 (0)