Skip to content

fix(web): guarantee a checkpoint on dashboard Stop/Kill (#245) - #254

Merged
Jason Robert (jrob5756) merged 1 commit into
mainfrom
fix/245-web-stop-checkpoint
Jun 16, 2026
Merged

fix(web): guarantee a checkpoint on dashboard Stop/Kill (#245)#254
Jason Robert (jrob5756) merged 1 commit into
mainfrom
fix/245-web-stop-checkpoint

Conversation

@jrob5756

Copy link
Copy Markdown
Collaborator

Fixes#245.

Problem

A dashboard Kill while an agent was actively running — and the Stop startup-race fallback — cancelled the engine task from the CLI wrapper, unwinding through the engine's except asyncio.CancelledError arm, which intentionally emits no workflow_failed and saves no checkpoint. The wrapper then raised ExecutionErroroutside the engine, so progress was lost silently with no UI feedback. The pause→Kill path only worked because it raised InterruptErrorinside the engine.

Changes

Backend

  • engine/workflow.py: new idempotent handle_dashboard_stop() — writes a best-effort checkpoint and emits a single workflow_failed (flagged stopped_by_user, carrying checkpoint_path or checkpoint_unavailable_reason) plus checkpoint_saved. Flags the in-loop InterruptError path stopped_by_user for parity; corrects the misleading CancelledError comment.
  • cli/run.py: threads engine into _execute_with_stop_signal; on a stop-driven cancel it calls handle_dashboard_stop, while a self-raised InterruptError (pause→Kill) is re-raised untouched (no double-handling).
  • web/server.py: POST /api/stop now queues (_pending_stop) until set_interrupt_event binds the engine event, replacing the progress-losing hard-stop fallback.

Frontend (React bundle rebuilt + committed under web/static/)

  • Dedicated, calm "Workflow Stopped" banner showing Checkpoint saved: <path> or No checkpoint could be saved — <reason>; store/types updated; clearer Stop/Kill tooltips.

Tests & docs

  • New/updated: TestHandleDashboardStop (4), _execute_with_stop_signal wiring (2), server-queue rewrite (3), integration Kill-mid-step (1).
  • Full test_web + test_cli + test_engine sweep: 1244 passed, 4 skipped. Ruff lint + ty typecheck clean; frontend tsc -b clean.
  • Updated CHANGELOG, docs/cli-reference.md, AGENTS.md.

Out of scope: #244 (periodic checkpoints) — complementary, tracked separately.

@jrob5756
Jason Robert (jrob5756)force-pushed the fix/245-web-stop-checkpoint branch 2 times, most recently from d14351b to eaf95daCompareJune 16, 2026 21:25
A dashboard Kill while an agent was actively running — and the Stop
startup-race fallback — cancelled the engine task from the CLI wrapper,
unwinding through the engine's `except asyncio.CancelledError` arm which
intentionally emits no `workflow_failed` and saves no checkpoint. The
wrapper then raised `ExecutionError` outside the engine, so progress was
lost silently with no UI feedback.
- engine: add idempotent `handle_dashboard_stop()` that writes a
best-effort checkpoint and emits `workflow_failed` (flagged
`stopped_by_user`, with `checkpoint_path` or `checkpoint_unavailable_reason`)
plus `checkpoint_saved`. Flag the in-loop `InterruptError` path
`stopped_by_user` for parity; correct the misleading `CancelledError`
comment.
- cli: thread `engine` into `_execute_with_stop_signal`; call
`handle_dashboard_stop` on a stop-driven cancel, and re-raise a
self-raised `InterruptError` (pause->Kill) untouched.
- web/server: queue `POST /api/stop` (`_pending_stop`) until the engine
binds the interrupt event instead of falling back to a hard stop.
- dashboard: dedicated "Workflow Stopped" banner showing the checkpoint
outcome; clearer Stop/Kill tooltips; rebuilt static bundle.
- tests + docs (CHANGELOG, cli-reference, AGENTS).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jrob5756
Jason Robert (jrob5756) merged commit 2b77f90 into mainJun 16, 2026
9 checks passed
@jrob5756
Jason Robert (jrob5756) deleted the fix/245-web-stop-checkpoint branch June 16, 2026 21:40
Jason Robert (jrob5756) added a commit that referenced this pull request Jun 17, 2026
Resolve conflicts from #252 (context_tier), #253 (script stdin), #254/#245
(dashboard-stop checkpoint), and #255 (periodic checkpoints):
- cli/run.py: keep both the validator event cases and the new
checkpoint_save_failed console case in the on_event chain.
- AGENTS.md / examples/README.md: keep both features' sections.
- Dashboard bundle: rebuilt from merged frontend source (one bundle reflects
main's ErrorBanner/Header/store changes and the validator events/handlers).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: Web Stop/Kill can terminate a run without writing a checkpoint

1 participant

@jrob5756