subagent

package
v0.1.9 Latest Latest
Warning

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

Go to latest
Published: Aug 20, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package subagent implements sub-agents: isolated agent loops that run with their own fresh context while sharing the main provider adapter and tool set. The model can delegate a focused task (or several tasks in parallel) and receive each sub-agent's final answer — the building block for task decomposition and parallel research, mirroring opencode's sub-agents.

Safety: a sub-agent runs with a sub-registry that (1) drops the interactive tools (ask_user, review_changes) and the subagent tool itself (no recursion), and (2) denies every gated command — destructive shell operations always require the main agent's approval modal, never a silent background run.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Merge

func Merge(reports []string) string

Merge combines per-sub-agent reports into one concise, de-duplicated summary. It keeps the per-agent structure (### headers and **Status:** lines are always preserved) but collapses identical content lines that several agents repeat (the same error message, the same file path) so the merged view is small enough to drop straight back into the main context without re-bloating it.

Types

type Role

type Role string

Role defines the specialist role of a swarm participant.

const (
	RoleArchitect Role = "ARCHITECT" // Researches, plans, and outputs concrete blueprints (Read-only)
	RoleBuilder   Role = "BUILDER"   // Implements the blueprint with surgical code edits
	RoleAuditor   Role = "AUDITOR"   // Audits changes for correctness, regressions, and tests
)

type RunMetrics added in v0.1.1

type RunMetrics struct {
	Answer      string
	Tokens      int
	Cost        float64
	Compactions int
}

RunMetrics carries a finished sub-agent run's answer plus the tokens and estimated cost it consumed, so callers (the swarm, /cost breakdowns) can attribute usage to a specific phase instead of lumping everything together.

type Runner

type Runner struct {
	Adapter provider.ProviderAdapter
	Model   string
	// CheapModel, when set, routes mechanical specialist roles (swarm BUILDER /
	// AUDITOR) to a cheaper model so reasoning-heavy roles (ARCHITECT) can use
	// the strong Model without paying flagship prices for mechanical work.
	// Empty = every role uses Model. Sub-agent/scout tasks always use Model.
	CheapModel string
	Tools      *tool.Registry // the main registry; sub-agents get a safe subset
	// BudgetUSD, when > 0, caps each sub-agent turn's estimated provider spend
	// (hard stop → graceful synthesis). Runaway sub-agents can no longer burn
	// tokens to the 10-minute wall-clock cap with no cost limit.
	BudgetUSD float64
	// Store, when non-nil, persists each sub-agent's isolated conversation to
	// SQLite so delegated work is auditable after the fact. Nil keeps the
	// previous behavior (fresh context, nothing persisted).
	Store *store.Store
	// Ask, when set, is the confirmation gate for MUTATING parallel tasks. A
	// sub-agent flagged Mutates (write/delete/exec) must be explicitly approved
	// by the user before it runs — this is the "controlled" half of BroCode's
	// parallel orchestration: fan-out is free and fast, but any side-effecting
	// parallel agent cannot act without a confirm. Nil = deny mutating tasks.
	Ask func(question string, options []string) (string, error)
	// ContextWindow is the token limit for sub-agent contexts. 0 defaults to 128k.
	ContextWindow int
}

Runner executes isolated sub-agent turns against the same provider adapter the main loop uses.

func (*Runner) ExecuteSwarm

func (r *Runner) ExecuteSwarm(ctx context.Context, task SwarmTask, onUpdate loop.TurnOutputHandler) (*SwarmResult, error)

ExecuteSwarm coordinates a 3-tier specialist swarm (Architect -> Builder -> Auditor). It runs each specialist with dedicated mode isolation, budget bounds, and progress streaming.

func (*Runner) Run

func (r *Runner) Run(ctx context.Context, task string) (string, error)

Run executes a single sub-agent and returns its answer.

func (*Runner) RunMany

func (r *Runner) RunMany(ctx context.Context, agents []SubAgent, parallel bool, onUpdate loop.TurnOutputHandler) ([]string, error)

RunMany executes the given tasks — concurrently when parallel is true, sequentially otherwise — and returns one report per task. Completed agents stream a one-line progress update through onUpdate (may be nil) so the caller sees results arrive incrementally instead of waiting for the whole batch.

func (*Runner) RunScoutSwarm

func (r *Runner) RunScoutSwarm(ctx context.Context, subpaths []string, goal string) string

RunScoutSwarm executes parallel speculative research subagents across different subdirectories, returning aggregated findings without polluting the main conversation (Inovasi 1).

type ScoutJob

type ScoutJob struct {
	ID     string
	Task   string
	Done   bool
	Result string
	Err    error
	// contains filtered or unexported fields
}

ScoutJob is one background research task.

type ScoutManager

type ScoutManager struct {
	Runner *Runner
	// contains filtered or unexported fields
}

ScoutManager owns the background scout jobs for a session.

func NewScoutManager

func NewScoutManager(r *Runner) *ScoutManager

NewScoutManager creates a scout manager backed by the given runner.

func (*ScoutManager) Cancel

func (sm *ScoutManager) Cancel(id string)

Cancel aborts a single running scout by its job id. Already-completed jobs are untouched.

func (*ScoutManager) CancelAll

func (sm *ScoutManager) CancelAll()

CancelAll aborts every running scout. Used when the session is interrupted or the program exits so background goroutines are not left dangling.

func (*ScoutManager) Drain

func (sm *ScoutManager) Drain() []string

Drain collects all completed-but-undelivered scout results and removes them from the manager. Returns one formatted report per finished job. Running jobs are left in place.

func (*ScoutManager) Pending

func (sm *ScoutManager) Pending() int

Pending returns the number of scouts still running.

func (*ScoutManager) Start

func (sm *ScoutManager) Start(ctx context.Context, task string) (string, error)

Start launches a background scout. Returns the job id immediately; the job runs in its own goroutine and its result is picked up by Drain.

func (*ScoutManager) StartWithProgress

func (sm *ScoutManager) StartWithProgress(ctx context.Context, task string, onProgress func(string)) (string, error)

StartWithProgress launches a background scout, forwarding its progress lines to onProgress (may be nil). Returns the job id immediately.

type ScoutTool

type ScoutTool struct {
	Manager *ScoutManager
}

ScoutTool is the native `scout` tool: it starts background research and returns immediately. Results are delivered to the model by the engine loop.

func (*ScoutTool) Description

func (t *ScoutTool) Description() string

func (*ScoutTool) Execute

func (t *ScoutTool) Execute(ctx context.Context, argsJSON string) (string, error)

func (*ScoutTool) Name

func (t *ScoutTool) Name() string

func (*ScoutTool) Parameters

func (t *ScoutTool) Parameters() map[string]any

type SubAgent

type SubAgent struct {
	ID        string `json:"id,omitempty"`         // optional label for the result
	Task      string `json:"task"`                 // the isolated task description
	Mode      string `json:"mode,omitempty"`       // "BUILDER" (default) or "PLANNER" (read-only)
	TargetDir string `json:"target_dir,omitempty"` // optional target sub-repository or working directory (e.g. 'services/payment' or 'auth-service')
	// Mutates marks a task that may write/delete/execute. Mutating parallel
	// agents are never run without explicit user confirmation (see Runner.Ask);
	// this keeps fan-out fast and read-only by default but still lets the model
	// request a supervised parallel mutation when it is actually useful.
	Mutates bool `json:"mutates,omitempty"`
}

SubAgent is a single delegated task.

type SwarmResult

type SwarmResult struct {
	Goal           string     `json:"goal"`
	ArchitectSpec  string     `json:"architect_spec"`
	BuilderOutput  string     `json:"builder_output"`
	AuditorVerdict string     `json:"auditor_verdict"`
	Success        bool       `json:"success"`
	TouchedFiles   []string   `json:"touched_files,omitempty"`
	Duration       string     `json:"duration"`
	Architect      RunMetrics `json:"architect_metrics,omitempty"`
	Builder        RunMetrics `json:"builder_metrics,omitempty"`
	Auditor        RunMetrics `json:"auditor_metrics,omitempty"`
	TotalTokens    int        `json:"total_tokens"`
	TotalCost      float64    `json:"total_cost"`
	Compactions    int        `json:"compactions"`
}

SwarmResult contains the combined synthesis from all swarm stages.

func (*SwarmResult) UsageLine added in v0.1.1

func (s *SwarmResult) UsageLine() string

UsageLine renders a one-line per-phase cost attribution for the swarm completion status (e.g. "arch 1.2k tok / $0.01 · build 9.4k tok / $0.09").

type SwarmTask

type SwarmTask struct {
	Goal       string        `json:"goal"`
	Context    string        `json:"context,omitempty"`
	AutoVerify bool          `json:"auto_verify,omitempty"`
	Timeout    time.Duration `json:"timeout,omitempty"`
}

SwarmTask represents a coordinated multi-stage task.

type SwarmTool

type SwarmTool struct {
	Runner *Runner
}

SwarmTool exposes the collaborative swarm to the agent loop.

func (*SwarmTool) Description

func (t *SwarmTool) Description() string

func (*SwarmTool) Execute

func (t *SwarmTool) Execute(ctx context.Context, argsJSON string) (string, error)

func (*SwarmTool) Name

func (t *SwarmTool) Name() string

func (*SwarmTool) Parameters

func (t *SwarmTool) Parameters() map[string]any

type Tool

type Tool struct {
	Runner *Runner
}

Tool is the native `subagent` tool registered in the main registry. The model calls it to delegate focused work to isolated sub-agents.

func (*Tool) Description

func (t *Tool) Description() string

func (*Tool) Execute

func (t *Tool) Execute(ctx context.Context, argsJSON string) (string, error)

func (*Tool) Name

func (t *Tool) Name() string

func (*Tool) Parameters

func (t *Tool) Parameters() map[string]any

Jump to

Keyboard shortcuts

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