Composer: Queue never reaches the agent, and Redirect stops it and fails the step #29

Closed
opened 2026-09-14 23:47:23 -04:00 by cmoriarty · 1 comment
Owner

The composer's two verbs do not reach the agent.

  • Queue (⏎) logs human.queue_prompt and nothing delivers it.
  • Redirect (⌘⏎) stops the agent and fails the step, which fails the run.

What happened (production, soundcheck run run_01M2HF4SNRBVJ6TA8ZX11T2Z4H, openspec.apply[1])

time seq event
23:29:21 2821 agent runs npm test 2>&1 | tail -30
23:32:30 2824 human.queue_prompt "how are the unit tests?" (never reaches opencode: no user message follows)
23:32:52 2825 human.redirect "status of the unit test suite?"
23:32:52 2826 oc.session.error MessageAbortedError, then session.idle
23:32:56 2833 osf.step.failed predicate_failed "group 1: 0/2 done"; groups 2–4 skipped, run failed

The redirect's prompt was never sent.

Cause

AgentExecutor.queue_prompt() and AgentExecutor.redirect() (src/osf/engine/executors.py) exist, but nothing calls them:

  • Routes: step_prompt, step_queue and step_redirect only append the human event.
  • Scheduler: it maps human.redirect to CancelIntent.INTERRUPT in _CANCEL_INTENTS, so Redirect is exactly Stop. The executor's wait loop returns ABORTED, _finish checks the completion predicate, and the step fails.
  • human.queue_prompt: it is read by nothing but boot recovery's "undelivered prompts" count, which already expects an executor to deliver it and write admit_prompt.
  • A second defect in the uncalled methods: both re-append the human event, so wiring them up as-is would loop.

Also seen, not a Braid bug

The agent looked stuck because soundcheck's vitest run takes 5–12 s per test in the production container (events.test.ts alone took 102 s). | tail -30 hid all progress until exit. Worth a separate look at the VM's CPU and PGlite start-up cost.

Done when

  • human.queue_prompt for a running agent step is delivered to its session (prompt_async, an admit_prompt operation with the same message id) without appending another human event.
  • human.redirect aborts the turn, then sends the text, and the step keeps running: its wait loop never ends the step on the redirect's own abort, and nothing marks the step interrupted.
  • Tests cover both: the executor on the event, and the scheduler not treating redirect as a cancel.
  • The failed soundcheck run is resumed once the fix is deployed.
The composer's two verbs do not reach the agent. - **Queue** (⏎) logs `human.queue_prompt` and nothing delivers it. - **Redirect** (⌘⏎) stops the agent and fails the step, which fails the run. ## What happened (production, soundcheck run `run_01M2HF4SNRBVJ6TA8ZX11T2Z4H`, `openspec.apply[1]`) | time | seq | event | |---|---|---| | 23:29:21 | 2821 | agent runs `npm test 2>&1 \| tail -30` | | 23:32:30 | 2824 | `human.queue_prompt` "how are the unit tests?" (never reaches opencode: no user message follows) | | 23:32:52 | 2825 | `human.redirect` "status of the unit test suite?" | | 23:32:52 | 2826 | `oc.session.error` MessageAbortedError, then `session.idle` | | 23:32:56 | 2833 | `osf.step.failed` predicate_failed "group 1: 0/2 done"; groups 2–4 skipped, run failed | The redirect's prompt was never sent. ## Cause `AgentExecutor.queue_prompt()` and `AgentExecutor.redirect()` (`src/osf/engine/executors.py`) exist, but nothing calls them: - **Routes:** `step_prompt`, `step_queue` and `step_redirect` only append the human event. - **Scheduler:** it maps `human.redirect` to `CancelIntent.INTERRUPT` in `_CANCEL_INTENTS`, so Redirect is exactly Stop. The executor's wait loop returns ABORTED, `_finish` checks the completion predicate, and the step fails. - **`human.queue_prompt`:** it is read by nothing but boot recovery's "undelivered prompts" count, which already expects an executor to deliver it and write `admit_prompt`. - **A second defect in the uncalled methods:** both re-append the human event, so wiring them up as-is would loop. ## Also seen, not a Braid bug The agent looked stuck because soundcheck's `vitest run` takes 5–12 s *per test* in the production container (events.test.ts alone took 102 s). `| tail -30` hid all progress until exit. Worth a separate look at the VM's CPU and PGlite start-up cost. ## Done when - `human.queue_prompt` for a running agent step is delivered to its session (`prompt_async`, an `admit_prompt` operation with the same message id) without appending another human event. - `human.redirect` aborts the turn, then sends the text, and the step keeps running: its wait loop never ends the step on the redirect's own abort, and nothing marks the step interrupted. - Tests cover both: the executor on the event, and the scheduler not treating redirect as a cancel. - The failed soundcheck run is resumed once the fix is deployed.
Author
Owner

Shipped in acbc533 and 2ca5a7c, change archived as 2026-09-26-composer-verbs-reach-the-agent (2334877), live in production (4f19d6f).

  • Queue delivers the message to the agent's session after the current turn. The queued chip clears when the message is delivered, not when the step stops.
  • Redirect stops the turn in progress and delivers the new message, and the step keeps running. It no longer fails the step.

Verified in production on run run_01M3F8PTF3EWBCB721BP869E9N (soundcheck#32, minimalist), during openspec.propose.proposal:

  • Queue: human.queue_prompt (seq 54114) was followed by opencode recording it as oc.message.user (54117), and the agent carried on.
  • Redirect: human.redirect (54187) aborted the turn (MessageAbortedError, 54188), was delivered as oc.message.user (54196), and the step stayed running on attempt 1.
Shipped in acbc533 and 2ca5a7c, change archived as `2026-09-26-composer-verbs-reach-the-agent` (2334877), live in production (`4f19d6f`). - **Queue** delivers the message to the agent's session after the current turn. The queued chip clears when the message is delivered, not when the step stops. - **Redirect** stops the turn in progress and delivers the new message, and the step keeps running. It no longer fails the step. **Verified in production** on run `run_01M3F8PTF3EWBCB721BP869E9N` (soundcheck#32, `minimalist`), during `openspec.propose.proposal`: - Queue: `human.queue_prompt` (seq 54114) was followed by opencode recording it as `oc.message.user` (54117), and the agent carried on. - Redirect: `human.redirect` (54187) aborted the turn (`MessageAbortedError`, 54188), was delivered as `oc.message.user` (54196), and the step stayed `running` on attempt 1.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
cmoriarty/braid#29
No description provided.