From 42efba06a831a0be9d06ff0f605b0a92038ae45f Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Wed, 28 May 2025 19:56:05 +0200 Subject: [PATCH 1/8] docs(event-handler): add docs for bedrock agents --- docs/features/event-handler/bedrock-agents.md | 142 ++++++++++++++++++ .../bedrock-agents/accessEventAndContext.ts | 24 +++ .../bedrock-agents/debugLogging.ts | 27 ++++ .../gettingStartedFunctionsTool.ts | 22 +++ .../bedrock-agents/sessionAttributes.ts | 40 +++++ .../bedrock-agents/stopConversation.ts | 35 +++++ .../templates/gettingStartedCdk.ts | 111 ++++++++++++++ .../templates/gettingStartedSam.yaml | 74 +++++++++ mkdocs.yml | 1 + .../event-handler/src/types/bedrock-agent.ts | 6 +- 10 files changed, 479 insertions(+), 3 deletions(-) create mode 100644 docs/features/event-handler/bedrock-agents.md create mode 100644 examples/snippets/event-handler/bedrock-agents/accessEventAndContext.ts create mode 100644 examples/snippets/event-handler/bedrock-agents/debugLogging.ts create mode 100644 examples/snippets/event-handler/bedrock-agents/gettingStartedFunctionsTool.ts create mode 100644 examples/snippets/event-handler/bedrock-agents/sessionAttributes.ts create mode 100644 examples/snippets/event-handler/bedrock-agents/stopConversation.ts create mode 100644 examples/snippets/event-handler/bedrock-agents/templates/gettingStartedCdk.ts create mode 100644 examples/snippets/event-handler/bedrock-agents/templates/gettingStartedSam.yaml diff --git a/docs/features/event-handler/bedrock-agents.md b/docs/features/event-handler/bedrock-agents.md new file mode 100644 index 000000000..1b1dac2b8 --- /dev/null +++ b/docs/features/event-handler/bedrock-agents.md @@ -0,0 +1,142 @@ +--- +title: Bedrock Agents +description: Event Handler for Amazon Bedrock Agents +status: new +--- + + + +Create [Amazon Bedrock Agents](https://docs.aws.amazon.com/bedrock/latest/userguide/agents.html#agents-how) and focus on building your agent's logic without worrying about parsing and routing requests. + +```mermaid +flowchart LR + Bedrock[LLM] <-- uses --> Agent + You[User input] --> Agent + Agent[Bedrock Agent] <-- tool use --> Lambda + + subgraph Agent[Bedrock Agent] + ToolDescriptions[Tool Definitions] + end + + subgraph Lambda[Lambda Function] + direction TB + Parsing[Parameter Parsing] --> Routing + Routing --> Code[Your code] + Code --> ResponseBuilding[Response Building] + end + + style You stroke:#0F0,stroke-width:2px +``` + +## Key Features + +* Easily expose tools for your Large Language Model (LLM) agents +* Automatic routing based on tool name and function details +* Graceful error handling and response formatting + +## Terminology + +**Event handler** is a Powertools for AWS feature that processes an event, runs data parsing and validation, routes the request to a specific function, and returns a response to the caller in the proper format. + +**Function details** consist of a list of parameters, defined by their name, data type, and whether they are required. The agent uses these configurations to determine what information it needs to elicit from the user. + +**Action group** is a collection of two resources where you define the actions that the agent should carry out: an OpenAPI schema to define the APIs that the agent can invoke to carry out its tasks, and a Lambda function to execute those actions. + +**Large Language Models (LLM)** are very large deep learning models that are pre-trained on vast amounts of data, capable of extracting meanings from a sequence of text and understanding the relationship between words and phrases on it. + +**Amazon Bedrock Agent** is an Amazon Bedrock feature to build and deploy conversational agents that can interact with your customers using Large Language Models (LLM) and AWS Lambda functions. + +## Getting Started + +```shell +npm i @aws-lambda-powertools/event-handler +``` + +### Required resources + +You must create an Amazon Bedrock Agent with at least one action group. Each action group can contain up to 5 tools, which in turn need to match the ones defined in your Lambda function. Bedrock must have permission to invoke your Lambda function. + +??? note "Click to see example IaC templates" + + === "AWS SAM" + + ```yaml + --8<-- "examples/snippets/event-handler/bedrock-agents/templates/gettingStartedSam.yaml" + ``` + + === "AWS CDK" + + ```typescript + --8<-- "examples/snippets/event-handler/bedrock-agents/templates/gettingStartedCdk.ts" + ``` + +### Usage + +To create an agent, use the `BedrockAgentFunctionResolver` to to register your tools and handle the requests. The resolver will automatically parse the request, route it to the appropriate function, and return a well-formed response that includes the tool's output and any existing session attributes. + +When passing the tool parameters to your handler, we will automatically cast them to the appropriate type based on the `type` field defined in the action group. This means you can use native JavaScript types like `string`, `number`, `boolean` without worrying about parsing them yourself. + +Currently, we don't support parsing `array` types, so you will receive them as strings. + +=== "Define a tool" + + ```typescript hl_lines="4 6 22" + --8<-- "examples/snippets/event-handler/bedrock-agents/gettingStartedFunctionsTool.ts" + ``` + + 1. The `description` field is optional, but highly recommended in the action group definition. + +## Advanced + +### Handling errors + +By default, we will handle errors gracefully and return a well-formed response to the agent so that it can continue the conversation with the user. + +When an error occurs, we send back an error message in the response body that includes the error type and message. The agent will then use this information to let the user know that something went wrong. + +If you want to handle errors differently, you can return a `BedrockFunctionResponse` with a custom `body` and `responseState` set to `FAILURE`. This is useful when you want to abort the conversation. + +!!! tip + You can use the same technique to reprompt the user for missing information or for them to correct their input. Just return a `BedrockFunctionResponse` with a custom message and `responseState` set to `REPROMPT`. + +=== "Custom error handling" + + ```typescript hl_lines="19-25" + --8<-- "examples/snippets/event-handler/bedrock-agents/stopConversation.ts" + ``` + +### Accessing Lambda context and event + +You can access to the original Lambda event or context for additional information. These are passed to the handler function as optional arguments. + +=== "Access event and context" + + ```typescript hl_lines="7-9" + --8<-- "examples/snippets/event-handler/bedrock-agents/accessEventAndContext.ts" + ``` + +### Setting session attributes + +When Bedrock Agents invoke your Lambda function, it can pass session attributes that you can use to store information across multiple interactions with the user. You can access these attributes in your handler function and modify them as needed. + +=== "Working with session attributes" + + ```typescript hl_lines="25-28" + --8<-- "examples/snippets/event-handler/bedrock-agents/sessionAttributes.ts" + ``` + +### Logging + +By default, the `BedrockAgentFunctionResolver` uses the global `console` logger and emits only warnings and errors. + +You can change this behavior by passing a custom logger instance to the `BedrockAgentFunctionResolver` constructor and setting its log level. Alternatively, you can also enable [Lambda Advanced Logging Controls](https://docs.aws.amazon.com/lambda/latest/dg/monitoring-cloudwatchlogs-advanced.html) and setting the log level to `DEBUG`. + +When debug logging is enabled, the resolver will emit logs that show the underlying handler registration and the routing process. This is useful for understanding how the agent resolves the tools and routes the requests. + +For example, when using the [Powertools for AWS Lambda logger](../logger.md), you can set the `LOG_LEVEL` to `DEBUG` in your environment variables or at the logger level and pass the logger instance to the `BedrockAgentFunctionResolver` constructor to enable debug logging. + +=== "Debug logging" + + ```typescript hl_lines="9" + --8<-- "examples/snippets/event-handler/bedrock-agents/debugLogging.ts" + ``` diff --git a/examples/snippets/event-handler/bedrock-agents/accessEventAndContext.ts b/examples/snippets/event-handler/bedrock-agents/accessEventAndContext.ts new file mode 100644 index 000000000..0ddbd6bc0 --- /dev/null +++ b/examples/snippets/event-handler/bedrock-agents/accessEventAndContext.ts @@ -0,0 +1,24 @@ +import { BedrockAgentFunctionResolver } from '@aws-lambda-powertools/event-handler/bedrock-agent'; +import type { Context } from 'aws-lambda'; + +const app = new BedrockAgentFunctionResolver(); + +app.tool<{ city: string }>( + async ({ city }, { event, context }) => { + const { sessionAttributes } = event; + sessionAttributes.requestId = context.awsRequestId; + + return { + city, + temperature: '20°C', + condition: 'Sunny', + }; + }, + { + name: 'getWeatherForCity', + description: 'Get weather for a specific city', + } +); + +export const handler = async (event: unknown, context: Context) => + app.resolve(event, context); diff --git a/examples/snippets/event-handler/bedrock-agents/debugLogging.ts b/examples/snippets/event-handler/bedrock-agents/debugLogging.ts new file mode 100644 index 000000000..9acb83106 --- /dev/null +++ b/examples/snippets/event-handler/bedrock-agents/debugLogging.ts @@ -0,0 +1,27 @@ +import { BedrockAgentFunctionResolver } from '@aws-lambda-powertools/event-handler/bedrock-agent'; +import { Logger } from '@aws-lambda-powertools/logger'; +import type { Context } from 'aws-lambda'; + +const logger = new Logger({ + serviceName: 'WeatherServiceAgent', + logLevel: 'DEBUG', +}); +const app = new BedrockAgentFunctionResolver({ logger }); + +app.tool<{ city: string }>( + async ({ city }) => { + // Simulate fetching weather data for the city + return { + city, + temperature: '20°C', + condition: 'Sunny', + }; + }, + { + name: 'getWeatherForCity', + description: 'Get weather for a specific city', + } +); + +export const handler = async (event: unknown, context: Context) => + app.resolve(event, context); diff --git a/examples/snippets/event-handler/bedrock-agents/gettingStartedFunctionsTool.ts b/examples/snippets/event-handler/bedrock-agents/gettingStartedFunctionsTool.ts new file mode 100644 index 000000000..5bfa20214 --- /dev/null +++ b/examples/snippets/event-handler/bedrock-agents/gettingStartedFunctionsTool.ts @@ -0,0 +1,22 @@ +import { BedrockAgentFunctionResolver } from '@aws-lambda-powertools/event-handler/bedrock-agent'; +import type { Context } from 'aws-lambda'; + +const app = new BedrockAgentFunctionResolver(); + +app.tool<{ city: string }>( + async ({ city }) => { + // Simulate fetching weather data for the city + return { + city, + temperature: '20°C', + condition: 'Sunny', + }; + }, + { + name: 'getWeatherForCity', + description: 'Get weather for a specific city', // (1)! + } +); + +export const handler = async (event: unknown, context: Context) => + app.resolve(event, context); diff --git a/examples/snippets/event-handler/bedrock-agents/sessionAttributes.ts b/examples/snippets/event-handler/bedrock-agents/sessionAttributes.ts new file mode 100644 index 000000000..96231c059 --- /dev/null +++ b/examples/snippets/event-handler/bedrock-agents/sessionAttributes.ts @@ -0,0 +1,40 @@ +import { + BedrockAgentFunctionResolver, + BedrockFunctionResponse, +} from '@aws-lambda-powertools/event-handler/bedrock-agent'; +import type { Context } from 'aws-lambda'; + +const app = new BedrockAgentFunctionResolver(); + +app.tool<{ city: string }>( + async ({ city }, { event }) => { + const { + sessionAttributes, + promptSessionAttributes, + knowledgeBasesConfiguration, + } = event; + + // your logic to fetch weather data for the city + + return new BedrockFunctionResponse({ + body: JSON.stringify({ + city, + temperature: '20°C', + condition: 'Sunny', + }), + sessionAttributes: { + ...sessionAttributes, + isGoodWeather: true, + }, + promptSessionAttributes, + knowledgeBasesConfiguration, + }); + }, + { + name: 'getWeatherForCity', + description: 'Get weather for a specific city', + } +); + +export const handler = async (event: unknown, context: Context) => + app.resolve(event, context); diff --git a/examples/snippets/event-handler/bedrock-agents/stopConversation.ts b/examples/snippets/event-handler/bedrock-agents/stopConversation.ts new file mode 100644 index 000000000..7de8fdf9a --- /dev/null +++ b/examples/snippets/event-handler/bedrock-agents/stopConversation.ts @@ -0,0 +1,35 @@ +import { + BedrockAgentFunctionResolver, + BedrockFunctionResponse, +} from '@aws-lambda-powertools/event-handler/bedrock-agent'; +import type { Context } from 'aws-lambda'; + +const app = new BedrockAgentFunctionResolver(); + +app.tool<{ city: string }>( + async ({ city }, { event }) => { + try { + throw new Error('Simulated error for demonstration purposes'); + } catch (error) { + const { + sessionAttributes, + promptSessionAttributes, + knowledgeBasesConfiguration, + } = event; + return new BedrockFunctionResponse({ + body: `An error occurred while fetching the weather data for ${city}`, + responseState: 'FAILURE', + sessionAttributes, + promptSessionAttributes, + knowledgeBasesConfiguration, + }); + } + }, + { + name: 'getWeatherForCity', + description: 'Get weather for a specific city', + } +); + +export const handler = async (event: unknown, context: Context) => + app.resolve(event, context); diff --git a/examples/snippets/event-handler/bedrock-agents/templates/gettingStartedCdk.ts b/examples/snippets/event-handler/bedrock-agents/templates/gettingStartedCdk.ts new file mode 100644 index 000000000..583262596 --- /dev/null +++ b/examples/snippets/event-handler/bedrock-agents/templates/gettingStartedCdk.ts @@ -0,0 +1,111 @@ +import { Arn, RemovalPolicy, Stack, type StackProps } from 'aws-cdk-lib'; +import { CfnAgent } from 'aws-cdk-lib/aws-bedrock'; +import { + PolicyDocument, + PolicyStatement, + Role, + ServicePrincipal, +} from 'aws-cdk-lib/aws-iam'; +import { Runtime } from 'aws-cdk-lib/aws-lambda'; +import { NodejsFunction, OutputFormat } from 'aws-cdk-lib/aws-lambda-nodejs'; +import { LogGroup, RetentionDays } from 'aws-cdk-lib/aws-logs'; +import type { Construct } from 'constructs'; + +export class BedrockAgentsStack extends Stack { + constructor(scope: Construct, id: string, props?: StackProps) { + super(scope, id, props); + + const fnName = 'BedrockAgentsFn'; + const logGroup = new LogGroup(this, 'WeatherAgentLogGroup', { + logGroupName: `/aws/lambda/${fnName}`, + removalPolicy: RemovalPolicy.DESTROY, + retention: RetentionDays.ONE_DAY, + }); + const fn = new NodejsFunction(this, 'WeatherAgentFunction', { + functionName: fnName, + logGroup, + runtime: Runtime.NODEJS_22_X, + entry: './src/index.ts', + handler: 'handler', + bundling: { + minify: true, + mainFields: ['module', 'main'], + sourceMap: true, + format: OutputFormat.ESM, + }, + }); + + const agentRole = new Role(this, 'WeatherAgentRole', { + assumedBy: new ServicePrincipal('bedrock.amazonaws.com'), + description: 'Role for Bedrock weather agent', + inlinePolicies: { + bedrock: new PolicyDocument({ + statements: [ + new PolicyStatement({ + actions: ['bedrock:*'], + resources: [ + Arn.format( + { + service: 'bedrock', + resource: 'foundation-model/*', + region: 'us-*', + account: '', + }, + Stack.of(this) + ), + Arn.format( + { + service: 'bedrock', + resource: 'inference-profile/*', + region: 'us-*', + account: '*', + }, + Stack.of(this) + ), + ], + }), + ], + }), + }, + }); + + const agent = new CfnAgent(this, 'WeatherAgent', { + agentName: 'weatherAgent', + actionGroups: [ + { + actionGroupName: 'weatherActionGroup', + actionGroupExecutor: { + lambda: fn.functionArn, + }, + functionSchema: { + functions: [ + { + name: 'getWeatherForCity', + description: 'Get weather for a specific city', + parameters: { + city: { + type: 'string', + description: 'The name of the city to get the weather for', + required: true, + }, + }, + }, + ], + }, + }, + ], + agentResourceRoleArn: agentRole.roleArn, + autoPrepare: true, + description: 'A simple weather agent', + foundationModel: `arn:aws:bedrock:us-west-2:${Stack.of(this).account}:inference-profile/us.amazon.nova-pro-v1:0`, + instruction: + 'You are a weather forecast news anchor. You will be asked to provide a weather forecast for one or more cities. You will provide a weather forecast for each city as if you were a TV news anchor. While doing so, include the region or country of the city received from the tool. You will provide the forecast in a conversational tone, as if you were speaking to a viewer on a TV news program.', + }); + fn.addPermission('BedrockAgentInvokePermission', { + principal: new ServicePrincipal('bedrock.amazonaws.com'), + action: 'lambda:InvokeFunction', + sourceAccount: this.account, + sourceArn: `arn:aws:bedrock:${this.region}:${this.account}:agent/${agent.attrAgentId}`, + }); + } +} diff --git a/examples/snippets/event-handler/bedrock-agents/templates/gettingStartedSam.yaml b/examples/snippets/event-handler/bedrock-agents/templates/gettingStartedSam.yaml new file mode 100644 index 000000000..e402c6cb5 --- /dev/null +++ b/examples/snippets/event-handler/bedrock-agents/templates/gettingStartedSam.yaml @@ -0,0 +1,74 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 + +Globals: + Function: + Timeout: 30 + MemorySize: 256 + Runtime: nodejs22.x + +Resources: + HelloWorldFunction: + Type: AWS::Serverless::Function + Properties: + Handler: index.handler + CodeUri: hello_world + + # IAM Role for Bedrock Agent + WeatherAgentRole: + Type: AWS::IAM::Role + Properties: + RoleName: !Sub '${AWS::StackName}-WeatherAgentRole' + Description: 'Role for Bedrock weather agent' + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: bedrock.amazonaws.com + Action: sts:AssumeRole + Policies: + - PolicyName: bedrock + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: 'bedrock:*' + Resource: + - !Sub 'arn:aws:bedrock:us-*::foundation-model/*' + - !Sub 'arn:aws:bedrock:us-*:*:inference-profile/*' + + # Lambda Permission for Bedrock Agent + BedrockAgentInvokePermission: + Type: AWS::Lambda::Permission + Properties: + FunctionName: !Ref HelloWorldFunction + Action: lambda:InvokeFunction + Principal: bedrock.amazonaws.com + SourceAccount: !Ref 'AWS::AccountId' + SourceArn: !Sub 'arn:aws:bedrock:${AWS::Region}:${AWS::AccountId}:agent/${WeatherAgent}' + + # Bedrock Agent + WeatherAgent: + Type: AWS::Bedrock::Agent + Properties: + AgentName: weatherAgent + Description: 'A simple weather agent' + FoundationModel: !Sub 'arn:aws:bedrock:us-west-2:${AWS::AccountId}:inference-profile/us.amazon.nova-pro-v1:0' + Instruction: | + You are a weather forecast news anchor. You will be asked to provide a weather forecast for one or more cities. You will provide a weather forecast for each city as if you were a TV news anchor. While doing so, include the region or country of the city received from the tool. You will provide the forecast in a conversational tone, as if you were speaking to a viewer on a TV news program. + AgentResourceRoleArn: !GetAtt WeatherAgentRole.Arn + AutoPrepare: true + ActionGroups: + - ActionGroupName: weatherActionGroup + ActionGroupExecutor: + Lambda: !GetAtt WeatherAgentFunction.Arn + FunctionSchema: + Functions: + - Name: getWeatherForCity + Description: 'Get weather for a specific city' + Parameters: + city: + Type: string + Description: 'The name of the city to get the weather for' + Required: true diff --git a/mkdocs.yml b/mkdocs.yml index 2013a2b79..dd963129d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -45,6 +45,7 @@ nav: - features/metrics.md - Event Handler: - features/event-handler/appsync-events.md + - features/event-handler/bedrock-agents.md - features/parameters.md - features/idempotency.md - features/batch.md diff --git a/packages/event-handler/src/types/bedrock-agent.ts b/packages/event-handler/src/types/bedrock-agent.ts index b3657922d..6659dea22 100644 --- a/packages/event-handler/src/types/bedrock-agent.ts +++ b/packages/event-handler/src/types/bedrock-agent.ts @@ -45,9 +45,9 @@ type ParameterValue = ParameterPrimitives | Array; */ type ToolFunction> = ( params: TParams, - options?: { - event?: BedrockAgentFunctionEvent; - context?: Context; + options: { + event: BedrockAgentFunctionEvent; + context: Context; } ) => Promise; From 8c52a62d11f707dae098e9c6700d20e943b988d3 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Wed, 28 May 2025 19:58:29 +0200 Subject: [PATCH 2/8] chore: add bedrock agents to readme --- packages/event-handler/README.md | 80 ++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/packages/event-handler/README.md b/packages/event-handler/README.md index c4350745d..b7c460802 100644 --- a/packages/event-handler/README.md +++ b/packages/event-handler/README.md @@ -104,6 +104,86 @@ export const handler = async (event, context) => ## Bedrock Agent Functions +Event Handler for Amazon Bedrock Agent Functions. + +* Easily expose tools for your Large Language Model (LLM) agents +* Automatic routing based on tool name and function details +* Graceful error handling and response formatting + +### Handle tool use + +When using the Bedrock Agent Functions event handler, you can register a handler for a specific tool name. The handler will be called when the agent uses that tool. + +```typescript +import { BedrockAgentFunctionResolver } from '@aws-lambda-powertools/event-handler/bedrock-agent'; +import type { Context } from 'aws-lambda'; + +const app = new BedrockAgentFunctionResolver(); + +app.tool<{ city: string }>( + async ({ city }) => { + // Simulate fetching weather data for the city + return { + city, + temperature: '20°C', + condition: 'Sunny', + }; + }, + { + name: 'getWeatherForCity', + description: 'Get weather for a specific city', // (1)! + } +); + +export const handler = async (event: unknown, context: Context) => + app.resolve(event, context); +``` + +You can also work with session attributes, which are key-value pairs that can be used to store information about the current session. The session attributes are automatically passed to the handler and can be used to store information that needs to be persisted across multiple tool invocations. + +```typescript +import { + BedrockAgentFunctionResolver, + BedrockFunctionResponse, +} from '@aws-lambda-powertools/event-handler/bedrock-agent'; +import type { Context } from 'aws-lambda'; + +const app = new BedrockAgentFunctionResolver(); + +app.tool<{ city: string }>( + async ({ city }, { event }) => { + const { + sessionAttributes, + promptSessionAttributes, + knowledgeBasesConfiguration, + } = event; + + // your logic to fetch weather data for the city + + return new BedrockFunctionResponse({ + body: JSON.stringify({ + city, + temperature: '20°C', + condition: 'Sunny', + }), + sessionAttributes: { + ...sessionAttributes, + isGoodWeather: true, + }, + promptSessionAttributes, + knowledgeBasesConfiguration, + }); + }, + { + name: 'getWeatherForCity', + description: 'Get weather for a specific city', + } +); + +export const handler = async (event: unknown, context: Context) => + app.resolve(event, context); +``` + See the [documentation](https://docs.powertools.aws.dev/lambda/typescript/latest/features/event-handler/appsync-events) for more details on how to use the AppSync event handler. ## Contribute From 7547201c286fbeebd2faed3571ea273f4f37707a Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Wed, 28 May 2025 20:13:38 +0200 Subject: [PATCH 3/8] chore: switch to serverless airline --- docs/features/event-handler/bedrock-agents.md | 4 +-- .../bedrock-agents/accessEventAndContext.ts | 7 ++--- .../bedrock-agents/debugLogging.ts | 10 +++---- .../gettingStartedFunctionsTool.ts | 8 ++--- .../bedrock-agents/sessionAttributes.ts | 11 ++++--- .../bedrock-agents/stopConversation.ts | 6 ++-- .../templates/gettingStartedCdk.ts | 25 ++++++++-------- .../templates/gettingStartedSam.yaml | 30 +++++++++---------- 8 files changed, 47 insertions(+), 54 deletions(-) diff --git a/docs/features/event-handler/bedrock-agents.md b/docs/features/event-handler/bedrock-agents.md index 1b1dac2b8..9c5e80ac1 100644 --- a/docs/features/event-handler/bedrock-agents.md +++ b/docs/features/event-handler/bedrock-agents.md @@ -80,7 +80,7 @@ Currently, we don't support parsing `array` types, so you will receive them as s === "Define a tool" - ```typescript hl_lines="4 6 22" + ```typescript hl_lines="4 6 20" --8<-- "examples/snippets/event-handler/bedrock-agents/gettingStartedFunctionsTool.ts" ``` @@ -121,7 +121,7 @@ When Bedrock Agents invoke your Lambda function, it can pass session attributes === "Working with session attributes" - ```typescript hl_lines="25-28" + ```typescript hl_lines="24-27" --8<-- "examples/snippets/event-handler/bedrock-agents/sessionAttributes.ts" ``` diff --git a/examples/snippets/event-handler/bedrock-agents/accessEventAndContext.ts b/examples/snippets/event-handler/bedrock-agents/accessEventAndContext.ts index 0ddbd6bc0..72dea250e 100644 --- a/examples/snippets/event-handler/bedrock-agents/accessEventAndContext.ts +++ b/examples/snippets/event-handler/bedrock-agents/accessEventAndContext.ts @@ -10,13 +10,12 @@ app.tool<{ city: string }>( return { city, - temperature: '20°C', - condition: 'Sunny', + airportCode: 'XYZ', // Simulated airport code for the city }; }, { - name: 'getWeatherForCity', - description: 'Get weather for a specific city', + name: 'getAirportCodeForCity', + description: 'Get the airport code for a given city', } ); diff --git a/examples/snippets/event-handler/bedrock-agents/debugLogging.ts b/examples/snippets/event-handler/bedrock-agents/debugLogging.ts index 9acb83106..48b6be28d 100644 --- a/examples/snippets/event-handler/bedrock-agents/debugLogging.ts +++ b/examples/snippets/event-handler/bedrock-agents/debugLogging.ts @@ -3,23 +3,21 @@ import { Logger } from '@aws-lambda-powertools/logger'; import type { Context } from 'aws-lambda'; const logger = new Logger({ - serviceName: 'WeatherServiceAgent', + serviceName: 'serverlessAirline', logLevel: 'DEBUG', }); const app = new BedrockAgentFunctionResolver({ logger }); app.tool<{ city: string }>( async ({ city }) => { - // Simulate fetching weather data for the city return { city, - temperature: '20°C', - condition: 'Sunny', + airportCode: 'XYZ', // Simulated airport code for the city }; }, { - name: 'getWeatherForCity', - description: 'Get weather for a specific city', + name: 'getAirportCodeForCity', + description: 'Get the airport code for a given city', } ); diff --git a/examples/snippets/event-handler/bedrock-agents/gettingStartedFunctionsTool.ts b/examples/snippets/event-handler/bedrock-agents/gettingStartedFunctionsTool.ts index 5bfa20214..8929bd2e1 100644 --- a/examples/snippets/event-handler/bedrock-agents/gettingStartedFunctionsTool.ts +++ b/examples/snippets/event-handler/bedrock-agents/gettingStartedFunctionsTool.ts @@ -5,16 +5,14 @@ const app = new BedrockAgentFunctionResolver(); app.tool<{ city: string }>( async ({ city }) => { - // Simulate fetching weather data for the city return { city, - temperature: '20°C', - condition: 'Sunny', + airportCode: 'XYZ', }; }, { - name: 'getWeatherForCity', - description: 'Get weather for a specific city', // (1)! + name: 'getAirportCodeForCity', + description: 'Get the airport code for a given city', // (1)! } ); diff --git a/examples/snippets/event-handler/bedrock-agents/sessionAttributes.ts b/examples/snippets/event-handler/bedrock-agents/sessionAttributes.ts index 96231c059..895cd2e12 100644 --- a/examples/snippets/event-handler/bedrock-agents/sessionAttributes.ts +++ b/examples/snippets/event-handler/bedrock-agents/sessionAttributes.ts @@ -14,25 +14,24 @@ app.tool<{ city: string }>( knowledgeBasesConfiguration, } = event; - // your logic to fetch weather data for the city + // your logic to fetch airport code for the city return new BedrockFunctionResponse({ body: JSON.stringify({ city, - temperature: '20°C', - condition: 'Sunny', + airportCode: 'XYZ', }), sessionAttributes: { ...sessionAttributes, - isGoodWeather: true, + isCommercialAirport: true, }, promptSessionAttributes, knowledgeBasesConfiguration, }); }, { - name: 'getWeatherForCity', - description: 'Get weather for a specific city', + name: 'getAirportCodeForCity', + description: 'Get the airport code for a given city', } ); diff --git a/examples/snippets/event-handler/bedrock-agents/stopConversation.ts b/examples/snippets/event-handler/bedrock-agents/stopConversation.ts index 7de8fdf9a..0dbdd6fb5 100644 --- a/examples/snippets/event-handler/bedrock-agents/stopConversation.ts +++ b/examples/snippets/event-handler/bedrock-agents/stopConversation.ts @@ -17,7 +17,7 @@ app.tool<{ city: string }>( knowledgeBasesConfiguration, } = event; return new BedrockFunctionResponse({ - body: `An error occurred while fetching the weather data for ${city}`, + body: `An error occurred while fetching the airport code for ${city}`, responseState: 'FAILURE', sessionAttributes, promptSessionAttributes, @@ -26,8 +26,8 @@ app.tool<{ city: string }>( } }, { - name: 'getWeatherForCity', - description: 'Get weather for a specific city', + name: 'getAirportCodeForCity', + description: 'Get the airport code for a given city', } ); diff --git a/examples/snippets/event-handler/bedrock-agents/templates/gettingStartedCdk.ts b/examples/snippets/event-handler/bedrock-agents/templates/gettingStartedCdk.ts index 583262596..192a00472 100644 --- a/examples/snippets/event-handler/bedrock-agents/templates/gettingStartedCdk.ts +++ b/examples/snippets/event-handler/bedrock-agents/templates/gettingStartedCdk.ts @@ -16,12 +16,12 @@ export class BedrockAgentsStack extends Stack { super(scope, id, props); const fnName = 'BedrockAgentsFn'; - const logGroup = new LogGroup(this, 'WeatherAgentLogGroup', { + const logGroup = new LogGroup(this, 'AirlineAgentLogGroup', { logGroupName: `/aws/lambda/${fnName}`, removalPolicy: RemovalPolicy.DESTROY, retention: RetentionDays.ONE_DAY, }); - const fn = new NodejsFunction(this, 'WeatherAgentFunction', { + const fn = new NodejsFunction(this, 'AirlineAgentFunction', { functionName: fnName, logGroup, runtime: Runtime.NODEJS_22_X, @@ -35,9 +35,9 @@ export class BedrockAgentsStack extends Stack { }, }); - const agentRole = new Role(this, 'WeatherAgentRole', { + const agentRole = new Role(this, 'AirlineAgentRole', { assumedBy: new ServicePrincipal('bedrock.amazonaws.com'), - description: 'Role for Bedrock weather agent', + description: 'Role for Bedrock Airline agent', inlinePolicies: { bedrock: new PolicyDocument({ statements: [ @@ -69,23 +69,24 @@ export class BedrockAgentsStack extends Stack { }, }); - const agent = new CfnAgent(this, 'WeatherAgent', { - agentName: 'weatherAgent', + const agent = new CfnAgent(this, 'AirlineAgent', { + agentName: 'AirlineAgent', actionGroups: [ { - actionGroupName: 'weatherActionGroup', + actionGroupName: 'AirlineActionGroup', actionGroupExecutor: { lambda: fn.functionArn, }, functionSchema: { functions: [ { - name: 'getWeatherForCity', - description: 'Get weather for a specific city', + name: 'getAirportCodeForCity', + description: 'Get the airport code for a given city', parameters: { city: { type: 'string', - description: 'The name of the city to get the weather for', + description: + 'The name of the city to get the airport code for', required: true, }, }, @@ -96,10 +97,10 @@ export class BedrockAgentsStack extends Stack { ], agentResourceRoleArn: agentRole.roleArn, autoPrepare: true, - description: 'A simple weather agent', + description: 'A simple Airline agent', foundationModel: `arn:aws:bedrock:us-west-2:${Stack.of(this).account}:inference-profile/us.amazon.nova-pro-v1:0`, instruction: - 'You are a weather forecast news anchor. You will be asked to provide a weather forecast for one or more cities. You will provide a weather forecast for each city as if you were a TV news anchor. While doing so, include the region or country of the city received from the tool. You will provide the forecast in a conversational tone, as if you were speaking to a viewer on a TV news program.', + 'You are an airport traffic control agent. You will be given a city name and you will return the airport code for that city.', }); fn.addPermission('BedrockAgentInvokePermission', { principal: new ServicePrincipal('bedrock.amazonaws.com'), diff --git a/examples/snippets/event-handler/bedrock-agents/templates/gettingStartedSam.yaml b/examples/snippets/event-handler/bedrock-agents/templates/gettingStartedSam.yaml index e402c6cb5..aa531aab2 100644 --- a/examples/snippets/event-handler/bedrock-agents/templates/gettingStartedSam.yaml +++ b/examples/snippets/event-handler/bedrock-agents/templates/gettingStartedSam.yaml @@ -14,12 +14,11 @@ Resources: Handler: index.handler CodeUri: hello_world - # IAM Role for Bedrock Agent - WeatherAgentRole: + AirlineAgentRole: Type: AWS::IAM::Role Properties: - RoleName: !Sub '${AWS::StackName}-WeatherAgentRole' - Description: 'Role for Bedrock weather agent' + RoleName: !Sub '${AWS::StackName}-AirlineAgentRole' + Description: 'Role for Bedrock Airline agent' AssumeRolePolicyDocument: Version: '2012-10-17' Statement: @@ -38,7 +37,6 @@ Resources: - !Sub 'arn:aws:bedrock:us-*::foundation-model/*' - !Sub 'arn:aws:bedrock:us-*:*:inference-profile/*' - # Lambda Permission for Bedrock Agent BedrockAgentInvokePermission: Type: AWS::Lambda::Permission Properties: @@ -46,29 +44,29 @@ Resources: Action: lambda:InvokeFunction Principal: bedrock.amazonaws.com SourceAccount: !Ref 'AWS::AccountId' - SourceArn: !Sub 'arn:aws:bedrock:${AWS::Region}:${AWS::AccountId}:agent/${WeatherAgent}' + SourceArn: !Sub 'arn:aws:bedrock:${AWS::Region}:${AWS::AccountId}:agent/${AirlineAgent}' # Bedrock Agent - WeatherAgent: + AirlineAgent: Type: AWS::Bedrock::Agent Properties: - AgentName: weatherAgent - Description: 'A simple weather agent' + AgentName: AirlineAgent + Description: 'A simple Airline agent' FoundationModel: !Sub 'arn:aws:bedrock:us-west-2:${AWS::AccountId}:inference-profile/us.amazon.nova-pro-v1:0' Instruction: | - You are a weather forecast news anchor. You will be asked to provide a weather forecast for one or more cities. You will provide a weather forecast for each city as if you were a TV news anchor. While doing so, include the region or country of the city received from the tool. You will provide the forecast in a conversational tone, as if you were speaking to a viewer on a TV news program. - AgentResourceRoleArn: !GetAtt WeatherAgentRole.Arn + You are an airport traffic control agent. You will be given a city name and you will return the airport code for that city. + AgentResourceRoleArn: !GetAtt AirlineAgentRole.Arn AutoPrepare: true ActionGroups: - - ActionGroupName: weatherActionGroup + - ActionGroupName: AirlineActionGroup ActionGroupExecutor: - Lambda: !GetAtt WeatherAgentFunction.Arn + Lambda: !GetAtt AirlineAgentFunction.Arn FunctionSchema: Functions: - - Name: getWeatherForCity - Description: 'Get weather for a specific city' + - Name: getAirportCodeForCity + Description: 'Get the airport code for a given city' Parameters: city: Type: string - Description: 'The name of the city to get the weather for' + Description: 'The name of the city to get the airport code for' Required: true From 163eb314a3a704d5ca8575f06f6754924291c745 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Mon, 2 Jun 2025 16:57:42 +0200 Subject: [PATCH 4/8] Update bedrock-agents.md Co-authored-by: Stefano Vozza --- docs/features/event-handler/bedrock-agents.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/event-handler/bedrock-agents.md b/docs/features/event-handler/bedrock-agents.md index 9c5e80ac1..8938aca92 100644 --- a/docs/features/event-handler/bedrock-agents.md +++ b/docs/features/event-handler/bedrock-agents.md @@ -38,7 +38,7 @@ flowchart LR **Event handler** is a Powertools for AWS feature that processes an event, runs data parsing and validation, routes the request to a specific function, and returns a response to the caller in the proper format. -**Function details** consist of a list of parameters, defined by their name, data type, and whether they are required. The agent uses these configurations to determine what information it needs to elicit from the user. +**Function details** consist of a list of parameters, defined by their name, data type, and whether or not they are required. The agent uses these configurations to determine what information it needs to elicit from the user. **Action group** is a collection of two resources where you define the actions that the agent should carry out: an OpenAPI schema to define the APIs that the agent can invoke to carry out its tasks, and a Lambda function to execute those actions. From aa316b9a5abe90ba1d68d59d5f9d22be349bc197 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Mon, 2 Jun 2025 16:57:54 +0200 Subject: [PATCH 5/8] Update bedrock-agents.md Co-authored-by: Stefano Vozza --- docs/features/event-handler/bedrock-agents.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/event-handler/bedrock-agents.md b/docs/features/event-handler/bedrock-agents.md index 8938aca92..0209846ac 100644 --- a/docs/features/event-handler/bedrock-agents.md +++ b/docs/features/event-handler/bedrock-agents.md @@ -42,7 +42,7 @@ flowchart LR **Action group** is a collection of two resources where you define the actions that the agent should carry out: an OpenAPI schema to define the APIs that the agent can invoke to carry out its tasks, and a Lambda function to execute those actions. -**Large Language Models (LLM)** are very large deep learning models that are pre-trained on vast amounts of data, capable of extracting meanings from a sequence of text and understanding the relationship between words and phrases on it. +**Large Language Models (LLM)** are very large deep learning models that are pre-trained on vast amounts of data, capable of extracting meanings from a sequence of text and understanding the relationship between words and phrases within that text. **Amazon Bedrock Agent** is an Amazon Bedrock feature to build and deploy conversational agents that can interact with your customers using Large Language Models (LLM) and AWS Lambda functions. From ac7b3a19ad72194e63174e112944404879dde132 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Mon, 2 Jun 2025 16:58:01 +0200 Subject: [PATCH 6/8] Update bedrock-agents.md Co-authored-by: Stefano Vozza --- docs/features/event-handler/bedrock-agents.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/event-handler/bedrock-agents.md b/docs/features/event-handler/bedrock-agents.md index 0209846ac..cf4d5b8b0 100644 --- a/docs/features/event-handler/bedrock-agents.md +++ b/docs/features/event-handler/bedrock-agents.md @@ -72,7 +72,7 @@ You must create an Amazon Bedrock Agent with at least one action group. Each act ### Usage -To create an agent, use the `BedrockAgentFunctionResolver` to to register your tools and handle the requests. The resolver will automatically parse the request, route it to the appropriate function, and return a well-formed response that includes the tool's output and any existing session attributes. +To create an agent, use the `BedrockAgentFunctionResolver` to register your tools and handle the requests. The resolver will automatically parse the request, route it to the appropriate function, and return a well-formed response that includes the tool's output and any existing session attributes. When passing the tool parameters to your handler, we will automatically cast them to the appropriate type based on the `type` field defined in the action group. This means you can use native JavaScript types like `string`, `number`, `boolean` without worrying about parsing them yourself. From 08285008237656f5be0f41aad6a0d41eda4fb562 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Mon, 2 Jun 2025 20:52:35 +0200 Subject: [PATCH 7/8] Update bedrock-agents.md Co-authored-by: Leandro Damascena --- docs/features/event-handler/bedrock-agents.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/event-handler/bedrock-agents.md b/docs/features/event-handler/bedrock-agents.md index cf4d5b8b0..7dd5f93b0 100644 --- a/docs/features/event-handler/bedrock-agents.md +++ b/docs/features/event-handler/bedrock-agents.md @@ -72,7 +72,7 @@ You must create an Amazon Bedrock Agent with at least one action group. Each act ### Usage -To create an agent, use the `BedrockAgentFunctionResolver` to register your tools and handle the requests. The resolver will automatically parse the request, route it to the appropriate function, and return a well-formed response that includes the tool's output and any existing session attributes. +Use the `BedrockAgentFunctionResolver` to register your tools and handle the requests to your Lambda function. The resolver will automatically parse the request, route it to the appropriate function, and return a well-formed response that includes the tool's output and any existing session attributes. When passing the tool parameters to your handler, we will automatically cast them to the appropriate type based on the `type` field defined in the action group. This means you can use native JavaScript types like `string`, `number`, `boolean` without worrying about parsing them yourself. From ef20932d28aa83ff5750ff4e7fcf8cbe474315c5 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Tue, 3 Jun 2025 10:45:39 +0200 Subject: [PATCH 8/8] chore: add clarification --- docs/features/event-handler/bedrock-agents.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/event-handler/bedrock-agents.md b/docs/features/event-handler/bedrock-agents.md index 7dd5f93b0..fa81222ed 100644 --- a/docs/features/event-handler/bedrock-agents.md +++ b/docs/features/event-handler/bedrock-agents.md @@ -84,7 +84,7 @@ Currently, we don't support parsing `array` types, so you will receive them as s --8<-- "examples/snippets/event-handler/bedrock-agents/gettingStartedFunctionsTool.ts" ``` - 1. The `description` field is optional, but highly recommended in the action group definition. + 1. The `description` field is optional, but highly recommended in the action group definition so that the LLM can understand what the tool does and how to use it. ## Advanced