Skip to content

fix(ui): use the shared cloud catalog for status, preload and local-only - #6972

Merged
kovtcharov-amd merged 2 commits into
amd:mainfrom
ityashag:fix/ui-routers-shared-cloud-catalog
Nov 9, 2026
Merged

kovtcharov-amd merged 2 commits into
amd:mainfrom
ityashag:fix/ui-routers-shared-cloud-catalog

Conversation

@ityashag

@ityashag ityashag commented Nov 8, 2026 •

Copy link
Copy Markdown
Contributor

Summary

When the default chat model is a cloud model GAIA learns about at runtime, such as opencode.*, Settings no longer treats it as a local model. Before, /api/system/status reported it as local, so Settings › Advanced could offer to download or load it and warn about its context size, and the tray showed the local model server's state as if it mattered. The startup preload also tried to load it locally, and turning on Local AI only didn't clear it, so Settings kept pointing at a cloud model the policy forbids.

Why

The review on #6926 listed these call sites. #6962 has since fixed profile inference and Retry with… using _runs_on_this_pc. These three only need to classify the model, with no network call, so they use _ui_cloud_provider, as the chat helpers do since #6926. All three still called cloud_model_provider(model) with no metadata, which only recognizes the fireworks and amd prefixes. The review on this PR found the Local AI only one.

Still on the prefix-only check, for a follow-up: the Model server panel (system.py, which should read the loaded entry's recipe through is_cloud_model_entry) and the setup code (setup_runner.py, setup_plan.py).

Linked issue

Refs #4784. Follows #6907, #6926 and #6962.

Test plan

Run in a python:3.12-slim container with .[ui] and the test tools installed, on current main:

  • pytest tests/unit/chat/ui/test_server.py tests/unit/test_ui_warmup.py tests/unit/chat/ui/test_chat_helpers.py tests/unit/test_memory_router.py tests/unit/chat/ui/test_answer_retry.py: 577 passed, 5 skipped.
  • After the review: pytest tests/unit/chat/ui/test_server.py tests/unit/test_ui_warmup.py: 199 passed, 3 skipped. The tests now snapshot and restore the shared catalog instead of emptying it.
  • python util/lint.py --all: Black, isort, Flake8, Bandit and the MyPy ratchet pass. Pylint crashed in a parallel worker on my machine, and the same Pylint command passes when run alone.

With the source change reverted, both new tests fail:

FAILED test_server.py::TestSystemStatus::test_system_status_flags_a_discovered_cloud_model
FAILED test_server.py::TestNetworkPolicySetting::test_local_only_clears_a_discovered_cloud_custom_model
2 failed

Evidence

Each new test registers opencode.big-model with recipe: cloud in the shared catalog, the way /models reports it, and sets it as the custom model. /api/system/status now reports default_model_is_cloud: true, and PUT /api/settings with network_policy: local_ai_only now clears it.

The preload skip has no new test: it is an inner function of create_app, and its existing tests pass. Both checks only recognize a runtime cloud model once this process has read Lemonade's model list, the same limit _ui_cloud_provider has everywhere. Not tested against a real cloud provider.

  • Agent exposed in the Agent UI: N/A, the change is in the status payload above.
  • MCP tools / servers: N/A
  • CLI: N/A
  • HTTP API / REST: /api/system/status, covered by the test above.

Checklist

  • I have linked a GitHub issue above (Closes #N / Fixes #N / Refs #N).
  • I have described why this change is being made, not just what changed.
  • I have run linting and tests locally (python util/lint.py --all, pytest tests/unit/). Targeted tests only for this change.
  • I have attached real-world evidence matched to the surface I changed (see Evidence above), or marked each surface N/A.
  • I have updated documentation if user-visible behavior changed (see CONTRIBUTING.md). N/A: no docs describe this flag.

…catalog

System status and the startup preload called cloud_model_provider() with no
metadata, so a cloud model GAIA only learns about at runtime counted as local:
Settings offered to download or load it, and the preload tried to load it.
They now use _ui_cloud_provider, as the chat helpers do.
@github-actions github-actions Bot added the tests Test changes label Nov 8, 2026
@github-actions

github-actions Bot commented Nov 8, 2026

Copy link
Copy Markdown
Contributor

Verdict: Approve with suggestions

A cloud default model that GAIA only learns about at runtime (such as opencode.*) is now treated as cloud in two more places. Settings stops offering to download or load it as if it were local, and startup stops trying to preload it on this PC. Both now use the same check the chat path already uses. The change is small and correct, and it comes with a test that fails without the fix.

One related path still uses the old check, and it's worth a follow-up issue: switching Settings to Local AI only clears a saved cloud model, but it still won't recognise one of these runtime-discovered models. Settings would keep pointing at it. This PR didn't cause that, and it doesn't block the merge.

Real-world evidence

N/A: no evidence bundle was produced for this run. The PR description shows a unit test that reads /api/system/status through the test client and gets default_model_is_cloud: true, and that the test fails with the fix reverted. Nobody exercised this against a running server with a real cloud provider. Apart from that test, the verdict rests on static review.

🔍 Technical details

Issues

🟡 Follow-up: "Local AI only doesn't clear a runtime-discovered cloud custom model" (src/gaia/ui/routers/system.py:1258)
When the network policy flips to LOCAL_AI_ONLY, the settings handler clears custom_model only when cloud_model_provider(custom) (with no metadata) or the claude prefix matches. An opencode.* id fails both checks. It stays saved, and Settings keeps showing a model the policy forbids. Applying the same one-line change as this PR fixes it:

                _ui_cloud_provider(custom) or custom.lower().startswith("claude")

(It needs from .._chat_helpers import _ui_cloud_provider in scope.) The same old check also feeds the Model server panel, at system.py:1337 (is_cloud_model=cloud_model_provider), and the setup code (setup_runner.py:363, setup_runner.py:1849, setup_plan.py:843). Those are worth a look in the same follow-up.

🟢 The test resets the shared catalog to empty rather than to its previous state (tests/unit/chat/ui/test_server.py:125)
record_cloud_models({"data": []}) wipes whatever the module-global map held before. That's harmless today, because no other test seeds it and relies on it surviving. A fixture that snapshots and restores _CLOUD_MODELS/_CLOUD_PROVIDERS would be safer if more tests start seeding the catalog.

Checks

  • Sibling search: the remaining callers of cloud_model_provider(...) without metadata in src/gaia/ui/ are the ones listed above. turn_insights.py and _runs_on_this_pc already use the catalog check.
  • Known bug classes: the change adds no network calls, waits or shared-file writes. As the PR notes, _ui_cloud_provider only knows models from the catalog this process has already read. So on a cold start, the preload skip depends on /models having been read first. That is the same limit as the existing chat helpers, not a regression.
  • Doc drift: no docs describe default_model_is_cloud or the preload skip, and the diff removes no wording.

Strengths

  • It reuses the existing _ui_cloud_provider helper rather than adding another classification rule, so there is now one rule across chat, status and preload.
  • The regression test seeds the catalog the way /models reports it (recipe: cloud), so it exercises the real lookup instead of mocking it.
  • The unused cloud_model_provider import in server.py was removed along with the call it served.

From review. Turning on Local AI only cleared a cloud custom model only when
its prefix gave it away, so a runtime-discovered one such as opencode.* stayed
selected. It now uses _ui_cloud_provider too. The tests seed the shared
catalog through a helper that restores it afterwards.
@ityashag ityashag changed the title fix(ui): use the shared cloud catalog for status and preload fix(ui): use the shared cloud catalog for status, preload and local-only Nov 8, 2026
@kovtcharov-amd
kovtcharov-amd added this pull request to the merge queue Nov 9, 2026
Merged via the queue into amd:main with commit f65f841 Nov 9, 2026
37 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

tests Test changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants