Skip to content

fix: treat extension commands handled by Pi as non-turn prompts - #438

Merged
oxwen11 merged 3 commits into
mainfrom
fix/handled-extension-commands
Oct 6, 2026
Merged

oxwen11 merged 3 commits into
mainfrom
fix/handled-extension-commands

Conversation

@oxwen11

@oxwen11 oxwen11 commented Oct 5, 2026 •

Copy link
Copy Markdown
Owner

Requirement

Sending an extension slash command such as /mcp or /mcp login <server> in Pie fails with "Model request failed … Pi queued a prompt without an active server turn". Found while verifying #433, and it reproduced on main at 18ba5813.

Regression from #426. Pi reports a prompt disposition (started | queued | handled). rpc-mode.ts reduced that to started: disposition === "started", so a prompt an extension command consumed (handled) looked like a queued prompt with no active turn.

Since this opened, #429 forwarded disposition and stopped failing a queued prompt that has no server turn. The client still stayed on the optimistic submitted status, so the composer kept waiting.

Expected behavior

  • An extension command that Pi handles without starting a turn succeeds:
    • there is no error;
    • the optimistic bubble is removed;
    • the composer returns to idle;
    • the next prompt starts a normal turn.
  • A prompt Pi queued while the server has no turn is streamed, as on main after fix(server): stream a prompt Pi queued after the server turn ended #429. It is not an AgentOperationError.

Changes and risks

  • apps/app chat.ts: when a receipt is not started and the status is still the optimistic submitted, the status resets to ready. A running turn re-stamps the phase from its events.

  • Server admission already returns a non-started receipt for disposition: "handled" (fix(server): stream a prompt Pi queued after the server turn ended #429). This merge keeps that, and keeps fix(server): stream a prompt Pi queued after the server turn ended #429's attach-and-stream for a queued prompt with no server turn. The branch's prompt-admission-state error for that case is gone.

  • Prompt RPC disposition stays optional, matching main. Pi 1.0.2 still reports started | queued | handled; an extension command still calls preflightResult("handled") and returns without a turn. chore: stop passing --no-extensions to the Pi child #443 loads those commands in the Pi child, so this path is live.

  • Out of scope (would need contract changes):

    • Extension command output (notify) is still not shown in Pie.
    • Interactive UI requests outside a turn are still declined.

    So /mcp runs without error, but its output is not visible yet.

Verification

Tested revision: 84dbc549 (merge of origin/main 6bb30797 into ffb36b64).

  • pnpm --filter @getpie/server exec vitest run test/harness/pi/agent.test.ts: 24 passed. The handled-prompt case checks an empty non-started receipt and that the next prompt starts and finishes.
  • pnpm --filter @getpie/app exec vitest run src/features/chat/runtime/chat-queue.test.ts: 14 passed. The handled command returns status to ready.
  • pnpm check passed.
  • Pi 1.0.2 AgentSession.prompt still reports handled for an extension command and does not start a turn (installed package). Not re-run: the live web /mcp pass from ffb36b64.

@oxwen11

oxwen11 commented Oct 5, 2026

Copy link
Copy Markdown
Owner Author

Runtime evidence (pie-verify web, isolated PIE_HOME / PI_CODING_AGENT_DIR, fake e2e provider).

Before (main 18ba581): before-typed-mcp.png, then before-sent-mcp-error.png (error card). Video: the before recording-002.webm shows typing and sending /mcp.
After (ffb36b64): after-typed-mcp.png, then after-sent-mcp-no-error.png (no error, composer idle), then after-followup-prompt-replies.png (hello after mcp gets the fake reply). Video: the after recording-002.webm shows the same steps.

before-typed-mcp

before-sent-mcp-error

recording-002.webm

after-typed-mcp

after-sent-mcp-no-error

after-followup-prompt-replies

recording-002.webm

@github-actions

github-actions Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

React Doctor found no new issues. 🎉

Reviewed by React Doctor for commit 03cfced.

@pkg-pr-new

pkg-pr-new Bot commented Oct 5, 2026 •

Copy link
Copy Markdown
npx https://pkg.pr.new/oxwen11/pie/@getpie/cli@438

commit: 03cfced

@oxwen11

oxwen11 commented Oct 5, 2026

Copy link
Copy Markdown
Owner Author

auto-merge: no

head ffb36b644d6e — required CI green (Check, react-doctor, both Publish @getpie/cli preview, Continuous Releases, React Doctor), but fails the gate and the exclusions:

  • Gate: mergeable=CONFLICTING / mergeStateStatus=DIRTY against main (f6912c31e83b, fix(server): stream a prompt Pi queued after the server turn ended #429), so it is not MERGEABLE.
  • Exclusion (non-presentational fix / product behavior): packages/server/src/harness/pi/rpc/rpc-mode.ts and rpc-types.ts add a disposition field to the prompt RPC response; packages/server/src/harness/pi/process.ts returns an empty, non-started turn when disposition === "handled"; apps/app/src/features/chat/runtime/chat.ts flips status submitted → ready when no turn starts. This changes runtime prompt/turn control flow on both server and app.
  • Exclusion (tests that also change product control flow): the new tests in chat-queue.test.ts and agent.test.ts ship together with the control-flow changes above.

No allowed group (docs/tooling, lint/format, UI presentation) covers these hunks. Needs human review; rebase onto main to clear the conflict. Not merged.

…-commands

# Conflicts:
#	packages/server/src/harness/pi/process.ts
#	packages/server/src/harness/pi/rpc/rpc-mode.ts
#	packages/server/src/harness/pi/rpc/rpc-types.ts
#	packages/server/test/harness/pi/agent.test.ts
@oxwen11

oxwen11 commented Oct 6, 2026

Copy link
Copy Markdown
Owner Author

Merged origin/main (6bb30797) into this branch as 84dbc549. No rebase, no force push. PR is not merged.

Conflicts were only in the prompt-admission path (process.ts, rpc-mode.ts, rpc-types.ts, agent.test.ts). chat.ts auto-merged.

Resolution:

Checks: server agent.test.ts 24 passed (handled prompt, then the next prompt starts); chat-queue.test.ts 14 passed; pnpm check passed. Live web /mcp was not re-run.

@oxwen11

oxwen11 commented Oct 6, 2026

Copy link
Copy Markdown
Owner Author

Review + verification record — #438

  • Head: 03cfced49d256bcd457d22aa481befd881d20004, base: 7b4d86b1bd8caa1fb3d6c0c5e883b7e29930cc7f (trusted rules from base)
  • Required CI on this head: Check, react-doctor, both Publish @getpie/cli preview jobs — all pass.

Conclusion: verified, merging.

Review

  • chat.ts: when Pi returns a receipt with started: false, the client now drops the optimistic message and moves the optimistic submitted state back to ready. A turn that really starts still sets status from stream events, so the reset can't hide a running turn.
  • rpc-mode.ts / process.ts: comment-only changes.
  • New tests:
    • chat-queue.test.ts covers the not-started receipt returning to ready.
    • agent.test.ts checks that a prompt after a handled command still starts and finishes.
  • No trust boundary, persistence or contract changes.

Independent verification

Clean worktrees, isolated PIE_HOME, real Pi with the operator's model.

  • Tests: server agent.test.ts 24/24, app chat-queue.test.ts 14/14.
  • Web, before (main 7b4d86b1):
    • Steps: prompt → answer → send /mcp.
    • At 6 s the composer is still showing Stop generating. It only went back to idle at about 26 s.
  • Web, after (PR head):
    • Steps: prompt → answer → send /mcp.
    • The composer is idle at 1 s and at 6 s, with no error. The next prompt AFTER-MCP-438 is answered normally.
  • Desktop, after (PR head, Electron dev):
    • Steps: same flow.
    • The composer is idle at 1 s and at 6 s, and the next prompt AFTER-MCP-DESKTOP is answered.
  • The slash-command suggestion list is masked in the videos because it lists the operator's local skills.

Gaps / notes

  • On first launch, the Desktop dev renderer sat on the "Starting Pie" splash until one reload. This looks like Vite's first-compile timing in dev mode and is unrelated to this diff. It was not investigated further.
  • No Desktop "before" run. The changed code is the shared SPA chat runtime, and the bug is demonstrated in the Web before run.

Re-review is warranted if the receipt or status handling in chat.ts changes again.

438-main-after-mcp-6s

438-main-after-mcp-26s

438-after-mcp-1s

438-after-mcp-6s

438-after-next-prompt

438-desktop-after-mcp-6s

438-desktop-after-next-prompt

438-before-main.webm
438-after-pr.webm
438-desktop-pr.webm

@oxwen11
oxwen11 merged commit 9960a7b into main Oct 6, 2026
6 checks passed
@oxwen11
oxwen11 deleted the fix/handled-extension-commands branch October 6, 2026 05:33
@oxwen11

oxwen11 commented Oct 6, 2026

Copy link
Copy Markdown
Owner Author

Merged as 9960a7b (squash of verified head 03cfced; record: #438 (comment)).

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.

2 participants