tools

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Jul 9, 2026 License: MIT Imports: 41 Imported by: 0

Documentation

Index

Constants

View Source
const (
	ExecCommandToolName = "exec_command"
	WriteStdinToolName  = "write_stdin"
)
View Source
const (
	SandboxLikelyDeniedMeta  = "sandbox_likely_denied"
	SandboxDenialKindMeta    = "sandbox_denial_kind"
	SandboxDenialReasonMeta  = "sandbox_denial_reason"
	SandboxDenialKeywordMeta = "sandbox_denial_keyword"
)
View Source
const (
	SandboxDenialKindSandbox = "sandbox"
	SandboxDenialKindNetwork = "network"
)
View Source
const RequestPermissionsToolName = "request_permissions"
View Source
const ToolSearchToolName = "tool_search"

ToolSearchToolName is the canonical registry name of the deferred-tool loader. It is exported so the agent loop, CLI filter validation, and the partition can reference the loader without re-stating the literal (keeping all the gates that must treat it specially in agreement).

Variables

View Source
var ErrFileChangedOnDisk = errors.New("the file changed on disk since you last read it")

ErrFileChangedOnDisk is returned by CheckConflict when a file's current on-disk content no longer matches what a tool last read or wrote in this session — i.e. it was modified outside Zero. The write tools surface it with guidance to re-read before retrying, so a stale overwrite cannot silently clobber an external edit.

Functions

func AskUserNonInteractiveMessage

func AskUserNonInteractiveMessage() string

AskUserNonInteractiveMessage exposes the shared graceful-degradation message so the agent loop and the tool fallback stay in lock-step.

func BuildToolSearchDescription

func BuildToolSearchDescription(deferred []Tool) string

BuildToolSearchDescription renders the model-facing discovery instructions for deferred tools. This belongs on the tool_search tool definition, not as an extra user message, so the model can discover tools without treating discovery metadata as something to answer or acknowledge.

func DeferredLine

func DeferredLine(t Tool) string

DeferredLine renders the compact advertisement line for a single deferred tool, deriving the MCP server label from the tool's reported server name when available, falling back to the token parsed from the tool's name. It is the exported entry point the agent loop uses to build compact deferred metadata, so callers in other packages never touch the unexported formatters.

func DeferredSource

func DeferredSource(t Tool) string

DeferredSource reports the compact source label used in tool_search's dynamic description. MCP tools use their configured server name; other deferred tools fall back to the first name segment so families such as swarm_* are grouped.

func DeferredToolDiscoveryLine

func DeferredToolDiscoveryLine(t Tool) string

DeferredToolDiscoveryLine renders the compact name/source entry used in tool_search's dynamic description. It intentionally omits descriptions and schemas; those are revealed only after tool_search loads a matching tool.

func FormatAskUserAnswers

func FormatAskUserAnswers(questions []AskUserQuestion, answers []string) string

FormatAskUserAnswers renders question/answer pairs into a clear, model-readable block. Missing answers are surfaced explicitly so the model never silently treats an unanswered question as answered.

It distinguishes two shapes of "empty" the model would otherwise conflate: a wholesale dismissal (the user closed the prompt without answering ANYTHING) is flagged up front as a skip, so the model doesn't invent a default; a single blank field amid other answers is marked "(left blank)".

func HashContent

func HashContent(content []byte) string

HashContent returns the hex-encoded SHA-256 of content. Exported so the write tools and tests share one definition of a file's identity.

func IsDeferralEligible

func IsDeferralEligible(t Tool) bool

IsDeferralEligible reports whether a tool counts toward the DeferThreshold. A currently-deferred tool always counts. A tool may ALSO opt in via DeferralEligible() to keep counting while exposed eagerly (see above). This is the count partitionTools uses for the active-gate; whether a tool is actually hidden is still decided by IsDeferred.

func IsDeferred

func IsDeferred(t Tool) bool

IsDeferred reports whether a tool opts into deferred loading. A tool is deferred-eligible only if it implements deferredTool and its Deferred() method returns true; tools that do not implement the interface are eager.

func MsysProneCommandName added in v0.2.0

func MsysProneCommandName(name string) bool

MsysProneCommandName reports whether a bare command name commonly resolves to a Git-for-Windows MSYS binary that fails under the Windows restricted sandbox.

func MutationTargets

func MutationTargets(workspaceRoot string, name string, args map[string]any) []string

MutationTargets returns the workspace-relative paths a tool call will write to, so the session layer can snapshot their before-state for safe rewind. It is a pure helper (no I/O beyond path resolution) and returns nil for read-only tools and for bash (whose affected paths are not knowable before execution).

func NewAskUserTool

func NewAskUserTool() *askUserTool

NewAskUserTool builds the ask_user tool. It is read-only (it gathers input, never mutates the workspace). The agent loop intercepts ask_user calls and routes them to an interactive front-end when one exists; this tool's Run() is the fallback used when nothing intercepts the call (e.g. headless runs).

func NewSkillTool

func NewSkillTool(dir string) *skillTool

NewSkillTool builds the skill tool. An empty dir resolves to the standard skills data directory (skills.DefaultDir); pass an explicit dir in tests.

func NewUpdatePlanTool

func NewUpdatePlanTool() *updatePlanTool

Types

type ArgsPermissioner

type ArgsPermissioner interface {
	PermissionForArgs(args map[string]any) Permission
}

ArgsPermissioner is an optional interface a Tool can implement to refine its permission for a SPECIFIC call based on its arguments. When a tool implements it, the agent loop consults PermissionForArgs(args) instead of the static Safety().Permission when deciding whether the call needs approval. It exists to safely RELAX a prompt to allow for arguments the tool can prove are harmless (e.g. delegating to a read-only sub-agent); a tool must return its static, stricter permission whenever it cannot prove the call is safe.

type AskUserQuestion

type AskUserQuestion struct {
	Question           string
	Header             string
	Options            []string
	OptionDescriptions []string
	Recommended        string
	MultiSelect        bool
}

AskUserQuestion is one clarifying question the agent wants the user to answer. Options/MultiSelect are presentation hints for an interactive front-end; the tool itself never blocks on input.

func ParseAskUserQuestions

func ParseAskUserQuestions(args map[string]any) ([]AskUserQuestion, error)

ParseAskUserQuestions extracts the questionnaire from raw tool arguments. It is shared by the tool's Run() fallback and the agent loop's interactive path so both validate identically.

type Display

type Display struct {
	Summary string
	Kind    string // e.g. file, diff, search, shell
	// Preview is a multi-line, card-only body (e.g. a unified diff or file head)
	// for the TUI. It is NEVER sent to the model — Output stays the short summary
	// the model sees — so a rich code preview costs zero model tokens.
	Preview string
}

Display carries a short, structured summary of a tool result for the TUI/stream.

type ExecSessionController

type ExecSessionController interface {
	ExecSessions() []ExecSessionSnapshot
	StopExecSession(id int) bool
	StopAllExecSessions() []int
}

type ExecSessionSnapshot

type ExecSessionSnapshot struct {
	ID           int
	Command      string
	Cwd          string
	RelativeCwd  string
	StartedAt    time.Time
	LastUsedAt   time.Time
	TTY          bool
	Status       string
	ExitCode     *int
	RecentOutput string
	// OutputTruncated reflects the buffer's last-known truncation state (see
	// execOutputBuffer.peekTruncated), so a session listing (/ps) still shows
	// this even if the session is reaped before ever being polled again.
	OutputTruncated bool
}

type FileTracker

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

FileTracker records, per absolute path, the version of each file a tool read or wrote within a single session. A later write compares the current on-disk content against this baseline to detect a modification made outside Zero.

Construct with NewFileTracker. A nil *FileTracker is a valid no-op — every method tolerates it — so a caller that has not wired the feature (tests, MCP) needs no nil guards.

func NewFileTracker

func NewFileTracker() *FileTracker

func (*FileTracker) CheckConflict

func (tracker *FileTracker) CheckConflict(absPath string, currentContent []byte) error

CheckConflict reports ErrFileChangedOnDisk when absPath has a recorded baseline and currentContent (the bytes the caller just read from disk) no longer matches it. An untracked path returns nil: with no baseline there is nothing to conflict against, so a first-touch write is always allowed.

func (*FileTracker) CreatedFiles added in v0.3.0

func (tracker *FileTracker) CreatedFiles() []string

CreatedFiles returns the absolute paths of every brand-new file recorded via RecordCreated during this session, in first-created order. The caller owns the returned slice.

func (*FileTracker) Forget

func (tracker *FileTracker) Forget(absPath string)

Forget drops any recorded version for absPath, so the next read re-establishes the baseline. Used after a tool rewrites a file by a path other than its own (e.g. apply_patch) where the new content is not cheaply available to Record.

func (*FileTracker) Record

func (tracker *FileTracker) Record(absPath string, content []byte, info os.FileInfo)

Record stores the version of absPath given its content and optional stat info.

func (*FileTracker) RecordCreated added in v0.3.0

func (tracker *FileTracker) RecordCreated(absPath string)

RecordCreated notes that absPath is a brand-new file a tool just created in this session (as opposed to an overwrite of something that already existed).

func (*FileTracker) RecordHash added in v0.3.0

func (tracker *FileTracker) RecordHash(absPath string, hash string, info os.FileInfo)

RecordHash stores the version of absPath when the caller already computed the same HashContent-compatible SHA-256 while reading the file.

func (*FileTracker) Version

func (tracker *FileTracker) Version(absPath string) (FileVersion, bool)

Version returns the recorded version for absPath and whether one exists.

type FileVersion

type FileVersion struct {
	Hash  string
	Size  int64
	MTime time.Time
}

FileVersion is what a tool last observed for a file: an authoritative content hash plus cheap stat metadata kept for diagnostics.

type LocalControlArtifactOptions

type LocalControlArtifactOptions struct {
	Browser      localcontrol.BrowserOptions
	Desktop      localcontrol.DesktopOptions
	Terminal     localcontrol.TerminalOptions
	ArtifactsDir string
}

type PathScope

type PathScope interface {
	Roots() []string
}

PathScope is the multi-root write scope shared with the sandbox engine. *sandbox.Scope satisfies it; nil means workspace-only (today's behavior). Roots()[0] must be the workspace root (sandbox.Scope guarantees this ordering); relative paths and error messages key off it.

type Permission

type Permission string
const (
	PermissionAllow  Permission = "allow"
	PermissionPrompt Permission = "prompt"
	PermissionDeny   Permission = "deny"
)

type PlanItem

type PlanItem struct {
	ID      string
	Content string
	Status  string
	Notes   string
}

type PrePermissionRejecter

type PrePermissionRejecter interface {
	RejectBeforePermission(args map[string]any) (Result, bool)
}

PrePermissionRejecter lets a tool reject a call that cannot safely or validly run before any permission prompt is shown. Implementations must be purely local and deterministic: no filesystem, process, DNS, or network access.

type PropertySchema

type PropertySchema struct {
	Type        string          `json:"type"`
	Description string          `json:"description,omitempty"`
	Enum        []string        `json:"enum,omitempty"`
	Default     any             `json:"default,omitempty"`
	Items       *PropertySchema `json:"items,omitempty"`
	Minimum     *int            `json:"minimum,omitempty"`
	Maximum     *int            `json:"maximum,omitempty"`
	MinLength   *int            `json:"minLength,omitempty"`
	MinItems    *int            `json:"minItems,omitempty"`
	// Properties/Required describe nested object fields (for Type "object" or an
	// object-typed Items).
	Properties map[string]PropertySchema `json:"properties,omitempty"`
	Required   []string                  `json:"required,omitempty"`
}

type Registry

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

func NewRegistry

func NewRegistry() *Registry

func (*Registry) All

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

func (*Registry) Get

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

func (*Registry) Register

func (registry *Registry) Register(tool Tool)

func (*Registry) Run

func (registry *Registry) Run(ctx context.Context, name string, args map[string]any) Result

func (*Registry) RunWithOptions

func (registry *Registry) RunWithOptions(ctx context.Context, name string, args map[string]any, options RunOptions) (result Result)

type Result

type Result struct {
	Status          Status
	Output          string
	Truncated       bool
	Meta            map[string]string
	SandboxDecision *sandbox.Decision `json:"-"`
	// Redacted is set when secret scrubbing altered Output before it left the
	// tool-execution boundary.
	Redacted bool
	// ChangedFiles lists workspace-relative paths a mutating tool wrote;
	// entries under a granted extra write root are absolute, since
	// workspace-relative would be ambiguous there.
	ChangedFiles []string
	// Display carries a short, structured summary for the TUI / stream.
	Display Display
}

type RunOptions

type RunOptions struct {
	PermissionGranted bool
	PermissionMode    string
	Autonomy          string
	Sandbox           *sandbox.Engine
	ToolCallID        string
	SessionID         string
	Model             string
	ReasoningEffort   string
	Depth             int
	Cwd               string
	// FileTracker, when set, records the version of each file read or written this
	// session so write_file/edit_file can refuse to clobber a file that changed on
	// disk outside Zero since it was last read. nil disables the feature entirely
	// (the read/write tools behave exactly as before).
	FileTracker *FileTracker
	// EnabledTools / DisabledTools carry the run's operator tool filters so a
	// filter-aware tool (tool_search) never discloses or loads an operator-hidden
	// tool. They use the same allow/deny semantics as the agent's filter gate:
	// denied if listed in DisabledTools; if EnabledTools is non-empty, allowed
	// only when listed in it.
	EnabledTools  []string
	DisabledTools []string
	// Progress, when set, is called with each stream-json event emitted by a
	// specialist child process while it runs. Used by the TUI to show live
	// tool-call progress in the specialist card. nil is a no-op (the default
	// for every non-Task tool).
	Progress func(streamjson.Event)
	// Diagnostics, when set, returns a formatted language-diagnostics block for
	// a file a mutating tool just wrote ("" when clean or no server available).
	// edit_file/write_file append it to their output so the model sees an error
	// it introduced in the same turn instead of waiting for a later verification
	// pass. nil disables inline diagnostics.
	Diagnostics func(ctx context.Context, absPath string) string
}

type Safety

type Safety struct {
	SideEffect SideEffect
	Permission Permission
	Reason     string
	// AdvertiseInAuto allows selected non-allow tools to be visible in auto mode
	// while still requiring the normal permission flow before execution.
	AdvertiseInAuto bool
}

type SandboxPermissionOverride

type SandboxPermissionOverride string
const (
	SandboxPermissionsUseDefault                SandboxPermissionOverride = "use_default"
	SandboxPermissionsRequireEscalated          SandboxPermissionOverride = "require_escalated"
	SandboxPermissionsWithAdditionalPermissions SandboxPermissionOverride = "with_additional_permissions"
)

type ScaffoldOptions

type ScaffoldOptions struct {
	// Name is the tool/plugin id (a single path segment).
	Name string
	// Dir is the toolbox directory to create the plugin under (typically the user
	// plugins root).
	Dir string
	// Description is an optional human description; a default is used when empty.
	Description string
	// Runtime selects the entry-stub language; defaults to RuntimeShell.
	Runtime ScaffoldRuntime
}

ScaffoldOptions configures a single tool scaffold.

type ScaffoldResult

type ScaffoldResult struct {
	Name         string `json:"name"`
	PluginDir    string `json:"pluginDir"`
	ManifestPath string `json:"manifestPath"`
	EntryPath    string `json:"entryPath"`
}

ScaffoldResult reports the generated layout.

func Scaffold

func Scaffold(options ScaffoldOptions) (ScaffoldResult, error)

Scaffold generates a plugin-tool skeleton under options.Dir/<name>/ and returns the created paths. It refuses an invalid name, a missing dir, or an existing target so it never clobbers prior work.

type ScaffoldRuntime

type ScaffoldRuntime string

ScaffoldRuntime selects the entry-stub language. The default is a POSIX shell stub, which has no interpreter install dependency; node/python are offered for authors who prefer them. Runtimes are deliberately model-provider-agnostic.

const (
	RuntimeShell  ScaffoldRuntime = "shell"
	RuntimeNode   ScaffoldRuntime = "node"
	RuntimePython ScaffoldRuntime = "python"
)

type Schema

type Schema struct {
	Type                 string                    `json:"type"`
	Properties           map[string]PropertySchema `json:"properties,omitempty"`
	Required             []string                  `json:"required,omitempty"`
	AdditionalProperties bool                      `json:"additionalProperties"`
}

type SideEffect

type SideEffect string
const (
	// SideEffectNone marks a control-only tool that neither reads nor mutates
	// state — no read/write/shell/network/out-of-workspace effect. Examples:
	// tool_search (only reports already-registered tool schemas) and
	// escalate_model (only requests a loop-level model switch).
	SideEffectNone           SideEffect = "none"
	SideEffectRead           SideEffect = "read"
	SideEffectWrite          SideEffect = "write"
	SideEffectShell          SideEffect = "shell"
	SideEffectNetwork        SideEffect = "network"
	SideEffectLocalControl   SideEffect = "local_control"
	SideEffectLocalBrowser   SideEffect = "local_browser"
	SideEffectLocalDesktop   SideEffect = "local_desktop"
	SideEffectLocalTerminal  SideEffect = "local_terminal"
	SideEffectOutOfWorkspace SideEffect = "out_of_workspace"
)

type Status

type Status string
const (
	StatusOK    Status = "ok"
	StatusError Status = "error"
)

type Tool

type Tool interface {
	Name() string
	Description() string
	Parameters() Schema
	Safety() Safety
	Run(ctx context.Context, args map[string]any) Result
}

func CoreNetworkTools

func CoreNetworkTools() []Tool

func CoreReadOnlyTools

func CoreReadOnlyTools(workspaceRoot string) []Tool

func CoreReadOnlyToolsScoped

func CoreReadOnlyToolsScoped(workspaceRoot string, scope PathScope) []Tool

func CoreShellTools

func CoreShellTools(workspaceRoot string) []Tool

func CoreShellToolsScoped

func CoreShellToolsScoped(workspaceRoot string, scope PathScope) []Tool

func CoreTools

func CoreTools(workspaceRoot string) []Tool

func CoreToolsScoped

func CoreToolsScoped(workspaceRoot string, scope PathScope) []Tool

func CoreWriteTools

func CoreWriteTools(workspaceRoot string) []Tool

func CoreWriteToolsScoped

func CoreWriteToolsScoped(workspaceRoot string, scope PathScope) []Tool

func NewApplyPatchTool

func NewApplyPatchTool(workspaceRoot string) Tool

func NewBashTool

func NewBashTool(workspaceRoot string) Tool

func NewEditFileTool

func NewEditFileTool(workspaceRoot string) Tool

func NewEscalateModelTool

func NewEscalateModelTool() Tool

NewEscalateModelTool builds the tool with the default model registry. If the default registry cannot be built the tool degrades gracefully: every run then reports "no escalation available" rather than failing.

func NewExecCommandTool

func NewExecCommandTool(workspaceRoot string, manager *execSessionManager) Tool

func NewGlobTool

func NewGlobTool(workspaceRoot string) Tool

func NewGrepTool

func NewGrepTool(workspaceRoot string) Tool

func NewLSPNavigateTool

func NewLSPNavigateTool(workspaceRoot string) Tool

NewLSPNavigateTool builds the tool with workspace-only path confinement.

func NewListDirectoryTool

func NewListDirectoryTool(workspaceRoot string) Tool

func NewLocalBrowserTools

func NewLocalBrowserTools(options localcontrol.BrowserOptions) []Tool

func NewLocalControlArtifactTools

func NewLocalControlArtifactTools(options LocalControlArtifactOptions) []Tool

func NewLocalDesktopTools

func NewLocalDesktopTools(options localcontrol.DesktopOptions) []Tool

func NewLocalTerminalTools

func NewLocalTerminalTools(options localcontrol.TerminalOptions) []Tool

func NewReadFileTool

func NewReadFileTool(workspaceRoot string) Tool

func NewReadMinifiedFileTool

func NewReadMinifiedFileTool(workspaceRoot string) Tool

func NewRequestPermissionsTool

func NewRequestPermissionsTool() Tool

func NewScopedApplyPatchTool

func NewScopedApplyPatchTool(workspaceRoot string, scope PathScope) Tool

func NewScopedBashTool

func NewScopedBashTool(workspaceRoot string, scope PathScope) Tool

func NewScopedEditFileTool

func NewScopedEditFileTool(workspaceRoot string, scope PathScope) Tool

func NewScopedExecCommandTool

func NewScopedExecCommandTool(workspaceRoot string, scope PathScope, manager *execSessionManager) Tool

func NewScopedGlobTool

func NewScopedGlobTool(workspaceRoot string, scope PathScope) Tool

func NewScopedGrepTool

func NewScopedGrepTool(workspaceRoot string, scope PathScope) Tool

func NewScopedLSPNavigateTool

func NewScopedLSPNavigateTool(workspaceRoot string, scope PathScope) Tool

NewScopedLSPNavigateTool builds the tool with its own lazily-started LSP manager (servers spin up on first use and are reused across calls within a session). The model-supplied path is resolved through the same scoped confinement the sibling read-only tools use, so a `..` or absolute path cannot read or open a file outside the workspace (or an extra granted root).

func NewScopedListDirectoryTool

func NewScopedListDirectoryTool(workspaceRoot string, scope PathScope) Tool

func NewScopedReadFileTool

func NewScopedReadFileTool(workspaceRoot string, scope PathScope) Tool

func NewScopedReadMinifiedFileTool

func NewScopedReadMinifiedFileTool(workspaceRoot string, scope PathScope) Tool

func NewScopedWriteFileTool

func NewScopedWriteFileTool(workspaceRoot string, scope PathScope) Tool

func NewToolSearchTool

func NewToolSearchTool(registry *Registry) Tool

NewToolSearchTool builds the tool_search tool over the given registry. The tool is informational/no-side-effect and is advertised even in auto mode so the model can always discover withheld tools.

func NewWebFetchTool

func NewWebFetchTool() Tool

func NewWebSearchTool

func NewWebSearchTool() Tool

NewWebSearchTool builds the web_search tool with the env-configured backend.

func NewWriteFileTool

func NewWriteFileTool(workspaceRoot string) Tool

func NewWriteStdinTool

func NewWriteStdinTool(manager *execSessionManager) Tool

Jump to

Keyboard shortcuts

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