18. Sub-tasks and background execution

[!ref] Full details in the User Manual, "Sub-tasks and background execution".

18.1 Dispatch params

Arg Type Default Description
prompt string Sub-task prompt; required
agent_id string Current persona Sub-persona to use
model string Current model Sub-task model
run_in_background bool false true ⇒ background
timeout_ms int 600_000 Foreground timeout; n/a in background

18.2 BackgroundRegistry

Field Default Description
Concurrent in-flight cap 64 Excess immediately rejected with retry hint
Terminal-state retention 30 min Aged-out beyond this
Priority killed > done External stop wins over natural completion

18.3 Sub-task tools

Tool Args Description
Agent prompt, agent_id, run_in_background? Dispatch one sub-task
AgentParallel legs[] (2–16), timeout_seconds? Parallel fan-out in one call (see §18.3.1)
TaskOutput task_id, limit? Pull state / output
TaskStop task_id Force-stop
StopAgentToolRun child_session_id Stop one running sub-agent (background / parallel leg); idempotent; synchronous inline sub-agents require stopping the whole turn
TaskWait task_ids, mode=all|any, timeout_seconds (default 300, max 1800) Block-and-wait
EnterPlanMode / ExitPlanMode none Enter / exit plan
TodoWrite todos Write / update todo

18.3.1 AgentParallel parameters

Param Type Default Notes
legs array required, 2–16; each an independent fresh-context sub-agent, aggregated when all finish
legs[].subagent_type string required, target subagent type
legs[].prompt string required, self-contained subtask prompt (a leg can't see main chat history)
legs[].description string optional, 3–5 words, for log / UI only
legs[].model string inherit optional, per-leg model override
timeout_seconds int 600 overall wait, max 1800; legs not done by then return pending and keep running in the background

Fewer than 2 errors out (use Agent); more than 16 are silently truncated to the first 16. Each leg is dispatched as a real background task with one internal Wait(all); per-leg output over 8000 runes is truncated (with a note to fetch full text via TaskOutput). Legs are leaf-level and cannot nest Agent / AgentParallel. v1 is all-mode only. Returns a ParallelResult (completed / num_ok / num_failed / num_pending / legs[] …, never throwing).

Rendering: the call card shows during execution and reflects each leg's running status from the live store (stops spinning once stopped); the result block isn't wrongly collapsed by the tool group in compact density.

18.4 Long-running task crash recovery

Background tasks (run_in_background=true) persist progress to a global on-disk directory (one JSON snapshot per task); reaching a terminal state (done / error / killed) deletes the snapshot.

Item Default Notes
Persistence scope Background tasks only Foreground synchronous tasks aren't persisted
Startup scan Async, non-blocking Dirty-entry cleanup first (entries whose parent session is gone are pruned), then remaining tasks are listed
Auto-resume toggle Off (auto_resume_tasks) Settings → Agent → Reflection; when on, a restart auto-continues (unattended / overnight)
Startup auto-resume cap 5 Prevents a "continue-message storm"; the rest go to the manual banner
Recovery mechanism Inject into parent session Doesn't respawn the sub-process directly; injects a "continue / re-delegate" message into the original parent session (visible to the user)
Manual entry Top recovery banner Each row offers Resume / Ignore, plus "Ignore all"

18.5 Self-repair loop reference

Errors are triaged by origin (request / gateway / upstream) and category, then mapped to 4 repair strategies, each with a per-session attempt cap:

Repair strategy For Cap
transient_compact (compact & retry) Context overflow 2
transient_fallback (switch provider, needs confirm) No channel / upstream overloaded / upstream auth failed 3
backoff (backoff retry) Rate-limit / timeout / network 3
terminal (hand back to user) Insufficient balance / re-login / model missing

Special cases: an auth_error of upstream origin is reclassified transient_fallback (a channel key failed, not the user's credentials); a still-retryable terminal is rescued to backoff; 5xx / 408 stay retryable, other 4xx terminate.

  • Network-jitter self-heal: on a transient disconnect / temporary offline, it probes "offline → online" and resumes, and that wait is not counted against the retry budget; connection-level transients (connection reset / momentary DNS failure / interrupted handshake) are sub-classified as network problems (rather than a generic llm_error).
  • Outcome heals (MaxOutcomeHeal = 3): length-truncated reply auto-continue (truncated_continue), reasoning-loop interruption (reasoning_loop), content-filter rephrase (content_filter).
  • Gate escalation: when the same check / test failure or a no-progress todo hits its cap (test gate 3×, no-progress todo 2×), the prompt escalates to change approach.
  • Provider fallback is confirmed back via App.RespondProviderFallback; frontend SelfRepairFallbackBanner; backend events self_repair:fallback_confirm / _applied / _declined / self_repair:outcome.

18.6 Experience-learning loop reference

Part Notes
Self-heal history learning (P1) Each heal kind's success/failure persists to ~/.config/avlcode/self-heal-stats.json; smoothed rate (succ+1)/(total+2). Samples < 5 use the default cap 3; rate < 0.2 → 1, 0.2–0.5 → 2, ≥ 0.5 → 3; each kind keeps ≥ 1, history only lowers
Auto-reflect (P2/P3) auto_reflect (default off, Settings → Agent → Reflection); on multi-step task wrap-up runs a GRAI+KISS retrospective async; reads the trace digest (up to 5 error steps) + self-heal stats, producing ≤ 8 Keep/Improve/Stop/Start lessons
Lesson destination Sedimented to the Memory Palace _pending draft inbox (room scratch, kind decision, never decays); requires human approval before entering the live bank; deduped by title; event reflection:done