NewHandler creates a type-safe tool handler from a function that accepts typed parameters. It unmarshals the tool-call arguments via [aijson.Unmarshal], which runs strict [encoding/json.Unmarshal] first and only falls back to a narrow set of shape repairs (stringified array, bare scalar where an arr
(fn func(context.Context, T) (*ToolCallResult, error))
| 23 | // tool_input_repaired log entry so per-(model, tool) repair rates can be |
| 24 | // tracked. |
| 25 | func NewHandler[T any](fn func(context.Context, T) (*ToolCallResult, error)) ToolHandler { |
| 26 | return func(ctx context.Context, toolCall ToolCall) (*ToolCallResult, error) { |
| 27 | var params T |
| 28 | args := toolCall.Function.Arguments |
| 29 | if args == "" { |
| 30 | args = "{}" |
| 31 | } |
| 32 | |
| 33 | err := aijson.Unmarshal([]byte(args), ¶ms, aijson.OnRepair(func(kinds []aijson.Kind) { |
| 34 | slog.InfoContext(ctx, "tool_input_repaired", |
| 35 | "tool", toolCall.Function.Name, |
| 36 | "repairs", kinds, |
| 37 | ) |
| 38 | })) |
| 39 | if err != nil { |
| 40 | return nil, err |
| 41 | } |
| 42 | return fn(ctx, params) |
| 43 | } |
| 44 | } |
| 45 | |
| 46 | type ToolHandler func(ctx context.Context, toolCall ToolCall) (*ToolCallResult, error) |
| 47 |
no outgoing calls