Documentation
¶
Overview ¶
Package tools provides ADK-side helpers for wiring tools into the agent. Today it holds only the GateToolset wrapper that bridges permissions.Gate to ADK's tool.Toolset interface; consumer projects add their own tool implementations on top.
Package tools provides ADK-side helpers and built-in tool implementations for the agent loop:
- GateToolset: bridges permissions.Gate to ADK Toolsets (used by mcp + skills)
- Built-in tool suite: file I/O, shell, todo tracking, output truncation
All built-in tools share a common shape via google.golang.org/adk/tool/functiontool and the helpers in this package: output truncation (Truncate) and gate consultation (via permissions.Gate). Tool authors define a typed Args + Result pair and a handler closing over any dependencies; builtins.go assembles them into the slice consumed by agent.WithTools.
Index ¶
- func BuiltinToolNames() []string
- func GateToolset(ts adktool.Toolset, gate *permissions.Gate, namespace string) adktool.Toolset
- func NewAskUserTool(opts AskUserOptions) (tool.Tool, error)
- func NewLifecycleTool(opts LifecycleOptions) (tool.Tool, error)
- func Truncate(s string, maxBytes, maxLines int) string
- type AskUserOptions
- type BuiltinTools
- type LifecycleEvent
- type LifecycleHandler
- type LifecycleOptions
- type Prompter
- type PrompterFunc
- type Registry
- type TodoItem
- type TodoStore
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func BuiltinToolNames ¶
func BuiltinToolNames() []string
BuiltinToolNames returns a fresh copy of the canonical built-in tool names. Order matches the field order in BuiltinTools so callers can iterate deterministically.
func GateToolset ¶
GateToolset wraps ts so every tool inside it goes through the permission gate before running. namespace is the policy bucket used for allow/deny matching ("mcp", "skill", etc.); a nil gate returns ts unchanged.
Reuses the existing permission UX: in `ask` mode the same prompt surface is used; in `allow` mode the same allowlist patterns apply (now with `mcp:<tool>` / `skill:<tool>` keys); in `yolo` mode the call proceeds. The bash denylist does NOT apply to non-bash tools.
func NewAskUserTool ¶
func NewAskUserTool(opts AskUserOptions) (tool.Tool, error)
NewAskUserTool wraps a Prompter as an ADK tool the agent can call during a turn. The tool's handler blocks until the prompter responds, then returns the answer as the tool result — so the agent's reasoning continues in the same turn (no end-of-turn break).
Use the in-turn pattern when the wait is short (interactive CLI, quick approval). For long waits where the model should release the turn (Scion-style: emit a status, end the turn, driver loop reads the next stdin message and starts a fresh agent.Run), use a status-emitting tool instead and let your driver loop handle the hand-off.
Returns an error only if opts.Prompter is nil.
func NewLifecycleTool ¶
func NewLifecycleTool(opts LifecycleOptions) (tool.Tool, error)
NewLifecycleTool wraps a LifecycleHandler as an ADK tool the agent can call to signal state ("thinking", "blocked", "done", custom). The consumer's handler decides where the events go: stdout, a status file, an orchestrator's event log, a websocket, etc.
Returns an error only if opts.Handler is nil or AllowedStates contains an empty entry.
func Truncate ¶
Truncate caps s at the lower of maxBytes / maxLines. When truncation occurs, a marker line is appended so the model knows it received an abridged output and can ask for more (e.g. via offset/limit on a re-read or a narrower grep).
maxBytes <= 0 means "no byte limit"; same for maxLines.
Types ¶
type AskUserOptions ¶
type AskUserOptions struct {
// Prompter is the consumer's delivery mechanism. Required.
Prompter Prompter
// Name overrides the tool's function name. Defaults to "ask_user"
// when empty.
Name string
// Description overrides the tool's description (the prose the
// model sees in its function-decl list). Empty falls back to a
// sensible default.
Description string
}
AskUserOptions configures NewAskUserTool.
type BuiltinTools ¶
type BuiltinTools struct {
Bash bool // /bin/sh -c with timeout + denylist + gate
ReadFile bool // Read a file with offset/limit
WriteFile bool // Atomic write/create
EditFile bool // Single-occurrence string replacement
ListDir bool // Sorted directory listing
Glob bool // Walk + filepath.Match by basename
Grep bool // Walk + RE2 regex per line
Todo bool // In-process plan tracker
}
BuiltinTools toggles core-agent's built-in tool suite. Each enabled flag becomes one entry in the returned Registry's Tools slice.
All defaults are on — every consumer that's writing an agent will almost certainly want read/write/edit/list/bash. The Todo store is always created; the toggle just controls whether the model can drive it via the `todo` tool.
To turn one off:
reg, _ := tools.Build(cfg, gate, tools.BuiltinTools{
Bash: false, // disable shell
ReadFile: true,
WriteFile: true,
EditFile: true,
ListDir: true,
Todo: true,
})
Or use Default() and override fields directly or via Disable:
b := tools.Default()
b.Disable("bash") // by canonical name; errors on typos
b.WriteFile = false // or set the field directly
reg, _ := tools.Build(cfg, gate, b)
func Default ¶
func Default() BuiltinTools
Default returns a BuiltinTools with every tool enabled. This is the recommended starting set for any agent that needs to act on its workspace.
func (*BuiltinTools) Disable ¶
func (b *BuiltinTools) Disable(name string) error
Disable turns off the named tool. Returns an error for unknown names so typos in --disable-tools or .agents/config.json fail loudly at startup rather than silently leaving the tool on. Calling Disable twice with the same name is a no-op.
type LifecycleEvent ¶
LifecycleEvent is the payload delivered to a LifecycleHandler each time the model calls a tool built by NewLifecycleTool. State is the value the model passed (e.g. "thinking", "blocked", "done"); Detail is the optional human-readable context. Time is the moment the handler received the call.
type LifecycleHandler ¶
type LifecycleHandler func(ctx context.Context, ev LifecycleEvent) error
LifecycleHandler receives each lifecycle emit. Returning a non-nil error surfaces the error string back to the model as the tool's response — useful for "this state isn't valid right now" feedback. A nil return acks the call with a generic "ok" so the model can keep working.
type LifecycleOptions ¶
type LifecycleOptions struct {
// Handler is invoked once per emit. Required.
Handler LifecycleHandler
// Name overrides the tool's function name. Defaults to
// "set_status" when empty.
Name string
// Description overrides the tool's description (the prose the
// model sees in its function-decl list). Empty falls back to a
// sensible default.
Description string
// AllowedStates, when non-empty, restricts the State values the
// tool will accept. A call with a State outside the set is
// rejected with an error result returned to the model — the
// handler is not invoked for the rejected call.
AllowedStates []string
}
LifecycleOptions configures NewLifecycleTool.
type Prompter ¶
Prompter delivers a question from the agent to a human (or any external authority) and returns their answer. Implementations decide the channel — stdin, websocket, queue, file watch, etc.
Returning a non-nil error signals "no user available" or transport failure; the agent sees the error string as the tool's response and can adapt (typically by proceeding with its best assumption or reporting the problem) instead of blocking forever.
Prompt should respect ctx cancellation so SIGTERM, deadlines, and agent-driven aborts unblock the tool cleanly.
func RefusePrompter ¶
RefusePrompter returns a Prompter that always errors with reason. Use in non-interactive runs (batch jobs, CI, daemon deployments without a wired-up channel) so the model gets a clear "no user available" signal as the ask_user tool result and adapts, rather than blocking forever on a missing reader.
Recommended reason text guides the model toward useful behavior:
tools.RefusePrompter("running unattended; proceed with reasonable defaults and explain in your final response")
func StaticPrompter ¶
StaticPrompter returns a Prompter that always returns answer with no delay. Test fixture; production code should not use this.
func StdinPrompter ¶
StdinPrompter reads the user's answer from in (typically os.Stdin). The question is written to out (typically os.Stderr) so it doesn't pollute stdout. Each call reads one newline-terminated line and returns it with surrounding whitespace trimmed.
Suitable for interactive CLI use and for stdin-driven adapters (e.g. Scion's tmux-fed message loop) where one line of input maps to one user answer.
Cancellation note: the underlying os.Stdin read isn't ctx-aware on every platform, so a hung read may not unblock until a newline arrives. For long-blocking deployments, wrap with a goroutine + channel pattern in your own Prompter.
type PrompterFunc ¶
PrompterFunc adapts a function to the Prompter interface for one-off uses.
type Registry ¶
Registry is the assembled built-in tool set returned by Build.
Tools is the slice you pass to agent.WithTools(...). Todo is the underlying store, exposed so hosts can render plan progress (e.g. for a /todo slash command in a TUI).
func Build ¶
func Build(cfg *config.Config, gate *permissions.Gate, b BuiltinTools) (*Registry, error)
Build constructs the registry. cfg supplies output-truncation caps; gate gates every tool call. Both are required.
We deliberately do NOT set ADK's functiontool.Config.RequireConfirmation even when the gate is in "ask" mode. core-agent's gate handles approval itself by calling its Prompter from inside each tool handler — going through ADK's HITL flow would be a second approval round-trip on top of ours.
type TodoItem ¶
type TodoItem struct {
ID int `json:"id"`
Status string `json:"status"` // "pending" | "in_progress" | "completed"
Text string `json:"text"`
}
TodoItem is one entry in the agent's plan.