fix(ui): stop silently accepting unimplemented agent_mode 'autonomous'#2257
Conversation
|
Verdict: Approve This makes the The fix is fail-loudly-compliant, the docs are updated in lockstep (spec + API model + endpoint docstrings), and the tests are thorough — including an equivalence test proving there's no phantom observation cycle. One minor consistency note below; nothing blocking. 🔍 Technical details🟢 MinorFrontend The TS type is now wider than the API accepts. No current selector sends Non-blocking — only flag it so the type and the API don't drift. Strengths
|
#2005) The default agent_mode 'autonomous' never ran its defining observation cycle — the tick handler idles when no goals exist, so the mode behaved byte-identically to 'goal_driven' while docs promised 'observe, infer, and execute own goals'. Users selecting the default got a no-op label. Until the observation cycle (docs/spec/autonomous-agent-mode.md §6.7) ships, be honest about what runs: - default agent_mode is now 'goal_driven' (identical behavior, truthful name) - PUT /api/settings rejects 'autonomous' with an actionable 400 pointing at 'goal_driven' and issue #2005 instead of silently accepting it - legacy DBs with 'autonomous' stored are normalized to 'goal_driven' via resolve_agent_mode() with a once-per-process warning, and GET /api/settings reports the effective mode - spec doc gains an implementation-status note so it no longer claims the mode is shipped and default Tests pin the settings API contract and prove the loop's legacy 'autonomous' path is identical to 'goal_driven' (no phantom observation cycle).
adff75e to
aa2f81d
Compare
Fixes #2005 (also covers the duplicate medium finding flagged in #2103).
Why this matters
Before: the documented default
agent_mode="autonomous"was a no-op label — the loop's tick handler has no observation cycle, so it behaved byte-identically togoal_drivenwhile the spec and API docs promised "observe, infer, and execute own goals". After: the default is honestlygoal_driven, selectingautonomousfails loudly with a 400 that says exactly why and what to use instead, and legacy DBs that already storedautonomouskeep working (normalized togoal_drivenwith a once-per-process warning). Zero behavior change for any existing user — only the labels stop lying.Scoped fix, not the full feature. The real observation cycle (spec §6.7) is a large open-ended build: six sensors (email/git/error-log/conversation/memory/system-state), a lightweight-model inference step, confidence-gated auto-approval against FAISS permission grants. That needs design decisions (sensor plumbing through connectors, auto-approval safety semantics, observe-model provisioning), so this PR makes the mode selection honest rather than shipping a half-baked cycle. The spec doc now carries an implementation-status note.
Follow-up needed for the full
autonomousmodeAgentLoop._run_step(sensors → lightweight-model inference →GoalStoreentries withsource="agent_inferred")safe_to_auto_executevs. FAISS permission grants)"autonomous"to_VALID_AGENT_MODES, flip the default back, and drop the legacy normalization inresolve_agent_mode()Test plan
pytest tests/unit/chat/ui/test_server.py tests/unit/chat/ui/test_agent_loop.py tests/unit/test_goal_store.py— 182 passedgoal_driven; PUTautonomous→ 400 with actionable detail (nothing persisted); PUTmanual/goal_drivenround-trip; legacy storedautonomousreported asgoal_drivenon GET_run_stepwith legacyautonomousreturns a directive identical togoal_driven(proves no phantom observation cycle);manualpauses; normalization warns exactly oncepython util/lint.py --allgreen