Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ package-lock.json

# CDK asset staging directory
.cdk.staging
cdk.out*
cdk.*out*

# Frontend build output
frontend/dist/
Expand Down
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ The example agent is built with the [Strands Agents framework](https://github.co
Flow:
1. Browser loads React app from CloudFront/S3
2. User authenticates with Cognito, receives JWT token
3. Browser calls AgentCore directly with JWT Bearer token
4. AgentCore validates JWT and processes agent requests
3. Browser calls AgentCore Runtime directly with JWT Bearer token
4. AgentCore Runtime validates JWT and executes agent
5. Agent processes requests and invokes Amazon Bedrock foundation model
6. AgentCore Memory stores and retrieves conversation context
7. Generative AI observability provides monitoring dashboards and insights

## Quick Start

Expand Down
36 changes: 0 additions & 36 deletions agent/Dockerfile

This file was deleted.

7 changes: 3 additions & 4 deletions agent/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
bedrock-agentcore
bedrock-agentcore-starter-toolkit
boto3
strands-agents
strands-agents-tools
uv
boto3
bedrock-agentcore
bedrock-agentcore-starter-toolkit
66 changes: 44 additions & 22 deletions agent/strands_agent.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,28 @@
from strands import Agent, tool
from strands_tools import calculator # Import the calculator tool
import json
import os
from typing import Final
from bedrock_agentcore.memory.integrations.strands.config import AgentCoreMemoryConfig
from bedrock_agentcore.memory.integrations.strands.session_manager import AgentCoreMemorySessionManager
from bedrock_agentcore.runtime import BedrockAgentCoreApp
from strands import Agent, tool
from strands_tools import calculator # Import the calculator tool
from strands.models import BedrockModel

# Constant variables
AGENTCORE_MEMORY_ID: Final[str] = os.environ["AGENTCORE_MEMORY_ID"]
MODEL_ID: Final[str] = "global.anthropic.claude-haiku-4-5-20251001-v1:0"
MODEL: Final[BedrockModel] = BedrockModel(model_id=MODEL_ID)

# Create the AgentCore app
app = BedrockAgentCoreApp()


# Create a custom tool
@tool
def weather():
"""Get the current weather. Always returns sunny weather."""
return "It's sunny and 72°F today!"

model_id = "global.anthropic.claude-haiku-4-5-20251001-v1:0"
model = BedrockModel(
model_id=model_id,
)

agent = Agent(
model=model,
tools=[calculator, weather],
system_prompt="You're a helpful assistant. You can do simple math calculation, and tell the weather.",
callback_handler=None
)

@app.entrypoint
async def agent_invocation(payload):
Expand All @@ -41,28 +40,51 @@ async def agent_invocation(payload):
if isinstance(payload, str):
payload = json.loads(payload)

# Extract the prompt from the payload
# Try AWS SDK format first (most common for production): {"input": {"prompt": "..."}}
# Fall back to direct format: {"prompt": "..."}
# Extract the prompt, actorId, and sessionId from the payload
# Try AWS SDK format first (most common for production): {"input": {"prompt": "...", "actorId": "...", "sessionId": "..."}}
# Fall back to direct format: {"prompt": "...", "actorId": "...", "sessionId": "..."}
user_input = None
actor_id = None
session_id = None

if isinstance(payload, dict):
if "input" in payload and isinstance(payload["input"], dict):
user_input = payload["input"].get("prompt")
actor_id = payload["input"].get("actorId")
session_id = payload["input"].get("sessionId")
else:
user_input = payload.get("prompt")
actor_id = payload.get("actorId")
session_id = payload.get("sessionId")

# Validate required fields
if not user_input:
raise ValueError(f"No prompt found in payload. Expected {{'prompt': '...'}} or {{'input': {{'prompt': '...'}}}}. Received: {payload}")

# response = agent(user_input)
# response_text = response.message['content'][0]['text']
if not actor_id or not session_id:
raise ValueError(f"No actorId or sessionId found in payload. Received: {payload}")

agent = Agent(
model=MODEL,
tools=[calculator, weather],
system_prompt="You're a helpful assistant. You can do simple math calculation, and tell the weather.",
session_manager=AgentCoreMemorySessionManager(
agentcore_memory_config=AgentCoreMemoryConfig(
memory_id=AGENTCORE_MEMORY_ID,
session_id=session_id,
actor_id=actor_id,
)
),
callback_handler=None,
)

# Stream response
stream = agent.stream_async(user_input)
async for event in stream:
if (event.get('event',{}).get('contentBlockDelta',{}).get('delta',{}).get('text')):
print(event.get('event',{}).get('contentBlockDelta',{}).get('delta',{}).get('text'))
yield (event.get('event',{}).get('contentBlockDelta',{}).get('delta',{}).get('text'))
if event.get("event", {}).get("contentBlockDelta", {}).get("delta", {}).get("text"):
print(event.get("event", {}).get("contentBlockDelta", {}).get("delta", {}).get("text"))
yield (event.get("event", {}).get("contentBlockDelta", {}).get("delta", {}).get("text"))

# return response_text

if __name__ == "__main__":
app.run()
4 changes: 2 additions & 2 deletions cdk/bin/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ import { AuthStack } from '../lib/auth-stack';

const app = new cdk.App();

// Infrastructure stack (ECR, IAM, CodeBuild, S3)
// Infrastructure stack (S3 bucket, IAM role)
new AgentCoreInfraStack(app, 'AgentCoreInfra', {
env: {
account: process.env.CDK_DEFAULT_ACCOUNT,
region: process.env.CDK_DEFAULT_REGION || 'us-east-1',
},
description: 'AgentCore Infrastructure: Container registry, build pipeline, and IAM roles (uksb-q3p3ydk6f3)',
description: 'AgentCore Infrastructure: S3 code bucket and IAM role for direct code deployment (uksb-q3p3ydk6f3)',
});

// Auth stack (Cognito User Pool)
Expand Down
60 changes: 60 additions & 0 deletions cdk/lib/auth-stack.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import * as cdk from 'aws-cdk-lib';
import * as cognito from 'aws-cdk-lib/aws-cognito';
import * as iam from 'aws-cdk-lib/aws-iam';
import { Construct } from 'constructs';

export class AuthStack extends cdk.Stack {
public readonly userPool: cognito.UserPool;
public readonly userPoolClient: cognito.UserPoolClient;
public readonly identityPool: cognito.CfnIdentityPool;

constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
Expand Down Expand Up @@ -48,6 +50,58 @@ export class AuthStack extends cdk.Stack {
preventUserExistenceErrors: true,
});

// Cognito Identity Pool for AWS SDK access
this.identityPool = new cognito.CfnIdentityPool(this, 'AgentCoreIdentityPool', {
identityPoolName: 'agentcore-identity-pool',
allowUnauthenticatedIdentities: false,
cognitoIdentityProviders: [{
clientId: this.userPoolClient.userPoolClientId,
providerName: this.userPool.userPoolProviderName,
}],
});

// IAM Role for authenticated users (frontend)
const authenticatedRole = new iam.Role(this, 'CognitoAuthenticatedRole', {
roleName: 'AgentCoreAuthenticatedRole',
description: 'Role for authenticated Cognito users to access AgentCore Memory',
assumedBy: new iam.FederatedPrincipal(
'cognito-identity.amazonaws.com',
{
'StringEquals': {
'cognito-identity.amazonaws.com:aud': this.identityPool.ref,
},
'ForAnyValue:StringLike': {
'cognito-identity.amazonaws.com:amr': 'authenticated',
},
},
'sts:AssumeRoleWithWebIdentity'
),
});

// Add policy for AgentCore Memory read-only access
const region = cdk.Stack.of(this).region;
const account = cdk.Stack.of(this).account;

authenticatedRole.addToPolicy(new iam.PolicyStatement({
sid: 'AgentCoreMemoryReadAccess',
effect: iam.Effect.ALLOW,
actions: [
'bedrock-agentcore:ListSessions',
'bedrock-agentcore:ListEvents',
],
resources: [
`arn:aws:bedrock-agentcore:${region}:${account}:memory/*`,
],
}));

// Attach roles to Identity Pool
new cognito.CfnIdentityPoolRoleAttachment(this, 'IdentityPoolRoleAttachment', {
identityPoolId: this.identityPool.ref,
roles: {
authenticated: authenticatedRole.roleArn,
},
});

// Outputs
new cdk.CfnOutput(this, 'UserPoolId', {
value: this.userPool.userPoolId,
Expand All @@ -66,5 +120,11 @@ export class AuthStack extends cdk.Stack {
description: 'Cognito User Pool Client ID',
exportName: 'AgentCoreUserPoolClientId',
});

new cdk.CfnOutput(this, 'IdentityPoolId', {
value: this.identityPool.ref,
description: 'Cognito Identity Pool ID',
exportName: 'AgentCoreIdentityPoolId',
});
}
}
69 changes: 0 additions & 69 deletions cdk/lib/build-trigger-stack.ts

This file was deleted.

45 changes: 0 additions & 45 deletions cdk/lib/build-waiter-function.ts

This file was deleted.

Loading