Repository navigation
Show a hosted session waiting for input in the desktop app - #790
Conversation
The flag rides the agent's activity clock but never advances it: a display hint must not delay a reap or seed a server-side idle marker. PTY vendors relay Stop and prompt-submit hooks to the daemon's loopback bridge, since PTY silence attests no turn boundary. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
PR Summary by QodoShow hosted sessions waiting for input in the desktop app
AI Description
Diagram
High-Level Assessment
Files changed (26)
|
Code Review by Qodo
1.
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ba9640e80f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // residual: a full ACP _pendingTurns queue drops input silently without throwing, so this | ||
| // can advance on a delivery that was actually dropped — kill-delaying only, accepted. | ||
| agent.ActivityClock.Advance(); | ||
| agent.ActivityClock.SetAwaitingInput(false); |
There was a problem hiding this comment.
Clear the wait flag for locally attached input
When the desktop composer or terminal answers a hosted Claude session, its bytes travel through AttachClientLoopAsync to SendRawInputAsync (AgentOrchestrator.LocalIpc.cs:340-345), not through this server-command path, so this clear never executes. The fallback hook does not cover that path either: the bundled Claude UserPromptSubmit entry runs only set-title-prompt.sh (kcap/hooks/hooks.json:104-110), not ClaudeHookCommand. Consequently, after a Stop has set the flag, the desktop continues to show NEEDS YOU while Claude processes the next prompt—indefinitely for a text-only response, or until the first PreToolUse for a tool-using response. Clear the flag after successful raw-input delivery or register the relay for Claude's prompt-submit hook.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in 8b98172: AttachClientLoopAsync clears the flag after a successful raw-input delivery whose bytes carry the submit key. Both the composer (paste envelope, then \r) and a terminal keystroke end up there, so this is the clearing edge for every locally driven PTY session regardless of which hooks are installed. A keystroke that submits nothing leaves the flag alone; both cases have tests.
| if (command switch { "stop" => true, "user-prompt-submit" or "pre-tool-use" => false, _ => (bool?) null } is { } waiting) | ||
| await DaemonInputWaitRelay.NotifyAsync("claude", sessionId, cwd, waiting); |
There was a problem hiding this comment.
Start the Claude hook budget before awaiting the relay
For a hosted Claude hook whose loopback bridge accepts a connection but stalls, this await can consume the relay's full one-second timeout before the five-second HookBudget is created on line 84. The installed PreToolUse hook itself has a hard five-second timeout (kcap/hooks/hooks.json:59-67), while subsequent exclusion work is allowed to consume the newly started full five-second budget, so Claude can terminate the process before a deny/ask decision is emitted. Include the relay in the existing hook budget (or reserve its time from that budget) so the new display hint cannot shorten the policy-decision window.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
The budget was already counting: HookBudget.Remaining is the ceiling less HookClock.Elapsed, and the clock starts when the process does, so the relay's second was never in addition to the five. The window it could narrow is real, though, so in 8b98172 the relay is capped at the lesser of one second and the budget's remaining time and skipped once that is gone; An_exhausted_hook_budget_skips_the_relay pins it.
A local client's input reaches a PTY agent as raw bytes on the attach socket, never through the server's send path, and the plugin's Claude prompt-submit hook does not run kcap, so the submit key is the one clearing edge the desktop composer and terminal have. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Review round addressed in 8b98172. The relay tests moved into their own classes ( |
…sktop-awaiting-input # Conflicts: # docs/CHANGES.md # src/Capacitor.App/ViewModels/SessionCardViewModel.cs # test/Capacitor.App.Tests.Unit/SessionCardViewModelTests.cs
Codex can complete a turn before the send that started it returns, and a PTY submit spray runs for seconds, so the clear after a delivery must yield to a wait that began during it. A subagent's tool hook inherits the parent's agent id but is not the parent's turn. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A PTY vendor relays only Stop, so a wait nothing cleared sees the next turn end as a second Stop with the flag already set; it must still outrank the delivery in flight. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
No tracker reference: neither a GitHub issue nor a Linear id exists for this report.
What & why
The web marks a session whose turn is over; the desktop app lit its needs-you pip only for a failed status or a pending ask, because the daemon's local status payload carried no turn-boundary fact. The daemon now owns an
awaiting_inputverdict on the agent's activity clock: a turn's falling edge sets it, a rising edge or a delivered input clears it, and the flag rides the local status payload without touching the activity evidence the reaper and the server's idle episodes read. Hosted Claude and Codex, whose PTY silence attests nothing, relay their Stop, prompt-submit and tool-call hooks to the daemon's loopback bridge on a newinput-waitroute beside the permission one. The app folds the flag into the rail pip for an answerable agent and labels the card and chat footer "Waiting for input".Where to look
AgentActivityClock.SetTurnInFlight: only a genuine falling edge sets the flag, so a runtime clearing its gate on the way to terminal does not read as waiting. The hook relay runs ahead of every server gate in the Claude and Codex hook commands, on a one-second cap, and only when bothKCAP_AGENT_IDand a loopbackKCAP_DAEMON_URLare present.Verification
Installed_codex_schema_matches_the_vendored_pin, the local newer-Codex environmental checkdotnet build Capacitor.slnx: 14 projects, 0 warnings.dotnet publish -c Releaseof the CLI: 0 IL warnings.🤖 Generated with Claude Code