Skip to content

fix: restore Pi child tools and preserve explicit requirements - #638

Merged
tt-a1i merged 5 commits into
openpi-dev:mainfrom
cuipengcx90:fix/child-tool-preflight-inherited-tools
Oct 4, 2026
Merged

tt-a1i merged 5 commits into
openpi-dev:mainfrom
cuipengcx90:fix/child-tool-preflight-inherited-tools

Conversation

@cuipengcx90

@cuipengcx90 cuipengcx90 commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Problem

Fixes #637. A parent's live tool surface can contain runtime-activated tools that a fresh SDK child has not activated or cannot register. The previous child preflight rejected these inherited misses, making ordinary subagent spawns fail. SDK children and the Web runtime also lacked Pi's native extension factories.

The initial patch introduced two additional gaps: the public Direct and Workflow entries tolerated misses even for explicitly declared role tools, and replay fingerprints ignored all synthetic extension identities. Independent review also found that a tool Pi refuses to activate could incorrectly satisfy preflight.

Value

Restore ordinary child execution with Pi's current tool surface while keeping explicit role requirements enforceable before the child's first prompt. Preserve replay safety when native and inline extensions are loaded.

Approach

  • Activate requested tools that the child has registered, within the existing parent-derived allowlist. Re-read Pi's actual active tools after activation; a requested activation alone cannot satisfy preflight. Tolerate and report unavailable tools only when the agent type omits an explicit tools list.
  • Share Pi's reviewed tool-search, codemode, and mcp factories between child resource loaders and the Web runtime. Keep native replacement behavior and the existing child tool policy.
  • Include reviewed native factory names and the executing Pi SDK version in replay fingerprints. Unknown inline or built-in identities disable replay; file-backed resources retain their content hashes.
  • Add public-entry regressions for Direct and Workflow, actual SDK child registration and rejected hidden activation coverage, and real SDK loader identity regressions. Preserve the investigation in the source-scoped record.

Validation

Candidate: e8c43cb1eb264a790e57954e4d4cf36db17faf72; locked Pi SDK 0.99.1, Bun 1.3.14, Node 26.8.1 on macOS.

  • bun run check: passed, including production Web build, configuration/documentation checks, formatting, lint, and TypeScript.
  • bun run test: passed; 2,130 Node tests passed, 8 skipped; 1,120 Vitest tests passed.
  • Restoring the original unconditional Workflow flag makes the explicit-role regression complete instead of rejecting. The original synthetic-path filter accepts unknown inline identities and collapses the three reviewed native factory identities into one replay key.
  • The regressions use local SDK Sessions and scripted responses without a remote model request. The reported live third-party browser/search package setup, external MCP servers, and Pi 0.99.2 have not been exercised by these tests.
  • Independent subagent review of the complete base-to-head diff found no remaining defects after repairing its rejected-activation finding. All 18 current-head GitHub checks passed. The first Windows setup integration attempt reached its existing 8-second subprocess limit; rerunning failed jobs passed on the same commit without a source change.

Impact

  • User-visible behavior: ordinary inherited missing tools report a narrowed surface and allow execution; missing explicit role tools still fail before prompting.
  • Model-visible context/tools: children and Web Sessions can register the native Pi tools; child access remains bounded by the parent's allowed surface.
  • Runtime/lifecycle: shared factory injection and post-bind activation use Pi's existing resource and tool seams; cancellation and cleanup mechanisms are retained.
  • Persisted configuration/data: no new settings or data format. Changed fingerprints prevent old replay identities from matching incompatible extension sets. Unverifiable inline identities disable replay.
  • Compatibility/risk: automated coverage uses the locked Pi 0.99.1 SDK. External dynamically registered tool implementations and server behavior remain outside this validation boundary.

崔朋 added 2 commits October 2, 2026 18:25
A subagent spawn fails before its first prompt whenever the parent session
holds a tool that a package activates on demand:

    Child tool preflight failed: requested tool(s) "web_search", ... are
    unavailable after child extensions initialized.

inheritedChildToolAllowlist() projects the parent's live active-tool
surface into the child's requested allowlist, but bindChildSessionExtensions()
only activates the hardcoded names in CHILD_SAFE_PACKAGE_TOOL_NAMES
(fd, rg, git_show, git_diff, git_log). Every other inherited name must
already be active in the fresh child session, which is false for tools
activated at runtime:

  - pi-web-access with toolActivation "auto" starts a session with only
    web_enable and activates web_search and friends after the model
    calls it
  - pi-agent-browser-native adds agent_browser_action/_qa/... only after
    agent_browser_tools enables them
  - MCP deferred exposure brings in tool_search; codemode exposure
    brings in codemode

Activate every requested name the child has registered instead. requested
is already the narrowing allowlist (parent surface minus
CHILD_EXCLUDED_TOOL_NAMES), so this cannot widen the child's boundary,
and it removes the dependency on a list that can never stay in sync with
what users install.

A name the child cannot expose at all no longer aborts the spawn either.
requested is inherited from the parent surface, so a narrowed child is
not a configuration error worth failing for; report it once with counts
and continue.

Fixes openpi-dev#637
…lists

Two independent defects made a subagent spawn fail, and the first fix for one
of them relaxed a contract the preflight exists for.

1. The inherited-tool report relaxed the check for every caller, so an explicit
   allowlist naming a tool the child cannot expose no longer failed. Three tests
   asserted that. Make the relaxation opt-in: bindChildSessionExtensions() keeps
   the hard failure by default and only reports when the caller passes
   tolerateInheritedMisses, which the two callers that project the parent's live
   surface now do (direct spawn and the workflow runner, through a new
   inheritedTools flag on SpawnTask / RunAgentOptions).

2. tool_search and codemode were never registered in a child, not merely
   inactive. Pi's built-in extensions (codemode, tool-search, mcp, llama.cpp)
   are builtin:true inline extensions whose code reaches a loader only through
   extensionFactories: the CLI's main() supplies them, an SDK caller has to.
   Inject tool-search and codemode, the two the parent activates; mcp stays out
   because a user's own MCP extension replaces it, and llama.cpp only serves
   local models.

3. The replay fingerprint realpath'd every extension, so injecting a built-in
   extension (a synthetic `builtin:name` path with no file behind it) threw and
   silently disabled journaling for every workflow agent call. Skip synthetic
   paths there; their code comes from the host pi version, not from project
   resources, which is what the fingerprint binds.

Tests: extension realpath helpers and the empty-package-filter assertion now
ignore synthetic extension paths.

Verified on pi 0.99.1 with bun 1.3.14: the three preflight tests pass, the
extension/shared, subagents, and workflows suites are at baseline (2 unrelated
worktree-cancellation timeouts), 1120 vitest cases pass, and typecheck, biome
format, lint, and the config/docs/discipline contract checks are clean.
@cuipengcx90
cuipengcx90 force-pushed the fix/child-tool-preflight-inherited-tools branch from 56c2b8e to b086e13 Compare October 2, 2026 10:39
@cuipengcx90 cuipengcx90 changed the title fix(subagents): activate inherited child tools instead of a fixed list fix(subagents): keep the child tool preflight hard for explicit allowlists, and register Pi's built-ins in children Oct 2, 2026
@github-actions github-actions Bot added area:workflows Workflow engine, capability, skills, or tests area:subagents Subagent delegation, skills, or tests labels Oct 2, 2026
崔朋 and others added 2 commits October 2, 2026 18:42
The web workbench builds its own session services and passed only its two custom
factories (command discovery, turn-change recording). Like the subagent child
loader, that left the session with no built-in registry: `builtin:tool-search`,
`builtin:codemode`, and `builtin:mcp` resolved to "Unknown built-in extension",
so `tool_search`, `codemode`, and MCP tools were never registered for a web
session either.

Move the factory list into extensions/shared/pi-builtin-extensions.ts and use it
from both call sites, so a fix to the built-in set lands in both.

Verified on pi 0.99.1: a loader built with the shared helper registers
`builtin:tool-search`, `builtin:codemode`, and `builtin:mcp` with no errors, and
the web/child suites are unaffected.
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Oct 4, 2026
@tt-a1i tt-a1i changed the title fix(subagents): keep the child tool preflight hard for explicit allowlists, and register Pi's built-ins in children fix: restore Pi child tools and preserve explicit requirements Oct 4, 2026

@tt-a1i tt-a1i left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the complete base-to-head change at e8c43cb, including an independent subagent correctness review. No remaining findings after fixing explicit-role tolerance, synthetic replay identities, and the independent review's rejected-activation finding.

The preflight now checks Pi's actual active tool surface, while child tool registration and nested execution remain within the parent-derived policy. Reviewed native factories bind replay identity to their enabled names and the executing Pi version; unknown inline identities disable replay.

Local validation passed: bun run check; bun run test (2,130 Node tests passed, 8 skipped; 1,120 Vitest tests passed). Independent child-session and replay-safety suites: 41 passed, 0 failed. The hidden-tool regression failed before the activation readback repair and passed afterward. Current-head remote CI and branch protection still need to clear before merge. External MCP servers and remote-provider/manual installed-runtime behavior were not validated in this review.

@tt-a1i
tt-a1i merged commit 94f6dfb into openpi-dev:main Oct 4, 2026
30 of 35 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:subagents Subagent delegation, skills, or tests area:workflows Workflow engine, capability, skills, or tests documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: subagent spawn fails when the parent holds runtime-activated tools

2 participants