You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Make human-steering escalation robust: a durable request/response (issue comment) + spawn-task delivery + release/resume, instead of marker-detect + live PTY injection over Slack #99
Human-steering escalation (agent hits ambiguity → asks a human → gets an answer → continues) is currently a ~6-link chain, and in a full day of testing nearly every link failed independently:
Agent emits the magic string [factory-needs-input] (in a DM or its output)
Factory detects that marker by watching the agent's stream
The design only works if all six links are healthy at the same instant. That is the opposite of robust, and it's why the ask round trip still cannot be demonstrated end-to-end.
Root fragilities
A magic text marker the agent must emit and factory must detect by parsing an output/message stream.
Bidirectional injection into a live TUI agent (codex), which is inherently racy — you're fighting the terminal's interactive state.
Proposed: escalation as a durable request/response record
Replace the chain with two durable operations and no live injection anywhere:
Agent hits ambiguity → posts its question as a comment on the source GitHub issue (it already has issue write via the .integrations mount), then exits cleanly.
Factory sees the question by reading the issue comments (data), not by parsing the agent's stream, and records "awaiting human answer."
Human replies as an issue comment.
Factory re-spawns the agent with question+answer folded into its new spawn task (release/resume) — never injected into a live agent.
Three principles, each kills a class of today's failures
Structured/durable ask, not a marker in a stream → removes links 1–2 (emission + detection fragility).
Delivery only via spawn task (proven reliable — see below) → the agent never receives anything by injection while running.
The escalation channel is the GitHub issue itself
No new store needed. The question is an issue comment, the answer is a reply comment, and the agent re-spawns reading the comments — durable, visible to the human in the natural place, and Slack becomes an optional mirror, off the critical path.
Concrete steps (ownership: almost entirely factory-side + one template change)
Step 0 — spawn-task delivery of the full briefing (no inject-on-top).Built and validated for the implementer: the codex implementer was spawned with the complete task including ask instructions (verified spawn cmdline), 0 injection failures, created the correct branch, did not fabricate. Remaining: extend to the reviewer (its critical injection still fails the same way) and land it. This is also what makes fix: abort dispatch after critical delivery failure #97 unnecessary (no critical injection left to abort on).
Step 1 — ask via issue comment, not [factory-needs-input] DM. Prompt change in src/dispatch/templates.ts. No new tool required (issue write already available); a structured ask_human MCP tool is an optional relay-side nicety.
Step 2 — factory detects the question from issue comments, not the agent stream. Reuse existing issue sync; optionally mirror to Slack for visibility (off critical path).
Step 3 — answer returns via re-spawn, using Release agents while awaiting human clarification #79's release/resume machinery (already merged), with the answer folded into the spawn task. Remove the live #injectPendingSlackClarification reply-injection.
Exists / reuse: spawn-task delivery (prototyped, needs reviewer + merge), Release agents while awaiting human clarification #79 release/resume, #injectPendingGithubClarification (GitHub reply path), the issue-as-store (the mount).
Genuinely new: the template instruction (ask via issue comment) and factory watching issue comments for the Q/A instead of the agent stream. That's the core of it.
Validation note
This must be validated on a quiet machine — every test so far was confounded by other agents (the pear app's lead/gap/query/durable) polluting process/session forensics. On a box running only the one dispatch, the proof is watchable and unfakeable: agent posts comment → exits → human replies → agent re-spawns and finishes.
Related
#94, #95 (Slack gate), #96 (fail-open on un-briefed agent), #97 (abort-on-critical-delivery-failure — becomes moot under Step 0), #98 (codex injection race — the immediate blocker this design removes), #79 (release/resume — the reply half already built), AgentWorkforce/cloud#2666 (the Slack ingest lie that Step 4 takes off the critical path).
Problem
Human-steering escalation (agent hits ambiguity → asks a human → gets an answer → continues) is currently a ~6-link chain, and in a full day of testing nearly every link failed independently:
[factory-needs-input](in a DM or its output)last_event_atreports the transport 6 weeks dead while webhooks deliver in ~8s: AgentWorkforce/cloud#2666delivery_injected: Locally-spawned agents never register with relaycast (send_dm agent_not_found) — briefing never delivered; root cause behind #96/#97; reproduces on two machines #98; the "abort when it fails" patch fix: abort dispatch after critical delivery failure #97 doesn't fire eitherThe design only works if all six links are healthy at the same instant. That is the opposite of robust, and it's why the ask round trip still cannot be demonstrated end-to-end.
Root fragilities
Proposed: escalation as a durable request/response record
Replace the chain with two durable operations and no live injection anywhere:
.integrationsmount), then exits cleanly.Three principles, each kills a class of today's failures
The escalation channel is the GitHub issue itself
No new store needed. The question is an issue comment, the answer is a reply comment, and the agent re-spawns reading the comments — durable, visible to the human in the natural place, and Slack becomes an optional mirror, off the critical path.
Concrete steps (ownership: almost entirely factory-side + one template change)
[factory-needs-input]DM. Prompt change insrc/dispatch/templates.ts. No new tool required (issue write already available); a structuredask_humanMCP tool is an optional relay-side nicety.#injectPendingSlackClarificationreply-injection.What already exists vs what's new
#injectPendingGithubClarification(GitHub reply path), the issue-as-store (the mount).Validation note
This must be validated on a quiet machine — every test so far was confounded by other agents (the pear app's lead/gap/query/durable) polluting process/session forensics. On a box running only the one dispatch, the proof is watchable and unfakeable: agent posts comment → exits → human replies → agent re-spawns and finishes.
Related
#94, #95 (Slack gate), #96 (fail-open on un-briefed agent), #97 (abort-on-critical-delivery-failure — becomes moot under Step 0), #98 (codex injection race — the immediate blocker this design removes), #79 (release/resume — the reply half already built), AgentWorkforce/cloud#2666 (the Slack ingest lie that Step 4 takes off the critical path).