toolkit

package
v0.1.20 Latest Latest
Warning

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

Go to latest
Published: Jul 30, 2026 License: Apache-2.0 Imports: 21 Imported by: 0

Documentation

Overview

Package toolkit provides a registry of built-in agent tools — file read/write/edit, shell, grep, and find — hardened for autonomous use with working-directory confinement, write/shell mutation serialisation, size caps, and output truncation. CoreToolSet adapts a registry to a core.ToolSet for use with core.GenerateText/StreamText or runtime.Chat.

Index

Constants

View Source
const (
	// DefaultMaxBytes is the maximum byte size for tool output sent to the LLM.
	DefaultMaxBytes = 50 * 1024 // 50KB

	// DefaultMaxLines is the maximum line count for tool output sent to the LLM.
	DefaultMaxLines = 2000

	// DefaultToolTimeout is the per-tool execution deadline. Tools that exceed
	// this are cancelled. The shell tool uses its own configurable timeout.
	DefaultToolTimeout = 60 * time.Second
)
View Source
const DefaultReadLines = 400

DefaultReadLines is the bounded line count used when no explicit read limit or full-file request is supplied.

Variables

View Source
var (
	ErrInteractiveUnsupported = errors.New("interactive prompts are not supported in this mode")
	ErrInteractiveCanceled    = errors.New("interactive prompt was canceled")
)

Functions

func FormatSize

func FormatSize(bytes int) string

FormatSize returns a human-readable size string.

func RegisterBuiltins

func RegisterBuiltins(reg *Registry, cwd string, indexes ...GrepIndex) error

RegisterBuiltins registers all built-in tools into the given registry. The cwd parameter sets the working directory for file and shell operations.

Types

type DiffDetails

type DiffDetails struct {
	Path       string `json:"path"`
	OldContent string `json:"old_content"`
	NewContent string `json:"new_content"`
}

DiffDetails is carried in Result.Details by tools that replace file content (edit, write), so callers such as the TUI can render a before/after diff instead of just a summary string.

type EditAction

type EditAction struct {
	OldText    string `json:"old_text"`
	NewText    string `json:"new_text"`
	ReplaceAll bool   `json:"replace_all,omitempty"`
}

EditAction is a single search-and-replace operation.

type EditParams

type EditParams struct {
	Path  string       `json:"path"`
	Edits []EditAction `json:"edits"`
}

EditParams are the parameters for the edit tool.

type Executor

type Executor func(ctx context.Context, params json.RawMessage, ui UIBridge) (Result, error)

Executor is a function that executes a tool with the given parameters.

type FindParams

type FindParams struct {
	Path     string `json:"path,omitempty"`      // directory to search in
	Pattern  string `json:"pattern,omitempty"`   // glob pattern for file names
	Type     string `json:"type,omitempty"`      // "file", "directory", or empty for both
	MaxDepth int    `json:"max_depth,omitempty"` // max directory depth (0 = unlimited)
	Exclude  string `json:"exclude,omitempty"`   // glob pattern to exclude (e.g. 'node_modules', '*.test.*')
}

FindParams are the parameters for the find tool.

type GrepIndex

type GrepIndex interface {
	Candidates(context.Context, string, bool, bool) ([]string, bool)
}

GrepIndex provides conservative workspace-wide candidate files. The grep tool remains responsible for authoritative matching and output formatting.

type GrepParams

type GrepParams struct {
	Pattern       string `json:"pattern"`
	Path          string `json:"path,omitempty"`    // file or directory
	Include       string `json:"include,omitempty"` // glob pattern for file names
	Literal       bool   `json:"literal,omitempty"`
	CaseSensitive bool   `json:"case_sensitive,omitempty"`
	ContextBefore int    `json:"context_before,omitempty"` // lines before each match (-B)
	ContextAfter  int    `json:"context_after,omitempty"`  // lines after each match (-A)
	Limit         int    `json:"limit,omitempty"`          // max matches to return
}

GrepParams are the parameters for the grep tool.

type HeadlessBridge

type HeadlessBridge struct {
	Logger  *slog.Logger
	Session string
}

HeadlessBridge is a UIBridge for autonomous runs where the execution environment (container, path jail, gate commands) is the permission model rather than a human: confirmations auto-approve, selections take the first option, and text input returns empty. Notify and Log are forwarded to Logger when set; a zero HeadlessBridge is silent.

func (HeadlessBridge) Confirm

func (HeadlessBridge) Input

func (HeadlessBridge) Log

func (b HeadlessBridge) Log(chunk string)

func (HeadlessBridge) Notify

func (b HeadlessBridge) Notify(title, level string)

func (HeadlessBridge) Select

func (HeadlessBridge) Select(_ context.Context, _ string, options []string) (string, error)

func (HeadlessBridge) SessionID

func (b HeadlessBridge) SessionID() string

type MutationQueue

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

MutationQueue serializes write operations to the same file path, preventing concurrent edits from clobbering each other during parallel tool execution.

A sync.RWMutex coordinates between shell commands and file-mutation tools. File mutations (write, edit) take a read lock so they can run concurrently with each other. Shell commands take the write lock, blocking all file mutations for the duration of the command.

func NewMutationQueue

func NewMutationQueue() *MutationQueue

NewMutationQueue creates a new per-file mutation queue.

func (*MutationQueue) Acquire

func (q *MutationQueue) Acquire(path string) (release func())

Acquire returns a lock for the given file path. The caller must call the returned release function when done with the mutation.

Acquire blocks while the global write lock is held (i.e. while a shell command is running).

Usage:

release := q.Acquire("/path/to/file.go")
defer release()
// ... perform read-modify-write ...

func (*MutationQueue) GlobalLock

func (q *MutationQueue) GlobalLock()

GlobalLock blocks until all in-flight per-file mutations complete, then prevents new per-file Acquire calls from proceeding until GlobalUnlock is called. Used by the shell tool to ensure no race between shell commands and file-mutation tools.

func (*MutationQueue) GlobalUnlock

func (q *MutationQueue) GlobalUnlock()

GlobalUnlock releases the global lock, allowing per-file mutations to proceed again.

type NonInteractiveBridge

type NonInteractiveBridge struct{}

func (NonInteractiveBridge) Confirm

func (NonInteractiveBridge) Input

func (NonInteractiveBridge) Log

func (NonInteractiveBridge) Notify

func (NonInteractiveBridge) Select

func (NonInteractiveBridge) SessionID

func (NonInteractiveBridge) SessionID() string

type PluginToolDef

type PluginToolDef struct {
	Name        string
	Description string
	InputSchema string // JSON Schema as string
}

PluginToolDef describes a tool provided by a plugin.

type PluginToolExecutor

type PluginToolExecutor func(ctx context.Context, pluginName, toolName string, args json.RawMessage) (Result, error)

PluginToolExecutor is called by the registry when a plugin tool is executed.

type ReadParams

type ReadParams struct {
	Path   string `json:"path"`
	File   string `json:"file,omitempty"`   // compatibility alias used by some providers
	Offset int    `json:"offset,omitempty"` // start line (1-based)
	Limit  int    `json:"limit,omitempty"`  // max lines to read
	Full   bool   `json:"full,omitempty"`   // explicitly allow a full-file response
}

ReadParams are the parameters for the read tool.

type ReadTracker

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

ReadTracker records which files the model has read so that mutation tools (write, edit) can enforce a read-before-write safety check.

func NewReadTracker

func NewReadTracker() *ReadTracker

NewReadTracker creates a new ReadTracker.

func (*ReadTracker) CheckRead

func (rt *ReadTracker) CheckRead(cwd, path string) error

CheckRead returns an error if the file at the given path has not been read by the model in this session. The path is normalised to absolute form. A file must be read (via the read tool) before it can be written, edited.

func (*ReadTracker) MarkRead

func (rt *ReadTracker) MarkRead(cwd, path string)

MarkRead records that a file at the given path has been read by the model. The path is normalised to absolute form before recording.

type Registry

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

Registry holds all registered tools and provides thread-safe access.

func NewRegistry

func NewRegistry() *Registry

NewRegistry creates an empty tool registry.

func (*Registry) All

func (r *Registry) All() []Tool

All returns all registered tools in insertion order.

func (*Registry) CoreToolSet

func (r *Registry) CoreToolSet(ui UIBridge) core.ToolSet

CoreToolSet adapts every registered tool to ai-sdk's core.ToolSet, binding ui as the bridge for each execution. Tool failures are encoded in the returned output rather than surfaced as Go errors, so the generation loop always feeds them back to the model; only context cancellation propagates as an error and aborts the run.

func (*Registry) Count

func (r *Registry) Count() int

Count returns the number of registered tools.

func (*Registry) Get

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

Get retrieves a tool by name.

func (*Registry) Names

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

Names returns the names of all registered tools.

func (*Registry) Register

func (r *Registry) Register(tool Tool) error

Register adds a tool to the registry. Returns an error if a tool with the same name is already registered (use Replace for overrides).

func (*Registry) RegisterPluginTool

func (r *Registry) RegisterPluginTool(pluginName string, def PluginToolDef) error

RegisterPluginTool registers a tool from a plugin in the registry.

The public, LLM-facing name is the plugin name and tool name, sanitised to the provider-safe character set and joined with pluginToolSep. Sanitising here - once, for every plugin - means plugin authors can return whatever names their upstream uses. Execution routes back to the plugin with its ORIGINAL, unmodified tool name (captured in the closure below), so the plugin never sees the sanitised form and needs no name translation of its own.

Returns an error if the resulting name is already registered.

func (*Registry) Replace

func (r *Registry) Replace(tool Tool) error

Replace registers a tool, overriding any existing tool with the same name.

func (*Registry) Schemas

func (r *Registry) Schemas() []Schema

Schemas returns the schemas of all registered tools in insertion order. This is the slice sent to the LLM in the tools[] field.

func (*Registry) SetPluginToolExecutor

func (r *Registry) SetPluginToolExecutor(executor PluginToolExecutor)

SetPluginToolExecutor sets the executor for plugin tools. The executor is called whenever a plugin-registered tool is invoked by the agent.

func (*Registry) Unregister

func (r *Registry) Unregister(name string)

Unregister removes a tool from the registry.

func (*Registry) UnregisterPluginTools

func (r *Registry) UnregisterPluginTools(pluginName string)

UnregisterPluginTools removes all tools belonging to a plugin. Plugin tools are identified by the sanitised "pluginName__" prefix in their names (see RegisterPluginTool).

type Result

type Result struct {
	Content   string `json:"content"`
	Details   any    `json:"details,omitempty"`
	IsError   bool   `json:"is_error,omitempty"`
	ErrorKind string `json:"error_kind,omitempty"`
	// MetricLabels adds tool-specific low-cardinality dimensions to the
	// coordinator's authoritative completion metric.
	MetricLabels map[string]string `json:"-"`

	// Execution fields are populated by the coordinator after execution so
	// the same facts drive events, metrics, and persisted tool messages.
	Duration    time.Duration `json:"duration,omitempty"`
	ResultBytes int           `json:"result_bytes,omitempty"`
	Truncated   bool          `json:"truncated,omitempty"`
	StartedAt   time.Time     `json:"started_at,omitzero"`
	CompletedAt time.Time     `json:"completed_at,omitzero"`
}

Result is the output of a tool execution.

type Schema

type Schema struct {
	Name        string          `json:"name"`
	Description string          `json:"description"`
	Parameters  json.RawMessage `json:"parameters"` // JSON Schema object
}

Schema describes a tool's interface for LLM function-calling.

type ShellParams

type ShellParams struct {
	Command string `json:"command"`
	Timeout int    `json:"timeout,omitempty"` // seconds, defaults to 120
}

ShellParams are the parameters for the shell tool.

type Tool

type Tool struct {
	Schema  Schema
	Execute Executor
	Source  string // "builtin", "extension:<name>"
}

Tool is a registered tool comprising its schema and executor.

func NewEditTool

func NewEditTool(cwd string, mq *MutationQueue, rt *ReadTracker) Tool

NewEditTool creates the built-in edit tool.

func NewFindTool

func NewFindTool(cwd string) Tool

NewFindTool creates the built-in find tool.

func NewGrepTool

func NewGrepTool(cwd string, indexes ...GrepIndex) Tool

func NewReadTool

func NewReadTool(cwd string, rt *ReadTracker) Tool

NewReadTool creates the built-in read tool.

func NewShellTool

func NewShellTool(cwd string, mq *MutationQueue) Tool

NewShellTool creates the built-in shell execution tool.

func NewWriteTool

func NewWriteTool(cwd string, mq *MutationQueue, rt *ReadTracker) Tool

NewWriteTool creates the built-in write tool.

type TruncationResult

type TruncationResult struct {
	Content      string
	Truncated    bool
	OriginalSize int
	OriginalLine int
	OutputLines  int // number of complete lines kept in Content
}

TruncationResult holds the potentially truncated content and metadata.

func TruncateHead

func TruncateHead(content string, maxLines, maxBytes int) TruncationResult

TruncateHead keeps the first N lines/bytes, dropping the tail, and appends a generic truncation notice. Good for search results and listings.

func TruncateHeadRaw

func TruncateHeadRaw(content string, maxLines, maxBytes int) TruncationResult

TruncateHeadRaw keeps the first N lines/bytes, dropping the tail, without appending a truncation notice. Callers append their own context-specific notice (e.g. read's "Use offset=N to continue"). Never returns partial lines: if the first line alone exceeds maxBytes, Content is empty with OutputLines 0.

func TruncateTail

func TruncateTail(content string, maxLines, maxBytes int) TruncationResult

TruncateTail keeps the last N lines/bytes, dropping the head. Good for logs, command output.

type UIBridge

type UIBridge interface {
	Confirm(ctx context.Context, title, description string) (bool, error)
	Select(ctx context.Context, title string, options []string) (string, error)
	Input(ctx context.Context, title, placeholder string) (string, error)
	Notify(title, level string)
	Log(chunk string)
	// SessionID returns the session this bridge instance is scoped to for
	// the current tool call, or "" when there is no session context (e.g.
	// NonInteractiveBridge). Tools that need to correlate their own
	// forwarded events to the calling session (e.g. the agent tool) read
	// this instead of requiring it to be threaded through static config.
	SessionID() string
}

UIBridge allows tools to interact with the user through the TUI. This interface is satisfied by the extension/ui bridge implementation.

type WriteParams

type WriteParams struct {
	Path      string `json:"path"`
	Content   string `json:"content"`
	Overwrite bool   `json:"overwrite,omitempty"`
}

WriteParams are the parameters for the write tool.

Directories

Path Synopsis
Package rg embeds a statically-linked ripgrep binary and exposes a single entry point so the grep tool can always use authoritative rg matching.
Package rg embeds a statically-linked ripgrep binary and exposes a single entry point so the grep tool can always use authoritative rg matching.

Jump to

Keyboard shortcuts

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