fix(cli): buffer Pi prompts until RPC startup ready (#1146)

* fix(cli): buffer Pi prompts until RPC startup ready

A prompt POSTed immediately after spawn (a supported handoff pattern used
by hapi-ping-peer and intake scripts) could reach `pi --mode rpc` before
its `new_session`/`get_state` startup finished, wedging the turn:
`agent_start` then silence, no tool calls. The socket goes `active` (spawn
success) well before Pi's session is initialized, so `active` is not a
safe ready signal for Pi.

Gate outbound prompt/steer sends behind a startup ready gate on PiSession:
`runWhenReady()` delivers immediately once ready, else buffers FIFO;
`markReady()` fires on the first `get_state` response (the signal that
persists `metadata.piSessionId`, which working callers already wait for)
and drains the buffer in order. A 30s unref'd fallback timer force-drains
if `get_state` never lands, degrading to prior send-anyway behaviour
rather than swallowing the message forever.

Fixes #1143

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(cli): honor cancel-queued-message for buffered Pi prompts

Addresses the MAJOR review finding on the startup ready-buffer: while a
prompt is held behind runWhenReady, the hub can send cancel-queued-message
for its localId. Pi registered no onCancelQueuedMessage handler, so
ApiSessionClient acked removed:false, the hub marked the row invoked, yet
the buffered closure still drained on get_state and fired the cancelled
prompt.

Carry the localId with each buffered send and add
PiSession.cancelBufferedMessage, then register apiSession.onCancelQueuedMessage
so a cancel drops the still-buffered prompt (returns true) instead of
sending it. Once drained to Pi it cannot be recalled — returns false,
matching the other agents' queue.cancelByLocalId best-effort semantics.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
HeavyGee
2026-07-24 10:52:06 +08:00
committed by GitHub
co-authored by Cursor
parent 74ad25ec57
commit 7ca4e71fa0
5 changed files with 276 additions and 10 deletions
+7
View File
@@ -154,6 +154,13 @@ function handleResponse(
switch (command) {
case 'get_state': {
handleGetState(response.data, session);
// Pi has finished startup init (this is the response that persists
// metadata.piSessionId — the signal working callers already wait
// for). Release any prompts buffered during the spawn window so they
// reach an initialized Pi session instead of wedging (issue #1143).
// markReady is idempotent; a missing sessionId still flips ready so
// buffered prompts are never swallowed forever.
session.markReady();
break;
}
case 'set_model': {