* fix: always send frontend's chosen default model to agent-server (#807)
When the agent-server returns an empty model string (e.g. because no
settings have been saved yet), the adapter's type guard accepted it as
a valid string and forwarded it verbatim. The agent-server would then
fall back to its SDK default ('gpt-5.5') rather than using the
frontend's chosen default ('openhands/minimax-m2.7').
Fix: strengthen the guard in buildConfiguredOpenHandsAgentSettings to
also reject empty/whitespace-only strings, so the frontend's own
default is always sent explicitly:
llm.model =
typeof llm.model === 'string' && llm.model.trim().length > 0
? llm.model
: DEFAULT_SETTINGS.llm_model;
While here: align the legacy V0 /api/options/models mock endpoint's
default_model with DEFAULT_SETTINGS (was incorrectly set to claude-opus;
should be minimax-m2.7 to match the rest of the defaults), and document
the canonical default model and the two-location update rule in AGENTS.md.
Closes#807
Co-authored-by: openhands <openhands@all-hands.dev>
* refactor(tests): parameterize llm.model fallback tests + add spec + AGENTS.md
- Extract getModelFrom() helper to eliminate repeated as unknown as ModelPayload casts
- Consolidate 7 individual fallback it() blocks into two it.each() groups:
(1) agent_settings variants (undefined/empty/whitespace/no-llm-block/empty-settings)
(2) encryptedAgentSettings variants (empty model / empty object)
- Rename @spec annotation from BM-807 to LLD-001 (not a backend-management spec)
- Add specs/llm-defaults.md with LLD-001 checklist
- Add AGENTS.md note documenting canonical default model, its location, and
the two-location update rule
Co-authored-by: openhands <openhands@all-hands.dev>
---------
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: hieptl <hieptl.developer@gmail.com>
* Add backend management specs and @spec annotations
- Curate specs/backend-management.md with 4 behavioral specs (BM-001–BM-004)
- Add @spec comments to source and test files for traceability
- Add spec file convention note to AGENTS.md
Co-authored-by: openhands <openhands@all-hands.dev>
* Remove duplicate BM-002 test (non-conversation redirect)
The 'stays on settings' case was covered by two tests; keep the one
with the clearer assertion and drop the redundant copy.
Co-authored-by: openhands <openhands@all-hands.dev>
* Parameterize BM-002 tests with it.each
Collapse 3 identical-structure redirect tests into a single
parameterized it.each covering conversation detail, automation detail,
and non-ID routes.
Co-authored-by: openhands <openhands@all-hands.dev>
* Document @spec tagging convention in AGENTS.md
Co-authored-by: openhands <openhands@all-hands.dev>
---------
Co-authored-by: openhands <openhands@all-hands.dev>
* spec(BM-001): add spec + failing tests for auto-switch on connect
Adding a backend should automatically switch the active selection to it.
Currently addBackend registers the entry but leaves the user on the
previous backend, forcing a manual switch.
- specs/backend-management.md: BM-001 definition
- Two new test cases (cloud + local) that assert the active backend
changes after addBackend — both fail against the current implementation.
Co-authored-by: openhands <openhands@all-hands.dev>
* fix(BM-001): auto-switch active backend on addBackend
addBackend now calls setActiveSelection after registering the new entry,
so the user lands on the backend they just connected — whether via the
manual host+key form or the cloud OAuth device-flow login.
- src/contexts/active-backend-context.tsx: one-line fix in addBackend
- Updated add-backend-modal test to assert the new active selection
- Updated backend-selector tests that used addBackend purely as setup
to reset active to the default local backend afterward
Co-authored-by: openhands <openhands@all-hands.dev>
* chore: remove noisy @spec markers from test setup comments
Keep @spec BM-001 only where it marks the implementation or directly
asserts the spec behavior. Setup-only adjustments (resetting active
backend after addBackend) are incidental — plain comments suffice.
Co-authored-by: openhands <openhands@all-hands.dev>
* chore: consolidate @spec BM-001 to one test + one implementation site
The spec marker belongs in exactly two places: the line that implements
the behavior and the single test that verifies it. Removed the redundant
local-backend variant (same code path as cloud) and dropped @spec labels
from the modal test (its assertion stays, just without the tag).
Co-authored-by: openhands <openhands@all-hands.dev>
* refactor: remove setActive workarounds from backend-selector tests
Instead of manually resetting active state after addBackend, tests now
work with the auto-switch naturally:
- Local backend tests: click the seeded default 'Local' (which is no
longer active after auto-switch) to trigger the switch.
- Cloud org tests: add a local backend after the cloud one so the last
auto-switch lands on local, leaving cloud backends unselected and
their org rows visible in the dropdown.
No ctx.setActive(DEFAULT_LOCAL_BACKEND_ID) calls remain.
Co-authored-by: openhands <openhands@all-hands.dev>
* refactor: extract shared seed constants in backend-selector tests
SEED_LOCAL_1 and SEED_CLOUD_PRODUCTION replace 12+4 identical inline
config objects. The two remaining inline blocks have different apiKey
values and correctly stay as-is.
Co-authored-by: openhands <openhands@all-hands.dev>
---------
Co-authored-by: openhands <openhands@all-hands.dev>