github nicobailon/pi-subagents v0.79.0

4 hours ago

This release is about not losing work. When one session hands off to another in the same Pi process, the new session now owns the old one's background runs: it can see them, wait on them, steer, stop and resume them, and answer their questions. Coordinators can give a finished worker another round instead of starting over with a fresh child and a re-sent brief. Forked subagents and long sessions also spend fewer tokens, and updating pi-subagents mid-session no longer switches subagent off.

Highlights

  • Handoffs keep your background work. A session that takes over from another one in the same process gets that session's background runs, and a stopped workflow can be picked up with options: { reuseFrom: "<run id>" } without running its finished children again.
  • Resume a finished worker. Resuming a finished background child, a forked child, or a child that was already resumed once now works instead of failing with "session file is not under that nested run's session directory".
  • Fewer wasted tokens. Forked subagents reuse the parent's prompt cache (a fork's first request on a 60k-token Claude parent went from 9.6k to 60.8k cached tokens), /subagent-cost and other view-only reports no longer ride along in every request, and codemode no longer breaks the cache on every resume.
  • subagent survives updates. Updating or reloading pi-subagents mid-session no longer leaves subagent or bg_wait turned off.
  • RPC hosts see more. Each background child's agent, run id, requested model, and the model that actually answered.

Need to know

  • Children launched before this update still can't be resumed by a coordinator. Background and forked children now keep their session in a folder named by their run id, so only children started on 0.79.0 benefit.
  • Children that use Pi's built-in MCP tools need Pi 0.99.2 or later.

Changelog

Highlights

  • Handoffs keep your background work. A session that takes over from another one in the same Pi process can see, wait on, steer, stop and resume the old session's background runs, and a stopped workflow can be picked up with reuseFrom without running its finished children again.
  • Coordinators can give a finished worker another round. Resuming a finished background child, a forked child, or a child that was already resumed once now works instead of failing with "session file is not under that nested run's session directory".
  • Fewer wasted tokens. Forked subagents reuse the parent's prompt cache, /subagent-cost and other view-only reports no longer ride along in every request, and codemode no longer breaks the cache on every resume.
  • subagent survives updates. Updating or reloading pi-subagents mid-session no longer leaves subagent or bg_wait turned off.
  • RPC hosts see more: each background child's agent, run id, requested model, and the model that actually answered.

Added

  • Inspect replies (/subagents-inspect-rpc) now include resolvedModel: { provider, model }, the provider and model of the inspected child's latest reply. Before, a host could only see the requested model. The field is missing until the child replies, for a whole workflow or multi-step run, and for runs from before this release. A forked child's inherited history never counts. Thanks to @koenvg for reporting #2922.
  • The RPC subagent-async status snapshot now includes each background step's model, thinking level and agent. A workflow lane's label names the lane, not the agent, so hosts could not name a running child until it finished. Thanks to @agustinsacco for #2893 (#2892) and @kevinsleegerslameco for #2912 (#2911).
  • In a workflow that waits for its result, a background child's workflowChildren row now carries its agent and runId from launch, and that runId matches the child's run in the subagent-async snapshot. Before, the row had only { childId, state } until the child finished. Thanks to @kevinsleegerslameco for reporting #2911.
  • After a handoff, a relaunched workflow can reuse the work of a run that was stopped because the old session's runtime was replaced: pass options: { reuseFrom: "<run id>" }. Finished children are reused and running ones are awaited, even from another session, as long as the run ran the same script in the same cwd. Before, relaunching ran every child again, so two writers could share one output. The stop notice names the option and the run id. Thanks to @wireknight for reporting #2909.
  • A session that takes over from another one in the same Pi process, for example after a handoff to a new session file, now owns the old session's background runs. They show in its run list, fleet view and RPC snapshot. It can wait on, steer, stop, resume and inspect them, and it gets their notices and answers their supervisor questions. status shows Owner: inherited from session '…' (replaced in this process). for these runs. A fresh start, pi --continue, or another Pi process inherits nothing. Thanks to @wireknight for reporting #2909.

Changed

  • The pi-subagents skill now says that subagent, subagents_enable, subagent_supervisor, contact_supervisor and structured_output can't be called from codemode scripts. With codemode on, models used to try tools.subagent_supervisor(...) and get a "does not exist" error. Thanks to @CovetingEpiphany2152 for the report. (#2887)
  • Replying to a supervisor question that was already answered, expired or withdrawn now lists the questions still pending, so the parent can answer a newer one without another pending call. Thanks to @agustinsacco for #2895. (#2894)

Fixed

  • A coordinator could not resume its own finished background child: resume failed with "session file is not under that nested run's session directory", so it had to start a new child and send the brief again. The same happened for forked children (context: "fork") and for a child that had already been resumed once. All three now resume, with the same ownership checks as before. Background and forked children now keep their session in a folder named by their run id. Children launched before this update still can't be resumed. Thanks to @mannainsect for reporting #2924 and @GeorgeLautenschlager for showing it outside workflows. (#2932)
  • A coordinator child (one that delegates its own work) stayed stuck in bg_wait when one of its children asked it a question with contact_supervisor, so the questions expired unanswered. Its bg_wait now returns as soon as a question is waiting, as the parent's already does. Thanks to @mannainsect for reporting #2923.
  • A child's contact_supervisor question could expire before the parent saw it when the parent was busy in a long tool call, so the child gave up and asked again and the parent's late reply failed. The question's deadline now moves forward until the parent's model sees it. Thanks to @agustinsacco for the report. (#2894)
  • When a handoff or reload stopped an async workflow, its still-running children were listed as stopped, its notice didn't say that reusing finished children works only from the same session, and status offered a Revive: command to sessions that can't use it. The children now show as running, the notice explains how the same session and another session can reuse them, and status offers resume only to the session that launched the run. Thanks to @wireknight for reporting #2909.
  • After pi-subagents was updated or reloaded mid-session, subagent stayed off once the session started again (/reload or pi --continue), and subagents_enable wasn't offered either, so nothing could turn it back on. Pi records the unload as a removal of the extension's tools, and that was replayed as if you had turned subagent off. An unload is now recognized and the tools come back as you had them. Thanks to @bkdinoop for reporting #2910.
  • After such an update, a session continued in a new process (pi --continue) also kept bg_wait off, and a second update in that session lost subagent again. The tools the update removed now come back when the session starts, unless they are excluded for this process. (#2916)
  • Forked subagents now reuse the parent's prompt cache. A fork used to replace the parent's system prompt and tools, so its first request re-read the whole conversation. It now sends the parent's system prompt, tools and messages unchanged, and gets its own instructions in a <subagent_instructions> block at the start of its task. A fork also sees the parent's project context and skills even when its agent turns them off. On Claude with a 60k-token parent, a fork's first request went from 9.6k cached and 52k written tokens to 60.8k cached and 1.7k written. See tool-reference.md for the forks that still miss the cache. Fresh children are unchanged. Thanks to @gabsn for #2879.
  • /subagent-cost and other view-only slash reports no longer go into every later model request. They are still saved, shown in the TUI and sent to RPC callers. /run results stay in context because the model needs them. Reports saved before this update stay until compaction, so updating doesn't break a session's prompt cache. Thanks to @isjiajia01 for #2927 and @summer-tt for the report. (#2925)
  • With Pi's codemode on, every start or resume of a session added another copy of codemode's note to the bg_wait description, so the provider re-read the conversation without its prompt cache. The note now appears once and a resumed session keeps its tool declaration. Thanks to @SamuelBadr for the report. (#2889)
  • When a provider stopped a child with an error, such as a content-filter refusal, the child reported only the stop code. Its error now includes the provider's reply text as Reply text: … (up to 500 characters), so a refusal can be told apart from an outage. In a failed workflow, each failed child's line also starts with its own error instead of the Run fan-out: N/64 used line. Thanks to @stanleytelehealth for #2913.
  • A read-only child running grep … 2>/dev/null could be flagged needs_attention: the redirect counted as a file change, and output containing words like "error" counted as a failure. Redirects to /dev/null no longer count as changes, and a tool call counts as failed only when its result says isError: true. Calls blocked by a hard toolBudget don't count either. Thanks to @Liaokc for the fix and @builtroller for the report. (#2878, #2884)
  • A notice about a long-running bash call in a child suggested command.status, command.yield and command.cancel even when the child had no command controller, so following it failed with "No command controller is available for this child." The notice now suggests them only when they work. Thanks to @G0-0000 for #2882. (#2880)
  • On Pi 1.2 and later, the watchdog took the system prompt of a run started by an extension message (for example a wake sent with triggerTurn: true) as your prompt and showed it to its reviewer model as a real requirement. These runs no longer add to the watchdog's scope, and their edits are still reviewed against your earlier prompts. Thanks to @isjiajia01 for #2928 and @sternnick for reporting #2926.
  • A child using built-in MCP tools failed after 10 seconds even when its server was still connecting normally. It now waits for the connection, fails promptly when a connection fails, and stops waiting when the child is stopped or times out. This needs Pi 0.99.2 or later. Thanks to @qsgy-edge for #2904.
  • An extension that force-exits a headless run on quit could kill the background runner when one of its children ended, so the run failed with "Async runner process N exited with code 0 before writing a result". The runner now sets PI_SUBAGENT_RUNNER_PID to its own pid, so an extension can compare it with process.pid and leave the runner alone. Processes spawned from a child inherit the value but have their own pid. See extension-api.md. Thanks to @hughy for #2885. (#2883)
  • After Pi auto-compacted in the middle of a turn, the async and Fleet status widgets stayed hidden until the whole run ended. They now come back as soon as the compaction finishes. Thanks to @agustinsacco for #2891. (#2890)
  • When a background subagent finished, the parent often logged Failed to acknowledge the mission observer ... Timed out waiting for another process to finish updating with a stack trace and stalled for 200 ms. It now retries quietly a moment later. Thanks to @RainbowXie for the report. (#2896)
  • A finished mission run from an earlier Pi process in the same session was synced to its mission again every 60 seconds, rewriting the mission record each time. It is now synced once. Thanks to @BelovedYaoo for reporting #2905.

Don't miss a new pi-subagents release

NewReleases is sending notifications on new releases.