From 8c3c08c50be8b22341e5d55eb0bae75f375e21dc Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Thu, 11 Jun 2026 17:19:20 -0300 Subject: [PATCH] Update implementation to make it cleaner --- tests/test_tui_gateway_server.py | 15 +++++++ tui_gateway/server.py | 4 +- web/src/pages/ModelsPage.tsx | 69 ++++++++++++++++---------------- 3 files changed, 51 insertions(+), 37 deletions(-) diff --git a/tests/test_tui_gateway_server.py b/tests/test_tui_gateway_server.py index 8cffed89005..3ac5c37090f 100644 --- a/tests/test_tui_gateway_server.py +++ b/tests/test_tui_gateway_server.py @@ -1091,6 +1091,21 @@ def test_config_sync_switches_unpinned_session(monkeypatch): assert session["config_model_seen"] == ("new/model", "nous") +def test_config_sync_treats_auto_provider_as_unset(monkeypatch): + _patch_config_model(monkeypatch, "new/model", provider="auto") + session = _sync_test_session(config_model_seen=("old/model", "")) + calls = [] + monkeypatch.setattr( + server, + "_apply_model_switch", + lambda sid, sess, raw, **kw: calls.append(raw), + ) + + server._sync_agent_model_with_config("sid", session) + + assert calls == ["new/model"] + + def test_config_sync_skips_session_pinned_by_model_command(monkeypatch): _patch_config_model(monkeypatch, "new/model") session = _sync_test_session( diff --git a/tui_gateway/server.py b/tui_gateway/server.py index 3cf05d10214..c5d87a68a3a 100644 --- a/tui_gateway/server.py +++ b/tui_gateway/server.py @@ -1424,6 +1424,8 @@ def _config_model_target() -> tuple[str, str]: provider = "" if isinstance(cfg_model, dict): provider = str(cfg_model.get("provider") or "").strip() + if provider.lower() == "auto": + provider = "" return model, provider @@ -2033,8 +2035,6 @@ def _sync_agent_model_with_config(sid: str, session: dict) -> None: session["config_model_seen"] = target if target == seen: return - if seen is None and target[0] == (getattr(agent, "model", "") or ""): - return model, provider = target raw = f"{model} --provider {provider}" if provider else model try: diff --git a/web/src/pages/ModelsPage.tsx b/web/src/pages/ModelsPage.tsx index a736d41ea1d..77953412b6f 100644 --- a/web/src/pages/ModelsPage.tsx +++ b/web/src/pages/ModelsPage.tsx @@ -855,39 +855,34 @@ export default function ModelsPage() { }); }, []); - const load = useCallback( - (opts?: { silent?: boolean }) => { - if (!opts?.silent) { - setLoading(true); - setError(null); - } - Promise.all([ - api.getModelsAnalytics(days), - api.getAuxiliaryModels().catch(() => null), - ]) - .then(([models, auxData]) => { - setData(models); - setAux(auxData); - }) - .catch((err) => { - if (!opts?.silent) setError(String(err)); - }) - .finally(() => { - if (!opts?.silent) setLoading(false); - }); - }, - [days], - ); + const load = useCallback(() => { + setLoading(true); + setError(null); + Promise.all([ + api.getModelsAnalytics(days), + api.getAuxiliaryModels().catch(() => null), + ]) + .then(([models, auxData]) => { + setData(models); + setAux(auxData); + }) + .catch((err) => setError(String(err))) + .finally(() => setLoading(false)); + }, [days]); - const onAssigned = useCallback(() => { - // Reload aux state after any assignment change. + const refreshAux = useCallback(() => { api .getAuxiliaryModels() .then(setAux) .catch(() => {}); - setSaveKey((k) => k + 1); }, []); + const onAssigned = useCallback(() => { + // Reload aux state after any assignment change. + refreshAux(); + setSaveKey((k) => k + 1); + }, [refreshAux]); + useLayoutEffect(() => { // Period selector + refresh both live in afterTitle so the controls // sit immediately next to the page title instead of being pinned to @@ -912,7 +907,7 @@ export default function ModelsPage() { ghost size="icon" className="text-muted-foreground hover:text-foreground" - onClick={() => load()} + onClick={load} disabled={loading} aria-label={t.common.refresh} > @@ -932,18 +927,22 @@ export default function ModelsPage() { }, [load]); // Model assignments can change outside this page (config editor, chat - // /model --global, CLI) — refetch silently when the page regains focus. + // /model --global, CLI), so refetch them when the page regains focus. useEffect(() => { - const refetch = () => { - if (document.visibilityState === "visible") load({ silent: true }); + let last = 0; + const onFocus = () => { + if (document.visibilityState !== "visible") return; + if (Date.now() - last < 1000) return; + last = Date.now(); + refreshAux(); }; - window.addEventListener("focus", refetch); - document.addEventListener("visibilitychange", refetch); + window.addEventListener("focus", onFocus); + document.addEventListener("visibilitychange", onFocus); return () => { - window.removeEventListener("focus", refetch); - document.removeEventListener("visibilitychange", refetch); + window.removeEventListener("focus", onFocus); + document.removeEventListener("visibilitychange", onFocus); }; - }, [load]); + }, [refreshAux]); return (