Repository navigation
fix: reject oversized run timeouts - #2517
Merged
Merged
Conversation
quifox
marked this pull request as ready for review
September 27, 2026 14:02
Contributor
|
action: "resume" passed timeoutMs straight to the runner deadline, so an oversized value still reached setTimeout. Also move the entry into 0.73.0.
Contributor
|
Want your agent to iterate on Greptile's feedback? Try greploops. |
reyhansofian
added a commit
to reyhansofian/pi-subagents
that referenced
this pull request
Oct 1, 2026
* fix: preserve read-only acceptance for risky review topics (#2191) * fix: preserve read-only acceptance for risky review topics * fix: retain risk gates for unclassified review tasks * docs: credit contributor for #2191 * fix: remove conflicting Fleet shortcut (#2205) * fix: remove conflicting Fleet shortcut * test: update Fleet hint expectations * feat: add PI_SUBAGENT_CACHE_RETENTION to set a child-only cache tier (#2190) * feat: add PI_SUBAGENT_CACHE_RETENTION to set a child-only cache tier Anthropic prices a cache write by the retention requested: the 1h tier costs more per write than the 5m one. A long-lived parent conversation earns that back by surviving idle gaps, but children are short-lived and rarely idle long enough to claim the longer window, so a wide fanout pays the higher write price with no benefit. PI_CACHE_RETENTION=long PI_SUBAGENT_CACHE_RETENTION=short keeps the longer window for the parent only, the split Claude Code makes between its main conversation and its subagents. Unset by default, so children inherit the parent's retention and behaviour is unchanged unless opted into. Spawned children take it through the launch env; in-process children wrap their own session stream function, since pi resolves retention per request as options.env?.[name] || process.env[name]. Scoping it per session rather than mutating process.env avoids racing a parent turn that streams concurrently. Verified end-to-end against a real child session: with the parent on long, parent turns report cacheWrite1h == cacheWrite and the child reports cacheWrite1h == 0. * test: cover the child cache-retention override; credit the change Adds focused regression coverage for both paths the override takes: the in-process stream wrapper and the spawned-child launch environment. Cases are the configured tier, unset inheritance, overriding a parent tier, preservation of other request env values and options, no mutation of process.env, sibling-session isolation, and a missing stream function. Extracts childCacheRetentionEnv so the spawned-child form is testable rather than an inline conditional spread at the spawn site. Adds the Unreleased changelog entry. * ci: bound Windows test concurrency (#2208) Cap Windows test-file concurrency and drain test-owned helper processes before fixture cleanup. Preserve Ubuntu scheduling and existing lifecycle deadlines. * fix: preserve stronger model exclusions (#2212) Preserve @rnavarro’s provisioning-failure handling and contributor credit while capping its TTL and retaining stronger live model diagnostics. * fix: report acceptance policy in capability rows (#2213) Preserve @Alice39s’s capability-reporting contribution and credit while sanitizing free-form labels in compact human rows. * fix: drain owned Windows process trees before cleanup (#2217) Fixes #2207. * fix: re-anchor cwd before workflow workers * test: fail fast when the stale-cwd fixture dies * fix: restore previous cwd after workflow worker start * test: assert runWorkflowScript restores the caller cwd * fix: report unexpected cwd restore failures Re-anchor a stale parent workflow process cwd before worker construction so a removed checkout directory no longer fails the launch, and restore the caller cwd afterwards. Only the intended missing-directory restore case is ignored; other failures are reported instead of hidden. Thanks to [@trewwwsec](https://github.com/trewwwsec) for #2211. * test: document the win32 cwd-skip and assert no cwd drift on failure * fix: avoid cwd mutation for healthy workflow launches * test: await workflow fixture teardown * test: make cwd access failure portable * test: support Node 24 module mocks * fix: restore operator-authorized delegation policy (#2218) Fixes #2216. Reported by and credited to @AlexDochioiu. * fix: keep revival startup waits non-blocking * fix: retain reconciled root failure diagnostics * fix: prefer exact agent names * test: isolate agent home boundary fixture * fix: compare canonical home directory identity * fix: avoid jiti for native async runner startup * docs: credit contributor for #2220 * fix: gate native async runner by capabilities * feat: route watchdog findings by importance * fix: apply httpIdleTimeoutMs to the detached runner dispatcher (#2227) Apply Pi's httpIdleTimeoutMs setting to the detached async runner's undici dispatcher on both the Node entrypoint and the standalone binary bootstrap, so async children against slow local models are no longer cut at undici's 300s header/body defaults while foreground children wait as configured. Project .pi/settings.json overrides the agent dir settings; 0 disables; invalid values warn and fall back to 300s. Diagnosis credit: @JordiPosthumus in #2199. * fix: keep progress updates out of parent turns * docs: credit silent supervisor progress contributors * test: make standalone revival lease proof deterministic (#2232) * feat: parameterize workflow scripts (#2234) Allow bounded plain-JSON arguments for inline, file-backed, validated, and scheduled workflows while preserving raw-script authority boundaries. * feat(tui): fold async widget with a header click (#2235) * feat(tui): fold async widget with a header click * docs: credit async widget header click contribution * chore: drop Pi 0.85.0 pi-server supplementation shim (#2236) * docs: add unreleased highlights and merge Added sections * fix: make Herdr bridge discovery nonblocking and dedupe unreleased helpers (#2237) * refactor: inline deadline checkpoint timing * refactor: deduplicate Herdr session helpers * fix: make Herdr bridge discovery nonblocking * test: trim duplicate unreleased coverage * test: make detached process cleanup portable * fix: settle asynchronous Herdr commands safely * fix: restore deadline checkpoint guard * refactor: remove synchronous bridge discovery * refactor: reuse Herdr status subscriptions * refactor: share chain output schema projection * test: restore edge case assertions * refactor: require Herdr session ownership * fix: settle Herdr async commands after SIGKILL * fix: await remaining Herdr ssh calls on the create and reconnect path * refactor: shrink chain output schema projection * fix: close adopted Herdr transport when disposal races reconnect * fix: reuse owner cleanup when disposal races Herdr reconnect * fix: surface ssh spawn failures in Herdr bridge discovery * fix: keep stopped aggregate children non-resumable (#2242) * fix: keep stopped aggregate children non-resumable * docs: credit stopped-child resume contribution (#2242) * fix: contain nested controls within the issuing subtree (#2243) * fix: contain nested controls within the issuing subtree * docs: credit subtree control contribution (#2243) * fix: start maintenance timers with the session (#2247) * fix: start maintenance timers with the session (cherry picked from commit 9eaf14e21cac98a51ab524a8a20a5d308bf23b2c) * docs: credit session maintenance contribution (#2244) (cherry picked from commit 4d910eff1904b33ef8cff3c20b13e3af57030f54) * fix(ci): count only maintenance-owned lifecycle timers (cherry picked from commit f299bd142926cb4ef5adb0b0f9b94ee47182c54b) * chore: drop manual maintenance lifecycle harness The real-Pi probe from #2244 is not wired into any script or CI and is pinned to Pi 0.85.1; the unit regression covers the timer lifecycle contract. --------- Co-authored-by: Skolte <[email protected]> * fix: explain a child model that an unloaded provider extension serves (#2249) * fix: explain a child model that an unloaded provider extension serves A foreground child runs inside the parent process and never loads the parent's ambient extensions, so a model registered by one of them fails Pi's model resolution with only `Model "x" not found`. Keep that core error and add the host rule and both remedies, matching the existing missing-tool diagnostic: an agent that needs a provider extension's models must run as a background child (`async: true`), or load the extension through `subagentOnlyExtensions`/`extensions`. The same annotation covers a background child launched without the ambient extensions, with the remedies that fit that host. Both hosts annotate only a creation/prompt failure that produced no turn, so exit codes and failure detection are unchanged. (cherry picked from commit c7c94b74fbcdaef59c9915a5a2bcdbfe20bf5b1f) * fix: report a capability ceiling that denies the child's provider extension A launch under `capabilityCeiling.denyExtensions` loads no extension at all, so the ambient-extension remedies cannot work there: `async: true` does not lift a ceiling, and listed `subagentOnlyExtensions`/`extensions` entries are suppressed by it. Both hosts now name the ceiling and its sources and point at the remedies that can work instead of directing the operator at changes the ceiling discards. The formatter takes the launch's resolved ceiling; the ordinary branches are unchanged when no ceiling is active. (cherry picked from commit 04589d5fc2dfa1c9fe5687ef9b09fb09aeff6f91) * test: clean up each diagnostic fixture directory `beforeEach` created a unique temp directory per test while the single `after` hook removed only the last one, leaving the earlier fixtures behind. (cherry picked from commit 9df89ffd91cfe18be52f4011492bf092aeb96b83) * docs: credit the contributor in the model diagnostic entry (cherry picked from commit a3b30b585579ecd737ddc4b296b9bdfef387ba71) * fix: qualify the async remedy in the model diagnostic A background child with an explicit `extensions` list also skips the ambient extensions, so `async: true` alone does not load a provider extension for it. --------- Co-authored-by: pwguler <[email protected]> * fix(runner): recognize Windows Bun standalone hosts (#2246) * fix(runner): recognize Windows Bun standalone hosts (cherry picked from commit 5b2d931403462a2c5cfe0fbcb6ed4095e1a77df1) * docs: clarify Windows standalone coverage and contributor credit (cherry picked from commit ad62a968b1d28b01421ff5486dc2ab61dd235b0f) --------- Co-authored-by: JohnsonRan <[email protected]> * feat: record the requested model and pre-attempt skips in run results (#2250) * feat: expose requested model evidence * docs: say skippedModels covers cached-exclusion drops only * fix: preserve rejected report content in diagnostic artifacts (#2257) * fix: preserve rejected report content in diagnostic artifacts (cherry picked from commit a34fb31407789979335afe6f819c5911fa13e1f6) * docs: changelog entry for rejected-report artifact fix (#2255) --------- Co-authored-by: Pietro Bongiovanni <[email protected]> * fix: retry premature stream termination (#2258) * fix: Retry premature stream termination Allow an unused fallback model to recover when a provider stream closes\nbefore its terminal event. Keep these per-request failures out of the\npersisted model-exclusion cache. (cherry picked from commit 6c190eeef5182bec8783b3eac5ebdc8ce7edcc25) * docs: credit the contributor in the stream-termination retry entry (#2256) --------- Co-authored-by: Naresh <[email protected]> * fix: honor PI_SUBAGENTS_PI_CODING_AGENT_PACKAGE_ROOT in the detached background runner (#2259) * fix: honor PI_SUBAGENTS_PI_CODING_AGENT_PACKAGE_ROOT in the detached runner (cherry picked from commit b372c2604430c458395c5758e553f6376c29f518) * fix: match foreground host precedence; add changelog credit (cherry picked from commit a6b813cb76ce55634cbe1ebc7bec67853eaa91e2) * test: cover a whitespace-only package-root override Also correct the comment that described the override as resolving first; argv discovery wins, matching the foreground resolver. * docs: say the package-root override still requires the canonical package Both resolvers validate the @earendil-works/pi-coding-agent name and its peers, so a renamed manifest is rejected even with the override set. --------- Co-authored-by: Phaethon <[email protected]> * docs: state that an existing operator path already satisfies a request VISION now says to name the existing path to the same outcome before adding anything, and that a second path fits only when the first loses work, cannot express the need, or is unavailable where it occurs. * perf: ship compiled JavaScript in the npm package (#2260) * perf: ship compiled JavaScript in npm package * fix: alias every host peer in the fallback loader for compiled runners On Node without module.registerHooks the preload delegates to runner-peer-loader.mjs, which only redirected pi-tui. A compiled runner launched on plain Node relies on the full JITI_ALIAS map the jiti CLI path used to consume, so the fallback loader now honors the same nativeRunner rule as the preload. * test: load the packaged entry with host peer aliases in the clean-install smoke Real Pi serves its own packages to extensions as virtual modules. The fixture has no Pi process, so the packaged entry is loaded after the host peer aliases are resolved and passed to jiti as aliases; loading it bare failed on CI with a missing @earendil-works/pi-coding-agent. * test: make fallback loader aliases portable * fix: scope compiled-runner peer aliases to package imports Pi's jiti loader must keep filesystem-path aliases when loading external child extensions. Applying the native hooks process-wide converted those paths to file URLs on Node 24, so provider extensions failed to register. Scope the full alias map to imports from the compiled package and leave external extensions to Pi. * fix: preserve peer aliases for native TypeScript runners Compiled runners must scope native hooks so Pi jiti can load external extensions, while source runners still need full aliases for generated external factories. Carry an explicit compiled-runner flag through the preload and test both launch contracts. * refactor: remove automatic model fallback (#2270) * refactor: remove automatic model fallback * test: identify compiled clean-install runtime * fix: let nested reviewers collect async results (#2272) - let nested reviewers collect session-owned async child results - preserve readable result references across replay and persistence races - enforce exact run and session ownership across result sources - report malformed owned result payloads as explicit failures Co-authored-by: Shahar Mor <[email protected]> * fix: avoid routine intermediate workflow child wakes (#2273) - keep routine successful workflow-child settlements context-only - wake the exact owner when terminal result publication fails - recognize a matching durable pending payload as committed publication - record failure-wake delivery only after the notification succeeds Co-authored-by: Greg Tiller <[email protected]> * fix: preserve watchdog scope on compaction (#2275) * fix: Preserve watchdog scope on compaction - Keep bounded user prompts available after session compaction - Clear transient orchestration activity independently - Add lifecycle regression coverage for compaction and session switch * docs: Credit watchdog scope fix - Add the compaction scope fix to the unreleased changelog - Credit @nimeetshah0 and reference PR #2263 --------- Co-authored-by: Nimeet Shah <[email protected]> * feat: gate inspector and project opening by authority policy (#2277) Gate `inspector.open` and `project.open` behind authority policy while preserving child-safe rejection precedence. Replaces #2269. Co-authored-by: kev <[email protected]> * fix: inherit parent providers in local foreground children (#2276) Bind local foreground provider inheritance to the exact invoking parent and isolate each child model runtime. Pane-native remote children continue using remote-machine provider discovery. Replaces #2274. Co-authored-by: Allen Lowe <[email protected]> * chore: release v0.68.0 * docs: improve v0.68.0 highlights * test: keep Herdr reconnect fixtures release-safe (#2282) * fix(inspector): detect Ghostty without launching it (#2285) * fix(inspector): probe Ghostty app reachability before taking over cmux embeds the Ghostty kernel and also sets TERM_PROGRAM=ghostty, so the Ghostty inspector plugin took over in cmux sessions. The AppleScript it runs then connected to a stale or missing "Ghostty" application registration and failed with -1728/-2741, leaving the inspector unusable (Enter did nothing useful in the async widget). Probe whether an application named "Ghostty" is actually reachable via osascript before claiming availability. When the probe fails (missing app, stale LaunchServices registration, or a non-Ghostty bundle such as cmux), the plugin declines and the dispatcher falls back to the inspector.command hint instead of emitting AppleScript errors. Adds unit tests covering platform/TERM_PROGRAM gating, the success path, the cmux stale-registration failure (-1728), and the empty-version edge case. * fix(inspector): require Ghostty host bundle id, keep osascript probe as fallback Address Greptile review on #2281: P1 (Probe Can Select Wrong App): when cmux sets TERM_PROGRAM=ghostty while standalone Ghostty is also installed, the osascript probe reached that separate app and returned true, so the dispatcher took over and operated on Ghostty's front window instead of the current cmux session. Availability now checks the macOS host bundle id (__CFBundleIdentifier): standalone Ghostty is com.mitchellh.ghostty, cmux is com.cmuxterm.app. When the host id is present and not Ghostty, the plugin declines regardless of whether Ghostty is reachable. The osascript reachability probe remains as a fallback only when the host id is absent (SSH/tmux-style non-GUI hosts). P2 (Contributor Credit Is Missing): the Unreleased changelog entry now credits @wangpi26 and references #2281, per the external-contributor-credit review rule. Adds tests for the host-bundle match, the cmux mismatch (even with a reachable Ghostty app), and the absent-host fallback path. * fix(inspector): propagate Ghostty probe errors, reduce at availability layer Address Greptile P2 (preserve-error-signals) on #2281: detectGhosttyApp wrapped every probe failure in a catch that returned false, making expected "app unavailable" failures indistinguishable from operational failures (timeouts, permission denials, malformed AppleScript). That discarded useful diagnostics, violating the repository directive not to turn thrown/rejected errors into less-informative results. detectGhosttyApp now propagates probe failures unchanged. The reduction to boolean happens one layer up in the availability predicate, whose InspectorPlugin.available contract is boolean by interface definition: a probe failure means the plugin cannot take over, so the predicate returns false there explicitly rather than swallowing the error inside the helper. Adds tests asserting detectGhosttyApp returns true on a non-empty version, false on an empty version, and rejects (propagates) on a probe failure. * fix(inspector): require Ghostty host identity --------- Co-authored-by: wangpi26 <[email protected]> * fix: keep optional npm root discovery silent when npm is unavailable Global package-root discovery probes `npm root -g` at startup. `execSync` inherits stderr, so on a host without npm the shell's "command not found" message reached the Pi terminal even though the optional probe's failure is already handled. Ignore stderr for the probe in both discovery copies so a missing or broken npm stays quiet. Assisted-by: pi (deepseek-v4-flash-vision-exp) * fix(acceptance): preserve staged index baseline (#2286) * test: harden missing npm regression * fix: stop predicting a child's tools from its parent's session Host tool discovery read pi.getAllTools(), which pi filters by the host session's own --tools and excludeTools. A dispatcher started with a narrow allowlist was therefore treated as a runtime missing read, bash and grep, and every child lost those tools; because each child's registry then became its own plan, the loss compounded at every hop until nothing but contact_supervisor survived. Prediction cannot work here. A child is a separate session created by createAgentSession, which builds its own tools, and for detached children the plan is resolved in a different process than the one that runs them. The child already validates its real registry against requiredTools on agent_start, before its first model call, and reports exactly which tools are missing, so the pre-launch guess is removed along with the review and scout lane check and the audit fields that only it produced. Fork hosts keep their guarantee through that same check: a runtime whose builtin menu differs fails the launch and names the tools, rather than having its children silently stripped by a parent's inference. Closes #2289 * fix(worktrees): fail closed on dependency link errors (#2288) * fix(async): isolate revival confirmation handshake * fix(orca-progress-tabs): keep the viewer one-liner free of backslashes Orca runs `terminal create --command` through the user's login shell, while the viewer one-liner is quoted as a POSIX single-quoted string. fish collapses `\\` inside single quotes to `\`, so `node -e` received `char==='\'` — an unterminated string literal — and every progress tab opened on a SyntaxError instead of the progress mirror. Comparing against `String.fromCharCode(92)` removes the only two backslashes from the viewer script, so the same quoted command round-trips through POSIX shells and fish alike. The `'"'"'` quoting idiom is unchanged, and the regression test asserts the generated command carries no backslash. * fix: keep detached workflow work visible and accurately reported Preserve explicit async dispatch without treating launch receipts as completed child work or final report references. Retain session-owned nested routing after coordinator cleanup and prevent mission-only directories from shadowing real runs. * fix(delegation): report blocked tool budgets * fix(delegation): require exact budget block message * feat(acceptance): typed gates bridge json stdout into structuredOutput (#2315) * feat(acceptance): typed gates bridge json stdout into structuredOutput `gate` now accepts `{ command, output: "json", schema?, timeoutMs? }` in addition to the string form. When a typed gate passes, its stdout is parsed (and validated against `schema` when given) and becomes the child's `structuredOutput`, recorded on the verify run and projected into status.json. Empty, truncated, non-JSON, or schema-invalid stdout fails the gate so the verdict is never dropped silently. Typed gates are never memoized, because their inputs (a report, a log) can change without the tracked tree changing, and `output: "json"` rejects `outputSchema` so a run has one structured-output source. This lets a post-run classifier supply a verdict that `runs.lanes` and workflow scripts branch on without the parent reading the child's output. Docs cover the gate contract and command-runner agents as typed workflow steps; `examples/typed-gate` is a runnable, vendor-free version of both. Also corrects the tool reference: `maxOutput` has no default cap. * fix(acceptance): reject explicit typed verify commands combined with outputSchema The gate shorthand already rejected output: "json" alongside outputSchema, but the same policy written as an explicit acceptance.verify entry slipped through and the agent's structured_output silently won over the gate value. Both spellings normalize to the same verify commands, so preflight now checks the normalized policy once and names which spelling conflicted. * fix(acceptance): keep one structured-output source across every spelling Greptile pointed out that an agent-declared outputSchema could still coexist with a typed gate. The check now runs once after agent defaults are merged, where the effective outputSchema (launch param or frontmatter) and the effective acceptance (gate, explicit verify list, or defaultAcceptance) are both known, and the error names both sources. Documented in the tool reference, changelog, and the bundled pi-subagents skill, which also gains a note on typed gates and command-runner agents as typed steps. * chore(release): v0.69.0 Typed gates with JSON verdicts, Ghostty detection fix for embedding terminals, and quiet startup without npm. * fix(runner): settle aborted runs whose session creation hangs abortChild returned early when no session existed yet, so it never armed the ABORT_SETTLE_MS backstop. A hung factory.create() therefore ignored the run timeout, stop and interrupt indefinitely, and because session opens are serialized process-wide, one wedged extension startup left the run "running" until the 24h stale-run threshold. Abort the session only when one exists and always arm the settle timer. A session that arrives after the forced settle is already disposed by the launch block. * fix: keep native async runner with configured extensions (#2314) * fix: keep native async runner with configured extensions * docs: include pull request in contributor credit * feat: add child-only extension defaults * fix: stabilize inline workflow coverage key * test(async): observe revival confirmation control * fix: reject invalid workflows before admission * fix: reconcile native child usage at settlement * fix: preflight direct async worktrees * fix: tolerate Windows supervisor scan races * fix: expand conditional schema diagnostics * fix(release): prevent source package publication * feat(agents): add descendant agent allowlists * fix: keep project memory across linked worktrees * fix(status): show workflow child transcripts (#2337) * fix permission session routing isolation (#2334) * fix: give reviewers bounded working-tree diffs (#2333) * docs: normalize unreleased changelog sections (#2340) * docs: clarify async child accounting (#2341) Document `/subagent-cost` as the supported combined parent and child accounting view, including missing-artifact lower-bound semantics and the limitation of Pi built-in session totals. Thanks to @swarajban for #2313. * refactor: simplify unreleased workflow changes (#2343) * fix: wake waits for nested supervisor requests (#2345) * chore(release): v0.70.0 * docs: require implementation topology preflight (#2350) * docs: require implementation topology preflight * docs: reconcile staged fix topology * fix: support Pi 0.86 (#2349) * fix: support Pi 0.86 * fix: keep live detail hints readable * ci: shard Windows tests * test: batch foreign workflow steering cases * fix(child-session): preserve host SDK ownership (#2352) * test(pi-spawn): cover host package root discovery from installed entries * fix(child-session): load the host SDK from the resolved host package root The default in-process child session factory imported @earendil-works/pi-coding-agent through a bare specifier, which resolves against the extension's own node_modules tree. On npm-hosted Pi installations the peer packages live outside that tree, and Pi 0.86.0 no longer serves virtual module resolution to extension code, so foreground child launches failed with ERR_MODULE_NOT_FOUND while the host itself ran fine. Resolve the host package root (PI_SUBAGENTS_PI_CODING_AGENT_PACKAGE_ROOT override, then pi-subagents' install location, then the running pi binary's location) and import the host's entry file by file URL, so children share the host's single SDK instance. A bare import remains the last resort; an explicitly overridden root that cannot be imported is reported instead of masked. * fix(child-session): prefer the running host root, validate root identity, preserve host errors Address review findings on the host-SDK loader: - Prefer the running pi process's location over the package manager's view of pi-subagents' install tree, matching how the existing child-launch code treats installed-package resolution as the last fallback. An extension tree that contains its own (stale) pi-coding-agent copy no longer shadows the host that owns the child. - Validate package.json identity before importing a selected root, as the documented override contract promises: roots naming another package are rejected with a configuration error instead of executing unrelated code. - Stop masking host SDK failures: only module-resolution failures on an auto-discovered root fall through to the bare specifier; evaluation and dependency errors from a correctly discovered host are reported as-is. * test(child-session): cover override identity rejection and Windows symlink portability - Rejecting an override root whose package.json name is not @earendil-works/pi-coding-agent now has direct coverage. - The bin-symlink discovery test skips on Windows, where file symlinks require elevated privileges, matching the established test pattern. * fix(child-session): preserve host SDK ownership --------- Co-authored-by: nazerim <[email protected]> * refactor: remove inferred no-edit completion failures (#2356) * refactor: base acceptance inference on declared roles * refactor: remove inferred no-edit completion failures * fix(package): launch compiled inspector bootstrap (#2361) * fix(package): launch compiled inspector bootstrap * test: stabilize async acceptance timeout assertion * docs(agents): clarify custom writer roles (#2363) * fix: preserve internal provider context (#2365) * chore: cut over Pi support to 0.86.1 * fix(watchdog): declare helper working directories * fix: route pruned summaries through model registry * docs(changelog): credit Pi 0.86.1 runtime fixes * fix: complete Pi 0.86.1 support cutover * fix: drop obsolete Pi smoke targets * refactor: simplify Pi runtime fixtures * fix(watchdog): reject unsafe helper cwd * fix(watchdog): reject Unicode cwd separators * fix: show resolved workflow child model (#2367) * fix(agents): apply model settings to runtime-registered agents (#2369) * fix(agents): apply subagent model settings to runtime-registered agents Runtime-registered agents were appended to discovery after every settings pass, so `subagents.defaultModel`, `defaultProvider`, `defaultThinking`, and `agentOverrides.<name>` never reached them and they silently inherited the parent session model while `/subagents-models` reported the same. `mergeRuntimeAgents` now takes the discovery context (cwd, scope, preferred provider) and runs runtime agents through the existing default/override pipeline. Only the model-tier override fields (`model`, `defaultProvider`, `fast`, `thinking`) apply; prompt, tools, context, and every other field stay owned by the registering extension. A definition `model` still wins over `defaultModel`, and `model: false` returns the agent to session inheritance. * Update CHANGELOG.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix(agents): preserve provider context for runtime views --------- Co-authored-by: bioShaun <[email protected]> Co-authored-by: oms004 <[email protected]> Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * refactor: deslop unreleased v0.70.0 changes (#2370) * refactor: tighten typed cleanup fixtures * fix(tui): clarify expand key fallback hints * test(tui): align expand-key fallback coverage * fix(runtime): resolve host SDK exports correctly (#2371) * test: contain test runner resource usage (#2372) * test: contain test runner resource usage * test: track the owning test process * chore(release): v0.70.1 * fix(context): support Pi 0.87 session edits (#2381) * fix: raise Pi AI peer floor to 0.86.1 Credit to @samuela for the precise #2373 compatibility report. * feat(rpc): expose subagent cost as data Supersedes #2378 while preserving Ray Tri’s authored implementation and linked changelog credit. Thanks @raymondtri. * fix(watchdog): restore Pi 0.86 host compatibility Closes #2377. Thanks @zieglar for the report and reproduction. * fix(resume): preserve retained parent authority Closes #2379. Thanks @riskywhat for the report and reproduction, and @shkrabov for the earlier allowlist foundation in #2338. * perf: load subagent tool on demand Supersedes #2380 while preserving Timon Albrecht’s authored implementation and linked changelog credit. Thanks @Knimoms. * feat(delegation): expose cumulative per-attempt usage Supersedes #2374 while preserving @bioShaun’s authored implementation commit and linked changelog credit. Thanks @bioShaun. * fix(observability): expose external CLI logs Closes #2375. Thanks @Shujakuinkuraudo for the detailed reproduction and diagnosis. * fix(agents): default workers to fresh context Closes #2384. Thanks @eduardopicolo-cb for the detailed report. * feat: expose async workflow lifecycle events Supersedes #2382 while preserving Navid EMAD’s authored implementation and linked changelog credit. Thanks @navidemad. * fix: align MCP direct tool names with pi-mcp-adapter Closes #2394. Thanks @qsgy-edge for the detailed report, implementation, and validation. * fix(notify): dedupe shared completion sends Closes #2389. Thanks @hongchu098 for the detailed reproduction and diagnosis. * fix: detect dynamic tool support from the running Pi installation (#2398) * fix: detect dynamic tool support from the running Pi installation The host SDK is not a dependency of this package, so a bare module resolution only succeeds where it happens to be installed next to us — a repository checkout with devDependencies. Every distributed install (npm or git) resolved nothing, warned, and silently kept the subagent tool eager: the compact subagents_enable loader never appeared, even on hosts that support it. Read the version from the running host instead, using the same root precedence as host-owned child sessions (running host, explicit override, install tree). The 0.86.1 floor is unchanged, and a missing host package now reports that it could not verify support instead of claiming the host is too old. Closes #2397. * fix: keep host manifest failures visible while gating dynamic tools Review feedback on the first revision: the probe collapsed every read or parse failure into undefined, so a selected root with a broken manifest was silently replaced by a different Pi installation, and the caller could only report a generic "could not locate" warning. The selected root is now authoritative — running host, then an explicit override, then the install tree, the precedence host-owned child sessions already use — and its concrete manifest failure, missing version, or foreign package identity is reported as the reason. The version floor message also names the installation it measured, so a decision made from an unconfirmed root cannot look like it came from the running host. * fix: fail closed when the running Pi host cannot be verified The activation gate only trusts the Pi that owns the session: the running host, or an explicit PI_SUBAGENTS_PI_CODING_AGENT_PACKAGE_ROOT override. An SDK reachable through our own install tree cannot be proven to be that installation, so it no longer decides the version floor — dynamic activation stays off, and the reason names the unconfirmed root. Tests that exercise activation now declare the host they simulate instead of relying on a copy next to the checkout. * fix: classify watchdog diff as read-only (#2410) * fix(agents): honor hidden skill model invocation (#2412) * fix(agents): respect disable-model-invocation when injecting subagent skills Skills marked `disable-model-invocation: true` are meant to be user-only: invocable via explicit `/skill:name` commands but excluded from the model- facing skill set. pi-subagents' skill loader parsed only `name`/`description` and never read that flag, so any broad skill list resolved for a child could leak hidden skills into the subagent's `<available_skills>` prompt. Parse `disable-model-invocation` from skill frontmatter (matching the pi host's loader semantics: only the literal string "true" opts out) and thread it through discovery and resolution as `disableModelInvocation`. Filter on it in `buildSkillInjection` — the single chokepoint every prompt-injection path funnels through — so hidden skills never reach a child prompt regardless of which caller assembled the list. Explicitly naming a hidden skill still resolves it (it stays user-invocable), but it is dropped at injection time, aligning with the "hidden = user-only" contract. Add test/unit/skills-disable-model-invocation.test.ts covering metadata exposure, explicit-name resolution, buildSkillInjection filtering (including the all-hidden empty case), the pushEntry priority-upgrade branch, and non-"true" flag values. * fix(agents): honor disable-model-invocation in proactive skill recommendations Greptile review follow-ups for #2400: - recommendProactiveSkillSubagents drops hidden skills (and their descriptions) from model-facing proactive recommendations; the AvailableSkill type now carries disableModelInvocation. - Fix the priority-upgrade test to actually exercise pushEntry's same-file branch: register the shared skill dir via a settings entry, then a same-target symlink, so the second pass hits the same resolved file at higher project priority. - Add a recommendation test pinning that hidden skills are not suggested. - Credit @toRolex in the Unreleased changelog, per repo policy. * test(agents): cover name-level source precedence for disableModelInvocation The previous test claimed to exercise pushEntry's same-file priority-upgrade branch, but pushEntry keys its seen map by path.resolve (lexical), and the .pi/skills root scan lexically covers any .pi-relative settings path — so that branch never actually ran. Replace it with a test over the path that is reachable in practice: two same-named skills from different sources, where name-level dedup (chooseHigherPrioritySkill) keeps the higher-priority project entry and that entry must carry the flag. Verified by mutation: disabling the flag read in readSkill, or breaking the higher-priority-wins dedup, both turn the test red. Also drop the now-unused makeProjectPackageSkill helper. * fix(skills): match host YAML boolean semantics --------- Co-authored-by: rolex <[email protected]> * fix: resolve host peer aliases through symlinks (#2413) * fix: resolve host peer aliases through symlinks * docs: credit pnpm peer alias fix --------- Co-authored-by: Henrique Bastos <[email protected]> * fix: clarify retained child fallback guidance (#2416) * fix: preserve structured output rejection evidence (#2418) * fix(runner): authorize revival before heavy imports (#2419) * fix(runner): authorize revival before heavy imports * fix(runner): retain binary loader context after startup * fix(runner): load compiled execution through Jiti * fix(runner): keep revival candidate IO lightweight * fix(watchdog): settle structured-only child terminals (#2424) * fix(watchdog): honor structured terminal settlement * fix: preserve structured evidence on failed runs * fix: reconcile structured failure evidence seams * fix: discover compiled Bun host package roots (#2425) * fix: discover compiled Bun host package roots * fix(host): use target-platform manifest paths * fix(host): report argv manifest failures without fallback * test(host): pin synthetic POSIX root platform * fix(reviewer): report unavailable diff without Git HEAD (#2426) * fix: keep reviewer diff tool available without Git baseline * test: assert non-Git reviewer diff diagnostic independently * fix(async): report runner exit code and signal when a runner dies without a result (#2427) * fix(async): report runner exit code and signal when a runner dies without a result Refs #2423 * fix(async): keep runner exit on sticky unknown process-terminal proofs * fix(workflow): name the workflow child that has no agent (#2428) Refs #2422 * test(async): bound part-3 lifecycle waits so a stalled runner fails by name (#2429) * fix(prompts): discover symlinked prompt workflow files (#2431) * fix(prompts): discover symlinked prompt workflow files Closes #2430 * fix(prompts): only skip dangling prompt symlinks; surface other stat errors * feat(intercom): keep readable child session names by claiming the route as the intercom ID (#2433) * fix(runner): strip inherited Git routing environment (#2440) * fix(runner): strip inherited Git routing environment * fix(runner): also filter external CLI default env; test both launch points * fix(runner): match Git routing variable names case-insensitively --------- Co-authored-by: Nico Bailon <[email protected]> * feat(status): expose workflow terminal proof (#2442) * feat(status): expose workflow terminal proof * fix(status): share workflow child process evidence with capacity release Accept runner startup failures, skip synchronous children, and check runner identity, matching the existing workflow capacity release rules. --------- Co-authored-by: Nico Bailon <[email protected]> * fix: restore activated tools and require workflow child evidence (#2444) * chore(release): v0.71.0 * fix(worktree): keep UTF-8 naming labels within byte cap (#2447) * fix(worktree): keep naming labels within byte cap when truncation splits multi-byte UTF-8 truncateUtf8 cut the encoded buffer at exactly maxBytes and decoded the dangling bytes to U+FFFD (3 bytes each), so a label truncated at a multi-byte boundary could exceed the 256-byte naming-label cap. The runner then wrote async status files that readStatus rejects with "steps[i].naming.label exceeds 256 UTF-8 bytes", leaving the run stuck as a "corrupt active async run" at every startup. Back off to a code-point boundary before decoding instead, matching the existing truncateUtf8Head approach in notify.ts. Adds a regression test covering split points around the cap. * docs(changelog): credit UTF-8 label fix contributor --------- Co-authored-by: chenhaoxiang <[email protected]> * fix(status): report the child's actual context limit (#2448) * fix: declare typebox as peerDependency, not dependency (#2455) * fix: declare typebox as peerDependency, not dependency typebox is host-provided by Pi; listing it in dependencies installs a physical copy that bypasses Pi's extension module mapping and creates duplicate runtime modules (Pi warns on startup). Move it to peerDependencies with a "*" range, matching other Pi extensions. * fix: treat typebox as a host peer across manifest, lockfile, and tests * fix(binary): pass Pi's TypeBox to the binary runner loader --------- Co-authored-by: Nico Bailon <[email protected]> * fix(fast): accept any native openai-codex model (#2457) * fix: pair awaited workflow child lifecycle events (#2458) * fix: pair awaited workflow child lifecycle events * test: trim awaited child lifecycle assertions * test: remove redundant detached lifecycle checks * fix(external-job): service bridges of child-launched runs (#2450) * fix(external-job): service bridges of child-launched runs Only the root session's async job tracker serviced external-job bridge requests. A child session's fanout subagent tool launched async runs but never serviced their bridges, so an external-job agent launched by a child stayed queued. A child session now services the bridges of the external-job runs it launches. Closes #2449 * fix(external-job): keep child runs tracked until runner metadata settles async-execution writes the launch status.json before the runner starts. Its steps carry only agent and status, with no runner field, and the subagent:async-started event fires at that point. The runner adds the runner metadata later. externalJobBridgeEligibility reads an omitted runner as not-required, so the child sweeper deleted the run when it swept before the runner wrote its status. The runner then wrote its bridge request, and nothing serviced it. The child sweeper now keeps every run until the run is final, as the root tracker does. It skips servicing on sweeps where the status says no bridge is required, and re-checks on the next sweep. Refs #2449 * fix(supervisor): show question text in pending requests (#2461) * test: wait for terminal status after structured-evidence result (#2459) * test: record terminal-proof diagnostics for post-proceed import timeout (#2463) * test: record terminal-proof diagnostics for post-proceed import timeout * test: keep post-proceed diagnostics from changing the test outcome * test: poll for the rejection marker instead of fs.watchFile (#2464) * fix(external-job): follow up child-launched external-job runs (#2466) * fix(external-job): follow up child-launched external-job runs A session resolves the runs of its children as nested runs, and the nested resume path always needs a Pi session file. An external-job run has none. So resume from a child failed with "does not have a persisted session file to resume from", and the provider's followUp never ran. Only root-launched async runs reached the external-job follow-up path. When the selected step of a nested run has an external-job runner, the resume target now comes from the run's own directory, built with resolveAsyncResumeTarget and nestedRunScope. The existing follow-up gates then apply, and a live run gets the existing "still running" message. A launch status has no runner yet. If the agent definition is external-job, the resume fails closed with the existing "no persisted provider metadata" message. Nested Pi runs with a session file keep session-file revival. A child launches the follow-up under its nested route, so the duplicate check now looks there too. Before, a repeated resume from a child called the provider's followUp a second time. * fix(external-job): surface agent discovery errors on nested resume A launch-status nested run looked up its agent definition to decide whether it was an external-job run, but swallowed discovery failures and fell back to the Pi session-file error. Let the discovery error reach the caller instead. --------- Co-authored-by: Nico Bailon <[email protected]> * test(nested-control): wait for runner terminal proof and keep its cwd out of the fixture (#2470) * test(nested-control): wait for runner terminal proof before cleanup A complete run is not proof that its runner exited, and signal-zero on the status pid can remain positive on Windows after an identity-matched runner close was observed. Use the persisted process-terminal proof to finish the test, and avoid spawning the runner with a disposable fixture directory as cwd. Keep cleanup errors visible instead of relying on an unproven longer retry. * test(nested-control): record the source run cwd outside the fixture A follow-up runner starts in the source run's recorded cwd, not the caller's, so passing ctx(os.tmpdir()) did not move it. Record the isolated test root as the nested run's cwd instead. * fix(council): load the council protocol through a guide topic (#2469) * fix(council): load the council protocol through a guide topic /council told the model to read the council-mode skill files by relative path. Under pi --no-skills those files are neither in context nor resolvable from the cwd, so the council could not start. Add a council guide topic that returns the packaged skill plus the references it asks for, and point the prompt at it. Closes #2467 * docs(council): enable subagent first and note the council topic source * fix(tui): stop async widget flicker while Fleet roster is open (#2468) * fix(tui): stop async widget flicker while Fleet roster is open * fix(tui): recompute Fleet coverage on refresh instead of retaining it Retaining coverage across refreshes could hide workflow details from both surfaces for a frame when navigation or live stats change roster fit. Recompute coverage synchronously with the last paint width so the async widget, which paints above the roster, always sees current coverage. Also credit the contributor in the changelog. * fix: avoid stale pi-ai during tool activation (#2471) * fix: avoid stale pi-ai during tool activation * docs: credit stale pi-ai activation fix * docs: align dispatch contract guidance with runtime (#2473) (#2476) * fix: avoid blocking session startup on global agent discovery (#2477) * fix: avoid blocking session startup on global agent discovery * fix: align runtime discovery and wake session catalog waiters * test: make global npm fixtures safe for quoted paths * fix: await current agent catalog for direct execution * fix: tighten unreleased async lifecycle paths (#2479) * fix(foreground): isolate awaited child lifecycle observer failures * fix(child): scope external-job bridge tracking to owning session * perf(fleet): reuse keyed prepaint roster output * docs: clarify external-job follow-up in packaged guide * test(foreground): assert typed child result without casting * fix(foreground): emit completion after status read failure * fix(foreground): preserve completion subscriber delivery * fix(activation): accept stray subagents_enable arguments (#2492) * fix(cost): include async single and chain child usage (#2490) Fixes #2484. Thanks to @zeezooz for the report. * fix: enforce the capability ceiling before fork preparation (#2481) A foreground launch that uses fork context now checks every agent that can launch against the full launch ceiling (request, session, and inherited child-runtime) before building the pruned writer or branching the parent session, and rechecks each agent right before its fork is prepared. Dynamic fan-out templates bounded to zero items and fully fresh launches keep the existing child-launch check. Co-authored-by: Antonio Correa <[email protected]> * feat: support external inspector registration (#2482) Loaded extensions can register external inspector providers through the pi-subagents:inspector-register:v1 event or the pi-subagents/inspectors helper. Fleet and inspector actions use them after the built-in Herdr and Ghostty inspectors. Registrations are shared by the pi-subagents runtimes on the Pi event bus, so they survive a duplicate-runtime takeover, and are cleared when the last runtime shuts down. Co-authored-by: ninjapenguin <[email protected]> * fix(models): resolve provider-prefixed catalog ids (#2491) Fixes #2487. A provider-qualified query such as openrouter/auto-beta now falls back to a unique normalized id match inside that provider when fuzzy matching finds nothing. Thanks to @schmlblk for the diagnosis. * perf: load the subagent executor and Fleet on first use (#2493) Related to #2480. The extension entry no longer imports the foreground executor graph or the Fleet view at startup; they load through a memoized dynamic import on first use. Registration is unchanged. Entry import drops from 264 to 199 pi-subagents modules. Thanks to @h4yfans for the profiling in #2480. * fix(async): scope runner liveness probes to the PID namespace (#2498) Stale-run reconciliation no longer marks a live async run failed when a Pi process in a different PID namespace (another container, or a macOS/Windows host sharing a container's PI_SUBAGENTS_TEMP_ROOT) probes its PID and gets ESRCH. Runs record their Linux PID namespace; a probe that cannot match it falls back to the existing 24-hour stale-status rule. Related to #2494 and #2495. * fix(watchdog): route helper model calls through the session registry (#2497) Watchdog review, child-watchdog permission arbitration, and the Prompt Audit rewrite now use ctx.modelRegistry.streamSimple instead of the legacy provider-config lookup plus the global compat dispatcher, so models from complete providers reach their provider-owned stream. Also drops the incorrect claim that provider-extension models need async children. Fixes #2496. * chore: deslop unreleased changes (#2500) * test(deadline): give the short-lead checkpoint case the default result wait (#2501) * chore(release): v0.72.0 * ci(release): require maintainer approval before publishing * chore(release): v0.72.1 * ci: shorten the test workflow critical path (#2502) * ci: shorten the test workflow critical path Build and pack the standalone candidate once and run matrix modes four at a time. Split Ubuntu into two shards and Windows into four, keeping Windows at two concurrent files per runner. Typecheck once and cancel superseded PR runs. * ci: keep standalone modes serial Four concurrent modes pushed CPU-bound parents past their 45s deadline. * ci: give non-PR test runs their own concurrency group * feat(workflows): label workflow failures with a kind (#2509) * feat(workflows): classify script failure kinds Fixes #2506 * fix(workflows): classify runtime failures * fix(workflows): leave stopped workflows without a failure kind * fix(workflows): label runtime SyntaxErrors as script failures * docs(workflows): remove duplicated failure-kind paragraph * fix(workflows): cap workflow result text and mark cut previews (#2508) * fix(workflows): cap workflow result text and mark cut previews Fixes #2505 * fix(workflows): cap oversized workflow failure errors * fix(workflows): bound child errors in workflow call trace text * fix(workflows): keep full trace errors in the saved workflow result * fix(workflows): save the full workflow result outside child outputs * fix(workflows): reject unknown literal agent names before child launch (#2507) * fix(workflows): reject unknown literal agent names before child launch Fixes #2504 * fix(workflows): match launch-time agent discovery in prevalidation * fix(workflows): skip agent prevalidation when runs is rebound * fix(workflows): resolve the parent model only for workflow requests * fix(workflows): keep the saved full workflow result within artifact retention (#2510) * fix(workflows): keep the saved full workflow result within artifact retention * docs(workflows): state saved workflow result retention per artifact location * fix: resolve MCP direct tools from the adapter's mcp-adapter.json config (#2511) pi-mcp-adapter 3.0 reads <agent dir>/mcp-adapter.json and .pi/mcp-adapter.json and no longer reads Pi's own mcp.json files. Child direct-tool resolution now reads the same files in the adapter's order. Co-authored-by: Li JiangHeng <[email protected]> * fix(activation): tell the model when enabled tools arrive on bridged providers (#2514) * fix(activation): tell the model when enabled tools arrive on bridged providers * test: pin the bridged-provider guidance in the enable result * feat(tui): color running subagent spinners with Pi's thinking-level colors (#2512) Running glyphs use Pi's thinking-level border color: one child uses its recorded thinking level (else the main session's level), several children use the main session's level. Co-authored-by: pwguler <[email protected]> * test(missions): give competing lock-recovery writers time to start on Windows (#2515) * refactor: tidy the unreleased changes before release (#2516) Resolve each child's thinking level and header tone once per row, build every tagged workflow error through taggedWorkflowError, type the main thinking-level read, delimit status.json field names in truncation notices, cut duplicate or projection-only tests, and tighten the new workflow docs paragraph and three changelog entries. * chore(release): v0.73.0 * fix: reject oversized run timeouts (#2517) Co-authored-by: quifox <[email protected]> * fix(agents): advertise subagents via a named prompt section (#2519) Co-authored-by: reevo <[email protected]> * test(runner-bootstrap): poll startup state instead of fs.watchFile (#2520) * test: stop temp-root cleanup from failing passing Windows test files (#2521) * test(workflows): wait for durable async outcomes (#2522) * fix: reject stops after the runner stops reading them (#2523) * chore(release): v0.73.1 * feat: show new version highlights once after an upgrade (#2524) * fix(activation): let the model check its tool list after subagents_enable (#2525) The subagents_enable result told the model that on some providers subagent appears only after the next user prompt, so it should not retry it in this turn. pi-subagents cannot tell which provider is running, so on native Pi providers, and on bridges that refresh the tool list mid-turn, the model was told to wait even though subagent was already available. The result now tells the model to check its own tool list: if a subagent tool is there (possibly with a prefix), call it, starting with list+capabilities; if not, the provider fixes the tool list for the whole prompt, so wait for the next user prompt instead of retrying. The --exclude-tools subagents_enable operator hint and the appended advertised catalog are unchanged. * fix: support older Git diff prefix options (#2527) * fix: support older Git diff prefix options * docs: credit Git compatibility fix --------- Co-authored-by: quifox <[email protected]> * fix(activation): enable subagents_enable on in-process hosts (#2531) Drop the filesystem host-version probe from the dynamic tool gate. Pi 0.86.1 is already the oldest supported host, and in-process hosts such as pi-web cannot provide argv or env evidence of their package root, so the probe only produced a false warning and kept subagent eager. The gate now checks only that getAllTools, getActiveTools, and setActiveTools exist. Fixes #2526 * test: run tool activation smoke in CI (#2528) * test: run tool activation smoke in CI * docs: credit tool activation CI coverage --------- Co-authored-by: quifox <[email protected]> * fix(supervisor): skip attention notices for answered supervisor requests (#2532) A native supervisor request is already its own parent turn. The async tracker now emits the needs-attention control event immediately for status and waits, marked so control-notices does not start a parent turn, and sends the parent notice plus intercom copy after 60 seconds only when the request is still unanswered and the run is still active. Fixes #2529 * feat(agents): allow advertise through agentOverrides (#2534) Adds `advertise` as a supported `subagents.agentOverrides.<name>` field so builtin and custom agents can join the parent-prompt catalog from settings without copying the agent file. Runtime-registered agents still cannot be advertised. Co-authored-by: gao.wei.strive <[email protected]> * fix: align MCP config hash with pi-mcp-adapter 3.1.0 (#2539) pi-mcp-adapter 3.1.0 adds a stdio server's inheritEnv and literalEnv settings to its config hash. Child MCP direct-tool resolution still computed the old hash, so every cached stdio entry looked stale and mcp: selectors failed closed. The child hash now matches the adapter 3.1.0 identity, pinned by a golden-value test. Co-authored-by: Li JiangHeng <[email protected]> * fix: recover child aborts when compaction starts late (#2537) Pi can emit compaction_start after agent_settled. The foreground and background child runners latched the compaction marker only on agent_settled, so this event order left the safe abort recovery disabled. Both runners now latch the marker for the late order too, covered by integration fixtures that script it. Co-authored-by: jiuai233 <[email protected]> * fix(retention): reclaim async runs bound to terminal or pruned missions (#2536) Async run retention kept every run with a mission binding forever, so old runs accumulated once their mission finished or was pruned. Retention now reclaims old runs whose mission is terminal or no longer exists. It keeps runs whose mission is still active, whose binding or mission record cannot be read, and runs with a pending mission observer index, because the watcher needs the run's binding to retry that mission sync. Fixes #2535 Co-authored-by: julu <[email protected]> * feat(model-scope): add scoped allow token for Pi's scoped models (#2538) subagents.modelScope allow lists accept a reserved scoped token. At each child launch it expands in the parent to the parent session's scoped models (Pi's /scoped-models), so subagent restrictions follow Pi's model scoping without a second copy of the list. Every launch path passes the scoped-model snapshot; background runs keep the set captured at start. When the parent session is unscoped, scoped means the same as inherit, which is narrower than Pi's unscoped behavior. An enforced scoped entry with no parent model fails closed like inherit. Violation messages list at most 8 patterns. Co-authored-by: Corey Ryan Hanson <[email protected]> * fix(skills): drop extension skills when inheritSkills is false (#2541) With inheritSkills: false, skills from extensions loaded into an in-process child still reached the child's prompt. Pi applies noSkills only to the initial skill set, and extendResources later merges resources_discover skill paths without checking it. The child loader now also passes skillsOverride returning no skills when noSkills is set; Pi applies it on every skills update. Herdr-placed children still rely on Pi's --no-skills. Fixes #2540 * feat(config): let users turn off subagent features they don't use (#2543) Co-authored-by: tmustier <[email protected]> * refactor: deslop unreleased changes (#2545) - tests: fold duplicated advertise-override, mission-retention, and model-scope cases into their existing owners; drive the supervisor grace-period tracker tests from the event recorder and move the noticeDeferred check to control-notices; reuse createChildSafeState and makeMinimalCtx in disabled-features; drop duplicate config-load pairs - src: trim narrating comments in model-scope, async-retention, the MCP hash, and the upgrade notice; drop the redundant binding-file probe in retention; compact the advertise override parser; type createSubagentParamsSchema as typeof SubagentParams - copy: shorten the subagents_enable result; omit missions/watchdog guide topics from the description when those features are disabled - docs: merge the duplicate scheduledRuns and reserved-scoped sentences * feat(workflows): keep reload-stopped workflow work and reuse it on relaunch (#2547) * feat(workflows): reuse finished children when relaunching a runtime-replaced workflow * feat(async): await an existing async run's result by identity * feat(workflows): keep awaited async children running on reload and re-attach on relaunch * fix(workflows): claim re-attached results atomically and stop revived waits on reload * refactor(workflows): deslop and simplify runtime-replaced reuse * fix(workflows): stop re-attached children on user stop * fix(workflows): relaunch re-attached children that failed * fix(deps): bump undici to 8.10.2 for GHSA-3wwx-pv8p-q78v (#2548) undici 8.10.0 is in the range of GHSA-3wwx-pv8p-q78v (fixed in 8.10.2). pi-subagents pins it exactly, so npm audit failed for every package depending on pi-subagents. Only EnvHttpProxyAgent is used, not the affected WebSocket client. Co-authored-by: Advait Paliwal <[email protected]> * test(agents): mark package fixture root (#2553) The broad package-discovery test resolved its project root to a marked ancestor when the temp directory sat inside a Pi project, so root-agent was not discovered. Mark the fixture with its own .pi directory. Co-authored-by: Nico Bailon <[email protected]> * perf(watchdog): capture the diff baseline without blocking session start (#2563) Fixes #2560. * perf(retention): probe Windows process start time without blocking (#2564) Fixes #2559. * herdr: avoid counting workflow coordinators (#2556) * herdr: avoid counting workflow coordinators * herdr: refresh foreground child count on lifecycle changes * test(herdr): trim duplicate coordinator count tests and credit #2556 --------- Co-authored-by: Nico Bailon <[email protected]> * perf(supervisor): stop idle Windows channel polling (#2565) Fixes #2558. * fix(workflows): report siblings stopped by a failed workflow as stopped (#2566) Fixes #2562. * fix(workflows): report foreground siblings stopped by a failed workflow as stopped (#2568) Fixes #2567. * fix(children): follow the parent session's project trust (#2570) Fixes #2569. * fix(workflows): stop async workflows and their children on user stop (#2572) * fix(workflows): stop async workflows and their children on user stop Fixes #2571. * fix(workflows): keep stops from another session off a live workflow * feat(mcp): support Pi built-in MCP for mcp: tool selections (#2573) * feat(mcp): resolve mcp: selectors against Pi built-in MCP in the parent * feat(mcp): load Pi built-in MCP for selected tools in child sessions * feat(mcp): support Pi built-in MCP for mcp: tool selections Connect the parent resolver and the child runtime for foreground and background children. The parent's built-in resolution travels to the async runner in the step, so the runner no longer falls back to adapter resolution, and background children get MCP_DIRECT_TOOLS=__none__. Foreground launches that select a server only an extension reg…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Run-level
timeoutMs/maxRuntimeMsvalues above Node.js' maximum timer delay (2_147_483_647ms) can reachsetTimeout. Node clamps those oversized delays to roughly 1 ms, so a caller asking for a very long deadline can see the run time out almost immediately.The project already enforces this timer bound for
config.timeoutMsand other timer-backed settings, but explicit run-level timeouts were not consistently bounded.Fix
2_147_483_647in the existing timeout resolver.Validation
test/unit/timeout-defaults.test.ts: maximum boundary accepted, oversizedtimeoutMsandmaxRuntimeMsrejected.test/integration/single-execution.part-2.test.ts: oversized workflow timeout rejected before child launch.single-execution.part-2: 192/192 passed.npm run typecheck: passed.git diff --check: passed.