Conversation
…hboard Closes #134 When a workflow hit its `max_iterations` limit, the engine's interactive prompt was console-only — no event was emitted, so the web dashboard went dark with the last visible event being an `agent_completed`. Users monitoring via `--web` had no indication that the workflow was paused or what action was needed. ## Backend Two new event types emitted from `_check_iteration_with_prompt` and `_check_parallel_group_iteration_with_prompt` in `engine/workflow.py`: - `iteration_limit_reached` — emitted **before** the console prompt with `{agent_name|group_name, current_iteration, max_iterations, agent_history (last 5), possible_loop, skip_gates}`. - `iteration_limit_resolved` — emitted **after** the prompt with `{agent_name|group_name, continue_execution, additional_iterations}`. The `possible_loop` heuristic flags when the last 3 history entries are the same agent (signal for a stuck review loop). The `skip_gates` flag tells subscribers whether the gate is interactive or about to auto-stop. The console subscriber and JSONL log subscriber require no changes — the existing console prompt UI still drives interactive resolution; the new events are additive for downstream consumers. ## Frontend - New `EventType` entries in `types/events.ts` plus `IterationLimitReachedData` / `IterationLimitResolvedData` interfaces. - New `iterationLimitGate` slice in `workflow-store.ts` (set on reached, cleared on resolved); both events also produce activity-log and event-log entries. - `StatusBar.tsx` shows an amber-tinted banner "Iteration limit reached: <agent> N/N — awaiting console input" when the gate is open, falling back to the normal status when resolved. Bundled `web/static/` assets rebuilt via `npm run build`. ## Tests - New `tests/test_engine/test_iteration_limit_events.py` with 3 cases: reached event payload + skip_gates flag + possible_loop heuristic; resolved event in skip_gates mode; reached emitted before resolved. - `make lint` clean. - Full suite: 2374 passed (1 unrelated live Copilot integration test excluded). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Address PR #162 review findings. Critical: iteration_limit_resolved is now wrapped in an outer finally so the dashboard gate always closes — even when the prompt itself raises (EOFError on non-TTY, KeyboardInterrupt race, asyncio.CancelledError, unexpected console errors). Without this guarantee, the original #134 symptom (silently dark dashboard) recurs on the error path. The resolved event now carries an `aborted: bool` flag so subscribers can distinguish exception-driven stops from deliberate ones. Applied to both the single-agent and parallel-group helpers. human.py: _prompt_for_additional_iterations now also catches EOFError (non-TTY environments like CI, '< /dev/null', containers without a terminal). Treated as "stop", same as the user typing 0. Frontend hardening: - workflow-store.ts: null iterationLimitGate in workflow_completed and workflow_failed (defense-in-depth — orphan gate banner cannot persist past terminal workflow states). Inline gate type replaced with IterationLimitReachedData | null so future fields propagate (already fixed an agent_count drift). Both event handlers warn when target name is missing. - events.ts: IterationLimitReachedData and IterationLimitResolvedData are now discriminated unions on agent_name XOR group_name+agent_count (eliminates 4 illegal states + the `?? ?? 'workflow'` fallback chain consumers had to write). Always-emitted fields (possible_loop, skip_gates, agent_history, additional_iterations) marked required. Added optional aborted field. JSDoc tightened to describe the last-3-same-agent heuristic and the skip_gates auto-decision. Tests grew 3 -> 10 cases covering: interactive continue path, interactive decline path, prompt-raises-aborted path, EOFError-clean-stop path, parallel-group emission site, possible_loop=False for mixed history, possible_loop=False for short history, and a strengthened ordering test that asserts no agent events fall between reached/resolved. make lint, make typecheck, tsc -b && vite build all clean. Full suite: 2382 passed, 9 skipped. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Merged
jrob5756
added a commit
that referenced
this pull request
May 6, 2026
- conductor resume flag parity with run (#158) - reasoning effort displayed in dashboard (#160) - iteration_limit_reached/resolved events for dashboard (#162) - registry latest now means default branch HEAD, not newest tag (#157) - forbid extra fields on Agent/Parallel/ForEach/Workflow schemas (#159) - pretty-print tool args/results in dashboard events (#161) - capture uv stdout+stderr on Windows install failure (#156) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #134
Problem
When a workflow hit its
max_iterationslimit, the engine prompted the user via a console-only RichIntPromptwhile the web dashboard went silently dark — the last visible event was anagent_completed, then nothing. Users monitoring via--webhad no indication that the workflow was paused or what action was needed; they had to switch to the console terminal to discover the prompt.Backend
Two new event types emitted from
_check_iteration_with_promptand_check_parallel_group_iteration_with_promptinengine/workflow.py:iteration_limit_reached— emitted before the console prompt:{ "agent_name": "reviewer", // or "group_name" for parallel "current_iteration": 20, "max_iterations": 20, "agent_history": ["architect", "reviewer", "architect", "reviewer", "architect"], "possible_loop": true, "skip_gates": false }iteration_limit_resolved— emitted after the prompt:{ "agent_name": "reviewer", "continue_execution": true, "additional_iterations": 10 }The
possible_loopheuristic flags when the last 3 history entries are the same agent — a strong signal for a stuck review loop. Theskip_gatesflag lets subscribers distinguish interactive gates from auto-stop scenarios.The console subscriber and JSONL log subscriber needed no changes — the existing console prompt continues to drive interactive resolution; the new events are purely additive for downstream consumers.
Frontend
types/events.ts— added the two event types and matchingIterationLimitReachedData/IterationLimitResolvedDatainterfaces.workflow-store.ts— added aniterationLimitGateslice (set on reached, cleared on resolved). Both events produce activity-log and event-log entries on the relevant agent/group node.StatusBar.tsx— shows an amber-tinted banner "Iteration limit reached: N/N — awaiting console input" when the gate is open, falling back to normal status text when resolved.Bundled
web/static/assets rebuilt vianpm run build(the standard build pipeline).Tier-1 fix only
This PR delivers the dashboard-visibility half of the issue (emit events, render the gate). It does not make the gate web-resolvable from the dashboard — the user still answers via the console prompt. Web-resolvable iteration gates would require bidirectional WebSocket coordination similar to human gates and is out of scope for this fix.
Tests
tests/test_engine/test_iteration_limit_events.pywith 3 cases:skip_gatesflag +possible_loopheuristicskip_gatesmode (auto-stop)make lintclean.Verification
In a workflow with a tight
max_iterationslimit and--web, the dashboard now:iteration_limit_reached→ StatusBar turns amber: "Iteration limit reached: reviewer 20/20 — awaiting console input"iteration_limit_resolvedclears the gate and StatusBar returns to normal.