Help us shape the future of Go! Take the 2026 Go Developer Survey

tools

package
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: Nov 1, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Overview

Package tools provides a registry, dispatch, and explicit JSON-Schema helpers for tools the LLM may call.

Schemas are explicit; the package does not generate schemas from struct types (ADR-018). Callers who want struct-driven schemas use invopop/jsonschema:

import jsonschema "github.com/invopop/jsonschema"
schema, _ := json.Marshal(jsonschema.Reflect(&FooArgs{}))

Tool handlers capture the dependencies they need (storage, logger, clock) at registration time via closure (ADR-021). The Environment passed to a Handler carries only fields that genuinely change per dispatch: SessionID and TurnID.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrDuplicateTool is returned by Registry.Register when the tool name
	// is already registered.
	ErrDuplicateTool = errors.New("aikido/tools: duplicate tool registration")
	// ErrUnknownTool is returned by Registry.Dispatch when no tool of the
	// called name is registered.
	ErrUnknownTool = errors.New("aikido/tools: unknown tool")
	// ErrInvalidArguments is returned by Registry.Dispatch when the call's
	// arguments are not a JSON object or lack a required field of the tool's
	// schema. The message names the tool and the field.
	ErrInvalidArguments = errors.New("aikido/tools: invalid tool arguments")
	// ErrToolPanicked is returned by Registry.Dispatch when the handler
	// panicked. The message names the tool and the panic value.
	ErrToolPanicked = errors.New("aikido/tools: tool panicked")
)

Functions

func Array

func Array(items any, description string) map[string]any

Array builds an array-typed property schema.

func Boolean

func Boolean(description string) map[string]any

Boolean builds a boolean-typed property schema.

func Enum

func Enum(description string, values ...string) map[string]any

Enum builds a string-typed enum property schema.

func Integer

func Integer(description string) map[string]any

Integer builds an integer-typed property schema.

func Number

func Number(description string) map[string]any

Number builds a number-typed property schema.

func Object

func Object(properties map[string]any, required ...string) json.RawMessage

Object builds a JSON Schema "object" from a property map and a list of required property names. Output is deterministic (properties are emitted in the order Go's encoding/json sorts map keys, which is alphabetical). Nil properties produce an object without properties.

Object panics if properties hold a value encoding/json cannot encode (a channel, a function): schemas are literals written at registration time, so that is a programmer error (ERR-001).

Example
package main

import (
	"fmt"

	"github.com/govengers/aikido/tools"
)

func main() {
	schema := tools.Object(map[string]any{
		"path":  tools.String("File to read."),
		"limit": tools.Integer("Maximum lines."),
	}, "path")
	fmt.Println(string(schema))
}
Output:
{"properties":{"limit":{"description":"Maximum lines.","type":"integer"},"path":{"description":"File to read.","type":"string"}},"required":["path"],"type":"object"}

func String

func String(description string) map[string]any

String builds a string-typed property schema.

Types

type Environment

type Environment struct {
	// SessionID is the agent session the call belongs to.
	SessionID string
	// TurnID identifies the model reply that made the call; calls of the
	// same reply share it.
	TurnID uuid.UUID
}

Environment carries per-call execution context to a Handler.

type Handler

type Handler func(ctx context.Context, arguments json.RawMessage, environment Environment) (Result, error)

Handler is the function signature every tool implements. arguments holds the model's raw JSON arguments, unvalidated. A returned error is shown to the model as the tool's failure, so it can correct itself.

type Registry

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

Registry holds tool definitions and their handlers. It is safe for concurrent use; the zero value is not usable, use NewRegistry.

Example
package main

import (
	"context"
	"encoding/json"
	"fmt"

	"github.com/govengers/aikido/llm"
	"github.com/govengers/aikido/tools"
)

func main() {
	registry := tools.NewRegistry()
	err := registry.Register(llm.ToolDefinition{
		Name:        "greet",
		Description: "Greet a person by name.",
		Parameters:  tools.Object(map[string]any{"name": tools.String("Who to greet.")}, "name"),
	}, func(_ context.Context, arguments json.RawMessage, _ tools.Environment) (tools.Result, error) {
		var parsed struct {
			Name string `json:"name"`
		}
		if err := json.Unmarshal(arguments, &parsed); err != nil {
			return tools.Result{}, fmt.Errorf("greet arguments: %w", err)
		}
		return tools.Result{Content: "Hello, " + parsed.Name + "!"}, nil
	})
	if err != nil {
		fmt.Println(err)
		return
	}

	result, err := registry.Dispatch(context.Background(), llm.ToolCall{
		ID: "call-1", Name: "greet", Arguments: `{"name":"Ada"}`,
	}, tools.Environment{SessionID: "conversation-1"})
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(result.Content)
}
Output:
Hello, Ada!

func NewRegistry

func NewRegistry() *Registry

NewRegistry returns an empty Registry.

func (*Registry) Definitions

func (r *Registry) Definitions() []llm.ToolDefinition

Definitions returns all registered tool definitions in registration order, as a new slice.

func (*Registry) Dispatch

func (r *Registry) Dispatch(ctx context.Context, call llm.ToolCall, environment Environment) (Result, error)

Dispatch routes a ToolCall to its handler and returns the handler's result and error unchanged.

Before the handler runs, Dispatch checks the arguments: empty arguments count as {}, anything else must be a JSON object (not null) holding every required field of the tool's schema (a JSON null field counts as missing). The handler receives the arguments verbatim ({} for empty ones) and still parses them.

It returns an error matching ErrUnknownTool if the name is not registered, ErrInvalidArguments if the argument check fails, and ErrToolPanicked if the handler panicked; the error messages are written for the model, so it can correct the call.

Example

Dispatch refuses a call that lacks a required argument before the handler runs, and turns a handler panic into an error; both messages are written for the model.

package main

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"

	"github.com/govengers/aikido/llm"
	"github.com/govengers/aikido/tools"
)

func main() {
	registry := tools.NewRegistry()
	err := registry.Register(llm.ToolDefinition{
		Name:       "divide",
		Parameters: tools.Object(map[string]any{"by": tools.Integer("Divisor.")}, "by"),
	}, func(context.Context, json.RawMessage, tools.Environment) (tools.Result, error) {
		panic("division by zero")
	})
	if err != nil {
		fmt.Println(err)
		return
	}

	_, err = registry.Dispatch(context.Background(), llm.ToolCall{Name: "divide", Arguments: `{}`}, tools.Environment{})
	fmt.Println(errors.Is(err, tools.ErrInvalidArguments))
	_, err = registry.Dispatch(context.Background(), llm.ToolCall{Name: "divide", Arguments: `{"by":0}`}, tools.Environment{})
	fmt.Println(errors.Is(err, tools.ErrToolPanicked))
	_, err = registry.Dispatch(context.Background(), llm.ToolCall{Name: "multiply"}, tools.Environment{})
	fmt.Println(errors.Is(err, tools.ErrUnknownTool))
}
Output:
true
true
true

func (*Registry) Has

func (r *Registry) Has(name string) bool

Has reports whether a tool is registered.

func (*Registry) Register

func (r *Registry) Register(definition llm.ToolDefinition, handler Handler) error

Register adds a tool. It returns an error for an empty name or a nil handler, and an error matching ErrDuplicateTool if the name is taken.

Dispatch enforces the "required" list of definition.Parameters; a Parameters value that is not a JSON object schema enforces nothing.

type Result

type Result struct {
	Content any
}

Result is what a Handler returns. Content is JSON-serialized to the model; nil is sent as JSON null.

Directories

Path Synopsis
Package shell is a virtual bash for agents: the model writes ordinary shell (pipes, &&, loops, variables, redirects, globs) and every file the script touches is a file of a vfs.Storage, so overlays, dry runs, mounts and path policy keep working.
Package shell is a virtual bash for agents: the model writes ordinary shell (pipes, &&, loops, variables, redirects, globs) and every file the script touches is a file of a vfs.Storage, so overlays, dry runs, mounts and path policy keep working.

Jump to

Keyboard shortcuts

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