Skip to content

fix(cursor): make quiet timeouts retryable by Pi - #1075

Merged
yetone merged 1 commit into
magpie-community:mainfrom
wuuli:fix/cursor-quiet-retry
Nov 13, 2026
Merged

yetone merged 1 commit into
magpie-community:mainfrom
wuuli:fix/cursor-quiet-retry

Conversation

@wuuli

@wuuli wuuli commented Nov 13, 2026

Copy link
Copy Markdown
Contributor

Summary

A Cursor Run that goes silent after partial output ends with Cursor went quiet: … (try again). At that point the response is already an HTTP 200 stream, and Pi classifies the error by its message. Those words do not match Pi's retry rules, so the turn stops without using its retry budget.

Append ; stream timed out to the existing Quiet.fire() message, for both idle and heartbeat-only timeouts:

Cursor silence → Quiet.fire() → streamed error
  before: "Cursor went quiet: … (try again)"                   → Pi stops
  after:  "Cursor went quiet: …; stream timed out (try again)" → Pi's bounded retry

The diagnostic prefix, last-frame details, 502 status, timeout limits and failure semantics stay the same. This applies to retained native and stateless Runs. Bump the Cursor package to 0.2.46, update the timeout assertions and README, and add an optional loopback integration script for an installed Pi SDK without adding a dependency.

Related to #550 and #616. #616 already uses timed out for the retained Run's lifetime deadline; this applies the same compatibility treatment to the separate quiet watchdog. It does not resolve the underlying Cursor stalls reported in #550.

Evidence

With Pi 1.5.2 and synthetic SSE responses, a tool completes once and the following answer emits partial text then the actual Quiet.fire() error:

Case Requests Automatic retries Tool executions Result
Unmodified main (b40a853) 2 0 1 Stops on the timeout; recovery assertion fails
Patched, next attempt succeeds 3 1 1 RECOVERED
Patched, every attempt fails 4 2 1 Stops with an error when the configured budget is exhausted

The script also asserts that completed tool results remain in retry context and partial output from failed attempts is omitted. All model traffic stays on loopback; no real credentials or user sessions are used. Reproduction commands are in the Cursor README.

  • Cursor streaming tests check the error message itself against the existing Pi and magpie retry patterns for both Run paths and both watchdog limits, and verify that a timeout does not emit [DONE].
  • bun scripts/check.mjs: passed for the full repository.
  • git diff --check: passed.
  • bun test packages/cursor: 421 passed, 0 failed (4268 assertions).
  • Full bun test with a temporary home: 8547 passed, 9 skipped, 2 failed. Both failures are outside the changed package:
    • packages/zcode/start.test.mjs, “caps that land after the hold armed…”: expected 24 requests, got 23. The identical assertion failed on the fourth isolated run against unmodified b40a853.
    • packages/agent-office/jump.test.mjs, “office.hooks.mjs imported without…”: expected 1 session, got 16 under inherited agent-directory environment variables. The same test passes on both unmodified main and this branch with a minimal isolated environment.

Merge Danger

Door: two-way. Reverting restores the old error wording; no configuration or stored-state migration.

Blast Radius: Cursor quiet-timeout errors. Clients that recognize timeout wording can now retry an already-failed turn using their own retry policy, adding requests when Cursor remains unavailable. The plugin adds no retry loop. Normal responses and routing are unchanged; the synthetic Pi cases cover completed-tool preservation, not every client's replay behavior.

@yetone
yetone merged commit 463bbfe into magpie-community:main Nov 13, 2026
@yetone

yetone commented Nov 13, 2026

Copy link
Copy Markdown
Contributor

Thanks @wuuli, merged; it goes out as cursor 0.2.46. I checked Pi's current retry list (packages/ai/src/utils/retry.ts has timed? out) and that magpie's own retry decision still goes by the 502 status, so nothing changes on magpie's side. The cursor tests pass (421). I didn't run the Pi integration script.

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