toolset

package
v0.2.4-alpha.1 Latest Latest
Warning

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

Go to latest
Published: May 22, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Overview

Package toolset is the catalog of every tool the agent can construct.

Responsibilities split cleanly across the project:

  • Each internal/tools/<family> package knows how to BUILD its tools and reports the names it owns via Names(). It does NOT know whether those tools are eagerly or lazily loaded — that policy lives one layer up.

  • toolset.Build is the single name → instance resolver. One switch lists every tool the agent supports; auditing the surface = reading this file.

  • toolset.ToolState holds per-agent shared state (e.g. *todo.TodoStore) so stateful tool families can be constructed with the right backing data. The agent constructs one ToolState per agent instance, so two agents built from the same profile get isolated state.

  • The agent (internal/agent) decides WHICH tools to build eagerly (ActiveTools — exposed every turn) vs which to mark as lazy-loadable (DeferredTools — materialized on demand when first invoked).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Build

func Build(names []tools.ToolName, s *ToolState) ([]tools.Tool, error)

Build resolves each name to a tool instance via the public default Registry. Stateful tools pull their backing state from s; stateless tools are package-level singletons.

Unknown names return an error — there is no silent fallback.

External hosts that need to register additional tools should call pkg/toolset.DefaultRegistry().Register at startup before agent construction.

func Describe

func Describe(name tools.ToolName) (tools.Descriptor, error)

Describe returns the metadata (tools.Descriptor) for a tool name without registering the tool with any agent. Internally this constructs a throwaway instance just long enough to read its static metadata fields — for stateful tools the short-lived backing state is immediately garbage-collected.

Use Build when you actually need to call Execute.

Types

type ToolState

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

ToolState carries the shared backing state for stateful tool families. Accessors are lazy — state is allocated only when the first tool that needs it is built. Pass the same *ToolState to every Build call for an agent so siblings within a family share state.

Cross-cutting consumers (TUI, session persistence) hold this through the agent (via agent.ToolState()) and read state through the typed accessors rather than peeking into tool internals.

func NewToolState

func NewToolState() *ToolState

func (*ToolState) AgentGroup

func (s *ToolState) AgentGroup() *meta.SpawnGroup

func (*ToolState) Config

func (s *ToolState) Config() *config.Config

Config returns the runtime configuration this ToolState was bootstrapped with, or nil if the agent never installed one (tests, narrow harnesses). Tools that need settings (TavilyAPIKey, FetchMaxBytes, AppHome, etc.) read through this accessor instead of importing pkg/config directly.

func (*ToolState) DeferredLookup

func (s *ToolState) DeferredLookup() meta.DeferredLookup

DeferredLookup returns the currently-installed lookup for TOOL_SEARCH, or nil if none. Used as the late-bound lookup passed into meta.NewToolSearch.

func (*ToolState) HasAgentGroupPanel

func (s *ToolState) HasAgentGroupPanel() bool

HasAgentGroupPanel reports whether a SpawnGroup has already been allocated. The agent loop uses this to skip drain calls in runs that never spawned a subagent (avoids forcing the lazy allocation just to peek at an empty panel).

func (*ToolState) HasUserPromptQueue

func (s *ToolState) HasUserPromptQueue() bool

HasUserPromptQueue reports whether a UserPromptQueue has already been allocated. The agent loop uses this to skip the drain in runs that never had user input queued (avoids forcing the lazy allocation just to peek at an empty queue).

func (*ToolState) HasWakeupQueue

func (s *ToolState) HasWakeupQueue() bool

HasWakeupQueue reports whether a WakeupQueue has already been allocated. The agent loop uses this to skip the drain call in runs that never built the SCHEDULE_WAKEUP tool (avoids the lazy allocation just to peek at an empty queue).

func (*ToolState) PlanController

func (s *ToolState) PlanController() mode.PlanModeController

PlanController returns the currently-installed plan-mode controller, or nil if none. The EnterPlanMode / ExitPlanMode tools read through this lookup at Execute time so the *Agent can register itself after agent.New returns without an init ordering hazard.

func (*ToolState) QuestionBroker

func (s *ToolState) QuestionBroker() question.Broker

QuestionBroker returns the question back-channel, or nil if not installed. The AskUserQuestion tool reads through this at Execute time.

func (*ToolState) ReadTracker

func (s *ToolState) ReadTracker() *fs.ReadTracker

ReadTracker returns the session read-tracker shared by all fs tools, allocating one on first use.

func (*ToolState) RegisterStore

func (s *ToolState) RegisterStore(store observable.Store)

RegisterStore plugs a TaskGroup into the unified change stream. ToolState subscribes to store and re-publishes every Change to its own observers. Lazy accessors below call this on first allocation, so callers that just use the typed accessors get registration for free.

func (*ToolState) SetConfig

func (s *ToolState) SetConfig(cfg *config.Config)

SetConfig installs the runtime configuration on this ToolState. Called by agent.New after the agent finishes constructing so tool factories don't have to thread cfg explicitly. Subagents inherit the parent's config by getting their own ToolState with the same pointer.

func (*ToolState) SetDeferredLookup

func (s *ToolState) SetDeferredLookup(d meta.DeferredLookup)

SetDeferredLookup installs the lookup TOOL_SEARCH will read from. The agent layer calls this exactly once (root agent only); the *Agent itself satisfies meta.DeferredLookup.

func (*ToolState) SetPlanController

func (s *ToolState) SetPlanController(c mode.PlanModeController)

SetPlanController installs the controller EnterPlanMode / ExitPlanMode will mutate. The agent layer calls this exactly once after construction; only the root agent satisfies the interface (subagents inherit nil and the tools surface a clear error if invoked there).

func (*ToolState) SetQuestionBroker

func (s *ToolState) SetQuestionBroker(b question.Broker)

SetQuestionBroker installs the broker the AskUserQuestion tool will block on. The agent layer calls this once after construction via WithQuestionBroker.

func (*ToolState) SetSkillRegistry

func (s *ToolState) SetSkillRegistry(r *skill.Registry)

SetSkillRegistry installs the skill catalog the SKILL tool will read from. The host (cmd/evva) calls this once at startup with the merged home+workdir registry. Subagents inherit the same pointer via agent.WithSkillRegistry.

func (*ToolState) SetSubagentSpawner

func (s *ToolState) SetSubagentSpawner(sp meta.SubagentSpawner)

SetSubagentSpawner installs the spawner the AGENT tool will delegate to. The agent layer calls this exactly once, after constructing its Agent struct, so the *Agent itself satisfies meta.SubagentSpawner.

func (*ToolState) SetWorktreeController

func (s *ToolState) SetWorktreeController(c mode.WorktreeController)

SetWorktreeController installs the controller EnterWorktree / ExitWorktree will read through. Called once after construction; only the root agent satisfies the interface (subagents leave the slot nil and the tools surface a clear error if invoked there).

func (*ToolState) SkillRegistry

func (s *ToolState) SkillRegistry() *skill.Registry

SkillRegistry returns the currently-installed skill catalog, or nil if none. The SKILL tool reads through this lookup at Execute time so the host can SetSkillRegistry any time before the model invokes it.

func (*ToolState) SubagentSpawner

func (s *ToolState) SubagentSpawner() meta.SubagentSpawner

SubagentSpawner returns the currently-installed spawner, or nil if none. Used as the lookup closure passed into meta.NewAgent at build time so the AGENT tool sees a late-bound spawner without an init ordering hazard.

func (*ToolState) Subscribe

func (s *ToolState) Subscribe(fn observable.Observer)

Subscribe registers an observer that receives every Change from every registered TaskGroup. The agent uses this to bridge into its event sink.

func (*ToolState) TodoStore

func (s *ToolState) TodoStore() *todo.TodoStore

TodoStore returns the todo subsystem's backing store, allocating one on first use. The todo_write tool constructed against the same ToolState shares it. First-use also registers the store on the change stream so the agent's event bridge picks up every todo mutation without per-store wiring.

func (*ToolState) UserPromptQueue

func (s *ToolState) UserPromptQueue() *UserPromptQueue

UserPromptQueue returns the side-channel for prompts the user typed while a Run was in flight, allocating one on first use. The UI's submit handler Enqueue's; the agent loop's drainUserPrompts pulls every entry and folds them into the session as fresh RoleUser messages between iterations.

func (*ToolState) WakeupQueue

func (s *ToolState) WakeupQueue() *meta.WakeupQueue

WakeupQueue returns the SCHEDULE_WAKEUP side-channel, allocating one on first use. WakeupTool Enqueue's the prompt here when its sleep finishes; the agent loop Drain's the queue at the top of every iteration and appends each entry as a RoleUser message.

func (*ToolState) Workdir

func (s *ToolState) Workdir() string

Workdir returns the configured workdir, or "" if no Config is installed. Together with Config() this satisfies the pkg/tools.State interface so downstream tool factories can read config + workdir without reaching for internal accessors.

func (*ToolState) WorktreeController

func (s *ToolState) WorktreeController() mode.WorktreeController

WorktreeController returns the currently-installed worktree controller, or nil if none. The EnterWorktree / ExitWorktree tools read through this lookup at Execute time so the *Agent can install itself after agent.New returns without an init ordering hazard.

type UserPromptQueue

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

UserPromptQueue is the bridge that lets the UI hand the agent a fresh user message WITHOUT starting a new Run. The agent loop drains the queue at the top of every iteration and folds each entry into the session as a RoleUser message — same pattern as drainAsyncSubagents / drainWakeupPrompts.

Why a side-channel and not just another Run: while a Run is in flight the previous assistant turn's tool_calls may not yet be answered. A second Run that appended RoleUser there would orphan the tool_calls and every provider would 400 (the bug we fixed earlier in this branch). The queue defers the append to a safe point — between iterations, after the previous turn's RoleTool message has landed — so the conversation stays well-formed.

Subagents do not drain this queue; the user has no view into the subagent's loop, so enqueuing there would be invisible. Each agent has its own ToolState (and therefore its own queue), so subagent queues simply stay empty.

func NewUserPromptQueue

func NewUserPromptQueue() *UserPromptQueue

NewUserPromptQueue returns a fresh, empty queue.

func (*UserPromptQueue) Drain

func (q *UserPromptQueue) Drain() []string

Drain returns every queued prompt and clears the queue. Returns nil (not an empty slice) when nothing is queued so callers can short-circuit with a single nil-check.

func (*UserPromptQueue) Enqueue

func (q *UserPromptQueue) Enqueue(prompt string)

Enqueue appends a prompt to be delivered on the next loop iteration. Empty / whitespace-only prompts are silently dropped — they'd produce a useless empty RoleUser turn.

func (*UserPromptQueue) Len

func (q *UserPromptQueue) Len() int

Len reports the number of pending prompts without draining. UIs use this to badge a "+N queued" indicator on the status bar without consuming the queue.

Jump to

Keyboard shortcuts

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