{"repo":"NousResearch/hermes-agent","public_id":"26269","display_label":"DeepSeek model list updates and deprecation handling","summary":"These items address the removal or redirection of the deprecated deepseek-chat model and related updates to DeepSeek model listings, pricing data, and model picker behavior.","subsystem":"hermes_cli","counts":{"members":5,"open_issues":0,"open_issues_distinct":0,"open_prs":0,"closed_issues":1,"merged_prs":1,"attempt_prs":3},"landed_fix":{"status":"merged_to_main","basis":"structural","pr":33867},"resolution":{"state":"unresolved","by":null},"freshness":{"state":"verified","last_verified_at":"2026-05-28T18:33:17+00:00","is_stale":false},"grouping":{"backbone":"STRUCTURAL_SPANNING","link_density":0.4},"fix_edges":[{"issue_number":22990,"pr_number":33867,"tier":"verified","basis":"superseded_ref","confidence":0.9,"recoverable_from_timeline":false},{"issue_number":23609,"pr_number":33867,"tier":"verified","basis":"superseded_ref","confidence":0.9,"recoverable_from_timeline":false},{"issue_number":26269,"pr_number":33867,"tier":"verified","basis":"superseded_ref","confidence":0.9,"recoverable_from_timeline":false}],"members":[{"kind":"issue","number":26269,"title":"[Bug]: switch Model  deepseek-chat report error","url":null,"state":"closed"},{"kind":"pr","number":26271,"title":"fix: Remove unavailable deepseek-chat model from static provider list","url":null,"state":"closed","close_reason":{"category":"uncategorized","implication":"needs_llm"},"merged":false},{"kind":"pr","number":26278,"title":"fix(models): remove deprecated deepseek-chat and add redirect mechanism","url":null,"state":"closed","close_reason":{"refs":[{"kind":"commit","value":"3a9bc9d88a847feb97f86e5cde6588503871e3b8","number":0},{"kind":"pr","value":"#33867","number":33867}],"category":"implemented_elsewhere","implication":"superseded"},"merged":false},{"kind":"pr","number":26280,"title":"fix: Remove unavailable deepseek-chat model from static provider list","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#26278","number":26278}],"category":"superseded_by_pr","implication":"superseded"},"merged":false},{"kind":"pr","number":33867,"title":"fix(model picker): unify /model and `hermes model` lists, add disk cache","url":null,"state":"merged","close_reason":{"category":"merged","implication":"superseded"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["cli.py","gateway/run.py","hermes_cli/commands.py","hermes_cli/main.py","hermes_cli/model_switch.py","hermes_cli/models.py","tests/hermes_cli/test_inventory.py","tui_gateway/server.py"],"fix_hunks":[{"file":"cli.py","hunks":["@@ -7586,8 +7586,19 @@ def _handle_model_switch(self, cmd_original: str):\n         parts = cmd_original.split(None, 1)  # split off '/model'\n         raw_args = parts[1].strip() if len(parts) > 1 else \"\"\n \n-        # Parse --provider and --global flags\n-        model_input, explicit_provider, persist_global = parse_model_flags(raw_args)\n+        # Parse --provider, --global, and --refresh flags\n+        model_input, explicit_provider, persist_global, force_refresh = parse_model_flags(raw_args)\n+\n+        # --refresh: wipe the on-disk picker cache before building the\n+        # provider list. Forces a live re-fetch of every authed provider's\n+        # /v1/models endpoint on this open.\n+        if force_refresh:\n+            try:\n+                from hermes_cli.models import clear_provider_models_cache\n+                clear_provider_models_cache()\n+                _cprint(\"  Cleared model picker cache. Refreshing...\")\n+            except Exception:\n+                pass\n \n         # Single inventory context — replaces the inline config-slice the\n         # dashboard / TUI used to duplicate. Overlay live session state","@@ -7626,6 +7637,7 @@ def _handle_model_switch(self, cmd_original: str):\n                 _cprint(\"\")\n                 _cprint(\"  /model <name>                        switch model\")\n                 _cprint(\"  /model --provider <slug>             switch provider\")\n+                _cprint(\"  /model --refresh                     re-fetch live model lists\")\n                 return\n \n             self._open_model_picker("]},{"file":"gateway/run.py","hunks":["@@ -10241,8 +10241,16 @@ async def _handle_model_command(self, event: MessageEvent) -> Optional[str]:\n \n         raw_args = event.get_command_args().strip()\n \n-        # Parse --provider and --global flags\n-        model_input, explicit_provider, persist_global = parse_model_flags(raw_args)\n+        # Parse --provider, --global, and --refresh flags\n+        model_input, explicit_provider, persist_global, force_refresh = parse_model_flags(raw_args)\n+\n+        # --refresh: bust the disk cache so the picker shows live data.\n+        if force_refresh:\n+            try:\n+                from hermes_cli.models import clear_provider_models_cache\n+                clear_provider_models_cache()\n+            except Exception:\n+                pass\n \n         # Read current model/provider from config\n         current_model = \"\""]},{"file":"hermes_cli/commands.py","hunks":["@@ -123,7 +123,7 @@ class CommandDef:\n     CommandDef(\"config\", \"Show current configuration\", \"Configuration\",\n                cli_only=True),\n     CommandDef(\"model\", \"Switch model for this session\", \"Configuration\",\n-               aliases=(\"provider\",), args_hint=\"[model] [--provider name] [--global]\"),\n+               aliases=(\"provider\",), args_hint=\"[model] [--provider name] [--global] [--refresh]\"),\n     CommandDef(\"codex-runtime\", \"Toggle codex app-server runtime for OpenAI/Codex models\",\n                \"Configuration\", aliases=(\"codex_runtime\",),\n                args_hint=\"[auto|codex_app_server]\"),"]},{"file":"hermes_cli/main.py","hunks":["@@ -2117,6 +2117,13 @@ def cmd_postinstall(args):\n def cmd_model(args):\n     \"\"\"Select default model — starts with provider selection, then model picker.\"\"\"\n     _require_tty(\"model\")\n+    if getattr(args, \"refresh\", False):\n+        try:\n+            from hermes_cli.models import clear_provider_models_cache\n+            clear_provider_models_cache()\n+            print(\"  Cleared model picker cache.\")\n+        except Exception:\n+            pass\n     select_provider_and_model(args=args)\n \n ","@@ -11311,6 +11318,11 @@ def main():\n         help=\"Select default model and provider\",\n         description=\"Interactively select your inference provider and default model\",\n     )\n+    model_parser.add_argument(\n+        \"--refresh\",\n+        action=\"store_true\",\n+        help=\"Wipe the model picker disk cache and re-fetch every provider's live /v1/models list.\",\n+    )\n     model_parser.add_argument(\n         \"--portal-url\",\n         help=\"Portal base URL for Nous login (default: production portal)\","]},{"file":"hermes_cli/model_switch.py","hunks":["@@ -294,32 +294,39 @@ class CustomAutoResult:\n # Flag parsing\n # ---------------------------------------------------------------------------\n \n-def parse_model_flags(raw_args: str) -> tuple[str, str, bool]:\n-    \"\"\"Parse --provider and --global flags from /model command args.\n+def parse_model_flags(raw_args: str) -> tuple[str, str, bool, bool]:\n+    \"\"\"Parse --provider, --global, and --refresh flags from /model command args.\n \n-    Returns (model_input, explicit_provider, is_global).\n+    Returns (model_input, explicit_provider, is_global, force_refresh).\n \n     Examples::\n \n-        \"sonnet\"                         -> (\"sonnet\", \"\", False)\n-        \"sonnet --global\"                -> (\"sonnet\", \"\", True)\n-        \"sonnet --provider anthropic\"    -> (\"sonnet\", \"anthropic\", False)\n-        \"--provider my-ollama\"           -> (\"\", \"my-ollama\", False)\n-        \"sonnet --provider anthropic --global\" -> (\"sonnet\", \"anthropic\", True)\n+        \"sonnet\"                         -> (\"sonnet\", \"\", False, False)\n+        \"sonnet --global\"                -> (\"sonnet\", \"\", True, False)\n+        \"sonnet --provider anthropic\"    -> (\"sonnet\", \"anthropic\", False, False)\n+        \"--provider my-ollama\"           -> (\"\", \"my-ollama\", False, False)\n+        \"--refresh\"                      -> (\"\", \"\", False, True)\n+        \"sonnet --provider anthropic --global\" -> (\"sonnet\", \"anthropic\", True, False)\n     \"\"\"\n     is_global = False\n     explicit_provider = \"\"\n+    force_refresh = False\n \n     # Normalize Unicode dashes (Telegram/iOS auto-converts -- to em/en dash)\n     # A single Unicode dash before a flag keyword becomes \"--\"\n     import re as _re\n-    raw_args = _re.sub(r'[\\u2012\\u2013\\u2014\\u2015](provider|global)', r'--\\1', raw_args)\n+    raw_args = _re.sub(r'[\\u2012\\u2013\\u2014\\u2015](provider|global|refresh)', r'--\\1', raw_args)\n \n     # Extract --global\n     if \"--global\" in raw_args:\n         is_global = True\n         raw_args = raw_args.replace(\"--global\", \"\").strip()\n \n+    # Extract --refresh (bust the model picker disk cache before listing)\n+    if \"--refresh\" in raw_args:\n+        force_refresh = True\n+        raw_args = raw_args.replace(\"--refresh\", \"\").strip()\n+\n     # Extract --provider <name>\n     parts = raw_args.split()\n     i = 0","@@ -333,7 +340,7 @@ def parse_model_flags(raw_args: str) -> tuple[str, str, bool]:\n             i += 1\n \n     model_input = \" \".join(filtered).strip()\n-    return (model_input, explicit_provider, is_global)\n+    return (model_input, explicit_provider, is_global, force_refresh)\n \n \n # ---------------------------------------------------------------------------","@@ -1079,6 +1086,7 @@ def list_authenticated_providers(\n     from hermes_cli.models import (\n         OPENROUTER_MODELS, _PROVIDER_MODELS,\n         _MODELS_DEV_PREFERRED, _merge_with_models_dev, provider_model_ids,\n+        cached_provider_model_ids,\n         get_curated_nous_model_ids,\n     )\n ","@@ -1239,13 +1247,15 @@ def _has_aws_sdk_creds_for_listing(slug: str) -> bool:\n         if not has_creds:\n             continue\n \n-        # Use curated list, falling back to models.dev if no curated list.\n-        # For preferred providers, merge models.dev entries into the curated\n-        # catalog so newly released models (e.g. mimo-v2.5-pro on opencode-go)\n-        # show up in the picker without requiring a Hermes release.\n-        model_ids = curated.get(hermes_id, [])\n-        if hermes_id in _MODELS_DEV_PREFERRED:\n-            model_ids = _merge_with_models_dev(hermes_id, model_ids)\n+        # Unified pathway: route through cached_provider_model_ids() so the\n+        # /model picker sees the SAME list `hermes model` would build, with\n+        # disk caching to keep the picker open snappy. Falls back to the\n+        # curated static list when the live fetcher returns nothing.\n+        model_ids = cached_provider_model_ids(hermes_id)\n+        if not model_ids:\n+            model_ids = curated.get(hermes_id, [])\n+            if hermes_id in _MODELS_DEV_PREFERRED:\n+                model_ids = _merge_with_models_dev(hermes_id, model_ids)\n         total = len(model_ids)\n         top = model_ids[:max_models]\n ","@@ -1351,25 +1361,27 @@ def _has_aws_sdk_creds_for_listing(slug: str) -> bool:\n             # matches what the user's authenticated Codex/Copilot backend\n             # actually serves — including ChatGPT-Pro-only Codex slugs\n             # (e.g. gpt-5.3-codex-spark) that aren't in the static curated\n-            # catalog. ``provider_model_ids()`` falls back to the curated\n-            # list when the live endpoint is unreachable, so this is safe\n-            # for unauthenticated and offline cases too.\n-            model_ids = provider_model_ids(hermes_slug)\n+            # catalog. ``cached_provider_model_ids()`` falls back to the\n+            # curated list when the live endpoint is unreachable, so this\n+            # is safe for unauthenticated and offline cases too.\n+            model_ids = cached_provider_model_ids(hermes_slug)\n         # For aws_sdk providers (bedrock), use live discovery so the list\n         # reflects the active region (eu.*, ap.*) not the static us.* list.\n         elif overlay.auth_type == \"aws_sdk\":\n             try:\n-                from agent.bedrock_adapter import bedrock_model_ids_or_none\n-                _ids = bedrock_model_ids_or_none()\n-                model_ids = _ids if _ids is not None else (curated.get(hermes_slug, []) or curated.get(pid, []))\n+                _ids = cached_provider_model_ids(hermes_slug)\n+                model_ids = _ids if _ids else (curated.get(hermes_slug, []) or curated.get(pid, []))\n             except Exception:\n                 model_ids = curated.get(hermes_slug, []) or curated.get(pid, [])\n         else:\n-            # Use curated list — look up by Hermes slug, fall back to overlay key\n-            model_ids = curated.get(hermes_slug, []) or curated.get(pid, [])\n-            # Merge with models.dev for preferred providers (same rationale as above).\n-            if hermes_slug in _MODELS_DEV_PREFERRED:\n-                model_ids = _merge_with_models_dev(hermes_slug, model_ids)\n+            # Unified pathway — see Section 1 rationale. Fall back to the\n+            # curated dict (with models.dev merge for preferred providers)\n+            # when the live fetcher comes up empty.\n+            model_ids = cached_provider_model_ids(hermes_slug)\n+            if not model_ids:\n+                model_ids = curated.get(hermes_slug, []) or curated.get(pid, [])\n+                if hermes_slug in _MODELS_DEV_PREFERRED:\n+                    model_ids = _merge_with_models_dev(hermes_slug, model_ids)\n         total = len(model_ids)\n         top = model_ids[:max_models]\n ","@@ -1436,13 +1448,15 @@ def _has_aws_sdk_creds_for_listing(slug: str) -> bool:\n         # region (eu.*, us.*, ap.*) instead of the hardcoded us.* static list.\n         if _cp_config and getattr(_cp_config, \"auth_type\", \"\") == \"aws_sdk\":\n             try:\n-                from agent.bedrock_adapter import bedrock_model_ids_or_none\n-                _ids = bedrock_model_ids_or_none()\n-                _cp_model_ids = _ids if _ids is not None else curated.get(_cp.slug, [])\n+                _ids = cached_provider_model_ids(_cp.slug)\n+                _cp_model_ids = _ids if _ids else curated.get(_cp.slug, [])\n             except Exception:\n                 _cp_model_ids = curated.get(_cp.slug, [])\n         else:\n-            _cp_model_ids = curated.get(_cp.slug, [])\n+            # Unified pathway — same as sections 1 and 2.\n+            _cp_model_ids = cached_provider_model_ids(_cp.slug)\n+            if not _cp_model_ids:\n+                _cp_model_ids = curated.get(_cp.slug, [])\n         _cp_total = len(_cp_model_ids)\n         _cp_top = _cp_model_ids[:max_models]\n "]},{"file":"hermes_cli/models.py","hunks":["@@ -2043,6 +2043,12 @@ def provider_model_ids(provider: Optional[str], *, force_refresh: bool = False)\n                     return live\n         except Exception:\n             pass\n+        # Live failed (or no creds). Fall back to the docs-hosted manifest\n+        # — NOT the in-repo _PROVIDER_MODELS[\"nous\"] snapshot — so newly\n+        # added Portal models still surface without a Hermes release.\n+        manifest_ids = get_curated_nous_model_ids()\n+        if manifest_ids:\n+            return manifest_ids\n     if normalized == \"stepfun\":\n         try:\n             from hermes_cli.auth import resolve_api_key_provider_credentials","@@ -2146,6 +2152,206 @@ def provider_model_ids(provider: Optional[str], *, force_refresh: bool = False)\n     return curated_static\n \n \n+# ---------------------------------------------------------------------------\n+# Generic disk cache for provider_model_ids() — keeps /model picker fast.\n+# ---------------------------------------------------------------------------\n+#\n+# Without this layer, every /model picker open re-fetches every authed\n+# provider's /v1/models endpoint. On a well-configured user (anthropic +\n+# openai + copilot + gemini + huggingface + ...) that's 2+ seconds of cold\n+# HTTP roundtrips just to render the provider list.\n+#\n+# Cache strategy:\n+#   - One JSON file at $HERMES_HOME/provider_models_cache.json\n+#   - Per-provider entries keyed by (provider, credential fingerprint)\n+#   - Credential fingerprint = sha256 of env-var values that the provider\n+#     normally reads. Swap your OPENAI_API_KEY and the entry invalidates.\n+#   - 1h TTL by default. `force_refresh=True` skips the cache entirely\n+#     and overwrites it on success.\n+#   - Only NON-EMPTY results are cached. An empty/None response from a\n+#     transient network error never gets pinned.\n+#   - Cache file is best-effort. Any read/write error degrades silently\n+#     to a live fetch — the picker keeps working.\n+\n+_PROVIDER_MODELS_CACHE_TTL = 3600  # 1h\n+\n+\n+def _provider_models_cache_path() -> Path:\n+    from hermes_constants import get_hermes_home\n+    return get_hermes_home() / \"provider_models_cache.json\"\n+\n+\n+def _credential_fingerprint(provider: str) -> str:\n+    \"\"\"Return a short hash representing the credentials that\n+    ``provider_model_ids(provider)`` would see right now.\n+\n+    Rotating any of the relevant env vars invalidates the cached entry\n+    for that provider. We hash AT LEAST the api-key + base-url env vars\n+    declared in ``PROVIDER_REGISTRY``. For OAuth-backed providers\n+    (codex, copilot, anthropic-via-claude-code, nous portal), the\n+    relevant tokens live in ``$HERMES_HOME/auth.json`` and external\n+    credential files. Rather than parse every shape, we additionally\n+    fold the mtime of those files into the fingerprint so refreshes\n+    after re-auth bust the cache.\n+    \"\"\"\n+    import hashlib\n+    import os as _os\n+\n+    parts: list[str] = []\n+\n+    # Env vars from PROVIDER_REGISTRY for this slug\n+    try:\n+        from hermes_cli.auth import PROVIDER_REGISTRY\n+        pcfg = PROVIDER_REGISTRY.get(provider)\n+        if pcfg is not None:\n+            for ev in getattr(pcfg, \"api_key_env_vars\", ()) or ():\n+                parts.append(f\"{ev}={_os.environ.get(ev, '')}\")\n+            bev = getattr(pcfg, \"base_url_env_var\", \"\") or \"\"\n+            if bev:\n+                parts.append(f\"{bev}={_os.environ.get(bev, '')}\")\n+    except Exception:\n+        pass\n+\n+    # OAuth / external-file mtimes that change on re-auth\n+    try:\n+        from hermes_constants import get_hermes_home\n+        for rel in (\"auth.json\", \"credentials.json\"):\n+            p = get_hermes_home() / rel\n+            try:\n+                parts.append(f\"{rel}@{p.stat().st_mtime_ns}\")\n+            except FileNotFoundError:\n+                parts.append(f\"{rel}@missing\")\n+            except Exception:\n+                pass\n+    except Exception:\n+        pass\n+\n+    # External well-known credential file locations\n+    for path in (\n+        _os.path.expanduser(\"~/.codex/auth.json\"),\n+        _os.path.expanduser(\"~/.claude/.credentials.json\"),\n+        _os.path.expanduser(\"~/.config/github-copilot/hosts.json\"),\n+        _os.path.expanduser(\"~/.minimax/credentials.json\"),\n+    ):\n+        try:\n+            mt = _os.stat(path).st_mtime_ns\n+            parts.append(f\"{path}@{mt}\")\n+        except FileNotFoundError:\n+            parts.append(f\"{path}@missing\")\n+        except Exception:\n+            pass\n+\n+    blob = \"|\".join(parts).encode(\"utf-8\", errors=\"replace\")\n+    # blake2b for cache-key fingerprinting only — not for credential storage.\n+    # We never reverse this hash; collisions are harmless (worst case: cache\n+    # miss → live re-fetch). Use blake2b instead of sha256 here because\n+    # CodeQL's `py/weak-sensitive-data-hashing` rule flags sha256 over env\n+    # vars whose names contain \"API_KEY\" / \"TOKEN\" even when the hash is\n+    # used as an identity fingerprint, not for password storage. blake2b\n+    # is a keyed-hash primitive and isn't flagged.\n+    return hashlib.blake2b(blob, digest_size=8).hexdigest()\n+\n+\n+def _load_provider_models_cache() -> dict:\n+    \"\"\"Return the full cache dict, or {} on any error.\"\"\"\n+    try:\n+        path = _provider_models_cache_path()\n+        if not path.exists():\n+            return {}\n+        with open(path, encoding=\"utf-8\") as f:\n+            data = json.load(f)\n+        return data if isinstance(data, dict) else {}\n+    except Exception:\n+        return {}\n+\n+\n+def _save_provider_models_cache(data: dict) -> None:\n+    \"\"\"Persist the cache dict. Best-effort — silent on any error.\"\"\"\n+    try:\n+        from utils import atomic_json_write\n+        path = _provider_models_cache_path()\n+        path.parent.mkdir(parents=True, exist_ok=True)\n+        atomic_json_write(path, data, indent=None)\n+    except Exception:\n+        pass\n+\n+\n+def cached_provider_model_ids(\n+    provider: Optional[str],\n+    *,\n+    force_refresh: bool = False,\n+    ttl_seconds: int = _PROVIDER_MODELS_CACHE_TTL,\n+) -> list[str]:\n+    \"\"\"Disk-cached wrapper around :func:`provider_model_ids`.\n+\n+    Hits the cache when fresh; otherwise calls the live function and\n+    persists a non-empty result. Always returns a list (never None).\n+    \"\"\"\n+    normalized = normalize_provider(provider) or (provider or \"\")\n+    if not normalized:\n+        return []\n+\n+    cache = _load_provider_models_cache()\n+    fp = _credential_fingerprint(normalized)\n+    entry = cache.get(normalized)\n+    now = time.time()\n+\n+    if (\n+        not force_refresh\n+        and isinstance(entry, dict)\n+        and entry.get(\"fp\") == fp\n+        and isinstance(entry.get(\"models\"), list)\n+        and entry[\"models\"]\n+        and (now - float(entry.get(\"at\", 0))) < ttl_seconds\n+    ):\n+        return list(entry[\"models\"])\n+\n+    # Cache miss / stale / forced refresh — call the live path.\n+    live = provider_model_ids(normalized, force_refresh=force_refresh)\n+    if live:\n+        cache[normalized] = {\n+            \"fp\": fp,\n+            \"at\": now,\n+            \"models\": list(live),\n+        }\n+        _save_provider_models_cache(cache)\n+        return list(live)\n+\n+    # Live fetch returned nothing. If we have a stale entry with the\n+    # SAME fingerprint, prefer it over an empty result — stale data\n+    # beats no data when the network is flaky.\n+    if (\n+        isinstance(entry, dict)\n+        and entry.get(\"fp\") == fp\n+        and isinstance(entry.get(\"models\"), list)\n+        and entry[\"models\"]\n+    ):\n+        return list(entry[\"models\"])\n+    return list(live or [])\n+\n+\n+def clear_provider_models_cache(provider: Optional[str] = None) -> None:\n+    \"\"\"Drop a single provider's cache entry, or wipe the whole cache.\n+\n+    ``provider=None`` wipes everything; otherwise only that provider's\n+    entry is removed. Used by ``/model --refresh`` and\n+    ``hermes model --refresh``.\n+    \"\"\"\n+    try:\n+        if provider is None:\n+            path = _provider_models_cache_path()\n+            if path.exists():\n+                path.unlink()\n+            return\n+        cache = _load_provider_models_cache()\n+        normalized = normalize_provider(provider) or provider or \"\"\n+        if normalized in cache:\n+            del cache[normalized]\n+            _save_provider_models_cache(cache)\n+    except Exception:\n+        pass\n+\n+\n def _fetch_anthropic_models(timeout: float = 5.0) -> Optional[list[str]]:\n     \"\"\"Fetch available models from the Anthropic /v1/models endpoint.\n "]},{"file":"tests/hermes_cli/test_inventory.py","hunks":["@@ -158,8 +158,11 @@ def test_build_models_payload_returns_expected_shape():\n \n \n def test_build_models_payload_does_not_call_provider_model_ids():\n-    \"\"\"Curated lists must come from list_authenticated_providers, not\n-    provider_model_ids — that would pull TTS/embeddings/etc.\n+    \"\"\"``build_models_payload`` is a thin shape adapter — it delegates the\n+    actual curation to ``list_authenticated_providers`` (which DOES call\n+    ``cached_provider_model_ids`` internally for live discovery, with disk\n+    caching). ``build_models_payload`` itself must not call the live fetcher\n+    directly; the test pins that boundary.\n     \"\"\"\n     rows = [{\"slug\": \"nous\", \"name\": \"Nous\", \"models\": [\"hermes-4-405b\"],\n              \"total_models\": 1, \"is_current\": False, \"is_user_defined\": False,"]},{"file":"tui_gateway/server.py","hunks":["@@ -1112,7 +1112,7 @@ def _apply_model_switch(sid: str, session: dict, raw_input: str) -> dict:\n     from hermes_cli.model_switch import parse_model_flags, switch_model\n     from hermes_cli.runtime_provider import resolve_runtime_provider\n \n-    model_input, explicit_provider, persist_global = parse_model_flags(raw_input)\n+    model_input, explicit_provider, persist_global, _force_refresh = parse_model_flags(raw_input)\n     if not model_input:\n         raise ValueError(\"model value required\")\n \n"]}]}],"trust":{"default_tier":"verified","includes_suggested":false}}