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 ¶
- Constants
- Variables
- func EventFromContext(ctx context.Context) (eventsource.BedrockAgentEvent, bool)
- func FunctionEventFromContext(ctx context.Context) (eventsource.BedrockAgentFunctionEvent, bool)
- func Handler(h http.Handler) func(context.Context, eventsource.BedrockAgentEvent) (Response, error)
- func OpenAPIJSON(r *eventhandler.Router, opts ...eventhandler.OpenAPIOption) ([]byte, error)
- func RequireConfirmation() eventhandler.RouteOption
- func SetKnowledgeBasesConfiguration(ctx context.Context, cfg []KnowledgeBaseConfiguration)
- func SetPromptSessionAttributes(ctx context.Context, attrs map[string]string)
- func SetSessionAttributes(ctx context.Context, attrs map[string]string)
- func Tool[In, Out any](f *Functions, name string, fn func(ctx context.Context, in In) (Out, error), ...)
- type APIResponse
- type FunctionResponse
- type FunctionResponseBody
- type FunctionResult
- type Functions
- type FunctionsOption
- type KnowledgeBaseConfiguration
- type Response
- type ResponseContent
- type ResponseState
- type Result
- type ToolOption
Examples ¶
Constants ¶
const DefaultTitle = "Powertools API"
DefaultTitle is the title of an agent's OpenAPI document when the router sets none, as in Powertools Python.
const MessageVersion = "1.0"
MessageVersion is the version of the response format.
Variables ¶
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.
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 ¶
func Handler(h http.Handler) func(context.Context, eventsource.BedrockAgentEvent) (Response, error)
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 ¶
SetPromptSessionAttributes sets the prompt session attributes the response carries.
func SetSessionAttributes ¶
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 ¶
func (f *Functions) Handle(ctx context.Context, e eventsource.BedrockAgentFunctionEvent) (FunctionResponse, error)
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.