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
5 changes: 5 additions & 0 deletions sfn-bedrockagentcore-harness-cdk/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules
build
cdk.out
cdk.context.json
package-lock.json
112 changes: 112 additions & 0 deletions sfn-bedrockagentcore-harness-cdk/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# AWS Step Functions with Amazon Bedrock AgentCore Harness Optimized Integration (CDK)

This pattern invokes an Amazon Bedrock AgentCore harness directly from AWS Step Functions using the optimized integration — with a 15-minute timeout (vs 60 seconds for the SDK integration), Converse-shaped responses, aggregated token metrics, and CloudWatch reasoning traces.

Learn more about this pattern at Serverless Land Patterns: https://serverlessland.com/patterns/sfn-bedrockagentcore-harness-cdk

Important: this application uses various AWS services and there are costs associated with these services after the Free Tier usage - please see the [AWS Pricing page](https://aws.amazon.com/pricing/) for details. You are responsible for any AWS costs incurred. No warranty is implied in this example.

## Requirements

* [Create an AWS account](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html) if you do not already have one and log in. The IAM user that you use must have sufficient permissions to make necessary AWS service calls and manage AWS resources.
* [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed and configured
* [Git Installed](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
* [Node.js 20+](https://nodejs.org/en/download/) installed
* [AWS CDK v2](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html) installed and bootstrapped
* An existing Amazon Bedrock AgentCore harness (see [Creating a harness](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/harness-create.html))

## Deployment Instructions

1. Create a new directory, navigate to that directory in a terminal and clone the GitHub repository:
```
git clone https://github.com/aws-samples/serverless-patterns
```
2. Change directory to the pattern directory:
```
cd serverless-patterns/sfn-bedrockagentcore-harness-cdk
```
3. Install dependencies:
```
npm install
```
4. Deploy the stack with your harness ARN:
```
cdk deploy --parameters HarnessArn=arn:aws:bedrock-agentcore:us-east-1:ACCOUNT_ID:harness/YOUR-HARNESS-NAME
```

## How it works

This pattern creates an AWS Step Functions state machine that:

1. **Invokes the harness** using the optimized integration (`arn:aws:states:::bedrockagentcore:invokeHarness`) — no AWS Lambda in the path
2. **Receives a Converse-shaped response** with the agent's final text, stop reason, token usage, and latency metrics
3. **Formats the output** extracting just the response text, token count, and latency
4. **Handles errors** with specific catches for throttling (exponential backoff) and missing harness

### Key differences from SDK integration

| Feature | SDK Integration | Optimized Integration (this pattern) |
|---|---|---|
| Resource URI | `arn:aws:states:::aws-sdk:bedrockagentcore:InvokeHarness` | `arn:aws:states:::bedrockagentcore:invokeHarness` |
| AWS Lambda required | No (but needed for streaming/parsing) | No |
| Response format | Raw API response | Converse-shaped (text only, tool use omitted) |
| Token metrics | Manual calculation | Aggregated across all turns automatically |
| CloudWatch traces | Not available | Turn-by-turn reasoning deep-links |
| Max timeout | 60 seconds (API call limit) | 15 minutes (Task state limit) |

### Architecture

```
User Input → AWS Step Functions → Amazon Bedrock AgentCore Harness
Model inference + tool use
Converse-shaped response
Step Functions → Formatted Output
```

## Testing

1. Start an execution:
```bash
SM_ARN=$(aws cloudformation describe-stacks \
--stack-name SfnBedrockagentcoreHarnessStack \
--query 'Stacks[0].Outputs[?OutputKey==`StateMachineArn`].OutputValue' \
--output text)

EXEC_ARN=$(aws stepfunctions start-execution \
--state-machine-arn $SM_ARN \
--input '{"prompt": "What is Amazon Bedrock AgentCore and how does a harness work?"}' \
--query 'executionArn' --output text)

echo "Execution: $EXEC_ARN"
```

2. Wait 10-30 seconds for the agent to reason, then check output:
```bash
aws stepfunctions describe-execution \
--execution-arn $EXEC_ARN \
--query '{status: status, output: output}'
```

3. Expected output format:
```json
{
"response": "Amazon Bedrock AgentCore is...",
"stopReason": "end_turn",
"tokensUsed": 1523,
"latencyMs": 8421
}
```

## Cleanup

```bash
cdk destroy
```

----
Copyright 2026 Amazon.com, Inc. or its affiliates. All Rights Reserved.

SPDX-License-Identifier: MIT-0
12 changes: 12 additions & 0 deletions sfn-bedrockagentcore-harness-cdk/bin/app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { SfnBedrockagentcoreHarnessStack } from '../lib/sfn-bedrockagentcore-harness-stack';

const app = new cdk.App();
new SfnBedrockagentcoreHarnessStack(app, 'SfnBedrockagentcoreHarnessStack', {
env: {
account: process.env.CDK_DEFAULT_ACCOUNT,
region: process.env.CDK_DEFAULT_REGION || 'us-east-1',
},
});
3 changes: 3 additions & 0 deletions sfn-bedrockagentcore-harness-cdk/cdk.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"app": "npx ts-node --prefer-ts-exts bin/app.ts"
}
81 changes: 81 additions & 0 deletions sfn-bedrockagentcore-harness-cdk/example-pattern.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
{
"title": "AWS Step Functions with Amazon Bedrock AgentCore Harness Optimized Integration (CDK)",
"description": "Invoke Amazon Bedrock AgentCore harness from AWS Step Functions using the optimized integration — zero Lambda, Converse-shaped responses, and token metrics.",
"language": "TypeScript",
"level": "200",
"framework": "AWS CDK",
"introBox": {
"headline": "How it works",
"text": [
"This pattern uses the AWS Step Functions optimized integration for Amazon Bedrock AgentCore to invoke a harness directly — no Lambda function required.",
"The harness orchestrates model inference, tool use, and multi-turn conversations. Step Functions receives a Converse-shaped response with aggregated token usage metrics.",
"The optimized integration provides CloudWatch deep-links for turn-by-turn agent reasoning traces, built-in retry/catch for throttling, and a 15-minute execution timeout.",
"The state machine includes error handling with specific catches for ResourceNotFoundException and ThrottlingException with exponential backoff."
]
},
"gitHub": {
"template": {
"repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/sfn-bedrockagentcore-harness-cdk",
"templateURL": "serverless-patterns/sfn-bedrockagentcore-harness-cdk",
"projectFolder": "sfn-bedrockagentcore-harness-cdk",
"templateFile": "lib/sfn-bedrockagentcore-harness-stack.ts"
}
},
"resources": {
"bullets": [
{
"text": "Invoke Amazon Bedrock AgentCore harness with Step Functions",
"link": "https://docs.aws.amazon.com/step-functions/latest/dg/connect-bedrockagentcore.html"
},
{
"text": "Amazon Bedrock AgentCore Harness",
"link": "https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/harness.html"
}
]
},
"deploy": {
"text": [
"<code>cdk bootstrap</code>",
"<code>npm install</code>",
"<code>cdk deploy --parameters HarnessArn=arn:aws:bedrock-agentcore:us-east-1:ACCOUNT:harness/YOUR-HARNESS</code>"
]
},
"testing": {
"text": [
"Start an execution with a prompt:",
"<code>aws stepfunctions start-execution --state-machine-arn $(aws cloudformation describe-stacks --stack-name SfnBedrockagentcoreHarnessStack --query 'Stacks[0].Outputs[?OutputKey==`StateMachineArn`].OutputValue' --output text) --input '{\"prompt\": \"What is Amazon Bedrock AgentCore?\"}'</code>",
"Check execution output (wait 10-30 seconds for agent reasoning):",
"<code>aws stepfunctions describe-execution --execution-arn EXECUTION_ARN --query 'output'</code>"
]
},
"cleanup": {
"text": [
"<code>cdk destroy</code>"
]
},
"authors": [
{
"name": "Nithin Chandran R",
"bio": "Technical Account Manager at AWS",
"linkedin": "nithin-chandran-r"
}
],
"patternArch": {
"icon1": {
"x": 20,
"y": 50,
"service": "sfn",
"label": "AWS Step Functions"
},
"icon2": {
"x": 80,
"y": 50,
"service": "bedrock",
"label": "Amazon Bedrock AgentCore"
},
"line1": {
"from": "icon1",
"to": "icon2"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as sfn from 'aws-cdk-lib/aws-stepfunctions';
import * as iam from 'aws-cdk-lib/aws-iam';

export class SfnBedrockagentcoreHarnessStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);

const harnessArn = new cdk.CfnParameter(this, 'HarnessArn', {
type: 'String',
description: 'ARN of the Amazon Bedrock AgentCore harness to invoke',
});

// Step Functions execution role with AgentCore permissions
const sfnRole = new iam.Role(this, 'SfnExecutionRole', {
assumedBy: new iam.ServicePrincipal('states.amazonaws.com'),
inlinePolicies: {
AgentCoreInvoke: new iam.PolicyDocument({
statements: [
new iam.PolicyStatement({
actions: [
'bedrock-agentcore:InvokeHarness',
'bedrock-agentcore:InvokeAgentRuntime',
],
resources: [harnessArn.valueAsString],
}),
],
}),
},
});

// State machine definition using the optimized integration
// arn:aws:states:::bedrockagentcore:invokeHarness (NOT the SDK integration)
const definition = {
Comment: 'Invoke Amazon Bedrock AgentCore harness using Step Functions optimized integration',
StartAt: 'InvokeHarness',
States: {
InvokeHarness: {
Type: 'Task',
Resource: 'arn:aws:states:::bedrockagentcore:invokeHarness',
Parameters: {
'HarnessArn': harnessArn.valueAsString,
'RuntimeSessionId.$': '$$.Execution.Name',
'Messages': [
{
'Content': [{ 'Text.$': '$.prompt' }],
'Role': 'user',
},
],
'SystemPrompt': [{ 'Text': 'You are a helpful AI assistant. Answer concisely and accurately.' }],
'MaxIterations': 50,
'TimeoutSeconds': 600,
},
Retry: [
{
ErrorEquals: ['BedrockAgentCore.ThrottlingException'],
IntervalSeconds: 2,
MaxAttempts: 3,
BackoffRate: 2.0,
},
],
Catch: [
{
ErrorEquals: ['BedrockAgentCore.ResourceNotFoundException'],
Next: 'HarnessNotFound',
},
{
ErrorEquals: ['States.ALL'],
Next: 'HandleError',
},
],
Next: 'FormatResponse',
},
FormatResponse: {
Type: 'Pass',
Parameters: {
'response.$': '$.Output.Message.Content[0].Text',
'stopReason.$': '$.StopReason',
'tokensUsed.$': '$.Usage.TotalTokens',
'latencyMs.$': '$.Metrics.LatencyMs',
},
End: true,
},
HarnessNotFound: {
Type: 'Fail',
Error: 'HarnessNotFound',
Cause: 'The specified Amazon Bedrock AgentCore harness was not found. Verify the HarnessArn parameter.',
},
HandleError: {
Type: 'Fail',
Error: 'InvocationFailed',
Cause: 'Amazon Bedrock AgentCore harness invocation failed.',
},
},
};

const stateMachine = new sfn.CfnStateMachine(this, 'HarnessStateMachine', {
definitionString: JSON.stringify(definition),
roleArn: sfnRole.roleArn,
stateMachineType: 'STANDARD',
});

new cdk.CfnOutput(this, 'StateMachineArn', {
value: stateMachine.attrArn,
description: 'AWS Step Functions state machine ARN',
});

new cdk.CfnOutput(this, 'HarnessArnOutput', {
value: harnessArn.valueAsString,
description: 'Amazon Bedrock AgentCore harness ARN',
});
}
}
17 changes: 17 additions & 0 deletions sfn-bedrockagentcore-harness-cdk/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "sfn-bedrockagentcore-harness-cdk",
"version": "1.0.0",
"bin": { "app": "bin/app.ts" },
"scripts": { "build": "tsc", "cdk": "cdk" },
"dependencies": {
"aws-cdk-lib": "^2.260.0",
"constructs": "^10.0.0",
"source-map-support": "^0.5.21"
},
"devDependencies": {
"@types/node": "^20.0.0",
"typescript": "~5.4.0",
"aws-cdk": "^2.260.0",
"ts-node": "^10.9.0"
}
}
Loading