bedrockagent

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 11, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Package bedrockagent serves the action groups of Amazon Bedrock agents: the Go side of Powertools for AWS Lambda (Python)'s BedrockAgentResolver and BedrockAgentFunctionResolver.

Action groups defined with an OpenAPI schema

The agent calls the API operations the schema describes. Write them as typed operations of an eventhandler.Router, each with a description (the agent reads it to choose the operation), and adapt the router with Handler:

type WeatherInput struct {
	City string `query:"city" required:"true" description:"The city"`
}

app := eventhandler.New()
eventhandler.Get(app, "/weather", getWeather,
	eventhandler.Description("Current weather of a city"))
lambda.Start(bedrockagent.Handler(app))

The same router writes the schema to upload: OpenAPIJSON returns it in OpenAPI 3.0.3, the version agents accept, with the title "Powertools API" unless the router sets one. Request validation works as on any router: an invalid call answers 422 with the details, which the agent reads. Set the session attributes, the prompt session attributes and the knowledge base configuration of the response with SetSessionAttributes, SetPromptSessionAttributes and SetKnowledgeBasesConfiguration, and read the event with EventFromContext. RequireConfirmation makes the agent ask the user before calling an operation.

Action groups defined with function details

The agent calls functions by name with typed parameters. Register a tool per function and hand Functions.Handle to lambda.Start:

fns := bedrockagent.NewFunctions()
bedrockagent.Tool(fns, "get_weather", func(ctx context.Context, in struct {
	City string `json:"city"`
}) (string, error) {
	return "Sunny in " + in.City, nil
})
lambda.Start(fns.Handle)

Differences from Powertools Python

  • A router is the resolver: there is no separate resolver type, and the OpenAPI document comes from the router (OpenAPIJSON(app)).
  • Session attributes of an OpenAPI action group are set through the request context, since the typed operation's response is the HTTP one; a function tool returns a Result.
  • Body properties are converted to the JSON type the agent declares before validation; Python passes strings for Pydantic to coerce.
  • A tool returning a string sends it as it is; Python JSON-quotes it ("\"hello\""), unlike its HTTP resolvers.
  • Registering a tool name twice panics; Python warns and replaces it.
  • The error body names the Go type of the error ("Error: errorString: ..."), since Go errors have no class.
  • Operations with security requirements are rejected by OpenAPI, where Python silently drops them.

Environment variables

POWERTOOLS_DEV turns on the router's debug mode; POWERTOOLS_DEBUG shows what the package does in the debug log.

Index

Examples

Constants

View Source
const DefaultTitle = "Powertools API"

DefaultTitle is the title of an agent's OpenAPI document when the router sets none, as in Powertools Python.

View Source
const MessageVersion = "1.0"

MessageVersion is the version of the response format.

Variables

View Source
var (
	// ErrMissingDescription reports an operation without a description,
	// which Bedrock agents need to choose it.
	ErrMissingDescription = errors.New("bedrockagent: Bedrock agents require a description on every operation")
	// ErrSecurityUnsupported reports an operation with security
	// requirements, which agent action groups do not support.
	ErrSecurityUnsupported = errors.New("bedrockagent: Bedrock agents do not support security requirements on operations")
)

Errors of the OpenAPI export.

View Source
var (
	// ErrUnknownFunction reports an event for a function no tool handles.
	ErrUnknownFunction = errors.New("unknown function")
	// ErrDuplicateTool reports a tool registered twice.
	ErrDuplicateTool = errors.New("bedrockagent: tool already registered")
	// ErrInvalidResponseState reports a ResponseState other than FAILURE
	// and REPROMPT.
	ErrInvalidResponseState = errors.New("responseState must be 'FAILURE' or 'REPROMPT'")
)

Errors of function action groups.

Functions

func EventFromContext

func EventFromContext(ctx context.Context) (eventsource.BedrockAgentEvent, bool)

EventFromContext returns the agent event the request was built from: Python's current_event (session id, input text, agent...).

func FunctionEventFromContext

func FunctionEventFromContext(ctx context.Context) (eventsource.BedrockAgentFunctionEvent, bool)

FunctionEventFromContext returns the event of the function call a tool is serving.

func Handler

Handler adapts h, usually an eventhandler.Router, to an agent action group defined with an OpenAPI schema: Python's BedrockAgentResolver.

The request is the API call the agent decided on: its method and its API path, with the path parameters filled in from the parameters of the same name; every parameter is a query parameter too, never split on commas; the application/json body properties form a JSON object, their values converted to the JSON type the agent declares (integer, number, boolean, array). The response carries the status and the body under its content type, plus the attributes set with SetSessionAttributes, SetPromptSessionAttributes and SetKnowledgeBasesConfiguration.

Example
package main

import (
	"context"
	"fmt"

	"github.com/alessandrolattao/powertools-lambda-go/eventhandler"
	"github.com/alessandrolattao/powertools-lambda-go/eventhandler/bedrockagent"
	"github.com/alessandrolattao/powertools-lambda-go/eventsource"
)

type WeatherInput struct {
	City string `query:"city" required:"true" description:"The city to look up"`
}

type Weather struct {
	City        string  `json:"city"`
	Temperature float64 `json:"temperature"`
}

func main() {
	app := eventhandler.New()
	eventhandler.Get(app, "/weather", func(ctx context.Context, in WeatherInput) (Weather, error) {
		bedrockagent.SetSessionAttributes(ctx, map[string]string{"lastCity": in.City})
		return Weather{City: in.City, Temperature: 21.5}, nil
	}, eventhandler.Description("Current weather of a city"))

	// In main: lambda.Start(bedrockagent.Handler(app))
	resp, err := bedrockagent.Handler(app)(context.Background(), eventsource.BedrockAgentEvent{
		ActionGroup: "weather", HTTPMethod: "GET", APIPath: "/weather",
		Parameters: []eventsource.BedrockAgentProperty{{Name: "city", Type: "string", Value: "Rome"}},
	})
	if err != nil {
		panic(err)
	}
	fmt.Println(resp.Response.HTTPStatusCode, resp.Response.ResponseBody["application/json"].Body, resp.SessionAttributes)
}
Output:
200 {"city":"Rome","temperature":21.5} map[lastCity:Rome]

func OpenAPIJSON

func OpenAPIJSON(r *eventhandler.Router, opts ...eventhandler.OpenAPIOption) ([]byte, error)

OpenAPIJSON returns the router's OpenAPI document in version 3.0.3, the one Bedrock agents read, as the indented JSON to upload as the action group's API schema: Python's BedrockAgentResolver.get_openapi_json_schema. The title defaults to DefaultTitle. Every operation needs a description (ErrMissingDescription) and none may set security requirements (ErrSecurityUnsupported).

Example
package main

import (
	"context"
	"fmt"
	"strings"

	"github.com/alessandrolattao/powertools-lambda-go/eventhandler"
	"github.com/alessandrolattao/powertools-lambda-go/eventhandler/bedrockagent"
)

type WeatherInput struct {
	City string `query:"city" required:"true" description:"The city to look up"`
}

type Weather struct {
	City        string  `json:"city"`
	Temperature float64 `json:"temperature"`
}

func main() {
	app := eventhandler.New()
	eventhandler.Get(app, "/weather", func(context.Context, WeatherInput) (Weather, error) { return Weather{}, nil },
		eventhandler.Description("Current weather of a city"), bedrockagent.RequireConfirmation())

	doc, err := bedrockagent.OpenAPIJSON(app)
	if err != nil {
		panic(err)
	}
	fmt.Println(strings.Contains(string(doc), `"openapi": "3.0.3"`), strings.Contains(string(doc), `"x-requireConfirmation": "ENABLED"`))
}
Output:
true true

func RequireConfirmation

func RequireConfirmation() eventhandler.RouteOption

RequireConfirmation asks the agent to confirm with the user before calling the operation: the x-requireConfirmation extension.

func SetKnowledgeBasesConfiguration

func SetKnowledgeBasesConfiguration(ctx context.Context, cfg []KnowledgeBaseConfiguration)

SetKnowledgeBasesConfiguration sets the knowledge base configurations the response carries.

func SetPromptSessionAttributes

func SetPromptSessionAttributes(ctx context.Context, attrs map[string]string)

SetPromptSessionAttributes sets the prompt session attributes the response carries.

func SetSessionAttributes

func SetSessionAttributes(ctx context.Context, attrs map[string]string)

SetSessionAttributes sets the session attributes the response carries, Python's BedrockResponse session_attributes. ctx is the request's context (a typed operation's ctx, or r.Context()); outside an agent invocation the call does nothing.

func Tool

func Tool[In, Out any](f *Functions, name string, fn func(ctx context.Context, in In) (Out, error), opts ...ToolOption)

Tool registers fn as the function name of the action group: Python's tool decorator. The parameters the agent passes are converted to the JSON type they declare (string, integer, number, boolean, array) and decoded into In by name, with its json tags: unknown parameters are ignored and missing ones stay zero. What fn returns is the body sent to the agent: a string as it is, anything else as JSON; return a Result to set the session attributes or the response state too. Registering a name twice panics with ErrDuplicateTool.

Example
package main

import (
	"context"
	"fmt"

	"github.com/alessandrolattao/powertools-lambda-go/eventhandler/bedrockagent"
	"github.com/alessandrolattao/powertools-lambda-go/eventsource"
)

func main() {
	fns := bedrockagent.NewFunctions()
	bedrockagent.Tool(fns, "get_weather", func(_ context.Context, in struct {
		City string `json:"city"`
		Days int    `json:"days"`
	},
	) (string, error) {
		return fmt.Sprintf("Sunny in %s for %d days", in.City, in.Days), nil
	})

	// In main: lambda.Start(fns.Handle)
	resp, err := fns.Handle(context.Background(), eventsource.BedrockAgentFunctionEvent{
		ActionGroup: "weather", Function: "get_weather",
		Parameters: []eventsource.BedrockAgentProperty{
			{Name: "city", Type: "string", Value: "Rome"},
			{Name: "days", Type: "integer", Value: "3"},
		},
	})
	if err != nil {
		panic(err)
	}
	fmt.Println(resp.Response.FunctionResponse.ResponseBody["TEXT"].Body)
}
Output:
Sunny in Rome for 3 days

Types

type APIResponse

type APIResponse struct {
	ActionGroup    string `json:"actionGroup"`
	APIPath        string `json:"apiPath"`
	HTTPMethod     string `json:"httpMethod"`
	HTTPStatusCode int    `json:"httpStatusCode"`
	// ResponseBody holds the body by content type.
	ResponseBody map[string]ResponseContent `json:"responseBody"`
}

APIResponse is the result of the API operation the agent called.

type FunctionResponse

type FunctionResponse struct {
	MessageVersion              string                       `json:"messageVersion"`
	Response                    FunctionResult               `json:"response"`
	SessionAttributes           map[string]string            `json:"sessionAttributes"`
	PromptSessionAttributes     map[string]string            `json:"promptSessionAttributes"`
	KnowledgeBasesConfiguration []KnowledgeBaseConfiguration `json:"knowledgeBasesConfiguration,omitempty"`
}

FunctionResponse is what the Lambda function of a function action group returns to the agent.

type FunctionResponseBody

type FunctionResponseBody struct {
	ResponseBody  map[string]ResponseContent `json:"responseBody"`
	ResponseState ResponseState              `json:"responseState,omitempty"`
}

FunctionResponseBody holds the body, as TEXT, and the response state.

type FunctionResult

type FunctionResult struct {
	ActionGroup      string               `json:"actionGroup"`
	Function         string               `json:"function"`
	FunctionResponse FunctionResponseBody `json:"functionResponse"`
}

FunctionResult is the result of the function the agent called.

type Functions

type Functions struct {
	// contains filtered or unexported fields
}

Functions dispatches the calls of a function action group to tools: Python's BedrockAgentFunctionResolver.

func NewFunctions

func NewFunctions(opts ...FunctionsOption) *Functions

NewFunctions returns Functions without tools.

func (*Functions) Handle

Handle calls the tool of the event's function and returns its response: pass it to lambda.Start. Failures never fail the invocation, as in Python: an unknown function or an error of the tool answers the body "Error: <type>: <message>", the type being the Go type of the error. Session attributes default to the event's.

type FunctionsOption

type FunctionsOption func(*Functions)

FunctionsOption configures Functions.

func WithSerializer

func WithSerializer(marshal func(v any) ([]byte, error)) FunctionsOption

WithSerializer replaces the JSON encoder of the bodies that are not strings: Python's serializer. The default is encoding/json/v2's Marshal with map keys sorted.

type KnowledgeBaseConfiguration

type KnowledgeBaseConfiguration struct {
	KnowledgeBaseID        string         `json:"knowledgeBaseId"`
	RetrievalConfiguration map[string]any `json:"retrievalConfiguration,omitempty"`
}

KnowledgeBaseConfiguration changes how the agent queries a knowledge base for the rest of the session.

type Response

type Response struct {
	MessageVersion              string                       `json:"messageVersion"`
	Response                    APIResponse                  `json:"response"`
	SessionAttributes           map[string]string            `json:"sessionAttributes,omitempty"`
	PromptSessionAttributes     map[string]string            `json:"promptSessionAttributes,omitempty"`
	KnowledgeBasesConfiguration []KnowledgeBaseConfiguration `json:"knowledgeBasesConfiguration,omitempty"`
}

Response is what the Lambda function of an OpenAPI action group returns to the agent.

type ResponseContent

type ResponseContent struct {
	Body string `json:"body"`
}

ResponseContent is a response body.

type ResponseState

type ResponseState string

ResponseState tells the agent how a function call went.

const (
	Failure  ResponseState = "FAILURE"
	Reprompt ResponseState = "REPROMPT"
)

The response states a function can report; the empty state is success.

type Result

type Result[T any] struct {
	Body                    T
	SessionAttributes       map[string]string
	PromptSessionAttributes map[string]string
	KnowledgeBases          []KnowledgeBaseConfiguration
	// ResponseState is empty, Failure or Reprompt.
	ResponseState ResponseState
}

Result is what a tool returns when it sets more than the body: Python's BedrockFunctionResponse.

type ToolOption

type ToolOption func(*tool)

ToolOption configures a tool.

func Description

func Description(description string) ToolOption

Description describes the tool. Agents read function descriptions from the action group's definition, not from the function: it documents the code, as in Python.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL