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

tool

package
v0.2.2 Latest Latest
Warning

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

Go to latest
Published: Aug 31, 2026 License: MIT Imports: 15 Imported by: 2

Documentation

Index

Constants

View Source
const AssemblyKind = "tool.Assembly"

AssemblyKind is the deployment resource kind of the standard tool assembly (registry + executor + optional dynamic injection).

View Source
const RegistryKind = "tool.Registry"

RegistryKind is the deployment resource kind of a tool registry.

View Source
const ToolName = "tool_search"

ToolName is the built-in tool_search tool name. The assembly registers it with ExposureAlways when dynamic injection is enabled, so the model always has a discovery path.

Variables

View Source
var DefaultBudget = Budget{
	MaxDefinitions: 32,
	MaxBytes:       16 * 1024,
}

DefaultBudget is the built-in budget: 32 tools or 16 KiB of definitions per turn, whichever is hit first.

Functions

func CallIDFromContext added in v0.1.30

func CallIDFromContext(ctx context.Context) (string, bool)

CallIDFromContext returns the active tool call id carried by ctx. ok=false means the caller is outside a tool execution (or the id was empty); consumers should treat the zero value as "unknown" rather than an error.

func Register

func Register(r *resource.Registry) error

Register adds the memory registry factory to r.

func WithCallID added in v0.1.30

func WithCallID(ctx context.Context, id string) context.Context

WithCallID returns a derived context carrying id as the active tool call id.

func WithSession

func WithSession(ctx context.Context, s Session) context.Context

WithSession attaches the per-run session to ctx.

Types

type Assembly

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

Assembly is the standard tool resource value: the aggregated registry (read surface), the executor (execution surface), and — when dynamic injection is configured — the injection policy that session views are created from.

func NewAssembly

func NewAssembly(sources []Source, opts ...AssemblyOption) (*Assembly, error)

NewAssembly builds an assembly from sources. With dynamic enabled, the built-in tool_search tool is appended as a source so it is part of the registry from construction (no post-build mutation).

func (*Assembly) Catalog

func (a *Assembly) Catalog() Catalog

Catalog returns the aggregated read surface.

func (*Assembly) Close

func (a *Assembly) Close() error

Close releases the registry (and any loaded deferred tools).

func (*Assembly) Dispatcher

func (a *Assembly) Dispatcher() Dispatcher

Dispatcher returns the executor. Assembly itself also implements Dispatcher by delegation, so callers can take either form.

func (*Assembly) Execute

func (a *Assembly) Execute(ctx context.Context, call message.ToolCall) message.ToolResult

Execute implements Dispatcher.

func (*Assembly) ExecuteAll

func (a *Assembly) ExecuteAll(ctx context.Context, calls []message.ToolCall) []message.ToolResult

ExecuteAll implements Dispatcher.

func (*Assembly) NewSession

func (a *Assembly) NewSession() Session

NewSession creates one per-run / per-conversation injection view. Without dynamic injection it returns a static session showing every tool.

type AssemblyFactory

type AssemblyFactory struct{}

AssemblyFactory builds the standard tool assembly resource without middleware: the executor runs a bare chain. Deployments that need middleware use the tool.Assembly/middleware impl.

func (AssemblyFactory) New

New implements resource.Factory.

func (AssemblyFactory) Spec

func (AssemblyFactory) Spec() resource.Spec

Spec implements resource.Factory.

type AssemblyOption

type AssemblyOption func(*assemblyOptions)

AssemblyOption configures NewAssembly.

func WithConflict

func WithConflict(p ConflictPolicy) AssemblyOption

WithConflict sets the duplicate-name policy for the underlying registry.

func WithDynamic

func WithDynamic(p Policy) AssemblyOption

WithDynamic enables dynamic tool injection with policy p. Zero fields fall back to DefaultPolicy; tool_search is registered with ExposureAlways automatically.

func WithMiddleware

func WithMiddleware(mws ...Middleware) AssemblyOption

WithMiddleware appends middleware to the executor chain, outermost first.

type AssemblySettings

type AssemblySettings struct {
	Dynamic *Policy `json:"dynamic,omitempty"`
}

AssemblySettings is the strict settings subtree of the memory assembly factory: the dynamic injection policy only. Middleware settings belong to the tool.Assembly/middleware impl (see core/tool/middleware); the memory impl rejects the "middlewares" key via strict decoding.

type Budget

type Budget struct {
	// MaxDefinitions caps the number of definitions. Zero falls back
	// to DefaultBudget.MaxDefinitions.
	MaxDefinitions int `json:"max_definitions,omitempty"`
	// MaxBytes caps the total serialized size of the definitions. Zero
	// falls back to DefaultBudget.MaxBytes.
	MaxBytes int64 `json:"max_bytes,omitempty"`
}

Budget caps how many definitions reach the model per turn.

type Catalog

type Catalog interface {
	// Get returns the tool registered under name.
	Get(name string) (Tool, bool)
	// Definitions returns the Definition of every tool in the catalog.
	Definitions() []message.ToolDefinition
}

Catalog is the read-side view of a tool collection: lookup plus model-facing definitions. A Registry implements it; read-side wrappers (e.g. the dynamic injection catalog) implement it over a base registry without being execution surfaces.

type ConflictPolicy

type ConflictPolicy int

ConflictPolicy decides what happens when two sources contribute a tool with the same name.

const (
	// ConflictError fails construction on any duplicate name. This is
	// the default: a silent overwrite usually means two sources
	// disagree about who owns a tool.
	ConflictError ConflictPolicy = iota
	// ConflictOverwrite lets a later source (in the explicit dep
	// order) replace an earlier tool with the same name. Use it when
	// a deployment intentionally overrides a base tool.
	ConflictOverwrite
)

type Dispatch

type Dispatch func(ctx context.Context, call message.ToolCall) message.ToolResult

Dispatch is the function form of "execute one tool call and return its result". Middleware operates on this signature.

Implementations should treat the input call as immutable and must always return a Result — errors are reported via Result.IsError, never returned out-of-band.

type Dispatcher

type Dispatcher interface {
	Execute(context.Context, message.ToolCall) message.ToolResult
	ExecuteAll(context.Context, []message.ToolCall) []message.ToolResult
}

Dispatcher is the execution contract consumers depend on: run one tool call, or several concurrently. *Executor is the canonical implementation, but tests and adapters may substitute their own.

type Executor

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

Executor dispatches tool calls against a Catalog through a middleware chain. The un-decorated core only looks the tool up and invokes it; every cross-cutting concern — recovery, telemetry, concurrency limits, timeouts, approval, audit — is middleware, declared at construction. The chain is immutable afterwards, so an Executor is safe for concurrent use by construction.

func NewExecutor

func NewExecutor(catalog Catalog, mws ...Middleware) *Executor

NewExecutor builds an Executor over catalog. Nil middleware values are skipped. catalog must be non-nil.

func (*Executor) Execute

func (e *Executor) Execute(ctx context.Context, call message.ToolCall) message.ToolResult

Execute runs one call through the middleware chain. All failures — unknown tool, tool error — surface as Result with IsError=true, never as a Go error.

func (*Executor) ExecuteAll

func (e *Executor) ExecuteAll(ctx context.Context, calls []message.ToolCall) []message.ToolResult

ExecuteAll runs every call concurrently through the chain and returns results in input order. Concurrency is unbounded by default; put a concurrency middleware in the chain to cap it.

type Exposure

type Exposure string

Exposure controls whether a tool appears in the model-visible Definitions. It is host policy, never part of message.ToolDefinition.

const (
	// ExposureAlways marks a tool that appears in Definitions every
	// turn. Keep this set small; it is the stable baseline.
	ExposureAlways Exposure = "always"
	// ExposureDirect marks a tool that appears only when it is
	// RequiredByName or has been selected/used recently.
	ExposureDirect Exposure = "direct"
	// ExposureDeferred marks a tool that is hidden until tool_search
	// surfaces it; once selected it stays visible for M rounds.
	ExposureDeferred Exposure = "deferred"
	// ExposureHidden marks a tool that never appears in Definitions
	// (not even via search). RequiredByName can still surface it, and
	// the tool remains callable by exact name at all times.
	ExposureHidden Exposure = "hidden"
)

func (Exposure) Valid

func (e Exposure) Valid() bool

Valid reports whether e is one of the four exposure levels.

type LazyTool

type LazyTool struct {
	Name        string
	Placeholder message.ToolDefinition
	Load        func(ctx context.Context) (Tool, error)
}

LazyTool is a deferred tool descriptor contributed by a Source. Name must equal Placeholder.Name; Load performs any network or process work the tool needs.

func (LazyTool) Validate

func (lt LazyTool) Validate() error

Validate checks the descriptor invariants.

type Middleware

type Middleware func(next Dispatch) Dispatch

Middleware wraps a Dispatch. mws[0] is outermost (sees the call first and the result last), matching agent.ComposeHost.

type Option

type Option func(*options)

Option configures a Registry.

func WithConflictPolicy

func WithConflictPolicy(p ConflictPolicy) Option

WithConflictPolicy sets the duplicate-name policy. The default is ConflictError; pass ConflictOverwrite to let later sources win.

type Policy

type Policy struct {
	// Default is the exposure applied to registered tools that have no
	// explicit entry in Exposures. Empty means ExposureDeferred.
	Default Exposure `json:"default,omitempty"`
	// Exposures maps tool names to explicit exposure levels.
	Exposures map[string]Exposure `json:"exposures,omitempty"`
	// SelectedRetention is how many rounds a selected tool stays
	// visible (M). Zero falls back to 5.
	SelectedRetention int `json:"selected_retention,omitempty"`
	// RecentWindow is how many rounds a recently used direct tool stays
	// visible. Zero falls back to 10.
	RecentWindow int `json:"recent_window,omitempty"`
	// Budget caps the visible set. Zero uses DefaultBudget.
	Budget Budget `json:"budget,omitempty"`
	// SearchWithLoad makes tool_search load every deferred source
	// before ranking, so hits are computed over real metadata instead
	// of placeholder declarations. Default is false (lazy search).
	SearchWithLoad bool `json:"search_with_load,omitempty"`
}

Policy is the host-declared injection policy for one assembly. Zero values mean "use DefaultPolicy" for every field except Exposures, so a partial settings subtree is sufficient.

func DefaultPolicy

func DefaultPolicy() Policy

DefaultPolicy returns the recommended policy: everything deferred by default, 5 selected rounds, 10 recent rounds, and the default budget.

func (Policy) Validate

func (p Policy) Validate() error

Validate checks policy invariants. Call after normalizePolicy when the policy may come from settings.

type Registrar added in v0.1.8

type Registrar interface {
	// Add registers one tool. Duplicate names follow the registry's
	// ConflictPolicy; adding to a closed registry returns an error.
	Add(t Tool) error
	// Remove unregisters the named tool, if present.
	Remove(name string)
}

Registrar is the runtime mutation surface of a Registry. Sources that discover tools after construction — an MCP server that connects in the background, a refresh that re-lists remote tools — use it to publish tools as they become available.

type Registry

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

Registry aggregates tools from many Source values. It implements Catalog; the underlying execution surface for an Executor is the same value. The tool set is fixed at construction — sources are a build-time concern — and changes at runtime only through the Registrar surface (Add/Remove), which deferred sources use to publish tools discovered after construction.

A Registry is safe for concurrent use. Close releases every contributed tool that implements io.Closer (deferred proxies included) and forbids further lazy loads.

func NewRegistry

func NewRegistry(sources []Source, opts ...Option) (*Registry, error)

NewRegistry builds a registry from sources in order. With the default ConflictError policy a duplicate name is an error; with ConflictOverwrite the later source wins.

func (*Registry) Add added in v0.1.8

func (r *Registry) Add(t Tool) error

Add registers one tool at runtime. It follows the same duplicate policy as construction and fails after Close.

func (*Registry) Close

func (r *Registry) Close() error

Close releases every tool that implements io.Closer (in reverse registration order) and marks the registry closed so deferred tools can no longer load. It is idempotent.

func (*Registry) Definitions

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

Definitions implements Catalog, sorted by name.

func (*Registry) Get

func (r *Registry) Get(name string) (Tool, bool)

Get implements Catalog. A deferred tool returns its proxy, which serves the placeholder definition until first Execute.

func (*Registry) Len

func (r *Registry) Len() int

Len returns the number of registered tools.

func (*Registry) Names

func (r *Registry) Names() []string

Names returns the registered tool names in sorted order.

func (*Registry) Remove added in v0.1.8

func (r *Registry) Remove(name string)

Remove unregisters the named tool at runtime. If the removed tool implements io.Closer, it is closed so runtime removals (e.g. a shrunk MCP tool projection) release whatever resources the tool holds; the close happens outside the registry lock and is best-effort. Unknown names are ignored; after Close it is a no-op.

type RegistryAttacher added in v0.1.8

type RegistryAttacher interface {
	Attach(r Registrar)
}

RegistryAttacher is an optional Source capability: the assembly hands the built Registry's Registrar to sources that need to publish tools after construction (background connects, refresh).

type RegistryFactory

type RegistryFactory struct{}

RegistryFactory builds a memory registry from its many tool.Source deps. The dep order (DepsMany's sorted key order) is the explicit source order used by ConflictOverwrite.

func (RegistryFactory) New

New implements resource.Factory.

func (RegistryFactory) Spec

func (RegistryFactory) Spec() resource.Spec

Spec implements resource.Factory.

type SearchHit

type SearchHit struct {
	Name        string  `json:"name"`
	Description string  `json:"description"`
	Score       float64 `json:"score"`
}

SearchHit is one tool_search result.

type SearchTool

type SearchTool struct{}

SearchTool is the model-facing discovery tool. It resolves the session from context (see WithSession) so one instance can be registered on the shared registry for all sessions.

func NewSearchTool

func NewSearchTool() SearchTool

NewSearchTool returns the tool_search implementation.

func (SearchTool) Definition

func (SearchTool) Definition() message.ToolDefinition

func (SearchTool) Execute

func (SearchTool) Execute(ctx context.Context, arguments string) (string, error)

Execute parses the query, ranks hits, and applies the select list.

type Session

type Session interface {
	Catalog

	// Require adds names to the RequiredByName set. Idempotent.
	Require(names ...string)
	// Select marks names as selected for the policy's retention
	// rounds. Selection carries an implicit load contract: a selected
	// tool must be loaded before the next Definitions call, otherwise
	// the model would see its placeholder schema. tool_search enforces
	// this by loading each name before selecting.
	Select(names ...string)
	// RecordCall records that the model called name this round,
	// refreshing its Selected and UsedRecently state.
	RecordCall(call message.ToolCall)
	// AdvanceTurn moves to the next round, expiring Selected and
	// UsedRecently entries. Call it once per inference round.
	AdvanceTurn()
	// Search ranks searchable definitions against query with BM25.
	// Search never loads deferred tools.
	Search(ctx context.Context, query string, limit int) ([]SearchHit, error)
	// SearchWithLoad loads every deferred tool before ranking, so hits
	// are computed over real metadata. It is the explicit opt-in for
	// hosts that need the complete tool set; tool_search itself follows
	// Policy.SearchWithLoad instead.
	SearchWithLoad(ctx context.Context, query string, limit int) ([]SearchHit, error)
	// Load eagerly loads every deferred tool. One failing source does
	// not stop the others; errors are joined.
	Load(ctx context.Context) error
	// EnsureLoaded forces the deferred load of the named tools so the
	// next Definitions call sees their real schemas. Unknown or
	// already-concrete tools are skipped.
	EnsureLoaded(ctx context.Context, names ...string) error
}

Session is the per-run / per-conversation injection view over a Catalog. An Engine creates one at run start, feeds the model Definitions() each round, records calls, and advances turns.

When the assembly was built without dynamic injection, the session is static: Definitions() shows every tool, and the stateful operations (Select/Require/RecordCall/AdvanceTurn) are no-ops while Search returns NotAvailable.

func SessionFromContext

func SessionFromContext(ctx context.Context) (Session, bool)

SessionFromContext returns the per-run session attached by the engine. Only tool_search and RecordCalls read it; the session is explicit run state, not assembly wiring.

type Source

type Source interface {
	Tools() []Tool
	LazyTools() []LazyTool
}

Source is a multi-tool contributor to a Registry: builtin Go functions, a sandbox-backed exec set, an MCP server, a YAML document, a host-provided collection. Sources are resources in the deployment DAG; a registry aggregates them through a Many dep.

Tools() are eager — available immediately without I/O. LazyTools() are deferred: the registry stores a proxy serving LazyTool.Placeholder as its definition, and the real implementation is loaded on first Execute (never at build time).

type Tool

type Tool interface {
	Definition() message.ToolDefinition
	Execute(ctx context.Context, arguments string) (string, error)
}

Tool is the interface that LLM-callable tools must implement.

func FuncTool

func FuncTool(def message.ToolDefinition, fn func(ctx context.Context, args string) (string, error)) Tool

FuncTool wraps a plain function as a Tool.

type ToolMeta

type ToolMeta struct {
	// RateLimit is the maximum number of executions per second this
	// tool can sustain. Zero means "no claim" (no rate limit applied).
	// A negative value is treated as zero.
	RateLimit float64

	// MutatesState declares that this tool has side effects beyond
	// returning a result (writes, posts, sends mail, ...). Zero value
	// (false) is the conservative default in the opposite direction:
	// callers that don't know better should assume the tool MAY mutate
	// state.
	MutatesState bool

	// SelfTimeout declares that the tool already bounds its own
	// execution time, so the timeout middleware should not impose its
	// default deadline on top.
	SelfTimeout bool
}

ToolMeta carries optional, execution-relevant metadata about a Tool.

All fields are advisory; a zero ToolMeta means "no claims, treat conservatively" (no rate limit, assume the tool may mutate state so retries are unsafe).

func MetadataOf

func MetadataOf(t Tool) ToolMeta

MetadataOf returns the ToolMeta declared by t, or a zero ToolMeta when t does not implement ToolMetadata. Safe on nil values.

type ToolMetadata

type ToolMetadata interface {
	Metadata() ToolMeta
}

ToolMetadata is an optional interface a Tool may implement to declare execution-relevant metadata. Tools that do not implement it are treated as if they returned a zero ToolMeta.

Directories

Path Synopsis
Package mcp attaches Model Context Protocol servers to a [tool.Registry], turning every tool a server exposes into an ordinary [tool.Tool].
Package mcp attaches Model Context Protocol servers to a [tool.Registry], turning every tool a server exposes into an ordinary [tool.Tool].
Package tooltest provides reusable fixtures and contract suites for core/tool implementations.
Package tooltest provides reusable fixtures and contract suites for core/tool implementations.

Jump to

Keyboard shortcuts

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