Skip to content

[DRAFT] - Subagents, reborn#2716

Draft
krissetto wants to merge 2 commits into
docker:mainfrom
krissetto:subagents-v2
Draft

[DRAFT] - Subagents, reborn#2716
krissetto wants to merge 2 commits into
docker:mainfrom
krissetto:subagents-v2

Conversation

@krissetto
Copy link
Copy Markdown
Contributor

No description provided.

@aheritier aheritier added area/agent For work that has to do with the general agent loop/agentic features of the app priority:high Major impact, should be addressed within 2 days status/needs-design Requires architectural discussion or design review labels May 11, 2026
@krissetto krissetto removed the priority:high Major impact, should be addressed within 2 days label May 11, 2026
krissetto added 2 commits May 13, 2026 16:30
Introduces a self-contained subagent execution stack that lets the
runtime spawn, supervise, and persist arbitrarily-nested child agents
without any external orchestration. The feature is contained behind the
LocalRuntime and its pkg/subagent dependencies; existing embedder-facing
APIs are unchanged.

## Config
- Adds config schema v9 with a top-level `sub_agents` list. Each entry
  names an agent defined elsewhere in the team and configures execution
  policy (max_depth, max_turns). The previous schema is frozen as v8.
- agent-schema.json and pkg/config/latest/types.go updated accordingly.
- Example: examples/subagents.yaml.

## pkg/subagent
New package that owns the subagent lifecycle independently of the
runtime loop:
- Manager: registry + supervisor for all live child agents. Controls
  max-depth/max-descendants limits, per-child Interrupt/Close/Stop and
  typed Send (steer / follow-up).
- Handle: per-child coordination handle returned to tool callers.
- Inbox (via pkg/inbox): bounded, back-pressured steer/follow-up queue
  with coalesced ready-signal channel.
- toolset.go: the six agent_ tools exposed to the model
  (subagent_start/send/inspect/list/finalize/stop).
- Status-only envelopes let interrupted child turns notify parent UI
  state without waking the parent agent loop or adding transcript noise.
- Parked interrupted children remain in-flight until they publish a real
  turn-completed envelope, ensuring parents continue waiting for their
  eventual completion.

## pkg/runtime
- session_state.go: per-RunStream coordination bundle (queues, wake
  policy, isChild flag) replacing scattered pointer parameters.
- wake_policy.go: rootWakePolicy and childWakePolicy; child sessions
  park between parent messages, root sessions use the existing Steer/
  FollowUp queues. drainParentEnvelopesMidTurn extracts the mid-turn
  envelope flush from the hot loop body.
- EventBus (eventbus.go): fan-out hub for broadcasting events to
  multiple subscribers (live-session SSE, TUI, tests). The recorder is
  registered here instead of being hard-wired into RunStream.
- SessionRecorder (recorder.go): replaces PersistenceObserver as the
  canonical persistence writer. Handles positional user-message inserts
  (idempotent replay), streaming-message lifecycle, compaction snapshots,
  and token usage. PersistenceObserver becomes a deprecated no-op stub.
- SubagentRunner / subagent_envelopes.go: inject child results back into
  the parent context as implicit user messages with kind=subagent_envelope.
  SubagentEnvelopeMessage constructor in pkg/session keeps the stamp
  logic in one place.
- session_tree.go / live_registry.go / live_event_source.go: live-tree
  snapshot and SSE fan-out for the /sessions/:id/tree and
  /live-sessions/… API surface.
- observability.go: SteerSessionByID / FollowUpSessionByID / …SessionByID
  unified via resolveSessionControl helper.
- initSubagentManager extracts the manager wiring from NewLocalRuntime.
- New events: SubAgentStarted/Sent/Update, ParentIdle/Resume,
  LiveSessionTreeChanged, TurnStarted/TurnEnded,
  ConnectionLost/ConnectionRestored.
- Remote client registry extended with all new event types.

## pkg/session
- AddMessageAt / PositionalStore interface: idempotent insert by index.
- AppendMessage: returns position alongside the usual append.
- SubagentEnvelopeMessage constructor.
- Migration adds the `implicit` and `kind` columns.

## pkg/server
- /sessions/:id/tree, /live-sessions/… SSE and control endpoints wired
  to the new live-session infrastructure. api.LiveSessionNode includes
  display fields (Title, Depth, LastPreview, CreatedAt, LastUpdateAt).

## pkg/app
- WithAttachedTeam / WithSnapshotController options plumbed for
  runtime-managed child tabs.
Adds TUI support for the runtime-managed subagent infrastructure
introduced in the preceding commit. No runtime logic is modified here;
this commit is purely UI wiring and new components.

## Sidebar
- Subagents section renders live child-agent rows with per-row status
  badges, preview text, and elapsed time. Rows highlight on hover and
  trigger ClickSubagent events for one-click attach.
- Hover/click zones are built post-render and kept in sync with
  subagentClickZones so mouse motion always hits the right row.
- Parent-session line click zones are also derived from rendered lines,
  so wrapped working-directory text cannot shift the parent hitbox.
- ParentIdle/Resume events dim the spinner while waiting on children;
  TurnStarted/TurnEnded drive workingAgent rather than StreamStartedEvent
  so the spinner correctly tracks turn-level activity, not session-level.
- Stream lifetime keeps the shared spinner ticking between StreamStarted
  and the first TurnStarted.
- ESC (StreamCancelledMsg) no longer marks subagents as terminal:
  child lifecycles are owned by the runtime, not by the parent turn.
- Status-only subagent updates refresh sidebar rows after attached-tab
  interrupts without adding transcript cards.
- Collapsed-mode shows a subagent count badge and parent-session back-
  link for sub-session tabs.

## Attached / live-child tabs
- NewAttached creates an App that forwards messages to a parent
  runtime via attachedSend rather than driving its own loop.
- WithAttachedTeam seeds the full parent team list so colour indices
  and sidebar agent rows stay consistent across tabs.
- focusEditorForNewTab / clearTransientUIForLeavingCurrentPage helpers
  keep hover state consistent on tab switches.

## Tool views
- New pkg/tui/components/tool/subagent package renders subagent_start /
  send / inspect / list / finalize / stop tool calls with status badges
  and truncated previews.
- factory.go maps all six agent_ tool names to the new renderer.

## Dialog
- tool_confirmation.go adds a subagent_start delegation card showing
  the delegating agent, the target agent name, and the task summary.
- session_tree dialog for browsing the live tree and opening child tabs.

## Performance / TUI improvements from main (merged via rebase)
- IncrementalRenderer in message.go avoids full re-parse on every
  streaming chunk; only the trailing region is re-rendered.
- URL span cache (urlSpanCache) in messages.go deduplicates link
  detection work across frames.
- Coalesced scroll handling (WheelCoalescedMsg) reduces re-render
  frequency under fast wheel input.
- tickPaused flag gates animation ticks while the model is idle,
  eliminating redundant View() calls.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/agent For work that has to do with the general agent loop/agentic features of the app status/needs-design Requires architectural discussion or design review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants