Skip to content

[Bug]: agent_prompt_stalled is reported for prompts that were delivered and submitted, and the retry pastes onto the leftovers #15976

Description

@Tauri-EPO

Summary

sendTerminalAgentPrompt reports agent_prompt_stalled when the prompt was delivered and Enter did land, if the agent answers without starting a turn. And because the paste concatenates onto whatever is already in the composer, each retry corrupts the next attempt — so a single false stall escalates into a garbled one.

Both halves were reproduced on v1.4.188 today.

The verification accepts exactly one kind of evidence

src/main/runtime/agent-prompt-submission-verification.ts:

function agentPromptLifecycleChanged(baseline, current): boolean {
  return current.workingSequence > baseline.workingSequence
}

workingSequence advances only in recordAgentPromptLifecycleState (orca-runtime.ts:12165-12185), on a null | idle | permission → working transition fed from OSC 9999 / OSC title status.

So the guard does not ask "was the prompt submitted?". It asks "did the agent start a turn within 5 s?". Those are different questions, and every submission the agent answers without starting a turn — a slash command, an unknown-command reply, anything handled locally by the TUI — is reported as a stall that did not happen.

Reproduction (2026-08-22, 14:20:37 → 14:20:45)

Composer pre-loaded with /hel, completion menu open. Then the exact Orca agent-prompt path — orca terminal send --text … --enter, which sets agentPrompt: true at src/cli/handlers/terminal.ts:114 and routes to sendTerminalAgentPrompt:

$ orca terminal send --terminal <h> --text 'Responda apenas: OK4' --enter --json
  "error": { "code": "agent_prompt_stalled", "message": "agent_prompt_stalled" }

Screen immediately after:

● Unknown command: /helResponda
● Args from unknown skill: apenas: OK4
❯

Three things are visible at once:

  1. The paste concatenated. /hel + Responda apenas: OK4 became /helResponda apenas: OK4. Residual composer content silently corrupts an injected preamble.
  2. The carriage return landed and submitted. Claude Code consumed the input and answered. The bracketed-paste race described in [Bug]: injected/sent prompts land in agent composer but are never submitted. Send reports success, worker sits idle. #14822 is not what happened here.
  3. Orca still reported agent_prompt_stalled, because an unknown-command reply is not a turn, so workingSequence never advanced.

Why the two halves compound

A first attempt returns agent_prompt_stalled and leaves its text parked in the composer. The documented recovery is to retry — and the retry pastes on top of the leftovers. The second attempt is now both garbled and stalled, and each further retry makes the composer worse.

In a multi-lane run today this produced twelve failed dispatches against ten successful ones, on both Claude and Codex agents. Every recovery required clearing the composer by hand before the retry could work.

Why this is not the issues it resembles

Suggested direction

Two independent changes; either helps, both together close it.

Do not paste onto residual content. Clear the composer, or refuse and report, rather than concatenating an injected prompt onto whatever a previous attempt or a human left behind. Silent concatenation is the part that turns one failure into a cascade.

Widen the accepted evidence, or narrow the claim. A submission that produced any agent output is not a stall. If the guard cannot tell "answered without a turn" from "never received it", then the verdict it reports should say so — agent_prompt_unverified is honest where agent_prompt_stalled is not, and a coordinator retries very differently on each.

Environment

Windows 11 Pro 26200, Orca v1.4.188, Claude Code v2.1.240. The reproduction used a throwaway Orca terminal and the public CLI only. Not platform-specific: the verification and the paste path are shared.

Activity

  1. AdamClaassens commented on Aug 22, 2026

    @AdamClaassens

    Additional Linux/OpenCode reproduction from Orca 1.4.188 and OpenCode 1.18.21. This strengthens the false-stall half of this issue and matches the downstream fenced-worker shape in #15920.

    Observed

    Three lifecycle-bearing injections were classified agent_prompt_stalled after 5-7 seconds even though OpenCode had received the task and begun visible reasoning. Orca then revoked each capability while terminal output continued for another 10-20 seconds. All three processes were stopped before repository work occurred.

    Dispatch Path Stage Capability hash Result Later terminal activity
    ctx_2c80132b5a74 fresh worker-start --agent opencode dispatch_input 3b34e55b9bb2d36293c556f9ecc2b34fa1262d48be33a5213ae0269b46898049 failed/revoked after 7s captured output included Planning parallel repository inspections; output continued about 20s after revocation
    ctx_1373faa62f62 pre-warmed idle OpenCode terminal reused by worker-start --retry-of dispatch_input decffb17af7f91e77d9b4d8aa9790b6d11c09bc6263226aae103d418d672c46c failed/revoked after 6s output continued about 14s after revocation
    ctx_55fee9e30615 pre-warmed idle OpenCode terminal via low-level dispatch --inject injected 5580c4b683452465f801a0ce69f381d5641d84bc589f110b093a689cfbdb181a failed/revoked after 5s output continued about 10s after revocation

    Runtime: fb9c8810-d416-4163-8d21-3992f9a59d6f. Full persisted process identities matched their exact terminal PTY/incarnation on every attempt:

    • ctx_2c80132b5a74: PTY suffix @@c8d36afe, incarnation 455b5b73-1cae-40eb-88ec-793c8d8a1348
    • ctx_1373faa62f62: PTY suffix @@b612e5de, incarnation d84dc985-f414-4e45-a6a6-8ff786092a17
    • ctx_55fee9e30615: PTY suffix @@55c57dec, incarnation f45e0234-e6b9-4077-9d6a-27e0ce237fa0

    A successful earlier OpenCode control, ctx_8f9f23f65224, ran 15m45s, sent a heartbeat and valid worker_done, and completed. It was stage=context_only with capability_hash=null, so it proves runtime/agent viability but does not exercise lifecycle injection settlement. Eight same-Run OpenCode successes had that same context-only/null-capability shape. All three lifecycle-bearing attempts failed.

    Simple task-spec length does not separate them: the failed specs were 4,356 and 4,728 bytes; successful same-Run OpenCode specs ranged from 2,677 to 7,187 bytes. Fresh versus pre-warmed readiness also did not separate them. The Orca process and OpenCode binary did not restart or change between the successful control and failures.

    Telemetry request

    Could the integration owner correlate these existing IDs through the settlement observer, without another reproduction? For each failed dispatch, the discriminating event chain is:

    1. exact Dispatch ID and capability hash;
    2. PTY/process incarnation;
    3. PTY write start/end and byte count;
    4. expected OpenCode acknowledgement source/value;
    5. observed acknowledgement or explicit absence;
    6. correlation decision;
    7. settlement timer start/deadline;
    8. event that selected agent_prompt_stalled and revoked the capability.

    The installed guide/schema, worker-show/worker-read, daemon log, and main trace expose none of that acknowledgement/correlation/timer chain. The remaining explanations are therefore bounded to missing, late, misrouted, or misinterpreted settlement evidence; the public records cannot distinguish them.

    Safety consequence: visible reasoning is not safe evidence of lifecycle readiness. In this reproduction the agents could continue acting after Orca had fenced them, so blindly retrying risks concurrent or unsupervised writers.

  2. Tauri-EPO commented on Sep 2, 2026

    @Tauri-EPO
    ContributorAuthor

    Another data point (Windows 11, Claude Code agent in the worker terminal, orca orchestration worker-start --task <t> --worktree path:<lane> --terminal <handle> on an already-running agent terminal), 2026-09-01/02:

    • 4 dispatches returned state: failed, stage: dispatch_input, last_failure: agent_prompt_stalled. All 4 were delivered and executed minutes later (the agent's own screen showed the task text and a working spinner; two produced a worker_done). One was dispatched twice on the assumption it had failed, and the agent received both copies ("despacho duplicado — trabalho feito uma vez").
    • On the dispatches marked failed, the worker's heartbeat messages never reached the coordinator run (only the final worker_done did) — consistent with the capability being revoked at the false stall ([Bug]: Orchestration preamble tells workers to IGNORE revoked capability, so coordinators waiting on worker_done never settle #16903).
    • Same terminal, same agent: other dispatches minutes apart returned stage: input_accepted normally. The difference seems to be delivery latency while the agent was finishing its previous turn, not agent boot.

    Net effect for a coordinator: failed/dispatch_input cannot be read as "not delivered"; re-dispatching duplicates work. A delivered-late outcome (or a longer ack wait when the terminal is a known live agent) would remove the ambiguity.

  3. Tauri-EPO commented on Sep 10, 2026

    @Tauri-EPO
    ContributorAuthor

    Retested on Orca 1.4.199 (Windows 11 Pro 26200, Claude Code 2.1.267, throwaway Orca terminal, public CLI only), 4 attempts, same shape as the original report: /hel pre-loaded in the composer, then orca terminal send --terminal <h> --text 'Responda apenas: OK4' --enter --wait-submit 10 --json.

    Half 2 (false stall) no longer reproduces: 0/4. Every attempt returned ok: true with stages: ["input_accepted"] and no turn_started, no error, after the 10 s observation window. That is the receipt shape from #16904 (in 1.4.199): "accepted, submission not observed" instead of agent_prompt_stalled.

    Half 1 (concatenation onto residual composer content) still reproduces: 4/4. Claude answered Unknown command: /helResponda / Args from unknown skill: apenas: OK4 each time, i.e. the injected text was pasted on top of the leftover /hel and submitted as one line.

    Receipt from attempt 2 (others identical apart from ids):

    "send": { "accepted": true, "bytesWritten": 33,
      "prompt": { "stages": ["input_accepted"], "provider": "claude", "observation": "supported", "generation": 27 } }

    So the remaining gap here is the composer hygiene part (clear or refuse on residual content), not the verdict.

  4. added theissue type on Sep 19, 2026
  5. brynnclaw commented on Oct 1, 2026

    @brynnclaw
    Contributor

    Status on current main, plus a proposed fix for the half that still reproduces.

    Half 2 (false agent_prompt_stalled) looks addressed on main. Every orchestration caller of sendTerminalAgentPrompt (coordinator dispatch, dispatch --inject, worker start and federation through dispatchPreambleSendOptions, plus terminal.send when it runs under an orchestration mutation) and the agent-launch prompt now pass acceptQueued + requestId. An unobserved turn start on those paths comes back as an input_accepted receipt, not an error. The coordinator also keeps a second guard: if a stall still surfaces, it maps it to dispatched-unobserved and does not resend. A plain terminal.send agent prompt with no orchestration mutation still verifies strictly, so it can still report a stall. That matches the 1.4.199 retest above (0/4).

    Half 1 (paste concatenates onto residual composer text) still holds on main. From reading the code: writeTerminalAgentPrompt writes the bracketed paste without looking at the composer. Nothing on the prompt path reads the screen before the paste. So /hel + Responda apenas: OK4 still becomes /helResponda apenas: OK4. Any retry after an unobserved submit pastes a second copy onto the first.

    Orca already has the piece needed to see this: detectTerminalComposerDraft (used by terminal read to split a composer draft out of the screen) recognizes the framed ❯ and bold › / » composers on the headless emulator. A fix on top of it, in the prompt path only:

    1. Before pasting, read the pane's headless emulator and classify what the composer holds, counting typed (non-dim) text only. A dim "suggested prompt" is not input and is pasted over as today.
    2. Other text in the composer: refuse with a new passthrough error agent_prompt_composer_not_empty and write nothing. This is the "refuse and report" option: a draft a human typed is never destroyed and never corrupted, and the caller gets a verdict it can act on.
    3. This exact prompt already in the composer (an earlier attempt whose Enter did not land): send Enter only, with no second paste. This makes a retry idempotent in the case the issue describes.
    4. Empty composer, a composer Orca does not recognize, or a screen model that is not trustworthy (provider-restored suffix, pending hydration): behave exactly as today.
    5. Right after its own Enter on the same pane, Orca waits a short settle window (1 s) before judging. That way a back-to-back second prompt is not refused just because the emulator still shows the first one, as long as the agent repaints within that window. A slower repaint (a loaded host, an SSH-relayed PTY) is a known limit: a different second prompt is refused with nothing written, and an identical one gets only an Enter.

    A long paste that the agent shows as a placeholder (for example [Pasted text #1 +N lines]) cannot be proven to be ours. It falls under (2): the retry is refused instead of pasting a second copy.

    Tests drive the real headless emulator with a Claude-shaped framed composer:

    • /hel in the composer: the send is refused and zero bytes are written. On main the paste goes out.
    • The same prompt parked in the composer: exactly one write, \r. On main the prompt is pasted a second time.
    • A dim suggestion only: the paste goes out as before.
    • Two prompts back to back: both go out.

    Not verified against a live Claude Code or Codex session. No captured PTY transcript of the Claude composer exists in the repo yet, so the frame in the tests is modeled on the shapes the existing detectTerminalComposerDraft tests cover.

    PR #24245 implements this direction.

  6. added a commit that references this issue on Oct 1, 2026
    154dfcf
  7. added a commit that references this issue on Oct 9, 2026
    baa2332
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions