Skip to content

feat(daemon): close pi adapter parity gaps β€” imagePaths, extraAllowedDirs, error events, sendAgentEvent routing#763

Merged
Siri-Ray merged 4 commits into
nexu-io:mainfrom
monotykamary:feat(daemon)-pi-adapter-parity
May 7, 2026
Merged

feat(daemon): close pi adapter parity gaps β€” imagePaths, extraAllowedDirs, error events, sendAgentEvent routing#763
Siri-Ray merged 4 commits into
nexu-io:mainfrom
monotykamary:feat(daemon)-pi-adapter-parity

Conversation

@monotykamary

Copy link
Copy Markdown
Contributor

Summary

The pi adapter was missing capabilities that every other recently-updated adapter (Qoder, Copilot, OpenCode) now supports. This PR closes four parity gaps so pi runs get the same error surfacing, file-access, and multimodal capabilities as the rest of the adapter catalog.

Why

Recent commits added Qoder CLI support, connection tests, Copilot stdin delivery, and OpenCode error surfacing (#691). The pi adapter:

  1. Discarded imagePaths β€” other adapters forward images via --attachment or inline args; pi's RPC protocol natively supports images on the prompt command but the daemon never sent them.
  2. Discarded extraAllowedDirs β€” other adapters use --add-dir to widen the agent's filesystem view so it can read skill seeds and design-system specs outside the project cwd; pi had no equivalent.
  3. Ignored extension_error and auto_retry_end failure events β€” these RPC events were silently dropped by mapPiRpcEvent, so extension errors and exhausted retries would never surface to the user.
  4. Routed events through send instead of sendAgentEvent β€” this bypassed the agentStreamError flag and the trackingSubstantiveOutput / agentProducedOutput guard added for issue Fix OpenCode runs completing in seconds without producing any outputΒ #691. A pi run that exited 0 without producing visible content was marked succeeded with an empty chat β€” the exact silent-failure shape Fix OpenCode runs completing in seconds without producing any outputΒ #691 fixed for OpenCode.

Changes

File What changes
apps/daemon/src/agents.ts buildArgs now accepts extraAllowedDirs (was _extra), filters to absolute paths, and forwards each as --append-system-prompt. Adds supportsImagePaths: true flag.
apps/daemon/src/pi-rpc.ts attachPiRpcSession accepts imagePaths, reads files into base64, and includes images on the RPC prompt command. mapPiRpcEvent handles extension_error β†’ error event and auto_retry_end with success: false β†’ error event.
apps/daemon/src/server.ts pi-rpc branch sets trackingSubstantiveOutput = true and passes sendAgentEvent instead of send, forwarding safeImages when supportsImagePaths is set.
apps/daemon/src/connectionTest.ts Passes imagePaths: [] to attachPiRpcSession for forward-compatibility.
docs/agent-adapters.md Adds pi to the adapter catalog table and Β§5.11 per-adapter section.

Testing

Check Result
vitest run tests/pi-rpc.test.ts 37/37 (28 existing + 9 new)
vitest run tests/agents.test.ts (pi subset) 4/4 pi tests pass (1 updated + 3 new)
tsc -p apps/daemon/tsconfig.json --noEmit No errors in changed files

New tests

tests/pi-rpc.test.ts (9 new):

  • extension_error maps to error event (3 variants: string, non-string, missing)
  • auto_retry_end with success=false maps to error (3 variants: with message, success=true, missing finalError)
  • attachPiRpcSession forwards images when imagePaths provided
  • attachPiRpcSession omits images when imagePaths is empty
  • attachPiRpcSession skips unreadable image paths gracefully

tests/agents.test.ts (3 new + 1 assertion):

  • pi.supportsImagePaths === true
  • pi args forward extraAllowedDirs as --append-system-prompt flags
  • pi args filter relative paths from extraAllowedDirs
  • pi args combine model, thinking, and extraAllowedDirs

What is NOT changed

  • No changes to the pi binary or its RPC protocol β€” all changes are in the daemon adapter layer
  • Other adapters are unaffected
  • No web UI changes
  • No contracts package changes

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

πŸ’‘ Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 98fea9e98b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with πŸ‘.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/daemon/src/server.ts Outdated

@mrcfps mrcfps left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@monotykamary thanks for closing the pi adapter parity gaps here β€” the image forwarding and error-event coverage are useful additions. I found one integration issue in the server wiring that currently breaks pi-rpc event delivery and needs a fix before merge.

Generated by Looper 0.6.1 Β· runner=reviewer Β· agent=opencode

Comment thread apps/daemon/src/server.ts Outdated
@lefarcen lefarcen added the feature New feature or enhancement label May 7, 2026

@lefarcen lefarcen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hi @monotykamary! Thanks for tackling these parity gaps β€” closing the pi adapter's missing capabilities is definitely the right direction. I've run a deep review on both the implementation and the reasoning.

Found 4 substantive issues that need attention before this can land safely β€” 2 in the server wiring logic that affect whether error tracking actually works, 1 in the image-forwarding path, and 1 documentation gap about access assumptions. See inline comments below for each.

Comment thread apps/daemon/src/server.ts
Comment thread apps/daemon/src/pi-rpc.ts
Comment thread apps/daemon/src/pi-rpc.ts
Comment thread docs/agent-adapters.md

@lefarcen lefarcen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The P1 server wiring issue from mrcfps's review (and my 07:12 review) is still present on this head.

The problem: server.ts passes sendAgentEvent into attachPiRpcSession, but attachPiRpcSession invokes its callback with the two-arg channel/payload shape: send('agent', payload) for normal events and send('error', { message }) from fail(). sendAgentEvent expects a single event object, so the first argument becomes the string 'agent'/'error' and the real payload is discarded. That means pi text deltas/status updates are emitted as malformed SSE, agentProducedOutput is never set, and the new error events won't set agentStreamError.

The fix: Adapt the callback at the call site or change attachPiRpcSession's callback contract consistently. Either:

  1. Wrap sendAgentEvent so it translates send('agent', payload) β†’ sendAgentEvent(payload) and send('error', { message }) β†’ existing error path, OR
  2. Change attachPiRpcSession to invoke send(payload) directly (single-arg) and handle errors outside.

Can't approve until this integration is corrected β€” it breaks the error-surfacing path this PR is trying to add.

@lefarcen

lefarcen commented May 7, 2026

Copy link
Copy Markdown
Contributor

Hi @monotykamary! πŸŽ‰
Thanks for the contribution β€” closing the pi adapter parity gaps is the right direction.
I will run a deep review and get back to you within 24h.

Thanks for making open-design better!
β€” open-design team

…pping, image hardening, docs clarification

- Fix P1: wrap sendAgentEvent in channel/payload adapter so pi-rpc events
  route correctly. agent channel payloads go through sendAgentEvent,
  error channel payloads go through createSseErrorPayload + agentStreamError.
- Fix P2: map message_update error deltas (type=error) to error events so
  partial-output failures surface after the agent started streaming.
- Fix P2: harden image forwarding with realpath symlink resolution,
  stat.isFile() check, extension whitelist, and count/total-byte budgets.
- Fix P2: clarify in docs that --append-system-prompt is only a hint and
  does not grant filesystem access; document cwd staging fallback.

@lefarcen lefarcen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All findings resolved in eab3633 βœ…

The P1 server wiring callback mismatch is fixed β€” sendAgentEvent now correctly receives single-arg event payloads via the channel/payload adapter wrapper. The error delta mapping, image hardening, and docs clarification are also in place. Nice work addressing the full review feedback!

CI is still running; once green this is good to merge from my side.

@mrcfps mrcfps left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@monotykamary thanks for the quick follow-up on the pi adapter parity fixes β€” the callback bridge, error-event mapping, and docs updates address the main flow well. I found one remaining image-boundary hardening gap that should be straightforward to tighten. πŸ‘

Generated by Looper 0.6.1 Β· runner=reviewer Β· agent=opencode

Comment thread apps/daemon/src/pi-rpc.ts
lefarcen
lefarcen previously approved these changes May 7, 2026

@lefarcen lefarcen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All prior findings from my 07:12 review are now addressed in eab3633. The server wiring callback is correctly adapted, error delta mapping is complete, image forwarding is hardened with symlink checks and budgets, and docs clarify the --append-system-prompt behavior.

LGTM πŸŽ‰

…warding

After fs.realpathSync, the resolved path can escape UPLOAD_DIR via
symlinks. Add uploadRoot param to attachPiRpcSession and verify that
realPath stays inside the resolved upload root. Both uploadRoot and
realPath are realpathSync'd to handle macOS /var β†’ /private/var.

Added 2 fixture tests: symlink outside uploadRoot is rejected, symlink
inside uploadRoot is allowed.

@mrcfps mrcfps left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@monotykamary thanks for the quick follow-up on the pi adapter parity work β€” the runtime fixes and image-boundary hardening are moving in the right direction. I found one remaining compile-time integration issue from the new uploadRoot parameter that needs to be addressed before this can merge. πŸ‘

Generated by Looper 0.6.1 Β· runner=reviewer Β· agent=opencode

Comment thread apps/daemon/src/connectionTest.ts

@lefarcen lefarcen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The compile-time integration issue from mrcfps's 08:57 review is still present on this head.

The problem: apps/daemon/src/connectionTest.ts line 867 calls attachPiRpcSession with imagePaths: [] but without uploadRoot. Since commit 99a8c1b added uploadRoot as a required parameter to the function signature (line 267 of apps/daemon/src/pi-rpc.ts), TypeScript will error with "Property 'uploadRoot' is missing" when building @open-design/daemon.

The fix: Add uploadRoot: undefined (or another safe value) to the attachPiRpcSession call in connectionTest.ts. Since imagePaths is empty in the connection-test path, uploadRoot doesn't need a real directory β€” undefined is sufficient and the image-forwarding code will skip it.

Comment thread apps/daemon/src/connectionTest.ts
@lefarcen

lefarcen commented May 7, 2026

Copy link
Copy Markdown
Contributor

@monotykamary The connectionTest.ts call site (line 867) still needs the uploadRoot parameter β€” the current head 99a8c1b1 doesn't include it in the attachPiRpcSession call. That's causing the CI build failure (Property 'uploadRoot' is missing).

Could you add uploadRoot: undefined (or another safe value) to the connectionTest.ts call? Since imagePaths is empty there, uploadRoot doesn't need a real directory.

@lefarcen

lefarcen commented May 7, 2026

Copy link
Copy Markdown
Contributor

@monotykamary I checked the current head (99a8c1b) and the compile-time integration issue mrcfps pointed out still needs fixing.

The call site at apps/daemon/src/connectionTest.ts line 867 currently looks like:

attachPiRpcSession({
  child,
  prompt,
  cwd,
  model: model ?? null,
  send,
  imagePaths: []
})

But attachPiRpcSession now requires uploadRoot in its signature (apps/daemon/src/pi-rpc.ts line 268). Please add uploadRoot to this call β€” for the connection-test path, passing uploadRoot: undefined or a safe no-image root is fine since imagePaths is empty.

This will unblock the daemon package build that's currently failing CI.

The connection test call site was missing the new uploadRoot param,
causing TS2345 in CI. Added uploadRoot: undefined since imagePaths
is empty and the boundary check is a no-op for this path.
@monotykamary monotykamary requested review from lefarcen and mrcfps May 7, 2026 10:58

@mrcfps mrcfps left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@monotykamary I reviewed the current ff24a81 head across the pi adapter arg wiring, pi-rpc event and image handling, server routing, connection-test call site, tests, and adapter docs. The prior callback bridge, image-boundary, and uploadRoot call-site concerns are addressed, and I don't see any remaining actionable implementation issues. Thanks for the careful follow-through on these parity fixes β€” this is a solid improvement for pi users. πŸ™

Generated by Looper 0.6.1 Β· runner=reviewer Β· agent=opencode

@lefarcen lefarcen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Compile-time integration issue resolved in ff24a81 βœ…

The uploadRoot: undefined parameter is now correctly passed to attachPiRpcSession in connectionTest.ts. This unblocks the daemon package build and satisfies the function signature requirement mrcfps and I flagged.

All prior findings from my reviews are now addressed. CI is green. LGTM πŸŽ‰

@lefarcen lefarcen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Fix verified at ff24a81 βœ…

The uploadRoot parameter is now correctly passed in connectionTest.ts line 874. CI is green and the compile-time integration issue is resolved.

@Siri-Ray Siri-Ray merged commit 8630fd3 into nexu-io:main May 7, 2026
1 check passed
@leilei926524-tech

Copy link
Copy Markdown
Contributor

Hi @monotykamary β€” quick note from the Open Design team.

You've already shipped 5 merged PRs here, which puts you in our top contributors. We've spun up a Discord #contributors channel and wanted to make sure you have the invite β€” you're exactly the kind of person it's built for:

πŸ‘‰ https://discord.gg/3C6EWXbdQQ

What you get there:

  • Faster PR feedback β€” maintainers are around in Discord throughout the day, review pings turn around in hours, not days
  • First look at updates β€” release notes, roadmap previews, and behavior changes before they hit GitHub
  • Skills & templates β€” community-built skills and design templates, easy to grab and reuse
  • Real user showcases β€” see what people are actually building with OD, including stuff we never imagined
  • Direct line to the Core Team β€” DMs welcome for anything that doesn't fit a GitHub thread

Drop in whenever β€” no introduction needed. The recent run has visibly moved the bar β€” thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature or enhancement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants