From 108c9f0b039853565b5e1367c92c9a640bd57643 Mon Sep 17 00:00:00 2001
From: Henrique <999396+hjgraca@users.noreply.github.com>
Date: Thu, 22 May 2025 12:29:29 +0100
Subject: [PATCH 01/52] bedrock agent function first commit
---
libraries/AWS.Lambda.Powertools.sln | 15 ++
...andler.BedrockAgentFunctionResolver.csproj | 20 ++
.../BedrockAgentFunctionResolver.cs | 104 ++++++++
.../InternalsVisibleTo.cs | 18 ++
.../Readme.md | 57 +++++
libraries/src/Directory.Packages.props | 1 +
...ambda.Powertools.EventHandler.Tests.csproj | 5 +
.../BedrockAgentFunctionResolverTests.cs | 232 ++++++++++++++++++
.../bedrockFunctionEvent.json | 27 ++
9 files changed, 479 insertions(+)
create mode 100644 libraries/src/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver.csproj
create mode 100644 libraries/src/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver/BedrockAgentFunctionResolver.cs
create mode 100644 libraries/src/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver/InternalsVisibleTo.cs
create mode 100644 libraries/src/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver/Readme.md
create mode 100644 libraries/tests/AWS.Lambda.Powertools.EventHandler.Tests/BedrockAgentFunctionResolverTests.cs
create mode 100644 libraries/tests/AWS.Lambda.Powertools.EventHandler.Tests/bedrockFunctionEvent.json
diff --git a/libraries/AWS.Lambda.Powertools.sln b/libraries/AWS.Lambda.Powertools.sln
index 5d7cd4f9..0ca62f24 100644
--- a/libraries/AWS.Lambda.Powertools.sln
+++ b/libraries/AWS.Lambda.Powertools.sln
@@ -109,6 +109,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AWS.Lambda.Powertools.Event
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AWS.Lambda.Powertools.EventHandler", "src\AWS.Lambda.Powertools.EventHandler\AWS.Lambda.Powertools.EventHandler.csproj", "{F4B8D5AF-D3CA-4910-A14D-E5BAEF0FD1DE}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver", "src\AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver\AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver.csproj", "{281F7EB5-ACE5-458F-BC88-46A8899DF3BA}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -590,6 +592,18 @@ Global
{F4B8D5AF-D3CA-4910-A14D-E5BAEF0FD1DE}.Release|x64.Build.0 = Release|Any CPU
{F4B8D5AF-D3CA-4910-A14D-E5BAEF0FD1DE}.Release|x86.ActiveCfg = Release|Any CPU
{F4B8D5AF-D3CA-4910-A14D-E5BAEF0FD1DE}.Release|x86.Build.0 = Release|Any CPU
+ {281F7EB5-ACE5-458F-BC88-46A8899DF3BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {281F7EB5-ACE5-458F-BC88-46A8899DF3BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {281F7EB5-ACE5-458F-BC88-46A8899DF3BA}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {281F7EB5-ACE5-458F-BC88-46A8899DF3BA}.Debug|x64.Build.0 = Debug|Any CPU
+ {281F7EB5-ACE5-458F-BC88-46A8899DF3BA}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {281F7EB5-ACE5-458F-BC88-46A8899DF3BA}.Debug|x86.Build.0 = Debug|Any CPU
+ {281F7EB5-ACE5-458F-BC88-46A8899DF3BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {281F7EB5-ACE5-458F-BC88-46A8899DF3BA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {281F7EB5-ACE5-458F-BC88-46A8899DF3BA}.Release|x64.ActiveCfg = Release|Any CPU
+ {281F7EB5-ACE5-458F-BC88-46A8899DF3BA}.Release|x64.Build.0 = Release|Any CPU
+ {281F7EB5-ACE5-458F-BC88-46A8899DF3BA}.Release|x86.ActiveCfg = Release|Any CPU
+ {281F7EB5-ACE5-458F-BC88-46A8899DF3BA}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
@@ -641,5 +655,6 @@ Global
{7FC6DD65-0352-4139-8D08-B25C0A0403E3} = {4EAB66F9-C9CB-4E8A-BEE6-A14CD7FDE02F}
{61374D8E-F77C-4A31-AE07-35DAF1847369} = {1CFF5568-8486-475F-81F6-06105C437528}
{F4B8D5AF-D3CA-4910-A14D-E5BAEF0FD1DE} = {73C9B1E5-3893-47E8-B373-17E5F5D7E6F5}
+ {281F7EB5-ACE5-458F-BC88-46A8899DF3BA} = {73C9B1E5-3893-47E8-B373-17E5F5D7E6F5}
EndGlobalSection
EndGlobal
diff --git a/libraries/src/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver.csproj b/libraries/src/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver.csproj
new file mode 100644
index 00000000..a392b395
--- /dev/null
+++ b/libraries/src/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver.csproj
@@ -0,0 +1,20 @@
+
+
+
+
+ AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver
+ Powertools for AWS Lambda (.NET) - Event Handler Bedrock Agent Function Resolver package.
+ AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver
+ AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver
+ net8.0
+ false
+ enable
+ enable
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libraries/src/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver/BedrockAgentFunctionResolver.cs b/libraries/src/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver/BedrockAgentFunctionResolver.cs
new file mode 100644
index 00000000..946b363c
--- /dev/null
+++ b/libraries/src/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver/BedrockAgentFunctionResolver.cs
@@ -0,0 +1,104 @@
+using Amazon.BedrockAgentRuntime.Model;
+using Amazon.Lambda.Core;
+
+// ReSharper disable once CheckNamespace
+namespace AWS.Lambda.Powertools.EventHandler
+{
+ ///
+ /// Resolver for Amazon Bedrock Agent functions.
+ /// Routes function calls to appropriate handlers based on function name.
+ ///
+ public class BedrockAgentFunctionResolver
+ {
+ private readonly Dictionary> _handlers = new();
+
+ ///
+ /// Registers a handler for a tool function without parameters.
+ ///
+ /// The function name to handle
+ /// Function handler without parameters
+ /// Optional description of the function
+ public BedrockAgentFunctionResolver Tool(string name, Func handler, string description = "")
+ {
+ _handlers[name] = (_, _) => handler();
+ return this;
+ }
+
+ ///
+ /// Registers a handler for a tool function with input.
+ ///
+ /// The function name to handle
+ /// Function handler with input
+ /// Optional description of the function
+ public BedrockAgentFunctionResolver Tool(string name, Func handler, string description = "")
+ {
+ _handlers[name] = (input, _) => handler(input);
+ return this;
+ }
+
+ ///
+ /// Registers a handler for a tool function with input and context.
+ ///
+ /// The function name to handle
+ /// Function handler with input and context
+ /// Optional description of the function
+ public BedrockAgentFunctionResolver Tool(string name, Func handler, string description = "")
+ {
+ _handlers[name] = (input, context) => handler(input, context ?? throw new ArgumentNullException(nameof(context)));
+ return this;
+ }
+
+ ///
+ /// Resolves and processes a Bedrock Agent function invocation.
+ ///
+ /// The function invocation input
+ /// Lambda execution context
+ public ActionGroupInvocationOutput Resolve(ActionGroupInvocationInput input, ILambdaContext? context = null)
+ {
+ return ResolveAsync(input, context).GetAwaiter().GetResult();
+ }
+
+ ///
+ /// Asynchronously resolves and processes a Bedrock Agent function invocation.
+ ///
+ /// The function invocation input
+ /// Lambda execution context
+ public async Task ResolveAsync(ActionGroupInvocationInput input, ILambdaContext? context = null)
+ {
+ return await Task.FromResult(HandleEvent(input, context));
+ }
+
+ private ActionGroupInvocationOutput HandleEvent(ActionGroupInvocationInput input, ILambdaContext? context)
+ {
+ if (string.IsNullOrEmpty(input.Function))
+ {
+ return new ActionGroupInvocationOutput
+ {
+ Text = "No function specified in the request"
+ };
+ }
+
+ if (_handlers.TryGetValue(input.Function, out var handler))
+ {
+ try
+ {
+ return handler(input, context);
+ }
+ catch (Exception ex)
+ {
+ context?.Logger.LogError($"Error executing function {input.Function}: {ex.Message}");
+ return new ActionGroupInvocationOutput
+ {
+ Text = $"Error executing function: {ex.Message}"
+ };
+ }
+ }
+
+ context?.Logger.LogWarning($"No handler registered for function: {input.Function}");
+ return new ActionGroupInvocationOutput
+ {
+ Text = $"No handler registered for function: {input.Function}"
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/libraries/src/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver/InternalsVisibleTo.cs b/libraries/src/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver/InternalsVisibleTo.cs
new file mode 100644
index 00000000..9e952373
--- /dev/null
+++ b/libraries/src/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver/InternalsVisibleTo.cs
@@ -0,0 +1,18 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+using System.Runtime.CompilerServices;
+
+[assembly: InternalsVisibleTo("AWS.Lambda.Powertools.EventHandler.Tests")]
\ No newline at end of file
diff --git a/libraries/src/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver/Readme.md b/libraries/src/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver/Readme.md
new file mode 100644
index 00000000..08947c02
--- /dev/null
+++ b/libraries/src/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver/Readme.md
@@ -0,0 +1,57 @@
+# AWS Lambda Powertools for .NET - Bedrock Agent Function Resolver
+
+## Overview
+The Bedrock Agent Function Resolver is a custom function resolver for AWS Lambda Powertools for .NET. It is designed to work with the Bedrock Agent, a tool that simplifies the process of building and deploying serverless applications on AWS Lambda.
+The Bedrock Agent Function Resolver allows you to easily resolve and invoke Lambda functions using the Bedrock Agent's conventions and best practices.
+This custom function resolver is part of the AWS Lambda Powertools for .NET library, which provides a suite of utilities for building serverless applications on AWS Lambda.
+## Features
+- Custom function resolver for AWS Lambda Powertools for .NET
+- Supports Bedrock Agent conventions and best practices
+- Simplifies the process of resolving and invoking Lambda functions
+- Integrates with AWS Lambda Powertools for .NET library
+- Supports dependency injection and configuration
+- Provides a consistent and easy-to-use API for resolving functions
+- Supports asynchronous and synchronous function invocation
+- Supports error handling and logging
+- Supports custom serialization and deserialization
+- Supports custom middleware and filters
+
+## Getting Started
+To get started with the Bedrock Agent Function Resolver, you need to install the AWS Lambda Powertools for .NET library and the Bedrock Agent Function Resolver package. You can do this using NuGet:
+
+```bash
+dotnet add package AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver
+```
+## Usage
+To use the Bedrock Agent Function Resolver, you need to create an instance of the `BedrockAgentFunctionResolver` class and register it with the AWS Lambda Powertools for .NET library. You can do this in your Lambda function's entry point:
+
+```csharp
+using Amazon.Lambda.Core;
+using Amazon.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver;
+
+
+[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
+
+namespace MyLambdaFunction
+{
+ public class Function
+ {
+ private readonly BedrockAgentFunctionResolver _functionResolver;
+
+ public Function()
+ {
+ // Create an instance of the Bedrock Agent Function Resolver
+ _functionResolver = new BedrockAgentFunctionResolver();
+ }
+
+ public async Task FunctionHandler(ILambdaContext context)
+ {
+ // Use the function resolver to resolve and invoke a Lambda function
+ var result = await _functionResolver.ResolveAndInvokeAsync("MyLambdaFunctionName", new { /* input parameters */ });
+
+ // Process the result
+ context.Logger.LogLine($"Result: {result}");
+ }
+ }
+}
+```
\ No newline at end of file
diff --git a/libraries/src/Directory.Packages.props b/libraries/src/Directory.Packages.props
index db4a6a7f..f9a4730c 100644
--- a/libraries/src/Directory.Packages.props
+++ b/libraries/src/Directory.Packages.props
@@ -9,6 +9,7 @@
+
diff --git a/libraries/tests/AWS.Lambda.Powertools.EventHandler.Tests/AWS.Lambda.Powertools.EventHandler.Tests.csproj b/libraries/tests/AWS.Lambda.Powertools.EventHandler.Tests/AWS.Lambda.Powertools.EventHandler.Tests.csproj
index eef47181..aab78861 100644
--- a/libraries/tests/AWS.Lambda.Powertools.EventHandler.Tests/AWS.Lambda.Powertools.EventHandler.Tests.csproj
+++ b/libraries/tests/AWS.Lambda.Powertools.EventHandler.Tests/AWS.Lambda.Powertools.EventHandler.Tests.csproj
@@ -32,6 +32,7 @@
+
@@ -40,6 +41,10 @@
PreserveNewest
+
+
+ PreserveNewest
+
diff --git a/libraries/tests/AWS.Lambda.Powertools.EventHandler.Tests/BedrockAgentFunctionResolverTests.cs b/libraries/tests/AWS.Lambda.Powertools.EventHandler.Tests/BedrockAgentFunctionResolverTests.cs
new file mode 100644
index 00000000..a406a15f
--- /dev/null
+++ b/libraries/tests/AWS.Lambda.Powertools.EventHandler.Tests/BedrockAgentFunctionResolverTests.cs
@@ -0,0 +1,232 @@
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using Amazon.BedrockAgentRuntime.Model;
+using Amazon.Lambda.TestUtilities;
+
+namespace AWS.Lambda.Powertools.EventHandler.Tests;
+
+public class BedrockAgentFunctionResolverTests
+{
+ private readonly ActionGroupInvocationInput _bedrockEvent;
+
+ public BedrockAgentFunctionResolverTests()
+ {
+ _bedrockEvent = JsonSerializer.Deserialize(
+ File.ReadAllText("bedrockFunctionEvent.json"),
+ new JsonSerializerOptions
+ {
+ PropertyNameCaseInsensitive = true,
+ Converters = { new JsonStringEnumConverter() }
+ })!;
+ }
+
+ [Fact]
+ public void TestFunctionHandlerWithNoParameters()
+ {
+ // Arrange
+ var resolver = new BedrockAgentFunctionResolver();
+ resolver.Tool("TestFunction", () => new ActionGroupInvocationOutput { Text = "Hello, World!" });
+
+ var input = new ActionGroupInvocationInput { Function = "TestFunction" };
+ var context = new TestLambdaContext();
+
+ // Act
+ var result = resolver.Resolve(input, context);
+
+ // Assert
+ Assert.Equal("Hello, World!", result.Text);
+ }
+
+ [Fact]
+ public async Task TestFunctionHandlerWithNoParametersAsync()
+ {
+ // Arrange
+ var resolver = new BedrockAgentFunctionResolver();
+ resolver.Tool("TestFunction", () => new ActionGroupInvocationOutput { Text = "Hello, World!" });
+
+ var input = new ActionGroupInvocationInput { Function = "TestFunction" };
+ var context = new TestLambdaContext();
+
+ // Act
+ var result = await resolver.ResolveAsync(input, context);
+
+ // Assert
+ Assert.Equal("Hello, World!", result.Text);
+ }
+
+ [Fact]
+ public void TestFunctionHandlerWithDescription()
+ {
+ // Arrange
+ var resolver = new BedrockAgentFunctionResolver();
+ resolver.Tool("TestFunction", () => new ActionGroupInvocationOutput { Text = "Hello, World!" },
+ "This is a test function");
+
+ var input = new ActionGroupInvocationInput { Function = "TestFunction" };
+ var context = new TestLambdaContext();
+
+ // Act
+ var result = resolver.Resolve(input, context);
+
+ // Assert
+ Assert.Equal("Hello, World!", result.Text);
+ }
+
+ [Fact]
+ public void TestFunctionHandlerWithMultiplTools()
+ {
+ // Arrange
+ var resolver = new BedrockAgentFunctionResolver();
+ resolver.Tool("TestFunction1", () => new ActionGroupInvocationOutput { Text = "Hello from Function 1!" });
+ resolver.Tool("TestFunction2", () => new ActionGroupInvocationOutput { Text = "Hello from Function 2!" });
+
+ var input1 = new ActionGroupInvocationInput { Function = "TestFunction1" };
+ var input2 = new ActionGroupInvocationInput { Function = "TestFunction2" };
+ var context = new TestLambdaContext();
+
+ // Act
+ var result1 = resolver.Resolve(input1, context);
+ var result2 = resolver.Resolve(input2, context);
+
+ // Assert
+ Assert.Equal("Hello from Function 1!", result1.Text);
+ Assert.Equal("Hello from Function 2!", result2.Text);
+ }
+
+
+ [Fact]
+ public void TestFunctionHandlerWithInput()
+ {
+ // Arrange
+ var resolver = new BedrockAgentFunctionResolver();
+ resolver.Tool("TestFunction",
+ (input) => new ActionGroupInvocationOutput { Text = $"Hello, {input.Function}!" });
+
+ var input = new ActionGroupInvocationInput { Function = "TestFunction" };
+ var context = new TestLambdaContext();
+
+ // Act
+ var result = resolver.Resolve(input, context);
+
+ // Assert
+ Assert.Equal("Hello, TestFunction!", result.Text);
+ }
+
+ [Fact]
+ public async Task TestFunctionHandlerWithInputAsync()
+ {
+ // Arrange
+ var resolver = new BedrockAgentFunctionResolver();
+ resolver.Tool("TestFunction",
+ (input) => new ActionGroupInvocationOutput { Text = $"Hello, {input.Function}!" });
+
+ var input = new ActionGroupInvocationInput { Function = "TestFunction" };
+ var context = new TestLambdaContext();
+
+ // Act
+ var result = await resolver.ResolveAsync(input, context);
+
+ // Assert
+ Assert.Equal("Hello, TestFunction!", result.Text);
+ }
+
+ [Fact]
+ public void TestFunctionHandlerNoToolMatch()
+ {
+ // Arrange
+ var resolver = new BedrockAgentFunctionResolver();
+ resolver.Tool("TestFunction", () => new ActionGroupInvocationOutput { Text = "Hello, World!" });
+
+ var input = new ActionGroupInvocationInput { Function = "NonExistentFunction" };
+ var context = new TestLambdaContext();
+
+ // Act
+ var result = resolver.Resolve(input, context);
+
+ // Assert
+ Assert.Equal("No handler registered for function: NonExistentFunction", result.Text);
+ }
+
+ [Fact]
+ public async Task TestFunctionHandlerNoToolMatchAsync()
+ {
+ // Arrange
+ var resolver = new BedrockAgentFunctionResolver();
+ resolver.Tool("TestFunction", () => new ActionGroupInvocationOutput { Text = "Hello, World!" });
+
+ var input = new ActionGroupInvocationInput { Function = "NonExistentFunction" };
+ var context = new TestLambdaContext();
+
+ // Act
+ var result = await resolver.ResolveAsync(input, context);
+
+ // Assert
+ Assert.Equal("No handler registered for function: NonExistentFunction", result.Text);
+ }
+
+ [Fact]
+ public void TestFunctionHandlerWithParameters()
+ {
+ // Arrange
+ var resolver = new BedrockAgentFunctionResolver();
+ resolver.Tool("TestFunction", () => new ActionGroupInvocationOutput { Text = "Hello, World!" });
+
+ var input = new ActionGroupInvocationInput
+ {
+ Function = "TestFunction",
+ RequestBody = new RequestBody
+ {
+
+ },
+ Parameters = new List
+ {
+ new Parameter
+ {
+ Name = "a",
+ Value = "1",
+ Type = "Number"
+ },
+ new Parameter
+ {
+ Name = "b",
+ Value = "1",
+ Type = "Number"
+ }
+ }
+ };
+ var context = new TestLambdaContext();
+
+ // Act
+ var result = resolver.Resolve(input, context);
+
+ // Assert
+ Assert.Equal("Hello, World!", result.Text);
+ }
+
+ [Fact]
+ public void TestFunctionHandlerWithEvent()
+ {
+ // Arrange
+ var resolver = new BedrockAgentFunctionResolver();
+ resolver.Tool("sum_numbers", (payload, context ) =>
+ {
+
+ return new ActionGroupInvocationOutput { Text = "2" };
+ });
+
+ var context = new TestLambdaContext();
+
+ // Act
+ var result = resolver.Resolve(_bedrockEvent, context);
+
+ // Assert
+ Assert.Equal("2", result.Text);
+ }
+}
+
+// Types
+// String
+// Number
+// Integer
+// Boolean
+// Array
\ No newline at end of file
diff --git a/libraries/tests/AWS.Lambda.Powertools.EventHandler.Tests/bedrockFunctionEvent.json b/libraries/tests/AWS.Lambda.Powertools.EventHandler.Tests/bedrockFunctionEvent.json
new file mode 100644
index 00000000..f2cedeb1
--- /dev/null
+++ b/libraries/tests/AWS.Lambda.Powertools.EventHandler.Tests/bedrockFunctionEvent.json
@@ -0,0 +1,27 @@
+{
+ "messageVersion": "1.0",
+ "function": "sum_numbers",
+ "sessionId": "455081292773641",
+ "agent": {
+ "name": "powertools-test",
+ "version": "DRAFT",
+ "id": "WPMRGAPAPJ",
+ "alias": "TSTALIASID"
+ },
+ "parameters": [
+ {
+ "name": "a",
+ "type": "number",
+ "value": "1"
+ },
+ {
+ "name": "b",
+ "type": "number",
+ "value": "1"
+ }
+ ],
+ "actionGroup": "utility-tasks",
+ "sessionAttributes": {},
+ "promptSessionAttributes": {},
+ "inputText": "Sum 1 and 1"
+}
\ No newline at end of file
From 64d3a618ebc0434f60b8a89038623014658d541a Mon Sep 17 00:00:00 2001
From: Henrique <999396+hjgraca@users.noreply.github.com>
Date: Sun, 25 May 2025 16:18:00 +0100
Subject: [PATCH 02/52] add methods that take DI services, match parameters
with handler arguments
---
...andler.BedrockAgentFunctionResolver.csproj | 2 +
.../BedrockAgentFunctionResolver.cs | 301 ++++++++++++++++--
.../BedrockAgentFunctionResolverExtensions.cs | 27 ++
.../ParameterAccessor.cs | 126 ++++++++
libraries/src/Directory.Packages.props | 1 +
.../BedrockAgentFunctionResolverTests.cs | 170 +++++++++-
6 files changed, 589 insertions(+), 38 deletions(-)
create mode 100644 libraries/src/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver/BedrockAgentFunctionResolverExtensions.cs
create mode 100644 libraries/src/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver/ParameterAccessor.cs
diff --git a/libraries/src/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver.csproj b/libraries/src/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver.csproj
index a392b395..87033029 100644
--- a/libraries/src/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver.csproj
+++ b/libraries/src/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver.csproj
@@ -10,11 +10,13 @@
false
enable
enable
+ true
+
\ No newline at end of file
diff --git a/libraries/src/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver/BedrockAgentFunctionResolver.cs b/libraries/src/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver/BedrockAgentFunctionResolver.cs
index 946b363c..5f33caa9 100644
--- a/libraries/src/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver/BedrockAgentFunctionResolver.cs
+++ b/libraries/src/AWS.Lambda.Powertools.EventHandler.BedrockAgentFunctionResolver/BedrockAgentFunctionResolver.cs
@@ -1,58 +1,254 @@
-using Amazon.BedrockAgentRuntime.Model;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text.Json.Serialization;
+using System.Threading.Tasks;
+using Amazon.BedrockAgentRuntime.Model;
using Amazon.Lambda.Core;
-// ReSharper disable once CheckNamespace
namespace AWS.Lambda.Powertools.EventHandler
{
- ///
- /// Resolver for Amazon Bedrock Agent functions.
- /// Routes function calls to appropriate handlers based on function name.
- ///
public class BedrockAgentFunctionResolver
{
- private readonly Dictionary> _handlers = new();
+ private readonly
+ Dictionary>
+ _handlers = new();
+
+ private static readonly HashSet _bedrockParameterTypes = new()
+ {
+ typeof(string),
+ typeof(int),
+ typeof(long),
+ typeof(double),
+ typeof(bool),
+ typeof(decimal),
+ typeof(DateTime),
+ typeof(Guid)
+ };
+
+ private static bool IsBedrockParameter(Type type) =>
+ _bedrockParameterTypes.Contains(type) || type.IsEnum;
///
- /// Registers a handler for a tool function without parameters.
+ /// Registers a handler that directly accepts ActionGroupInvocationInput and returns ActionGroupInvocationOutput
///
- /// The function name to handle
- /// Function handler without parameters
- /// Optional description of the function
- public BedrockAgentFunctionResolver Tool(string name, Func handler, string description = "")
+ public BedrockAgentFunctionResolver Tool(
+ string name,
+ Func handler,
+ string description = "")
{
- _handlers[name] = (_, _) => handler();
+ if (handler == null)
+ throw new ArgumentNullException(nameof(handler));
+
+ _handlers[name] = handler;
return this;
}
///
- /// Registers a handler for a tool function with input.
+ /// Registers a handler that directly accepts ActionGroupInvocationInput and returns ActionGroupInvocationOutput
///
- /// The function name to handle
- /// Function handler with input
- /// Optional description of the function
- public BedrockAgentFunctionResolver Tool(string name, Func handler, string description = "")
+ public BedrockAgentFunctionResolver Tool(
+ string name,
+ Func handler,
+ string description = "")
{
+ if (handler == null)
+ throw new ArgumentNullException(nameof(handler));
+
_handlers[name] = (input, _) => handler(input);
return this;
}
///
- /// Registers a handler for a tool function with input and context.
+ /// Registers a handler for a tool function with automatically converted return type.
+ ///
+ public BedrockAgentFunctionResolver Tool(
+ string name,
+ string description = "",
+ Delegate? handler = null)
+ {
+ // Delegate to the generic version with object as return type
+ return Tool