This release includes 1 breaking change for platform teams planning a safe upgrade.
✓ No known CVEs patched in this version
Topics
+13 more
Affected surfaces
Summary
AI summaryUpdates 1.20.4] - 2026-05-12, Tests, and textbox/searchbox/combobox/spinbutton across a mixed release.
Full changelog
[1.20.4] - 2026-05-12
Fixed — Browser agent: model 404, premature step kill, AX-tree starvation
claude-opus-4.6(andclaude-opus-4.5,claude-sonnet-4.6,claude-haiku-4.5) →404 not_found_error— the LLM catalogue (llm_models,llm_config_overrides) anddomains/llm_config/constants.pystored Anthropic 4.x model ids with a dot (claude-opus-4.6), but the Anthropic API only accepts the dashed form (claude-opus-4-6, …) —core/config/llm.pyalready used the dashed form. Any LLM type pointed at one of these (e.g.browser_agentafter the admin picked "Claude Opus 4.6") crashed at instantiation. Renamed to the dashed form everywhere: pricing/config seeds,mcp_app_react_agentdefault, unit tests, frontend i18n strings (claude-opus-4-5template label), docs. New Alembic migrationrename_anthropic_model_ids_001rewrites the existingllm_models.model_name/llm_config_overrides.modelrows (idempotent regex^(claude-[a-z]+-[0-9]+)\.([0-9]+)$→\1-\2, reversible); DEV migrated, PROD updated via the equivalent in-transaction SQL.browser_task_toolstep killed mid-task — the parallel executor wraps each tool step inasyncio.wait_for(timeout=step.timeout_seconds or DEFAULT_TOOL_TIMEOUT_SECONDS), andbrowser_task_tool(a full nested ReAct loop) was absent from_HIGH_LATENCY_TOOLS, so the planner's 30/60/120 stimeout_secondscancelled the loop before it could finish (observed step durations: exactly 30 009 / 60 020 / 120 009 ms, thenasyncio.CancelledErrorinsidebrowser_task_tool). Addedbrowser_task_toolto_HIGH_LATENCY_TOOLSwith a dedicated floorBROWSER_TOOL_TIMEOUT_SECONDS = 300 sand ceilingMAX_BROWSER_TOOL_TIMEOUT_SECONDS = 600 s(the genericMAX_TOOL_TIMEOUT_SECONDS = 120 sno longer applies to it).- Accessibility-tree truncation hid form controls —
BROWSER_AX_TREE_MAX_TOKENScode default raised5000 → 15000(newBROWSER_AX_TREE_MAX_TOKENS_DEFAULTconstant, referenced fromBrowserSettings);.env.example/.env.prod.exampleupdated.
Added — BROWSER_REACT_MAX_ITERATIONS
New env var (default 15, range 1–50) capping the create_react_agent recursion_limit of the browser agent loop run by browser_task_tool — mirrors REACT_AGENT_MAX_ITERATIONS / MCP_REACT_MAX_ITERATIONS. Constant BROWSER_REACT_MAX_ITERATIONS_DEFAULT, field browser_react_max_iterations on BrowserSettings, wired in browser_tools.py (was a hard-coded 15); .env.example / .env.prod.example and BROWSER_CONTROL.md updated.
Changed — Browser agent prompt (prompts/v1/browser_agent_prompt.txt)
Rewritten from web-research best practices (notably the browser-use agent prompt): explicit read-vs-transactional task modes, no fabricated query-param URLs, observe→act→verify loop with a mandatory snapshot after state-changing actions, stale-[ref] handling, autocomplete → click-the-suggestion (not Enter), fill only on real input controls (textbox/searchbox/combobox/spinbutton), cookie-banner/403/login obstacle handling, stuck-loop detection, stop-before-payment + report-only-facts. browser_agent_prompt added to the PromptName Literal (was missing — pre-existing gap).
Fixed — reasoning_effort ↔ model coherence (robustness on model/provider change)
Switching a model/provider on an LLM type could leave a reasoning_effort whose shape no longer matched the new model's reasoning_widget (e.g. a DeepSeek {"effort": "off"} enum value left on a config whose effective model became the Qwen toggle_budget default — the admin UI rendered it as "thinking disabled", so it looked fine), which then crashed the typed reasoning builder at get_llm() time (RuntimeError: ... must be ReasoningEffortToggleBudget, got ReasoningEffortEnum. Validation upstream is broken.). Three layers now prevent this:
- Frontend — the admin dialog normalizes
reasoning_effortto the newly selected model onmodel/providerchange: kept only if its shape fits the newreasoning_widget(and, forenum, the value is allowed), otherwise reset tonull. NewcoerceReasoningEffortForModel/reasoningEffortMatchesModelincomponents/settings/llm-config/reasoningHelpers.ts. - Write path —
LLMConfigService.update_configvalidatesreasoning_effortagainst the effective model (update.model, orLLM_DEFAULTS[llm_type].modelwhen the model override isnull), rejecting an incompatible combination with422+ structuredctx. - Merge runtime —
core/llm_config_helper.py::merge_config→ new_reconcile_reasoning_effortdrops any still-incompatiblereasoning_effortat merge time (stale override row, outdated seed, manual edit, a past bug), falling back to the model's default and loggingllm_config_reasoning_effort_dropped—get_llm()degrades gracefully regardless of the drift's origin.
Shared non-raising predicate reasoning_effort_matches_widget(caps, value) (twin of validate_reasoning_effort) in domains/llm_config/reasoning_validation.py — one source of truth for "is this value valid for this model?", reused by layers 1 and 3.
Fixed — Production build: stale GeoIP database date
apps/api/Dockerfile.prod hard-coded ARG DBIP_DATE=2026-03 for the DB-IP City Lite GeoIP download; db-ip.com keeps only the last ~2 months online, so the URL started returning 404 ("not in gzip format" after curl -L wrote the error page) and gunzip failed the production image build. The geoip-downloader stage now resolves the latest available month at build time — current month, then the previous one — using curl -fsSL (so a 404 cleanly falls through to the next candidate); still overridable with --build-arg DBIP_DATE=YYYY-MM. Build-only change, no runtime impact.
Tests
tests/unit/domains/llm_config/test_reasoning_validation.py::TestReasoningEffortMatchesWidget— none/enum/budget_int/toggle_budget cases incl. the{"effort": "off"}-on-Qwen regression.tests/unit/domains/llm_config/test_config_helper.py::TestEffectiveConfigReasoningReconciliation— incompatiblereasoning_effortoverride dropped, compatible kept, unknown model left untouched.apps/web/src/components/settings/llm-config/__tests__/reasoningHelpers.test.ts— 10 cases forreasoningEffortShape/reasoningEffortMatchesModel/coerceReasoningEffortForModel.test_reasoning_validation.py/test_constants.py/test_llm_defaults_compliance.py/test_reasoning_builders.pyupdated for theclaude-opus-4-6etc. rename.
Documentation
docs/technical/LLM_CONFIG_ADMIN.md— new "Cohérencereasoning_effort↔ modèle" section (the 3-layer guarantee),reasoning_validation.py/ReasoningWidget.tsx/reasoningHelpers.tsadded to the file map, PUT-semantics note.docs/technical/BROWSER_CONTROL.md—BROWSER_REACT_MAX_ITERATIONS+ browser step-timeout +BROWSER_AX_TREE_MAX_TOKENSnotes; new "Agent prompt" section summarising the prompt's behavioural contract.- In-app FAQ (
apps/web/locales/*/translation.json, 6 languages): newfaq.changelog.versions.v1_20_4entry (3 user/admin items);faq.intro.features.browserControlblurb refined (multi-step flow, stops at login/payment, reports a summary);faq.sections.tool_examples_externalq18/q19 refined (multi-step example, "good to know" note, corrected timing).docs/knowledge/06_external_services.mdpropagated from the updated FAQ.docs/GETTING_STARTED.mdcompatibility line bumped to v1.20.4 (with v1.20.1–v1.20.4 highlights).README.mdtop banner updated to v1.20.4 (v1.20.3 demoted to a<details>block). README.md/docs/technical/LLM_PRICING_TEMPLATES.md/docs/guides/GUIDE_CONFIG_ARCHITECTURE.md/ the 6apps/web/locales/*/translation.json—claude-opus-4.5→claude-opus-4-5in prose/examples.- Version bumped to
1.20.4acrossapps/api/pyproject.toml,apps/web/package.json,package.json, andapps/web/src/lib/version.ts(LAST_UPDATED = 2026-05-12T22:48:00, shown on the landing page).
Breaking Changes
- Renamed Anthropic model identifiers from dot notation (e.g., `claude-opus-4.6`) to dash notation (`claude-opus-4-6`) in all configuration, code, docs and database; migration performed by Alembic script `rename_anthropic_model_ids_001`.
Weekly OSS security release digest.
The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.
No spam, unsubscribe anytime.
Share this release
About LIA
All releases →Related context
Related tools
Beta — feedback welcome: [email protected]