Documentation
¶
Overview ¶
Package tools implements workspace-bound agent tools.
Package tools implements workspace-bound agent tools.
Package tools implements workspace-bound agent tools.
Index ¶
- Constants
- Variables
- func AdmissionDigest(agentName string, tiers Tiers) string
- func AdvertisedNames(core, deferred []string, reserve int) (names []string, dropped int)
- func AllToolNames() []string
- func ApplyRedactToolArgsEnv() bool
- func DeclaredToolNames() []string
- func DeferredIndex(candidates []TierCandidate) string
- func FilterNames(names []string, mode ScopeMode, allowlist map[string]struct{}, ...) []string
- func FirstLine(description string) string
- func FormatArgv(argv []string) string
- func HasWorkflowsDir(root string) bool
- func IsDeclaredToolName(name string) bool
- func IsKnownToolName(name string) bool
- func MandatoryDenylistSet(extra ...string) map[string]bool
- func MatchDeferred(query string, candidates []TierCandidate) []string
- func RedactToolArgs() bool
- func SetRedactToolArgs(on bool)
- func SetWorkflowToolsBuilder(b WorkflowToolsBuilder)
- func WorkspaceWriteCapable(reg *Registry, names []string) bool
- type Capability
- type CapableTool
- type DefaultOptions
- type EphemeralResultTool
- type ExecutionClass
- type PrivilegedTool
- type Registry
- func (r *Registry) Capability(name string, args json.RawMessage) Capability
- func (r *Registry) Clone() *Registry
- func (r *Registry) CloneForGeneration() *Registry
- func (r *Registry) CloneForGenerationExcluding(excludedNames ...string) *Registry
- func (r *Registry) Execute(ctx context.Context, name string, args json.RawMessage) (string, error)
- func (r *Registry) Get(name string) (Tool, bool)
- func (r *Registry) List() []Tool
- func (r *Registry) OpenAITools() []map[string]any
- func (r *Registry) Register(t Tool)
- type ResultBudgetTool
- type ScopeMode
- type ScopeOptions
- type SkillResourceReader
- type TierCandidate
- type Tiers
- type Tool
- type WorkflowToolsBuilder
Constants ¶
const ( MemorySaveToolName = "memory_save" MemorySearchToolName = "memory_search" MemoryDeleteToolName = "memory_delete" )
Tool names. Memory tools are durable, project- and language-generic: any agent in any workspace may save and search learnings (rule 60).
const EnvRedactToolArgs = "MIVIA_REDACT_TOOL_ARGS"
EnvRedactToolArgs enables argument redaction when set to a truthy value (1, true, yes, on). Set to 0/false/no/off to force off. Unset = config default.
const GetDiagnosticsToolName = "get_diagnostics"
GetDiagnosticsToolName is the registry name of the diagnostics tool.
const LoadToolsToolName = "load_tools"
LoadToolsToolName is the discovery tool that stages deferred-tool admission. It is a privileged session tool: the host registers it on the root registry only when the selected agent actually defers something.
const MaxAdmissionAttempts = 32
MaxAdmissionAttempts bounds total load_tools calls per agent binding, including idempotent and failing ones, so a looping model is stopped even when it never widens anything.
const MaxAdmissionNamesPerCall = 64
MaxAdmissionNamesPerCall bounds the "names" array a single load_tools call may stage. It is the per-call cap on that array (single source of truth; the cli schema's maxItems references it). Together with MaxAdmissionPublications it bounds the admitted set: at most 8 widenings of 64 names, 512 names, may ever be admitted into one binding's surface, and StageToolAdmission enforces that total so a perpetually-deferred stage cannot exceed it either.
const MaxAdmissionPublications = 8
MaxAdmissionPublications bounds how many surface widenings one agent binding may cause. Idempotent and failing calls never consume it.
const MaxAdvertisedTools = 128
MaxAdvertisedTools bounds the per-request tools[] array to the tightest documented ceiling among supported OpenAI-compatible providers (DeepSeek's chat-completions API caps "tools" at 128 functions). The advertised union (plan tools-advertising/01: core tier plus every deferred candidate, pinned for the binding's lifetime so the wire tools[] array never changes mid-turn) is truncated to this many names, core-then-deferred, when it would exceed the cap. Truncated names stay authorized and executable once admitted; they are simply never advertised for this binding.
const MultiEditToolName = "multi_edit"
MultiEditToolName is the registered name of the batched-edit tool.
const RunCommandToolName = "run_command"
RunCommandToolName is the registry name of the shell-exec tool. It is the only tool that reports a child failure in its body while Execute returns err=nil, so status readers must recognise it by name.
const SkillResourceToolName = "read_skill_resource"
Variables ¶
var CompiledMandatoryDenylist = []string{
"delegate",
"dispatch_tasks",
"spawn_agent",
"inspect_agents",
"join_run",
"cancel_run",
}
CompiledMandatoryDenylist is the baseline tool-name denylist for spawned agents. Config may only ADD names via [agents.guardrails] mandatory_tool_denylist; it may never remove these.
var DefaultRunAllowlist = []string{
"git",
"make", "cmake", "ninja",
"go", "gofmt",
"node", "npm", "npx", "yarn", "pnpm", "bun",
"python", "python3", "pip", "pip3", "pytest",
"cargo", "rustc",
"ruby", "gem", "bundle", "rake", "rspec",
"java", "javac", "mvn", "gradle",
"php", "composer", "phpunit",
"ls", "cat", "pwd", "echo", "grep", "egrep", "fgrep",
"sed", "awk", "head", "tail", "sort", "uniq", "cut", "tr", "wc",
"diff", "which", "whoami", "date", "hostname", "uname", "env",
"true", "false", "yes", "printf", "basename", "dirname",
"realpath", "readlink",
}
DefaultRunAllowlist is the built-in set of programs run_command may execute with no tools run_allowlist configured. It is open-by-default, deliberately smaller than the fuller list in .mivia/mivia.toml.example: common compilers/interpreters, their package managers, git, and read-only Unix utilities that cannot mutate the filesystem or escalate into arbitrary execution. It excludes shells (sh, bash - unrestricted execution makes the allowlist concept moot), file-mutating utilities (rm, cp, mv, mkdir, chmod, tar, and friends - run_command is not gated by tools write_path_blocklist, so a mutating program here would bypass it entirely), "find" (its -exec/-delete flags run arbitrary commands and delete files), and networking/container/infra tools (curl, wget, ssh, docker, kubectl, terraform). A project adds any of those explicitly via tools run_allowlist if it wants them; tools run_allowlist_only replaces this list entirely rather than extending it.
Owned here, not by internal/config: run_command is the enforcer of this policy, and per .agents/rules/60-tools-project-language-generic.md every model-facing tool implementation must stay project/language-generic and reusable outside this app - a tool package importing the app's own config system inverts that. internal/config imports this constant (not the reverse) to validate tools diagnostics_commands entries against the same effective allowlist run_command enforces.
Functions ¶
func AdmissionDigest ¶
AdmissionDigest fingerprints the tier decision an admitted set was made against: the agent name plus its core and deferred tiers. A resumed session whose digest no longer matches drops its admitted set fail-closed, because the names in it may no longer mean what they meant when they were admitted.
func AdvertisedNames ¶
AdvertisedNames returns core then deferred tool names for the advertised union, truncated to MaxAdvertisedTools minus reserve. reserve budgets slots for schemas the caller will append on top of these names (e.g. load_tools), so the FINAL wire tools[] array - names plus whatever the caller adds - never exceeds MaxAdvertisedTools; passing 0 truncates to MaxAdvertisedTools directly. It reports how many names were dropped by truncation so callers can surface the loss instead of it going silent (no silent caps).
func AllToolNames ¶
func AllToolNames() []string
AllToolNames returns a sorted catalogue of every workspace tool name the binary can register via NewDefaultRegistry (with a workspace and no DisableTools). Agent validation uses this to distinguish typos from intentionally disabled tools.
Session-control and ledger tools registered only by the CLI are not listed here; they are not selectable agent allowlist names.
func ApplyRedactToolArgsEnv ¶
func ApplyRedactToolArgsEnv() bool
ApplyRedactToolArgsEnv overrides the current setting from MIVIA_REDACT_TOOL_ARGS when the variable is set. Returns whether the env var was present.
func DeclaredToolNames ¶
func DeclaredToolNames() []string
DeclaredToolNames returns the static declared-tool catalogue: every name in AllToolNames except the activation-only read_skill_resource capability. Skill frontmatter `tools:` requirements and agent TOML tool declarations are validated against this catalogue (plan 43), so neither surface can statically require or declare the invocation-scoped resource reader.
func DeferredIndex ¶
func DeferredIndex(candidates []TierCandidate) string
DeferredIndex renders the frozen deferred-tool index injected into the system prompt once per agent binding. It is generated from the binding's full deferred set and never re-rendered after an admission, so system-prompt bytes stay stable for the binding's lifetime.
func FilterNames ¶
func FilterNames(names []string, mode ScopeMode, allowlist map[string]struct{}, extraDenylist []string) []string
FilterNames applies denylist + optional allowlist to a name set without a registry. Used by agent resolution policy before a registry exists.
func FirstLine ¶
FirstLine is the exported form of firstLine, for callers outside this package that need the identical one-line summary DeferredIndex uses (e.g. shrinking a deferred tool's advertised wire schema without duplicating the sentence-boundary logic).
func FormatArgv ¶
FormatArgv joins argv for operator-visible display (shell-safe quoting).
func HasWorkflowsDir ¶
HasWorkflowsDir reports whether root contains .mivia/workflows/.
func IsDeclaredToolName ¶
IsDeclaredToolName reports whether name is a statically declared tool that skills and agent TOMLs may reference (plan 43). The activation-only read_skill_resource capability is deliberately excluded.
func IsKnownToolName ¶
IsKnownToolName reports whether name appears in the compiled catalogue.
func MandatoryDenylistSet ¶
MandatoryDenylistSet returns the compiled denylist plus optional additions.
func MatchDeferred ¶
func MatchDeferred(query string, candidates []TierCandidate) []string
MatchDeferred returns candidate names whose name or description contains query, compared with strings.ToLower and no locale collation, in candidate (registration) order. An empty query matches nothing.
func RedactToolArgs ¶
func RedactToolArgs() bool
RedactToolArgs reports whether tool arguments should be redacted in model/UI output.
func SetRedactToolArgs ¶
func SetRedactToolArgs(on bool)
SetRedactToolArgs enables or disables tool-argument redaction for this process.
func SetWorkflowToolsBuilder ¶
func SetWorkflowToolsBuilder(b WorkflowToolsBuilder)
SetWorkflowToolsBuilder installs the factory that registers workflow tools when a workspace has .mivia/workflows/. Pass nil to clear.
func WorkspaceWriteCapable ¶
WorkspaceWriteCapable reports whether a registered tool surface can change workspace state.
Types ¶
type Capability ¶
type Capability struct {
Class ExecutionClass
ResourceKey string
Timeout time.Duration
MaxResultBytes int
}
Capability describes scheduling and safety metadata for one tool invocation.
func (Capability) Dedups ¶
func (c Capability) Dedups() bool
Dedups reports whether this capability participates in the per-turn tool dedup. ExecutionRead calls always execute fresh; Write/External tools dedup.
type CapableTool ¶
type CapableTool interface {
Tool
Capability(args json.RawMessage) Capability
}
CapableTool may expose scheduling metadata in addition to Tool.
type DefaultOptions ¶
type DefaultOptions struct {
Workspace *workspace.Root
RunAllowlist, RunAllowlistOnly, RunBlocklist, DisableTools []string
RunTimeoutSec, MaxReadBytes, MaxEditFileBytes, MaxOutputBytes, MaxWriteKB, MaxListDirEntries int
// MaxToolResultBytes is the agent-loop tool-result ceiling
// ([tools] max_tool_result_bytes). 0 = uncapped. When set, tools whose
// honest output framing depends on not being tail-cut by the loop
// (read_file's window header, find_references' JSON envelope) pre-clamp
// their own budgets below it.
MaxToolResultBytes int
// MaxTavilyResponseBytes is the byte bound the Tavily-backed tools
// (`search`'s provider path and `extract`) enforce on the response body
// AND on their composed result, and declare as their result budget
// ([tools] max_tavily_response_bytes). It is not a truncation cap: nothing
// is ever cut, an over-bound response is refused with an explicit error.
// 0 uses the built-in default. See web_response_budget.go.
MaxTavilyResponseBytes int
// MaxFetchKB bounds the body read by fetch_url (KiB, [tools]
// max_fetch_kb). 0 (from config) means unlimited; <=0 at tool construction
// means unlimited. When the registry constructs the tool, this value is
// already resolved by the config layer (unset-or-0 becomes the built-in
// 4096 KiB default; an operator's positive value passes through), so it is
// passed through as-is - the registry applies no default of its own.
MaxFetchKB int
// MemoryBackstopBytes is the OOM guard when MaxReadBytes is uncapped (0).
// 0 means the built-in 256 MiB default ([tools] memory_backstop_mb). Not a
// context-cost cap; cannot be disabled by setting 0.
MemoryBackstopBytes int
TavilyAPIKey string
EnvAllowlist, EnvAllowlistOnly, EnvBlocklist []string
EnvAllowKeywordBlocklist []string
SecretPathPatterns, SecretPathExceptions []string
// WritePathDenylist blocks writes to workspace-relative files or directories.
// It does not affect read tools.
WritePathDenylist []string
SearchIgnorePatterns []string
// MaxInspectRepositoryBytes bounds inspect_repository's output envelope
// ([tools] max_inspect_repository_bytes). 0 at construction resolves to
// the built-in 64 KiB default; the config layer already resolves an
// unset-or-0 knob to that same default before this struct is built.
MaxInspectRepositoryBytes int
// DiagnosticsCommands maps a command name to the argv of a project
// diagnostics command the get_diagnostics tool runs ([tools]
// diagnostics_commands, wired by the config layer; the deprecated
// [tools] diagnostics_command alias is folded into the "default" entry
// there). Empty means the tool is not registered. "default" is the
// reserved default entry; with no "default" and exactly one configured
// command, that sole command is the default. The tool is advertised only
// when the default command resolves against the run_command allowlist
// (see registerDiagnosticsTool).
DiagnosticsCommands map[string][]string
// WorkflowTools are pre-built Phase 7 workflow tools. They register only
// when the workspace has .mivia/workflows/ and no WorkflowToolsBuilder is
// installed. Prefer tools.SetWorkflowToolsBuilder for production wiring so
// this package does not import workflow/ledger (storage test import cycle).
WorkflowTools []Tool
// Memory is the durable agent memory backend. When nil, the memory tools
// (memory_save, memory_search) are not registered. Wired by the CLI from
// the resolved [memory] config; never constructed by a workspace file.
Memory memory.Store
}
DefaultOptions configures built-in tools.
type EphemeralResultTool ¶
type EphemeralResultTool interface {
Tool
EphemeralResultMarker(args json.RawMessage) string
}
EphemeralResultTool marks output that must be retained only while an active agent loop needs it. Its marker is safe for events and persisted history.
type ExecutionClass ¶
type ExecutionClass uint8
ExecutionClass describes the side effects and safe scheduling behavior of a tool.
const ( ExecutionRead ExecutionClass = iota ExecutionWrite ExecutionExternal )
type PrivilegedTool ¶
type PrivilegedTool interface {
Tool
Privileged()
}
PrivilegedTool marks a session-control tool that must never be exposed to a nested agent. The marker travels with the tool so future control tools do not depend solely on a name denylist.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry holds tools by name.
func NewDefaultRegistry ¶
func NewDefaultRegistry(opts DefaultOptions) *Registry
NewDefaultRegistry registers all v1 tools.
func ScopedRegistry ¶
func ScopedRegistry(src *Registry, opts ScopeOptions) *Registry
ScopedRegistry returns a fresh registry derived from src without mutating it. Tool object identity (including PrivilegedTool markers) is preserved for tools that pass the filter - filtering is not name-only reconstruction.
ScopeSpawned: drop mandatory denylist names and any PrivilegedTool. ScopeRoot: keep PrivilegedTool and denylist names (delegation stays available); when Allowlist is non-nil, non-privileged tools must be in the allowlist.
func ScopedRegistryWithTail ¶
func ScopedRegistryWithTail(src *Registry, opts ScopeOptions, tail []string) *Registry
ScopedRegistryWithTail is ScopedRegistry with an explicit ordering contract for host-mediated tool admission (plan tools/05 D8).
opts.Allowlist selects the core block, which is materialized in src order. Each name in tail is then appended in tail order, subject to the identical scope rules with its own name as the allowlist for that decision, plus one admission-only restriction: a denied name (compiled denylist or operator ExtraDenylist) is never admitted, in either mode. The extra restriction is what makes the guarantee hold on its own. Without it a ScopeRoot tail would re-enter an operator guardrail denial (INV-AG-29) that the caller's real allowlist excludes, because at root ScopedRegistry keeps a denylisted name whenever the allowlist carries it - and the per-name allowlist used here always carries it. Admission is a publication decision, never a grant: it can only ever narrow what the caller's own scope already authorized.
Because admitted tools land after the core block instead of materializing inside it, the core block's serialized schemas are byte-identical across admissions and the privileged session tools a dispatcher registers afterwards stay at the end.
Names absent from src, already in the core block, or repeated in tail are skipped; Register is idempotent by name regardless.
func (*Registry) Capability ¶
func (r *Registry) Capability(name string, args json.RawMessage) Capability
Capability returns scheduling metadata, using a conservative external classification for tools that do not implement CapableTool.
func (*Registry) Clone ¶
Clone returns an independent registry with the same tool instances and registration order. Dispatcher generations may register session-owned tools on the clone without mutating the live session registry.
func (*Registry) CloneForGeneration ¶
CloneForGeneration copies the base workspace tools while omitting privileged session-control tools that a fresh dispatcher must register once for its own generation.
func (*Registry) CloneForGenerationExcluding ¶
CloneForGenerationExcluding copies non-privileged tools while omitting generation-owned tools that the new dispatcher must construct afresh.
func (*Registry) OpenAITools ¶
OpenAITools returns the tools array for chat completions.
type ResultBudgetTool ¶
type ResultBudgetTool interface {
ResultBudgetBytes() int
}
ResultBudgetTool is implemented by tools whose result size is bounded by a configured content budget (read_file's max_read_bytes, run_command's max_output_bytes, find_references' JSON budget). The declared budget feeds the runtime dispatcher's runaway-output backstop derivation, which must sit strictly above every honest result. Unlike Capability.MaxResultBytes this is NOT a truncation bound: framing the tool emits on top of the content - window headers, truncation notices, argv echo - is covered by the dispatcher's input-allowance and slack terms, never cut.
type ScopeMode ¶
type ScopeMode int
ScopeMode selects root vs spawned registry filtering policy.
const ( // ScopeSpawned applies the mandatory denylist and drops PrivilegedTool // markers. Nested multi-step instances use this mode. ScopeSpawned ScopeMode = iota // ScopeRoot keeps privileged/delegation tools needed for the root session // to dispatch work, even when those names appear in the denylist. // Allowlist intersection still applies to non-privileged tools when set. ScopeRoot )
type ScopeOptions ¶
type ScopeOptions struct {
// Mode selects root vs spawned policy.
Mode ScopeMode
// Allowlist, when non-nil, is the set of tool names the agent may use.
// Nil means "no allowlist filter" (all non-denied tools pass). An empty
// non-nil map means deny-all (after denylist/privileged rules).
Allowlist map[string]struct{}
// ExtraDenylist adds operator denylist names on top of the compiled set.
// Only applied in ScopeSpawned (and always as name denials for non-privileged
// tools in ScopeRoot when listed in Allowlist intersection paths).
ExtraDenylist []string
}
ScopeOptions configures ScopedRegistry.
type SkillResourceReader ¶
SkillResourceReader is a host-held activation callback. The model can supply only a declared ID, never a path, scope, or skill selector.
type TierCandidate ¶
TierCandidate is one deferred tool's advertisement metadata. The host builds the candidate list once per agent binding, in live-registry order, so both the frozen prompt index and query matching see the same order.
type Tiers ¶
Tiers is an agent binding's split of its effective tool set into the always-advertised core and the deferred remainder.
func SplitTiers ¶
SplitTiers splits effective into core and deferred tools.
A nil core list means "no core configured", which keeps every effective tool core and leaves Deferred empty - the zero-config path is fully inert. A non-nil core list is intersected with effective: naming a tool the agent cannot invoke never widens authority. Both output lists preserve the order of effective, which is the live registry's registration order.
type Tool ¶
type Tool interface {
Name() string
Description() string
Parameters() map[string]any
Execute(ctx context.Context, args json.RawMessage) (string, error)
}
Tool is a single agent capability.
func NewSkillResourceTool ¶
func NewSkillResourceTool(read SkillResourceReader, activationKey string, maxResultBytes int) Tool
NewSkillResourceTool creates a fresh scoped reader for one activation.
type WorkflowToolsBuilder ¶
type WorkflowToolsBuilder func(opts DefaultOptions) []Tool
WorkflowToolsBuilder constructs Phase 7 workflow tools for a workspace. The tools package must not import workflow packages (ledger/storage) or it creates a test import cycle with internal/storage. CLI (and tests) set the builder via SetWorkflowToolsBuilder.
Source Files
¶
- capped_buffer.go
- default_registry.go
- delete.go
- diagnostics.go
- diagnostics_registry.go
- edit.go
- edit_lock.go
- edit_result.go
- env.go
- extract.go
- fetch_url.go
- file_observation.go
- find_references.go
- find_symbol_context.go
- fs_guard.go
- get_diagnostics.go
- gitignore.go
- glob_match.go
- go_to_definition.go
- http_client.go
- inspect_engine.go
- inspect_repository.go
- list_dir.go
- list_symbols.go
- memory.go
- names.go
- nav_json.go
- open_regular_unix.go
- privacy.go
- process.go
- process_unix.go
- read.go
- run.go
- run_command_default_allowlist.go
- scope.go
- search.go
- search_capability.go
- search_helpers.go
- search_local.go
- searcher.go
- searcher_tavily.go
- searcher_web_fetch.go
- skill_resource.go
- tier.go
- tools.go
- web_response_budget.go
- workflow_tools.go
- workspace_policy.go
- write.go