subagent

package
v0.29.0 Latest Latest
Warning

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

Go to latest
Published: Aug 14, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrUnknownJob = errors.New("unknown job ID")
	ErrNotSync    = errors.New("subagent is already async")
	ErrNotRunning = errors.New("subagent already finished")
)

Sentinel errors returned by promote/Promote, distinguishable by callers (e.g. pkg/serve maps them to specific HTTP statuses).

Functions

This section is empty.

Types

type Config

type Config struct {
	DefaultModel           core.Model
	CurrentModel           func() core.Model
	CurrentThinkingLevel   func() string
	CurrentPermissionCheck func() func(ctx context.Context, name string, args map[string]any) *core.ToolCallDecision
	ProviderFactory        func(core.Model) (core.Provider, error)
	AgentsMD               string
	PromptBuilder          func(opts agentcontext.SystemPromptOptions) string
	ParentTools            *core.Registry
	AppCtx                 context.Context
	WorkspaceRoot          string // CWD passed to system prompt builder
	SkillsIndex            string // pre-formatted skills index for system prompt
	MemoryIndex            string // pre-formatted memory index (one line per fact)

	// BashState, when non-nil, is the per-agent persistent shell state. The
	// subagent seeds an isolated copy for the child (subshell semantics) and
	// drops it when the child finishes. nil = no shell-state isolation.
	BashState *tool.BashState

	// OnAsyncComplete is called when an async subagent finishes (completed, failed, or cancelled).
	// truncated is true when resultTail is only the last N lines of the full output.
	OnAsyncComplete func(jobID, task, status, resultTail string, truncated bool)

	// OnAsyncJobChange is called when an async job starts or finishes.
	// count is the current number of running jobs.
	OnAsyncJobChange func(count int)

	// OnChildStart is called right before a child agent (sync or async) begins
	// running, with its jobID/task/model/thinking level, whether it's async, its start
	// time (so live UIs can compute elapsed and reconcile it after a reconnect),
	// and its stable per-session creation ordinal (accentIndex) for a
	// deterministic accent color that survives reconnects.
	OnChildStart func(jobID, task, model, thinking, originToolCallID string, async bool, startedAt time.Time, accentIndex int)

	// OnChildEvent is called for each typed bus event produced by translating
	// the child's core.AgentEvent stream (via bus.TranslateAgentEvent). inner
	// is already a concrete bus.* type (e.g. bus.TextDelta), never a raw
	// core.AgentEvent — pkg/subagent imports pkg/bus directly (no import
	// cycle: pkg/bus does not import pkg/subagent), so translation happens
	// here rather than at the call site.
	OnChildEvent func(jobID string, inner any)

	// OnChildUsage is called each time a child closes a message (its
	// message_end), with the child's accumulated usage/cost so far (cost using
	// the CHILD's model pricing) and how full its own context window is
	// (0-100, or -1 when its model has no known window). It lets live UIs show
	// running tokens/cost/context before the terminal OnChildEnd. Same
	// aggregation as OnChildEnd, so the live value stays consistent with the
	// final total.
	OnChildUsage func(jobID string, usage *core.Usage, costUSD float64, contextPct int)

	// OnChildEnd is called once when a child agent (sync or async) finishes.
	// Result/Error are the terminal child outcome, not the one-time model
	// delivery claim used by subagent_wait and async notifications.
	OnChildEnd func(jobID, task string, async bool, status, result, resultErr string, finishedAt time.Time, usage *core.Usage, costUSD float64)

	// Title generation is deliberately asynchronous: starting work must never
	// wait on a convenience model call. Resumed children keep their saved title.
	TitleModel   core.Model
	TitleEnabled bool
	OnChildTitle func(jobID, title string)

	// ChildMaxTurns caps the number of turns a child agent may take. 0 (or
	// negative) falls back to defaultChildMaxTurns.
	ChildMaxTurns int

	// ChildMaxRunDuration caps how long a child agent may run. 0 (or
	// negative) falls back to defaultChildMaxRunDuration.
	ChildMaxRunDuration time.Duration

	// MaxConcurrentAsync caps how many async subagent jobs may run at once.
	// 0 (or negative) falls back to defaultMaxConcurrentAsync.
	MaxConcurrentAsync int

	// TranscriptLoader loads a persisted subagent transcript by job ID,
	// enabling the "resume" parameter to continue a finished subagent's
	// conversation instead of starting fresh. nil = resume unsupported (the
	// tool reports a clear error when resume is requested). The caller wires
	// this to its session-scoped transcript store (see pkg/serve).
	TranscriptLoader func(jobID string) (ResumedTranscript, error)
}

type JobInfo

type JobInfo struct {
	JobID            string
	OriginToolCallID string
	Task             string
	Title            string
	Model            string
	Thinking         string
	Status           string
	Async            bool
	StartedAt        time.Time
	FinishedAt       time.Time
	// Usage/CostUSD carry the child's accumulated usage/cost so far (nil Usage
	// until the child has closed at least one message), so a reconnect snapshot
	// can restore live cost without resetting it.
	Usage   *core.Usage
	CostUSD float64
	// ContextPercent is how full the CHILD's own context window is (0-100),
	// or -1 when unknown — see job.contextPct.
	ContextPercent int
	// AccentIndex is the job's stable creation ordinal (see job.accentIndex),
	// used by clients to pick a deterministic accent color that survives
	// reconnects.
	AccentIndex int
}

JobInfo describes a live (or recently finished) subagent job.

type Jobs

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

Jobs is a handle onto the subagent job store, returned by RegisterAll.

func RegisterAll

func RegisterAll(reg *core.Registry, cfg Config) (*Jobs, error)

RegisterAll registers the subagent tools on reg and returns a handle onto the job store (for external consumers: init snapshot, tray UI, cancellation).

func (*Jobs) Cancel

func (j *Jobs) Cancel(jobID string) bool

Cancel requests cancellation of a running job. Returns false if no job with that ID is tracked (so callers can surface a 404); returns true if the job exists, whether or not it was still running (idempotent for finished jobs).

func (*Jobs) Has

func (j *Jobs) Has(jobID string) bool

Has reports whether a job with jobID is currently tracked.

func (*Jobs) Messages

func (j *Jobs) Messages(jobID string) []core.AgentMessage

Messages returns a defensive deep copy of the stored transcript for jobID.

func (*Jobs) Promote

func (j *Jobs) Promote(jobID string) error

Promote flips a running sync subagent job to async, unblocking its parent's blocking tool call while the child keeps running in the background. Propagates ErrUnknownJob, ErrNotSync, ErrNotRunning from the underlying store so callers (e.g. pkg/serve) can map them to specific responses.

func (*Jobs) Snapshot

func (j *Jobs) Snapshot() []JobInfo

Snapshot lists all jobs currently tracked (live and recently finished, subject to the store's TTL cleanup).

func (*Jobs) Steer

func (j *Jobs) Steer(jobID string, text string) bool

Steer queues a message for inter-step delivery to the running child agent of jobID. Returns false if no job with that ID is tracked, if the job is no longer running (finished, cancelled or still initializing), or if the child itself refused the message. Non-blocking; safe to call concurrently.

type ResumedTranscript added in v0.28.0

type ResumedTranscript struct {
	Messages []core.AgentMessage
	Model    string
	Thinking string
}

ResumedTranscript is what a TranscriptLoader hands back: the persisted child conversation plus the identity it ran under. Model/Thinking let a resume continue with the SAME model and thinking level the subagent already used instead of silently adopting the parent's; both are optional (empty on transcripts written before they were recorded, which fall back to the parent's settings, i.e. the historical behaviour).

Jump to

Keyboard shortcuts

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