fix(cli): restore Anton CLI for MindsHub users — minds-cloud crash + self-update loop (ENG-655)#240
Conversation
…self-update loop (ENG-655)
Two verified failures that made the standalone `anton` CLI unusable for MindsHub
users (desktop app + webapp are unaffected — they build the LLM client via
cowork-server's own build_llm_client and never call this updater).
1. Crash: `ValueError: Unknown planning provider: minds-cloud`.
The CLI's LLMClient registry only has anthropic/openai/openai-compatible;
MindsHub speaks the OpenAI-compatible API but the desktop/consolidated config
uses the first-class name "minds-cloud", which the CLI never mapped. Add an
AntonSettings field-validator that normalizes minds-cloud (and the underscore
spelling) → openai-compatible, so model_post_init derives the creds/base from
the minds_* fields and the existing provider handles it. Reproduced the crash
and the fix in a test.
2. Perpetual failed self-update that corrupts installs (reported on Windows).
`__version__` was hardcoded in anton/__init__.py and drifted from the release
tags (stuck at 2.26.6.30.1 across several releases) because the release
workflow only tags (pyproject is hatch-vcs / version-from-tag). The updater
read that stale constant as local_ver, so remote(tag) > local was always true
→ it force-reinstalled the running tool on every launch → on Windows that
partial reinstall bricked the env (missing rich._emoji_codes, typer rich_utils
ImportError, or "No module named 'anton'").
- Derive __version__ from installed package metadata (importlib.metadata) so it
always matches what's installed — kills the drift class at the root.
- Anti-thrash guard in updater.py: record a tag whose reinstall didn't take and
don't force-reinstall that same tag again until a newer one appears.
3. Escape hatch + dep cap: add a discoverable `--no-update` CLI flag (surfacing
the existing ANTON_DISABLE_AUTOUPDATES setting), and cap `rich<15` (rich 14 +
typer 0.24 verified compatible; the reported errors were reinstall corruption,
not a version range).
Tests: 5 for minds-cloud normalization incl. the from_settings crash repro; 3 for
the updater anti-thrash marker. Full suite passes (the 2 scratchpad failures are
pre-existing/environmental — they fail on clean staging too; subprocess can't
spawn in the sandbox).
NOTE for reviewer: the updater changes (dynamic version + anti-thrash) resolve the
loop deterministically in unit tests, but the uv-tool-install / hatch-vcs
interaction should be sanity-checked with a real `uv tool install git+...@<tag>`
on macOS + Windows before relying on it in the wild.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… legacy anton tool (ENG-655) Local uv-flow testing surfaced an additional root cause of the update loop. `_read_installed_anton_version()` matched `re.search(r"anton\s+(\S+)")`, but a real machine can have BOTH a leftover legacy `anton` tool (pre-rename) and the current `anton-agent` tool — `uv tool list` shows `anton` first, so the bare regex read the legacy tool's version (2.26.5.13.1) instead of anton-agent's (2.26.7.6.2). That made installed_ver != remote_ver → "Update skipped" forever, even after a correct install, and combined with the new anti-thrash marker would permanently block updates. Anchor the match to `anton-agent` (line-start, optional v prefix). Verified against the real `uv tool list` output. Two tests: dual-tool ordering, and the absent-anton-agent case (returns None → caller bails safely). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Local uv-flow verification (the reviewer note above)Tested the ✅ hatch-vcs derives the correct version from a git-tag install. Installing ➕ Additional root cause found + fixed (commit Still not exercised: the literal Tests: 28 pass (added dual-tool parsing cases). |
…alidator (ENG-655) Adversarial review of PR #240 surfaced two real gaps: 1. __version__ resolved only the "anton-agent" distribution → on a legacy install under the old "anton" dist name it raised PackageNotFoundError and fell back to "0.0.0.dev0", which makes the updater see local < remote and force-reinstall once per release — reintroducing the exact ENG-655 loop for that cohort. Now try "anton-agent" then "anton" before the dev fallback. Also wrap the whole block defensively: __init__ runs on every `import anton` (incl. the desktop's cowork-server), so it must never raise. 2. The minds-cloud → openai-compatible validator was case-sensitive; "MINDS-CLOUD" or padded values slipped through and re-hit the crash. Now lower()/strip() tolerant. Cross-surface review confirmed no app/webapp/instance regressions (validate_assignment is off so the harness setattr path is unaffected; cowork-server reads importlib.metadata directly, not anton.__version__; rich 14.3.3 satisfies <15; updater is CLI-only). Tests: added case/whitespace normalization case; suite 1148 passed (2 pre-existing scratchpad-subprocess failures unrelated, fail on clean staging too). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adversarial review (3 independent reviewers: import/version, updater, cross-surface) + fixesRan a strict multi-lens review of this PR. Two real gaps found and fixed in Fixed in this PR (
|
Summary
Two verified failures that made the standalone
antonCLI unusable for MindsHub users. Desktop app + webapp are unaffected — they build the LLM client via cowork-server's ownbuild_llm_clientand never invoke this updater (verified during the blast-radius review).Ticket: ENG-655
1 · Crash:
ValueError: Unknown planning provider: minds-cloudThe CLI's
LLMClientregistry only knowsanthropic/openai/openai-compatible. MindsHub speaks the OpenAI-compatible API, but the desktop/consolidated config uses the first-class nameminds-cloud, which the CLI never mapped — so a shared config hard-crashesLLMClient.from_settings.Fix: an
AntonSettingsfield-validator normalizesminds-cloud(and theminds_cloudspelling) →openai-compatible, so the existingmodel_post_initderives creds/base from theminds_*fields and the existing provider handles it.Reproduced locally before/after:
2 · Perpetual failed self-update that corrupts installs (Windows)
__version__was hardcoded inanton/__init__.pyand drifted from the release tags (stuck at2.26.6.30.1across ~3 releases) because the release workflow only tags (pyproject is hatch-vcs / version-from-tag). The updater read that stale constant aslocal_ver, soremote(tag) > localwas always true → it force-reinstalled the running tool on every launch → on Windows the partial reinstall bricked the env (No module named 'rich._emoji_codes',cannot import name 'rich_utils' from 'typer', orNo module named 'anton').Fix:
__version__from installed package metadata (importlib.metadata) so it always matches what's installed — kills the drift class at the root (no manual bump to forget).updater.py: record a tag whose reinstall didn't take and don't force-reinstall that same tag again until a genuinely newer one appears.3 · Escape hatch + dep cap
--no-updateflag (surfacing the existing but hiddenANTON_DISABLE_AUTOUPDATESsetting — users had no way to find it).rich<15. (rich 14 + typer 0.24 are verified compatible; the reported rich/typer errors were reinstall corruption, not a version range.)Tests
from_settingscrash repro.test_chat_scratchpadfailures are pre-existing/environmental — they fail on cleanstagingtoo (the scratchpad subprocess can't spawn in the sandbox).The updater changes (dynamic version + anti-thrash) resolve the loop deterministically in unit tests, but the
uv tool install/ hatch-vcs interaction should be sanity-checked with a realuv tool install git+…@<tag>on macOS + Windows before we lean on it in the wild.Immediate user workaround (until this ships)
Set
ANTON_DISABLE_AUTOUPDATES=truein~/.anton/.env.Not included (tracked separately)
.env→DBmigration (skip-and-log invalid provider). Different repo; latent, not triggered by these bugs.ANTON_DISABLE_AUTOUPDATES).🤖 Generated with Claude Code