feat(orchestrator): tell headless runs that no user is present - #156
feat(orchestrator): tell headless runs that no user is present#156rockymadden wants to merge 1 commit into
Conversation
Task YAMLs have been carrying hand-copied lines like "Do NOT ask for approval, confirmation, or feedback" to get autonomous behaviour. That phrasing forbids asking without saying nobody is there to ask, so an agent can honor it and still stop at a consent gate waiting for a reply that never arrives. Measured on the uipath-maestro-flow suite (128 tasks): 0 tasks state the run is headless, 51 of the 119 non-simulated tasks say nothing about autonomy at all, and the 68 that do are spread across 8 wording variants. Nine of the silent ones have a checker that executes the built artifact, so they grade a runtime result while giving the agent no signal. The orchestrator already knows which case it is in: simulated tasks are routed to _simulation_dialog_loop and never reach the prompt built in _evaluation_loop. Stating it once at that construction site covers every headless task and cannot drift, since no task author has to remember it. The preamble defers to the task's own instructions, so a task that deliberately asserts a refuse-and-surface (e.g. an upload-safety guard) still overrides it without needing an opt-out flag. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Claude finished @rockymadden's task in 1m 23s —— View job Code Review in Progress
|
There was a problem hiding this comment.
🟢 Approval recommended
The focused change is correctly isolated and covered by regression tests.
Pull request overview
Adds a standard headless-run preamble for autonomous, non-simulated evaluations.
Changes:
- Prepends the preamble after working-directory context.
- Keeps simulated-user dialogs unchanged.
- Adds tests for prompt ordering and simulation routing.
File summaries
| File | Description |
|---|---|
src/coder_eval/orchestrator.py |
Adds and routes the headless preamble. |
tests/test_orchestrator.py |
Tests headless and simulated paths. |
Review details
- Files reviewed: 2/2 changed files
- Comments generated: 0
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
Closed per thread feedback. Recording why, for anyone who finds this later. The orchestrator is the wrong layer. Two things this PR got wrong: Scale. I sized the simulated-task exposure from the Layer. Even with the simulated path excluded, baking a behavioral policy into the orchestrator makes it unconfigurable per experiment. The config mechanism already existed and I did not look for it. Replacement work moves to One open problem for whoever picks up the split: no tag or path convention distinguishes the 319 simulated tasks, and they are not confined to a directory ( |

Problem
Task YAMLs carry hand-copied lines like "Do NOT ask for approval, confirmation, or feedback" to get autonomous behavior. That phrasing forbids asking. It does not say nobody is there to ask.
Those are different instructions, and an agent can honor the first while still stopping at a consent gate to wait for a reply that never arrives. That is not hypothetical: in the 2026-09-04
skill-flow-*nightly, 5 of 8 tasks built and validated a flow, reported success, and never executed it. Every one of those prompts contained the "Do NOT ask" line.Measured across the
uipath-maestro-flowsuite (128 tasks):The instruction is hand-maintained, inconsistent, and missing from nearly half the suite.
Fix
The orchestrator already knows which case it is in. Simulated tasks are routed to
_simulation_dialog_loopatorchestrator.py:1925and never reach the prompt built in_evaluation_loop. The two paths are separate functions, so stating it once at that construction site covers every headless task, cannot reach a task that has a live user, and needs no conditional.Ordering is cwd → preamble → task prompt.
Why no opt-out flag
The last sentence defers to the task. A task that deliberately asserts a refuse-and-surface still overrides it.
skill-flow-eval-no-auto-uploadis the live example: it instructs the agent to refuse an upload and surface the choice, and it keeps working without anyone remembering to set a flag.I would rather find out that is too soft from a real run than add a config field on speculation.
Tests
Two, both in
tests/test_orchestrator.py:test_evaluation_loop_prepends_headless_preamble— the preamble reaches the agent, and the ordering holds.test_simulated_task_bypasses_the_headless_prompt_path— a simulated task delegates to the dialog loop and never builds the headless prompt.The second is the one that matters. The design rests entirely on the function boundary, so a refactor that merges the loops should fail loudly.
Verification
ruff format --check/ruff checkonsrcandtests: cleanpyrighton both changed files: 0 errorsmake lint(custom CE rules): 388 passedDownstream
UiPath/skillspins this viatests/.coder-eval-version(currently 0.11.5). Once this releases, that pin bumps and all 119 headless flow tasks get the declaration. The 68 hand-copied autonomy lines become redundant and can be swept separately.