tools

package
v1.0.1 Latest Latest
Warning

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

Go to latest
Published: May 16, 2026 License: Apache-2.0 Imports: 21 Imported by: 0

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

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

func GateToolset(ts adktool.Toolset, gate *permissions.Gate, namespace string) adktool.Toolset

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

func Truncate(s string, maxBytes, maxLines int) string

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

type LifecycleEvent struct {
	State  string
	Detail string
	Time   time.Time
}

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

type Prompter interface {
	Prompt(ctx context.Context, question string) (string, error)
}

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

func RefusePrompter(reason string) Prompter

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

func StaticPrompter(answer string) Prompter

StaticPrompter returns a Prompter that always returns answer with no delay. Test fixture; production code should not use this.

func StdinPrompter

func StdinPrompter(in io.Reader, out io.Writer) Prompter

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

type PrompterFunc func(ctx context.Context, question string) (string, error)

PrompterFunc adapts a function to the Prompter interface for one-off uses.

func (PrompterFunc) Prompt

func (f PrompterFunc) Prompt(ctx context.Context, q string) (string, error)

Prompt implements Prompter.

type Registry

type Registry struct {
	Tools []tool.Tool
	Todo  *TodoStore
}

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.

type TodoStore

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

TodoStore is the in-process backing for the agent's todo list. Ephemeral (one store per core-agent process); persistence across sessions can be added later if a consumer needs it.

func NewTodoStore

func NewTodoStore() *TodoStore

NewTodoStore returns a fresh, empty store.

func (*TodoStore) Items

func (s *TodoStore) Items() []TodoItem

Items returns a defensive copy of the current todo list. Useful for hosts that want to render plan progress (e.g. a /todo slash command).

Jump to

Keyboard shortcuts

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