subagents

package
v1.10.0 Latest Latest
Warning

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

Go to latest
Published: Jun 5, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package subagents provides foreground and background subagent spawning for task delegation. A subagent is a fully independent agent loop with its own LLM client, tool registry, and message history. It inherits the parent's config, persona, grimoire, and permissions but runs in isolation. Subagents may run in the foreground (blocking) or transition to background after a configurable threshold (#30), delivering their result via a channel.

Index

Constants

This section is empty.

Variables

View Source
var StaggerDelay = 500 * time.Millisecond

StaggerDelay is the configurable pause between concurrent subagent launches to avoid hitting provider rate limits. Zero means no delay. Default 500ms — safe for xAI's grok-build-0.1 at 6 concurrent agents.

Functions

func MergeWorktree added in v1.10.0

func MergeWorktree(repo string, wt *Worktree) error

MergeWorktree merges the worktree's branch back into the repo's current branch. Returns an error on conflict so the caller can surface it.

func RemoveWorktree added in v1.10.0

func RemoveWorktree(repo string, wt *Worktree) error

RemoveWorktree force-removes the worktree dir and deletes its branch.

Types

type DAGEntry added in v1.10.0

type DAGEntry struct {
	Run             *SubagentRun
	Goal            string // the full goal including persona overrides
	Workspace       string
	TurnCb          TurnCallback
	MaxTurns        int
	IsolateWorktree bool
	ResultCh        chan *SubagentRun // result sent here when complete
}

DAGEntry is a queued subagent waiting for dependencies to clear.

type Mailbox added in v1.10.0

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

Mailbox is a concurrency-safe per-address message store keyed by an agent's address (its element name). Drain is destructive.

func NewMailbox added in v1.10.0

func NewMailbox() *Mailbox

NewMailbox creates a new empty Mailbox.

func (*Mailbox) Drain added in v1.10.0

func (m *Mailbox) Drain(to string) []Message

Drain returns and clears all messages for an address.

func (*Mailbox) Post added in v1.10.0

func (m *Mailbox) Post(to, from, body string)

Post appends a message to the recipient's mailbox.

type Manager

type Manager struct {

	// OnBackgroundComplete is an optional callback invoked when a backgrounded
	// subagent finishes. The TUI may set this to surface a completion notice.
	// It is called from a goroutine; implementations must be goroutine-safe.
	// nil = no notification (default; non-TUI callers are unaffected).
	OnBackgroundComplete func(*SubagentRun)
	// contains filtered or unexported fields
}

Manager handles subagent lifecycle and execution.

func NewManager

func NewManager(cfg *config.Config, workspace string, isChild bool) *Manager

NewManager creates a subagent manager. Pass isChild=true when the manager itself is running inside a subagent to block recursive spawning.

func (*Manager) GetRun

func (m *Manager) GetRun(id string) (*SubagentRun, bool)

GetRun returns a subagent run by ID.

func (*Manager) Kill added in v1.10.0

func (m *Manager) Kill(selector string) bool

Kill cancels a specific in-flight subagent (task 6ffb5a7c). The selector may be the run id, the task id, OR the element/display name the user sees in /agents (e.g. "mizu" or "water") — users refer to agents by the name on screen, not the internal id (#d15ac448). Returns true if a cancellable run was found. The run's context is cancelled (which the runtime honors — task 349f1f14) and its status is marked failed so ListRuns reflects the kill immediately. A run that has already finished is left untouched and returns false.

func (*Manager) ListRuns

func (m *Manager) ListRuns() []*SubagentRun

ListRuns returns all subagent runs, most recent first.

func (*Manager) Resume added in v1.10.0

func (m *Manager) Resume(ctx context.Context, checkpointID string, turnCb TurnCallback) (*SubagentRun, error)

Resume continues a previously-failed subagent from its last checkpoint. checkpointID is the RunID returned by RunGoal and stored in SubagentRun.CheckpointID. It constructs a runner with the same options as executeSubagent so the resumed run shares the same workspace, turn limits, and callback wiring.

func (*Manager) Spawn

func (m *Manager) Spawn(ctx context.Context, goal string, workspace string, turnCb ...TurnCallback) (*SubagentRun, error)

Spawn creates and runs a subagent with the given goal. It blocks until the subagent completes or the context is cancelled.

func (*Manager) SpawnAsync added in v1.10.0

func (m *Manager) SpawnAsync(ctx context.Context, goal, workspace string, opts SpawnOptions) (<-chan *SubagentRun, *SubagentRun)

SpawnAsync starts a subagent in a goroutine and returns a buffered channel that receives the final *SubagentRun when it completes, plus the live run handle (status "running"). The channel has capacity 1 so the exec goroutine never blocks or leaks if the caller abandons the channel. The caller may wait on the channel or ignore it (e.g., after transitioning to background).

SpawnAsync does NOT handle DAG dependencies; use SpawnWithOptions for that.

func (*Manager) SpawnWithOptions added in v1.10.0

func (m *Manager) SpawnWithOptions(ctx context.Context, goal string, workspace string, opts SpawnOptions) (*SubagentRun, error)

SpawnWithOptions creates and runs a subagent with full options including DAG dependencies. If depends_on contains task IDs that haven't completed yet, the subagent blocks in "waiting" state until all dependencies clear, then auto-starts.

When opts.BackgroundAfter > 0, the call blocks up to that duration waiting for the subagent to finish. If the subagent is still running at the threshold, it transitions to "background" status and SpawnWithOptions returns the live (background) run immediately so the parent can resume. The result is later delivered via a goroutine that updates the run state and invokes m.OnBackgroundComplete (if set).

Default behavior (BackgroundAfter == 0) is unchanged: fully blocking.

type Message added in v1.10.0

type Message struct {
	From string
	To   string
	Body string
}

Message is a single inter-agent message.

type PostMessageTool added in v1.10.0

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

PostMessageTool is a built-in tool that allows a subagent to post a message to another subagent's mailbox. The recipient is identified by its element name (e.g. "fire", "water"). Messages are delivered at spawn time when the recipient agent next starts (spawn-time injection; live mid-run injection is a follow-up, see issue #31).

func NewPostMessageTool added in v1.10.0

func NewPostMessageTool(manager *Manager, from string) *PostMessageTool

NewPostMessageTool creates a post_message tool backed by the given manager. from should be the element name of the agent that holds this tool instance, or "parent" when the tool is held by the top-level orchestrator.

func (*PostMessageTool) Description added in v1.10.0

func (t *PostMessageTool) Description() string

func (*PostMessageTool) Execute added in v1.10.0

func (t *PostMessageTool) Execute(_ context.Context, input map[string]any, _ chan<- tools.ProgressEvent) (tools.ToolResult, error)

func (*PostMessageTool) InterruptBehavior added in v1.10.0

func (t *PostMessageTool) InterruptBehavior() tools.InterruptBehavior

func (*PostMessageTool) IsConcurrencySafe added in v1.10.0

func (t *PostMessageTool) IsConcurrencySafe(input map[string]any) bool

func (*PostMessageTool) IsReadOnly added in v1.10.0

func (t *PostMessageTool) IsReadOnly() bool

func (*PostMessageTool) Name added in v1.10.0

func (t *PostMessageTool) Name() string

func (*PostMessageTool) Parameters added in v1.10.0

func (t *PostMessageTool) Parameters() json.RawMessage

func (*PostMessageTool) ValidateInput added in v1.10.0

func (t *PostMessageTool) ValidateInput(input map[string]any) error

type SpawnAgentTool

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

SpawnAgentTool is a built-in tool that allows the model to spawn subagents for task delegation. The subagent runs in the foreground (blocks until complete) and returns its final result.

func NewSpawnAgentTool

func NewSpawnAgentTool(manager *Manager) *SpawnAgentTool

NewSpawnAgentTool creates a new spawn_agent tool backed by the given manager.

func (*SpawnAgentTool) Description

func (t *SpawnAgentTool) Description() string

func (*SpawnAgentTool) Execute

func (t *SpawnAgentTool) Execute(ctx context.Context, input map[string]any, progress chan<- tools.ProgressEvent) (tools.ToolResult, error)

func (*SpawnAgentTool) InterruptBehavior

func (t *SpawnAgentTool) InterruptBehavior() tools.InterruptBehavior

func (*SpawnAgentTool) IsConcurrencySafe

func (t *SpawnAgentTool) IsConcurrencySafe(input map[string]any) bool

func (*SpawnAgentTool) IsReadOnly

func (t *SpawnAgentTool) IsReadOnly() bool

func (*SpawnAgentTool) Name

func (t *SpawnAgentTool) Name() string

func (*SpawnAgentTool) Parameters

func (t *SpawnAgentTool) Parameters() json.RawMessage

func (*SpawnAgentTool) ValidateInput

func (t *SpawnAgentTool) ValidateInput(input map[string]any) error

type SpawnOptions added in v1.10.0

type SpawnOptions struct {
	TaskID          string        // user-assigned task ID for DAG references
	DependsOn       []string      // task IDs that must complete before this starts
	TurnCb          TurnCallback  // nested progress callback
	MaxTurns        int           // 0 = default (20)
	IsolateWorktree bool          // run this subagent in its own git worktree (#32)
	BackgroundAfter time.Duration // >0: auto-transition to background if the subagent runs longer than this (#30). 0 = always foreground (unchanged).
}

SpawnOptions holds optional parameters for Spawn.

type SubagentRun

type SubagentRun struct {
	ID           string    `json:"id"`
	TaskID       string    `json:"task_id,omitempty"` // user-assigned ID for DAG dependencies
	Name         string    `json:"name"`              // display name (e.g., "火 hi")
	Element      string    `json:"element"`           // english element (e.g., "fire")
	Goal         string    `json:"goal"`
	Workspace    string    `json:"workspace"`
	Status       string    `json:"status"`               // "waiting", "running", "background", "completed", "failed"
	DependsOn    []string  `json:"depends_on,omitempty"` // task_ids that must complete first
	Result       string    `json:"result"`
	Error        string    `json:"error,omitempty"`
	StartedAt    time.Time `json:"started_at"`
	EndedAt      time.Time `json:"ended_at,omitempty"`
	Turns        int       `json:"turns"`
	CheckpointID string    `json:"checkpoint_id,omitempty"` // run id to resume from on failure
}

SubagentRun tracks the state and result of a spawned subagent.

type TurnCallback added in v1.10.0

type TurnCallback func(turn int, maxTurns int, toolName string)

TurnCallback is called on each subagent turn so the parent can display nested progress. turn is 1-indexed, toolName is the tool being called on this turn (empty if the turn is a text response).

type Worktree added in v1.10.0

type Worktree struct {
	Path   string
	Branch string
}

Worktree is an isolated git worktree for a subagent.

func AddWorktree added in v1.10.0

func AddWorktree(repo, name string) (*Worktree, error)

AddWorktree creates a worktree for `name` on a new branch under <repo>/.celeste/worktrees/<name>.

Jump to

Keyboard shortcuts

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