Skip to content

feat(desktop): auto-restart agents on config change (Chunk F)#1649

Merged
wesbillman merged 2 commits into
mainfrom
feat/agent-auto-restart
Jul 8, 2026
Merged

feat(desktop): auto-restart agents on config change (Chunk F)#1649
wesbillman merged 2 commits into
mainfrom
feat/agent-auto-restart

Conversation

@wesbillman

@wesbillman wesbillman commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

What (Chunk F — the final Phase 1 slice)

Will's ask: users don't realize agents need a restart to pick up config changes — restart automatically instead of only badging. Detection already existed end-to-end (spawn_config_hash stamped at spawn → needs_restart in the summary poll → badge); this PR adds policy only.

Safety framing (reviewer's Finding 1, verbatim)

stop_managed_agent_process is SIGTERM → ≤1s → SIGKILL with no in-process drain. The policy predicate is therefore the only thing standing between this feature and killing a mid-turn agent. Every gate below is load-bearing, and the test matrix treats "fires while working" as a kill.

Design (pressure-tested in-channel, all findings resolved)

autoRestartPolicy.ts — pure decision core: fire / arm / hold.
Never-fire gates (each alone holds the line): opt-out toggle off · no drift · working (any source, typing included; flag and source both checked so a partial reader can't slip through) · observer relay not connected (Finding 3: connectionState gate subsumes the relay-drop pause heuristic) · remote backend · not running · edge consumed.
Fire additionally requires a 3-minute continuous quiescence window (Finding 4: hook-local continuity timer, reset on any working flicker or disconnect — the turn store prunes after 25s, so a relay hiccup must never read as idle).

Edge-triggered debounce (Finding 2, option b): one attempt per needsRestart false→true rising edge. Failed attempt → badge-only until the edge cycles. Falling edge or agent stop re-arms (reviewer's rearm rule: a manual stop/start cycle makes a re-drifting agent eligible again). Named semantic: a second config change after a failed attempt does not retry until the flag cycles.

useAutoRestartPolicy — mounted once in AppShell: 15s tick keeps the continuity clock honest between 5s summary polls; per-pubkey in-flight guard; pre-fire summary re-fetch re-verifies drift/enabled/running/idle immediately before firing (shrinks the accepted cross-window race to near-zero; both commands are idempotent and store-lock serialized).

Backendauto_restart_on_config_change record field (serde default true: existing records opt in, per product decision) + summary projection + standalone set_managed_agent_auto_restart command mirroring set_managed_agent_start_on_app_launch. UpdateManagedAgentInput stays frozen — the renegotiation shrank to record field + summary field.

Control surface — checkbox in the instance-edit dialog's advanced section (product decision: sufficient), persisted via the standalone setter.

Known/accepted (named, not hidden)

  • Mass-drift: a relay-URL or template edit flips N agents at once → N near-simultaneous restarts; stagger deemed scope creep.
  • ModelPicker's separate local hint may show a stale "restart to apply" after an auto-restart. Acceptable residual.
  • Failed attempts don't retry until the needsRestart edge cycles (fail-safe by design).

Validation

  • Policy matrix: 18/18 — never-fire rows one-gate-red-at-a-time exhaustive (11 rows), window boundary rows, all three edge-rearm rows.
  • Full frontend unit: 2161/2161. Rust: 1056/1056, clippy clean, both fmt gates clean.
  • tsc + biome clean. 59-test agent/persona e2e smoke slice green, zero spec edits.
  • 26 files: 13 are mechanical one-line test-fixture initializer additions (the new record field); core = types.rs + agent_settings.rs + agents.rs + runtime.rs + lib.rs (Rust), autoRestartPolicy.ts + useAutoRestartPolicy.ts + test (new), AppShell + hooks.ts + EditAgentAdvancedFields + AgentInstanceEditDialog + tauri.ts/types.ts/tauriManagedAgents.ts + e2eBridge (wiring).

Users don't realize agents need a restart to pick up config changes.
Detection already existed (spawn_config_hash -> needs_restart -> badge);
this adds the policy: a frontend hook (mounted once in AppShell)
auto-restarts a drifted agent via the existing stop/start commands when
every safety gate is green.

The policy predicate is safety-critical: stop is SIGTERM -> <=1s ->
SIGKILL with no in-process drain, so the never-fire gates are the only
thing between the policy and killing a mid-turn agent. Gates: per-agent
opt-out (default ON), needsRestart, not working (any working-signal
source defers, typing included), observer relay connected, local
backend, running status, un-consumed rising edge, and a 3-minute
continuous quiescence window (resets on any working flicker or
disconnect — the turn store prunes after only 25s, so a relay hiccup
must never read as idleness). Edge-triggered debounce: one attempt per
needsRestart rising edge; a failed attempt badges only until the edge
cycles (falling edge or agent stop re-arms). Pre-fire summary re-fetch
shrinks the cross-window stale race to near-zero; the commands
themselves are idempotent and store-lock serialized.

Backend: record field auto_restart_on_config_change (serde default
true, so existing records opt in per the product decision) + summary
projection + standalone set_managed_agent_auto_restart command
(mirroring start_on_app_launch — UpdateManagedAgentInput stays frozen).
Control surface: checkbox in the instance-edit advanced section.

Known/accepted: mass-drift (relay-URL or template edit) restarts N
agents near-simultaneously, no stagger; ModelPicker's local hint can
show stale "restart to apply" after an auto-restart; failed attempts
don't retry until the edge cycles.

Co-authored-by: Brain <21994759fc7a6fa6b965551d35cfd7897d262f2495467f2d78694ddcfa6a5c7e@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
@wesbillman

Copy link
Copy Markdown
Collaborator Author

Pinky review verdict: approved on the code against the locked Chunk F criteria (hook wiring / pre-fire re-fetch / default-ON containment / never-fire matrix exhaustiveness + all 3 rearm rows — all verified in the diff at dd39043). One mechanical fix required before Wes's gate: Desktop Core is red on a Biome format check for autoRestartPolicy.test.mjs (pure line-wrapping, zero logic diff) — run the formatter and push. Also: PR body says 23 files; gh reports 26 (the extras are more one-line Rust fixture initializers, same mechanical category — no scope concern). Full verdict in the Buzz thread.

… effect

Line-wrapping only in the test table, plus the reviewer-suggested
one-line comment on the intentionally dependency-less effect.

Co-authored-by: Brain <21994759fc7a6fa6b965551d35cfd7897d262f2495467f2d78694ddcfa6a5c7e@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
@wesbillman wesbillman merged commit a415f0f into main Jul 8, 2026
25 checks passed
@wesbillman wesbillman deleted the feat/agent-auto-restart branch July 8, 2026 19:09
wpfleger96 added a commit that referenced this pull request Jul 8, 2026
Three test struct literals missed the new auto_restart_on_config_change
field added by the auto-restart PR (#1649) that landed on main before this
rebase. Also wire State import in agent_settings.rs which the auto-restart
command requires.

This is a purely mechanical rebase-compatibility fix — no product logic
change.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
wpfleger96 added a commit that referenced this pull request Jul 8, 2026
Three test struct literals missed the new auto_restart_on_config_change
field added by the auto-restart PR (#1649) that landed on main before this
rebase. Also wire State import in agent_settings.rs which the auto-restart
command requires.

This is a purely mechanical rebase-compatibility fix — no product logic
change.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
wpfleger96 added a commit that referenced this pull request Jul 8, 2026
Three test struct literals missed the new auto_restart_on_config_change
field added by the auto-restart PR (#1649) that landed on main before this
rebase. Also wire State import in agent_settings.rs which the auto-restart
command requires.

This is a purely mechanical rebase-compatibility fix — no product logic
change.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
wpfleger96 added a commit that referenced this pull request Jul 9, 2026
Three test struct literals missed the new auto_restart_on_config_change
field added by the auto-restart PR (#1649) that landed on main before this
rebase. Also wire State import in agent_settings.rs which the auto-restart
command requires.

This is a purely mechanical rebase-compatibility fix — no product logic
change.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
wpfleger96 added a commit that referenced this pull request Jul 9, 2026
Three test struct literals missed the new auto_restart_on_config_change
field added by the auto-restart PR (#1649) that landed on main before this
rebase. Also wire State import in agent_settings.rs which the auto-restart
command requires.

This is a purely mechanical rebase-compatibility fix — no product logic
change.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
wpfleger96 added a commit that referenced this pull request Jul 9, 2026
Three test struct literals missed the new auto_restart_on_config_change
field added by the auto-restart PR (#1649) that landed on main before this
rebase. Also wire State import in agent_settings.rs which the auto-restart
command requires.

This is a purely mechanical rebase-compatibility fix — no product logic
change.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
wpfleger96 added a commit that referenced this pull request Jul 9, 2026
Three test struct literals missed the new auto_restart_on_config_change
field added by the auto-restart PR (#1649) that landed on main before this
rebase. Also wire State import in agent_settings.rs which the auto-restart
command requires.

This is a purely mechanical rebase-compatibility fix — no product logic
change.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
wpfleger96 added a commit that referenced this pull request Jul 10, 2026
Three test struct literals missed the new auto_restart_on_config_change
field added by the auto-restart PR (#1649) that landed on main before this
rebase. Also wire State import in agent_settings.rs which the auto-restart
command requires.

This is a purely mechanical rebase-compatibility fix — no product logic
change.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
wpfleger96 added a commit that referenced this pull request Jul 10, 2026
Three test struct literals missed the new auto_restart_on_config_change
field added by the auto-restart PR (#1649) that landed on main before this
rebase. Also wire State import in agent_settings.rs which the auto-restart
command requires.

This is a purely mechanical rebase-compatibility fix — no product logic
change.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
wpfleger96 added a commit that referenced this pull request Jul 10, 2026
Three test struct literals missed the new auto_restart_on_config_change
field added by the auto-restart PR (#1649) that landed on main before this
rebase. Also wire State import in agent_settings.rs which the auto-restart
command requires.

This is a purely mechanical rebase-compatibility fix — no product logic
change.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
wpfleger96 added a commit that referenced this pull request Jul 10, 2026
Three test struct literals missed the new auto_restart_on_config_change
field added by the auto-restart PR (#1649) that landed on main before this
rebase. Also wire State import in agent_settings.rs which the auto-restart
command requires.

This is a purely mechanical rebase-compatibility fix — no product logic
change.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Sign up for free to 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.

1 participant