tool

package
v0.3.2 Latest Latest
Warning

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

Go to latest
Published: May 4, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Package tool provides a unified ToolRegistry that normalizes built-in tools and MCP server tools under a single namespace and resolution scheme.

Built-in tools are registered under their bare name (e.g. "git_diff"). MCP tools follow the namespace convention "mcp.<server>.<tool>". Workflows reference tools by their qualified name; the registry resolves them unambiguously and detects collisions at registration time.

Index

Constants

This section is empty.

Variables

View Source
var ErrToolDenied = fmt.Errorf("tool: denied by policy")

ErrToolDenied is returned when a tool call is rejected by the policy.

Functions

func IsMCPName

func IsMCPName(name string) bool

IsMCPName returns true if the qualified name follows the MCP convention.

func IsMCPWildcard

func IsMCPWildcard(name string) bool

IsMCPWildcard returns true if name matches the MCP server wildcard pattern "mcp.<server>.*".

func ParseMCPName

func ParseMCPName(qualified string) (server, toolName string, err error)

ParseMCPName splits "mcp.<server>.<tool>" into server and tool name. Returns an error if the format is invalid.

func ParseMCPWildcard

func ParseMCPWildcard(name string) (server string, err error)

ParseMCPWildcard extracts the server name from a wildcard pattern "mcp.<server>.*". Returns an error if the format is invalid.

func RegisterAskUser

func RegisterAskUser(reg *Registry, handler AskUserHandler) error

RegisterAskUser registers claw-code-go's native `ask_user` tool. The handler controls behaviour: when nil, the default raises delegate.ErrAskUser so iterion's pause/resume flow takes over (CLI prompt → answer injection on resume). Tests and headless runners supply a handler that returns an Answer directly so the workflow proceeds inline.

The tool is available to any node with `interaction:` enabled; iterion's executor auto-includes it in such nodes' resolved tool list so workflow authors don't need to add `ask_user` to their `tools:` field.

func RegisterClawAll

func RegisterClawAll(reg *Registry, defaults ClawDefaults) error

RegisterClawAll registers the full curated set of claw tools (file IO, shell, search, web fetch, simple utilities, todo, subagents, plan mode, tasks, workers, teams, cron, MCP resources, LSP, tool_search) against reg using the registries and per-session state in defaults. It is the preferred one-shot entry point for hosts that want every iterion-supported tool surfaced without thinking about which family to wire.

Tools not yet usable from a workflow because the LLM would call them without context (web_search → needs BRAVE_API_KEY, computer_use → needs vision-capable model) are gated by explicit opt-in flags on ClawDefaults.

Calling this twice on the same registry will fail on the second call due to duplicate-name detection in the registry.

func RegisterClawBuiltins

func RegisterClawBuiltins(reg *Registry, workspace string) error

RegisterClawBuiltins registers the standard claw-code-go built-in tools against the given Registry, making them callable by claw-backend agents that declare e.g. `tools: [read_file, write_file, bash]` in their .iter fixture.

Workspace is forwarded to the bash tool for command validation; pass an empty string to skip workspace-based validation. Pass an empty string when registering on a registry that may be reused across workspaces.

The set is intentionally curated — these are the seven workflow-grade tools that map cleanly onto file IO, shell, search, and HTTP fetch. Specialised tools (todo_write, plan_mode, agent, mcp_*, ...) live in claw-code-go's internal/tools/ and are not auto-registered here; callers that need them should import claw-code-go/pkg/api/tools and register individual entries via RegisterClawTool.

func RegisterClawBuiltinsWithEnv

func RegisterClawBuiltinsWithEnv(reg *Registry, workspace string, bashExtraEnv []string) error

RegisterClawBuiltinsWithEnv is RegisterClawBuiltins plus an optional extraEnv slice (KEY=value entries) that the bash tool will append to the inherited environment on every call. Use this when iterion is invoked outside its devbox/nix shell and the caller wants to surface the project toolchain (go, gofmt, ...) to the LLM-driven shell so fixers can validate their patches in-loop. Pass nil for plain inheritance.

func RegisterClawComputerUse

func RegisterClawComputerUse(reg *Registry) error

RegisterClawComputerUse registers the desktop-control tools that require an X11 display — screenshot and the unified computer_use action dispatcher (left_click / right_click / middle_click / double_click / type / key / mouse_move / cursor_position / left_click_drag). Kept out of the default RegisterClawBuiltins set because most iterion workflows are headless; opt in via Defaults.IncludeComputerUse when you have an agent targeting a display (Xvfb covered by the live coverage test).

On a host without xdotool / ImageMagick `import` (or without a display), each call returns ErrComputerUseUnavailable wrapped — agents can detect the gap with errors.Is rather than parsing strings.

func RegisterClawConfig

func RegisterClawConfig(reg *Registry, configMap map[string]any) error

RegisterClawConfig registers the `config` tool against a host-supplied flat configuration map. Pass an empty map (not nil) if you have no configuration to expose — the tool will report `found: false` for every key, which is still a valid live result.

func RegisterClawCron

func RegisterClawCron(reg *Registry, cronReg *clawteam.CronRegistry) error

RegisterClawCron registers the four cron_* tools that share a *team.CronRegistry. Cron entries hold scheduled task prompts.

func RegisterClawLSP

func RegisterClawLSP(reg *Registry, lspReg *clawlsp.Registry) error

RegisterClawLSP registers the `lsp` action-dispatcher tool. The lsp.Registry tracks connected language servers; build it once via clawlsp.NewRegistry().

func RegisterClawMCPResources

func RegisterClawMCPResources(reg *Registry, provider clawmcp.Provider) error

RegisterClawMCPResources registers list_mcp_resources, read_mcp_resource and mcp_auth against the supplied Provider. The Provider is the one bridge between iterion's MCP manager and claw's resource introspection tools — passing nil falls back to an empty in-process Registry, which is fine for tests but not for hosts that already manage their own MCP servers.

func RegisterClawPlanMode

func RegisterClawPlanMode(reg *Registry, state *clawtools.PlanModeState) error

RegisterClawPlanMode registers `enter_plan_mode` and `exit_plan_mode`. Both tools share a *PlanModeState so they can coordinate the active flag and on-disk persistence directory.

func RegisterClawReadImage

func RegisterClawReadImage(reg *Registry) error

RegisterClawReadImage registers `read_image` only — the file/URL loader that returns a base64 content block downstream multimodal agents can splice into their next message. Unlike screenshot / computer_use this tool does not require a display, so it's safe in headless workflows.

func RegisterClawSimple

func RegisterClawSimple(reg *Registry) error

RegisterClawSimple registers the no-dependency claw tools that don't fit naturally into the file-IO/shell/HTTP set RegisterClawBuiltins covers: send_user_message, remote_trigger, sleep, notebook_edit, repl, structured_output. These are useful for nodes that want process-level utilities (timing, cell edits, REPL evaluation) but don't need a registry plumbed in.

func RegisterClawSkill

func RegisterClawSkill(reg *Registry, workDir string) error

RegisterClawSkill registers the `skill` tool, looking up skills at <workDir>/.claude/skills/. Pass an empty workDir to resolve against the process CWD.

func RegisterClawSubagents

func RegisterClawSubagents(reg *Registry, runner SubagentRunner) error

RegisterClawSubagents registers the `agent` tool. When `runner` is nil, the registration falls back to claw's metadata-only stub — useful for stand-alone tests where actually launching a child conversation is out of scope. When `runner` is non-nil, it is invoked directly: the LLM's tool_use lands in the runner, which is expected to coordinate the child loop.

func RegisterClawTasks

func RegisterClawTasks(reg *Registry, taskReg *clawtask.Registry) error

RegisterClawTasks registers the seven task_* tools (task_create, task_get, task_list, task_output, task_stop, task_update, run_task_packet). All share the same *task.Registry; pass a single instance built via clawtask.NewRegistry().

func RegisterClawTeams

func RegisterClawTeams(reg *Registry, teamReg *clawteam.TeamRegistry) error

RegisterClawTeams registers the four team_* tools that share a *team.TeamRegistry. Teams are named groupings of task IDs.

func RegisterClawTodo

func RegisterClawTodo(reg *Registry) error

RegisterClawTodo registers the `todo_write` tool for read/write of the project todo list at .claude/todos.json. No dependency.

func RegisterClawTool

func RegisterClawTool(reg *Registry, t api.Tool, exec func(ctx context.Context, input map[string]any) (string, error)) error

RegisterClawTool registers a single claw-code-go tool against the registry. Use this to add specialised tools that RegisterClawBuiltins does not include by default.

func RegisterClawToolSearch

func RegisterClawToolSearch(reg *Registry, snapshot ToolSnapshot) error

RegisterClawToolSearch registers the `tool_search` meta-tool. The snapshot closure is invoked on every call to capture the live tool catalog; pass nil to use an empty haystack (degraded but valid).

func RegisterClawWebSearch

func RegisterClawWebSearch(reg *Registry) error

RegisterClawWebSearch registers the `web_search` tool. Reads BRAVE_API_KEY (or compatible) at execute time; absence surfaces as a tool error.

func RegisterClawWorkers

func RegisterClawWorkers(reg *Registry, workerReg *clawworker.WorkerRegistry) error

RegisterClawWorkers registers the nine worker_* tools that share a *worker.WorkerRegistry. Workers are subprocess agents the runtime spawns and observes; the registry tracks their lifecycle.

func SchemaFingerprint

func SchemaFingerprint(schema json.RawMessage) string

SchemaFingerprint computes a deterministic SHA-256 hex digest of a JSON schema. The input is unmarshalled and re-marshalled to produce canonical (sorted-key, compact) JSON before hashing. Returns an empty string for nil or empty input.

Types

type AskUserHandler

type AskUserHandler func(ctx context.Context, q clawtools.Question) (clawtools.Answer, error)

AskUserHandler is invoked when the LLM calls ask_user. Returning an Answer + nil error completes the call inline (no workflow pause); returning an error of type *delegate.ErrAskUser triggers iterion's pause/resume flow. nil falls back to the latter (default behaviour).

type ClassifierChecker

type ClassifierChecker struct {
	Classifier permissions.Classifier
	Base       ToolChecker
	Logger     ClassifierLogger
}

ClassifierChecker wraps a permissions.Classifier (typically LLMClassifier chained over RuleClassifier) into iterion's ToolChecker interface. The classifier is consulted first and short-circuits on Allow/Deny; Ask falls through to the optional base checker.

A nil ClassifierChecker.Base treats Ask as Allow (the static policy is optional). Use BuildChecker as the base to keep workflow-level allowlists and per-node overrides intact while letting an LLMClassifier veto or pre-approve calls.

Logger is optional; when set, classifier errors and JSON decoding failures are surfaced at Warn level. Without a logger, errors fall through silently to the base checker (legacy behavior).

func (*ClassifierChecker) CheckContext

func (cc *ClassifierChecker) CheckContext(pctx PolicyContext) error

CheckContext implements ToolChecker.

type ClassifierLogger

type ClassifierLogger interface {
	Warn(format string, args ...any)
	Debug(format string, args ...any)
}

ClassifierLogger is the minimal logging surface ClassifierChecker uses to surface classifier errors and malformed inputs without coupling the tool package to a concrete logger. Both methods accept printf-style arguments.

log.Logger satisfies this interface implicitly via its Warn/Debug methods.

type ClawDefaults

type ClawDefaults struct {
	// Workspace is forwarded to bash for command validation and to the
	// skill tool for skill lookup. Leave empty to skip workspace
	// gating.
	Workspace string

	// Tasks, Workers, Teams, Crons, LSP hold the registries each tool
	// family needs. Leave nil to have RegisterClawAll allocate a fresh
	// empty registry.
	Tasks   *clawtask.Registry
	Workers *clawworker.WorkerRegistry
	Teams   *clawteam.TeamRegistry
	Crons   *clawteam.CronRegistry
	LSP     *clawlsp.Registry

	// MCPProvider feeds list_mcp_resources / read_mcp_resource /
	// mcp_auth. Hosts (e.g. iterion's MCP manager) implement the
	// Provider interface to avoid double-connecting servers; tests can
	// pass a Registry-backed provider via clawmcp.NewRegistryProvider.
	// Leave nil for RegisterClawAll to wire an empty in-process
	// Registry-backed provider — useful for stand-alone claw smoke
	// tests, not for hosts that have their own MCP infrastructure.
	MCPProvider clawmcp.Provider

	// Subagent, when non-nil, replaces claw's default metadata-only
	// agent executor with a real child-conversation runner. Hosts
	// build this via model.NewSubagentRunner. When nil, the agent
	// tool stays a stub (smoke-test parity).
	Subagent SubagentRunner

	// AskUser, when non-nil, replaces the default ask_user handler
	// (which raises delegate.ErrAskUser to trigger pause/resume) with
	// an inline handler. Tests use this to auto-answer the LLM so the
	// workflow continues without pausing.
	AskUser AskUserHandler

	// PlanMode is shared by enter_plan_mode and exit_plan_mode so the
	// pair can coordinate. Nil disables plan_mode tooling.
	PlanMode *clawtools.PlanModeState

	// IncludeWebSearch toggles registration of the `web_search` tool.
	// Off by default because it falls back to scraping DuckDuckGo Lite
	// when BRAVE_API_KEY is unset, which is brittle; tests typically
	// override the URL via env to point at a fixture.
	IncludeWebSearch bool

	// IncludeComputerUse toggles screenshot + computer_use registration.
	// Off by default since both require an X11 display. read_image is
	// always registered (no display needed).
	IncludeComputerUse bool

	// Config, when non-nil, is exposed via the `config` tool. Leave
	// nil to surface an empty map — the tool will still register but
	// every key lookup reports `found: false`.
	Config map[string]any

	// BashExtraEnv, when non-empty, is appended to the inherited
	// environment of every bash tool invocation (KEY=value entries).
	// Use this to surface a project-managed toolchain (devbox / nix /
	// asdf) bin path so the LLM-driven shell can run go/gofmt/etc.
	// even when the operator did not prefix the iterion launch with
	// `devbox run --`. Nil/empty means plain os.Environ() inheritance.
	BashExtraEnv []string
}

ClawDefaults bundles the registries and per-session state the optional claw tool families need. Hosts (e.g. iterion's CLI) build one ClawDefaults per run and pass it to RegisterClawAll, which wires every supported tool against shared in-memory state.

Field zero-values are populated lazily by RegisterClawAll so callers can opt into specific subsystems by leaving the rest at zero.

type Origin

type Origin struct {
	Kind   OriginKind // builtin or mcp
	Server string     // MCP server name (empty for built-ins)
}

Origin describes the provenance of a tool.

type OriginKind

type OriginKind int

OriginKind discriminates built-in vs MCP tools.

const (
	OriginBuiltin OriginKind = iota
	OriginMCP
)

func (OriginKind) String

func (ok OriginKind) String() string

type Policy

type Policy struct {
	// AllowedTools is the list of tool name patterns.
	// nil = open (everything allowed). Empty slice = deny all.
	AllowedTools []string
}

Policy controls which tools may be executed during a run. It enforces an allowlist of tool name patterns. If the allowlist is nil (zero-value), all tools are allowed (open policy). An empty non-nil allowlist denies everything.

Pattern syntax:

  • "*" → allow all tools
  • "git_diff" → exact match on qualified name
  • "mcp.github.*" → prefix match: any tool under the mcp.github namespace
  • "run_command" → exact match on a built-in

func DenyAllPolicy

func DenyAllPolicy() *Policy

DenyAllPolicy returns a policy that denies every tool.

func NewPolicy

func NewPolicy(patterns ...string) *Policy

NewPolicy creates a policy with the given allowed tool patterns.

func OpenPolicy

func OpenPolicy() *Policy

OpenPolicy returns a policy that allows all tools.

func (*Policy) Check

func (p *Policy) Check(qualifiedName string) error

Check returns nil if the tool is allowed, or a descriptive error if denied.

func (*Policy) CheckContext

func (p *Policy) CheckContext(ctx PolicyContext) error

CheckContext implements ToolChecker for the static Policy. It delegates to Check, ignoring all context fields except ToolName.

func (*Policy) IsAllowed

func (p *Policy) IsAllowed(qualifiedName string) bool

IsAllowed returns true if the given tool qualified name is permitted by this policy.

type PolicyContext

type PolicyContext struct {
	Ctx      context.Context
	NodeID   string
	NodeKind string // "agent", "judge", "tool", etc.
	ToolName string
	Input    json.RawMessage        // nil when unavailable
	Vars     map[string]interface{} // workflow vars, read-only
}

PolicyContext carries evaluation context for dynamic policies.

Ctx is the caller's request context. Checkers that perform I/O (LLM classifiers, remote rule lookups) must honour it for cancellation and deadlines. A nil Ctx is treated as context.Background by the classifier wrapper for backward compatibility, but callers should always populate it.

type Registry

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

Registry is a thread-safe store for tool definitions. It enforces unique qualified names and provides resolution by name.

func NewRegistry

func NewRegistry() *Registry

NewRegistry creates an empty tool registry.

func (*Registry) Len

func (r *Registry) Len() int

Len returns the number of registered tools.

func (*Registry) List

func (r *Registry) List() []*ToolDef

List returns all registered tools. The order is not guaranteed.

func (*Registry) ListByOrigin

func (r *Registry) ListByOrigin(kind OriginKind) []*ToolDef

ListByOrigin returns tools filtered by origin kind.

func (*Registry) ListByServer

func (r *Registry) ListByServer(server string) []*ToolDef

ListByServer returns tools from a specific MCP server.

func (*Registry) RegisterBuiltin

func (r *Registry) RegisterBuiltin(name string, desc string, schema json.RawMessage, exec func(ctx context.Context, input json.RawMessage) (string, error)) error

RegisterBuiltin adds a built-in tool. The name must not contain dots. Returns an error if the name collides with an existing registration.

func (*Registry) RegisterMCP

func (r *Registry) RegisterMCP(server, toolName, desc string, schema json.RawMessage, exec func(ctx context.Context, input json.RawMessage) (string, error)) error

RegisterMCP adds an MCP tool with the qualified name "mcp.<server>.<tool>". Both server and toolName must be non-empty and must not contain dots. Returns an error on collision.

func (*Registry) Resolve

func (r *Registry) Resolve(ref string) (*ToolDef, error)

Resolve looks up a tool by its reference name. Resolution rules:

  1. Exact match on qualified name.
  2. If ref has no dots and there is exactly one MCP tool whose bare name matches, return it (convenience shorthand). If multiple MCP tools share the same bare name, return an ambiguity error.

Returns an error if the tool is not found or is ambiguous.

func (*Registry) ResolveAll

func (r *Registry) ResolveAll(refs []string) ([]llmtypes.LLMTool, error)

ResolveAll resolves a list of tool references and returns the corresponding llmtypes.LLMTool slice. It stops at the first resolution error.

func (*Registry) ResolveMap

func (r *Registry) ResolveMap(refs []string) (map[string]llmtypes.LLMTool, error)

ResolveMap resolves a list of tool references and returns a map keyed by qualified name. Useful for the executor's tool lookup table.

type Rule

type Rule struct {
	NodeIDs  []string               // nil = any node
	NodeKind string                 // "" = any kind
	VarMatch map[string]interface{} // nil = any vars
	Allow    []string               // patterns to allow if this rule matches
	Deny     bool                   // if true, deny matched tools instead
}

Rule is a single conditional rule in a RulePolicy.

type RulePolicy

type RulePolicy struct {
	Rules    []Rule
	Fallback *Policy // nil = open (allow all if no rule matched)
}

RulePolicy evaluates an ordered list of conditional rules using first-match-wins semantics. If no rule matches, the Fallback policy is consulted. A nil Fallback means open (allow all).

func (*RulePolicy) CheckContext

func (rp *RulePolicy) CheckContext(ctx PolicyContext) error

CheckContext implements ToolChecker.

type SubagentRunner

type SubagentRunner func(ctx context.Context, input map[string]any) (string, error)

SubagentRunner is the host-supplied closure invoked when the LLM calls the agent tool. It receives the validated input map, spawns a child LLM conversation (typically against the same model registry the parent uses), and returns the child's final result formatted as JSON. Returning a string + nil error treats the call as successful; any non-nil error is surfaced to the LLM as a tool error.

type ToolChecker

type ToolChecker interface {
	CheckContext(ctx PolicyContext) error
}

ToolChecker is the interface for contextual tool policy evaluation.

func BuildChecker

func BuildChecker(workflowPatterns []string, nodeOverrides map[string][]string, varRules []VarRule) ToolChecker

BuildChecker constructs a ToolChecker from workflow-level patterns, optional per-node overrides, and optional var-conditional rules. Returns a simple *Policy when no overrides or rules are needed.

type ToolDef

type ToolDef struct {
	// QualifiedName is the unique key in the registry.
	// Built-ins: "git_diff"
	// MCP tools: "mcp.github.create_issue"
	QualifiedName string

	// Description explains what the tool does.
	Description string

	// InputSchema is the JSON Schema for the tool's input parameters.
	InputSchema json.RawMessage

	// Execute runs the tool with the given JSON input.
	Execute func(ctx context.Context, input json.RawMessage) (string, error)

	// Origin tracks where this tool came from.
	Origin Origin
}

ToolDef is the registry's canonical tool representation. Both built-in and MCP tools are stored as ToolDefs.

func (*ToolDef) ToDelegateDef

func (td *ToolDef) ToDelegateDef() delegate.ToolDef

ToDelegateDef converts a ToolDef into a delegate.ToolDef, which is the execution contract consumed by the backend dispatch layer.

func (*ToolDef) ToLLMTool

func (td *ToolDef) ToLLMTool() llmtypes.LLMTool

ToLLMTool converts a ToolDef into an llmtypes.LLMTool, which is the execution contract consumed by the LLM generation layer. Both built-in and MCP tools produce the exact same LLMTool shape. Tool names are sanitized (dots → underscores) for API compatibility.

type ToolSnapshot

type ToolSnapshot func() []api.Tool

ToolSnapshot returns the set of tools the model should see as the search haystack. Hosts pass a closure (instead of a static slice) so the snapshot is captured at execute time, after every other tool has been registered.

type VarRule

type VarRule struct {
	VarMatch map[string]interface{} // vars that must match
	Allow    []string               // tool patterns to allow when matched
}

VarRule maps a set of var conditions to tool patterns. When all vars match, the listed patterns are allowed.

Jump to

Keyboard shortcuts

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