Skip to content

fix: show a status as soon as an idle agent is prompted - #117

Open
morgan-wowk wants to merge 1 commit into
mainfrom
fix/thinking-indicator-on-prompt
Open

morgan-wowk wants to merge 1 commit into
mainfrom
fix/thinking-indicator-on-prompt

Conversation

@morgan-wowk

@morgan-wowk morgan-wowk commented Oct 21, 2026 •

Copy link
Copy Markdown

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

Before After
before after
No bubble, Prime reads "Ready", and there's no Stop button "Warming up..." shows right away, then switches to "Thinking..." on agent_start

Change

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 without agent_start/agent_end is now handled: a rejected prompt (response with success:false) fails the run, an accepted prompt with no agent_start within 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

@morgan-wowk
morgan-wowk force-pushed the fix/thinking-indicator-on-prompt branch 3 times, most recently from 43a6eea to 256b461 Compare October 21, 2026 22:31
@morgan-wowk morgan-wowk changed the title fix: show the thinking indicator as soon as an idle agent is prompted fix: show a status as soon as an idle agent is prompted Oct 21, 2026
@morgan-wowk
morgan-wowk requested a review from a team October 22, 2026 00:39
Comment thread apps/server/src/pi/piAgentManager.ts Resolved
Comment thread apps/server/src/pi/piAgentManager.ts Resolved
Comment thread apps/server/src/pi/piAgentManager.ts Resolved
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.
@morgan-wowk
morgan-wowk force-pushed the fix/thinking-indicator-on-prompt branch from 256b461 to 99305b5 Compare October 22, 2026 01:11
@morgan-wowk
morgan-wowk requested a review from camielvs October 22, 2026 01:15
}

/** Ends the run if an accepted prompt is not followed by `agent_start`. */
private armTurnlessPromptTimer(sessionId: string, agent: AgentProcess): void {

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.

🤖 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 completed with no output.
  • The late agent_start opens a new run with ingress: "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_state and end the run only if isStreaming is false. Pi sets isStreaming in runWithLifecycle before it emits agent_start, so a turn whose agent_start is delayed reads true.

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