Repository navigation
fix: show a status as soon as an idle agent is prompted - #117
morgan-wowk wants to merge 1 commit into
Conversation
43a6eea to
256b461
Compare
The run-level activity was only emitted when Pi reported agent_start, so anything Pi did between reading the prompt and starting the turn (most visibly the first prompt of a fresh session) left the chat with no status for several seconds. Emit a "Warming up..." activity when the prompt is written to an idle agent; agent_start replaces it with "Thinking...". The indicator must never outlive real work, so the ways a prompt can end without agent_start/agent_end are now handled: - Pi rejects the prompt in preflight (no usable model or credentials, a failing extension hook) with a failed `response`. That was ignored, leaving the agent busy indefinitely; it now fails the run with Pi's error. - Pi accepts the prompt but starts no turn (an extension command or input handler consumed it). If agent_start does not follow the ack within 5s, the run ends as completed. - Pi goes silent (a wedged process answers neither the prompt nor abort). If no ack, agent_start or compaction_start arrives within 60s, the run fails and the process is killed so the supervisor restarts it. Stop during warm-up is kept: Pi's abort is a no-op before its run exists, so the abort is resent on agent_start and the run settles as cancelled. A model change clears the pending prompt so the old process's watchdog cannot fail the new one.
256b461 to
99305b5
Compare
| } | ||
|
|
||
| /** Ends the run if an accepted prompt is not followed by `agent_start`. */ | ||
| private armTurnlessPromptTimer(sessionId: string, agent: AgentProcess): void { |
There was a problem hiding this comment.
🤖 This is an AI-generated code review comment.
The 5s grace timer can end a real turn when an extension's agent_start handler is slow. Low, not blocking.
Pi 0.78.1 waits for extension handlers before it writes an agent event to stdout. In _handleAgentEvent, await this._emitExtensionEvent(event) runs before this._emit(event). So nothing in Pi itself sits between the ack and agent_start, but any extension agent_start handler does. If that handler takes more than 5s:
- This timer ends the user's run as
completedwith no output. - The late
agent_startopens a new run withingress: "reaction". - The indicator clears, then "Thinking..." comes back.
Reproduced in the test harness: ack, tick 5s, then agent_start leaves the first run (ingress: "user") completed and puts the turn under a second run with ingress: "reaction". Routing to the user is fine, because RunRegistry keeps each participant's last audience across runs.
None of this repo's extensions register pi.on(...) handlers, so only a bundle extension can trigger this. Two options:
- Document the trade-off on
PROMPT_START_GRACE_MS. - Close it fully: when the timer expires, send
get_stateand end the run only ifisStreamingis false. Pi setsisStreaminginrunWithLifecyclebefore it emitsagent_start, so a turn whoseagent_startis delayed readstrue.
Problem
After a prompt was sent, the chat showed no status until Pi reported
agent_start, which left a gap of about 5s on a fresh session where the agent looked stalled.Before / after
agent_startChange
The server emits a "Warming up..." activity when a prompt is written to an idle agent, and ends the run whenever Pi answers the prompt without starting a turn, so the indicator can't outlive real work.
Why it's safe
Against published Pi
0.78.1, every way a prompt can end withoutagent_start/agent_endis now handled: a rejected prompt (responsewithsuccess:false) fails the run, an accepted prompt with noagent_startwithin 5s (e.g. an extension command) completes it, and a prompt Pi never acknowledges within 60s fails the run and restarts the process through the existing supervisor.Tests
All 491 server tests pass, including new cases for each path plus Stop during warm-up and a model change mid-warm-up, and end-to-end runs confirmed a healthy turn with real Pi and recovery from a stuck agent at 60s.
🤖 Generated with Claude Code