Skip to content

fix(provider-pi): deliver dynamic tool results to Bun-based pi - #3095

Open
fgrehm wants to merge 1 commit into
get-bb:mainfrom
fgrehm:fix/pi-bridge-bun-stdio-channel
Open

fix(provider-pi): deliver dynamic tool results to Bun-based pi#3095
fgrehm wants to merge 1 commit into
get-bb:mainfrom
fgrehm:fix/pi-bridge-bun-stdio-channel

Conversation

@fgrehm

@fgrehm fgrehm commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Human comments

This is something that almost made me give up on bb but my clanker got through and was able to diagnose the problem. TBH, not sure how this hasn't been reported before, I got it to do some searching on the repo issues / PRs / discussions but it did not find anything related.

Anyways, I hope this is the right way to fix the problem but if not, happy to provide more info about my environment as a separate ticket for discussion and investigation.

I'm about to rebuild my container with this patch + another one I got in the works and will report back if it goes sideways before marking the PR as ready for review.

What was wrong

The pi provider's dynamic tools (AskUserQuestion, update_environment_directory, plugin agent tools) hang forever under the shipped pi. pi has been distributed as a Bun-compiled binary since v0.55.0 (release assets, built via bun build --compile in earendil-works/pi scripts/build-binaries.sh#L205), and pi 0.85.0's binary embeds Bun 1.3.14.

Bun's net.Socket({ fd }) validates the fd and attaches no handle (_handle === null, no poll registered — see bun-v1.3.14 net.ts#L684 and the open upstream fix PRs oven-sh/bun#35341, #29141). The bridge→extension channel read (bb-pi-extension.ts#L177) relied on a Node-only behavior, so under the compiled pi every dynamic tool result was written but never read: the extension's tool promise never settled, pi never emitted tool_execution_end, and turns hung until manually stopped.

This is not a Bun regression (read adoption has never shipped) and cannot be worked around by pinning Bun because pi embeds its runtime. The existing suite missed it because the fake pi loads extensions under Node, where the fd semantics work.

What changed

  • plugins/provider-pi/src/bridge/bb-pi-extension.ts — the bridge→extension channel reader branches on the runtime: under Bun it reads fd 4 through Bun.file(fd).stream() (same newline framing and StringDecoder handling); under Node the existing net.Socket path is unchanged, with its non-blocking comment moved onto that branch. No message formats, wire content, or fd assignments changed — server↔daemon payloads are untouched, so HOST_DAEMON_PROTOCOL_VERSION is not bumped.
  • plugins/provider-pi/src/bridge/fake-pi-rpc.mjs — test fake: under runtimes without module.registerHooks (Bun) it stages the extension copy beside the package's gitignored node_modules so the extension's bare imports resolve natively; Node keeps the resolve-hook path. Header docs updated.
  • plugins/provider-pi/src/bridge/bridge.bun-runtime.test.ts (new) — regression test running the fake pi under Bun and driving a dynamic tool round trip end to end. Known limitation, called out: it skips when Bun is absent from PATH (it.skipIf(bunBinary() === null)), and no CI leg installs Bun today, so this guard does not run in CI yet (follow-up issue; without it, CI cannot detect a revert of the Bun branch).
  • An adversarial review pass shaped the change: staging lives in gitignored node_modules (not the source tree), the Bun branch is gated on the runtime rather than on registerHooks availability, and the single-message fd-4 coverage plus a bridge→extension liveness handshake are tracked as follow-ups rather than shipped here.
  • Verified against Bun 1.4.0 in the test and against Bun 1.3.14 (pi's embedded runtime) via a direct fd probe.

How you verified

  • plugins/provider-pi/src/bridge/bridge.bun-runtime.test.ts: red on main at timed out waiting for the tool result to reach pi under Bun (the exact production symptom), green with this change.
  • pnpm exec vitest run --config vitest.config.ts src/bridge/bridge.bun-runtime.test.ts src/bridge/bridge.round2.test.ts src/bridge/bridge.framing.test.ts — 13/13 pass (Bun on PATH).
  • pnpm exec turbo run typecheck --filter=bb-plugin-provider-pi — clean.
  • Live-incident capture (BB_PROVIDER_BRIDGE_RECORD_DIR): recorded lanes show the full request→response chain through the bridge's fd-4 write with no error anywhere, matching the failure mode; pi's own session file shows it only ever received the abort-path tool result.

AGENT GENERATED


Generated with "Omen Alpha" (Opencode Go) via BB / Pi

pi has shipped as a Bun-compiled binary since v0.55.0, and Bun's
net.Socket({ fd }) never attaches a read handle for a borrowed stdio
fd: the fd is validated and dropped, _handle stays null, and no poll
is ever registered (upstream gap, see oven-sh/bun#35341 and #29141,
both open). The pi extension read its result channel with
new net.Socket({ fd: 4 }), so under Bun-based pi nothing was ever
read: the tool promise never settled, pi never emitted
tool_execution_end, and every dynamic tool call (AskUserQuestion,
update_environment_directory, plugin agent tools) hung until
manually stopped.

Read the channel through Bun.file(fd).stream() when running under
Bun; Node keeps the existing net.Socket path. Teach fake-pi to load
extensions without module.registerHooks so the new regression test
can run the fake pi under Bun: it times out on main at the exact
production symptom and passes with this change.

Review follow-ups applied: stage fake-pi extension copies under the
package's gitignored node_modules; gate staging on the Bun runtime;
single-message fd-4 coverage and a CI bun leg are tracked as
follow-ups.
@fgrehm
fgrehm force-pushed the fix/pi-bridge-bun-stdio-channel branch from cee4ebc to 6fabae5 Compare September 5, 2026 03:05
@fgrehm
fgrehm marked this pull request as ready for review September 6, 2026 15:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant