{"repo":"NousResearch/hermes-agent","public_id":"2094","display_label":"MiniMax auth broken by Anthropic token refresh logic","summary":"These issues and PRs address a bug where Anthropic's token refresh mechanism overrides authentication for third-party providers using the anthropic_messages format, particularly MiniMax, causing 401 errors. Fixes focus on gating Anthropic token injection to native Anthropic endpoints only.","subsystem":"agent","counts":{"members":8,"open_issues":0,"open_issues_distinct":0,"open_prs":0,"closed_issues":2,"merged_prs":2,"attempt_prs":4},"landed_fix":{"status":"merged_to_main","basis":"structural","pr":2103},"resolution":{"state":"partially_resolved","by":"pr-2103"},"freshness":{"state":"stale","last_verified_at":"2026-03-21T23:20:08+00:00","is_stale":true},"grouping":{"backbone":"STRUCTURAL_PARTIAL","link_density":0.22714285714285715},"fix_edges":[{"issue_number":2094,"pr_number":2103,"tier":"verified","basis":"closing_ref","confidence":0.95,"recoverable_from_timeline":true},{"issue_number":2374,"pr_number":2388,"tier":"verified","basis":"superseded_ref","confidence":0.9,"recoverable_from_timeline":false},{"issue_number":2384,"pr_number":2388,"tier":"verified","basis":"closing_ref","confidence":0.95,"recoverable_from_timeline":true}],"members":[{"kind":"issue","number":2094,"title":"[Bug]: Error code: 401 - Authorization field missing. Minimax configuration.","url":null,"state":"closed"},{"kind":"issue","number":2374,"title":"MiniMax (/anthropic) auth gets overridden by Anthropic token refresh, causing 401","url":null,"state":"closed"},{"kind":"pr","number":2100,"title":"Fix: Resolve Minimax 401 Auth error by defaulting to anthropic_messages","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#2103","number":2103}],"category":"merged_via","implication":"superseded"},"merged":false},{"kind":"pr","number":2103,"title":"fix: resolve MiniMax 401 auth error by defaulting to anthropic_messages","url":null,"state":"merged","close_reason":{"category":"merged","implication":"superseded"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["hermes_cli/auth.py","hermes_cli/runtime_provider.py","tests/test_api_key_providers.py","tests/test_runtime_provider_resolution.py"],"fix_hunks":[{"file":"hermes_cli/auth.py","hunks":["@@ -145,7 +145,7 @@ class ProviderConfig:\n         id=\"minimax\",\n         name=\"MiniMax\",\n         auth_type=\"api_key\",\n-        inference_base_url=\"https://api.minimax.io/v1\",\n+        inference_base_url=\"https://api.minimax.io/anthropic\",\n         api_key_env_vars=(\"MINIMAX_API_KEY\",),\n         base_url_env_var=\"MINIMAX_BASE_URL\",\n     ),","@@ -168,7 +168,7 @@ class ProviderConfig:\n         id=\"minimax-cn\",\n         name=\"MiniMax (China)\",\n         auth_type=\"api_key\",\n-        inference_base_url=\"https://api.minimaxi.com/v1\",\n+        inference_base_url=\"https://api.minimaxi.com/anthropic\",\n         api_key_env_vars=(\"MINIMAX_CN_API_KEY\",),\n         base_url_env_var=\"MINIMAX_CN_BASE_URL\",\n     ),"]},{"file":"hermes_cli/runtime_provider.py","hunks":["@@ -387,6 +387,12 @@ def resolve_runtime_provider(\n             # (e.g. https://api.minimax.io/anthropic, https://dashscope.../anthropic)\n             elif base_url.rstrip(\"/\").endswith(\"/anthropic\"):\n                 api_mode = \"anthropic_messages\"\n+            # MiniMax providers always use Anthropic Messages API.\n+            # Auto-correct stale /v1 URLs (from old .env or config) to /anthropic.\n+            elif provider in (\"minimax\", \"minimax-cn\"):\n+                api_mode = \"anthropic_messages\"\n+                if base_url.rstrip(\"/\").endswith(\"/v1\"):\n+                    base_url = base_url.rstrip(\"/\")[:-3] + \"/anthropic\"\n         return {\n             \"provider\": provider,\n             \"api_mode\": api_mode,"]},{"file":"tests/test_api_key_providers.py","hunks":["@@ -92,8 +92,8 @@ def test_base_urls(self):\n         assert PROVIDER_REGISTRY[\"copilot-acp\"].inference_base_url == \"acp://copilot\"\n         assert PROVIDER_REGISTRY[\"zai\"].inference_base_url == \"https://api.z.ai/api/paas/v4\"\n         assert PROVIDER_REGISTRY[\"kimi-coding\"].inference_base_url == \"https://api.moonshot.ai/v1\"\n-        assert PROVIDER_REGISTRY[\"minimax\"].inference_base_url == \"https://api.minimax.io/v1\"\n-        assert PROVIDER_REGISTRY[\"minimax-cn\"].inference_base_url == \"https://api.minimaxi.com/v1\"\n+        assert PROVIDER_REGISTRY[\"minimax\"].inference_base_url == \"https://api.minimax.io/anthropic\"\n+        assert PROVIDER_REGISTRY[\"minimax-cn\"].inference_base_url == \"https://api.minimaxi.com/anthropic\"\n         assert PROVIDER_REGISTRY[\"ai-gateway\"].inference_base_url == \"https://ai-gateway.vercel.sh/v1\"\n         assert PROVIDER_REGISTRY[\"kilocode\"].inference_base_url == \"https://api.kilo.ai/api/gateway\"\n ","@@ -399,14 +399,14 @@ def test_resolve_minimax_with_key(self, monkeypatch):\n         creds = resolve_api_key_provider_credentials(\"minimax\")\n         assert creds[\"provider\"] == \"minimax\"\n         assert creds[\"api_key\"] == \"mm-secret-key\"\n-        assert creds[\"base_url\"] == \"https://api.minimax.io/v1\"\n+        assert creds[\"base_url\"] == \"https://api.minimax.io/anthropic\"\n \n     def test_resolve_minimax_cn_with_key(self, monkeypatch):\n         monkeypatch.setenv(\"MINIMAX_CN_API_KEY\", \"mmcn-secret-key\")\n         creds = resolve_api_key_provider_credentials(\"minimax-cn\")\n         assert creds[\"provider\"] == \"minimax-cn\"\n         assert creds[\"api_key\"] == \"mmcn-secret-key\"\n-        assert creds[\"base_url\"] == \"https://api.minimaxi.com/v1\"\n+        assert creds[\"base_url\"] == \"https://api.minimaxi.com/anthropic\"\n \n     def test_resolve_ai_gateway_with_key(self, monkeypatch):\n         monkeypatch.setenv(\"AI_GATEWAY_API_KEY\", \"gw-secret-key\")"]},{"file":"tests/test_runtime_provider_resolution.py","hunks":["@@ -479,8 +479,8 @@ def test_api_key_provider_explicit_api_mode_config(monkeypatch):\n     assert resolved[\"api_mode\"] == \"anthropic_messages\"\n \n \n-def test_api_key_provider_default_url_stays_chat_completions(monkeypatch):\n-    \"\"\"API-key providers with default /v1 URL should stay on chat_completions.\"\"\"\n+def test_minimax_default_url_uses_anthropic_messages(monkeypatch):\n+    \"\"\"MiniMax with default /anthropic URL should auto-detect anthropic_messages mode.\"\"\"\n     monkeypatch.setattr(rp, \"resolve_provider\", lambda *a, **k: \"minimax\")\n     monkeypatch.setattr(rp, \"_get_model_config\", lambda: {})\n     monkeypatch.setenv(\"MINIMAX_API_KEY\", \"test-minimax-key\")","@@ -488,9 +488,50 @@ def test_api_key_provider_default_url_stays_chat_completions(monkeypatch):\n \n     resolved = rp.resolve_runtime_provider(requested=\"minimax\")\n \n+    assert resolved[\"provider\"] == \"minimax\"\n+    assert resolved[\"api_mode\"] == \"anthropic_messages\"\n+    assert resolved[\"base_url\"] == \"https://api.minimax.io/anthropic\"\n+\n+\n+def test_minimax_stale_v1_url_auto_corrected(monkeypatch):\n+    \"\"\"MiniMax with stale /v1 base URL should be auto-corrected to /anthropic.\"\"\"\n+    monkeypatch.setattr(rp, \"resolve_provider\", lambda *a, **k: \"minimax\")\n+    monkeypatch.setattr(rp, \"_get_model_config\", lambda: {})\n+    monkeypatch.setenv(\"MINIMAX_API_KEY\", \"test-minimax-key\")\n+    monkeypatch.setenv(\"MINIMAX_BASE_URL\", \"https://api.minimax.io/v1\")\n+\n+    resolved = rp.resolve_runtime_provider(requested=\"minimax\")\n+\n+    assert resolved[\"provider\"] == \"minimax\"\n+    assert resolved[\"api_mode\"] == \"anthropic_messages\"\n+    assert resolved[\"base_url\"] == \"https://api.minimax.io/anthropic\"\n+\n+\n+def test_minimax_cn_stale_v1_url_auto_corrected(monkeypatch):\n+    \"\"\"MiniMax-CN with stale /v1 base URL should be auto-corrected to /anthropic.\"\"\"\n+    monkeypatch.setattr(rp, \"resolve_provider\", lambda *a, **k: \"minimax-cn\")\n+    monkeypatch.setattr(rp, \"_get_model_config\", lambda: {})\n+    monkeypatch.setenv(\"MINIMAX_CN_API_KEY\", \"test-minimax-cn-key\")\n+    monkeypatch.setenv(\"MINIMAX_CN_BASE_URL\", \"https://api.minimaxi.com/v1\")\n+\n+    resolved = rp.resolve_runtime_provider(requested=\"minimax-cn\")\n+\n+    assert resolved[\"provider\"] == \"minimax-cn\"\n+    assert resolved[\"api_mode\"] == \"anthropic_messages\"\n+    assert resolved[\"base_url\"] == \"https://api.minimaxi.com/anthropic\"\n+\n+\n+def test_minimax_explicit_api_mode_respected(monkeypatch):\n+    \"\"\"Explicit api_mode config should override MiniMax auto-detection.\"\"\"\n+    monkeypatch.setattr(rp, \"resolve_provider\", lambda *a, **k: \"minimax\")\n+    monkeypatch.setattr(rp, \"_get_model_config\", lambda: {\"api_mode\": \"chat_completions\"})\n+    monkeypatch.setenv(\"MINIMAX_API_KEY\", \"test-minimax-key\")\n+    monkeypatch.delenv(\"MINIMAX_BASE_URL\", raising=False)\n+\n+    resolved = rp.resolve_runtime_provider(requested=\"minimax\")\n+\n     assert resolved[\"provider\"] == \"minimax\"\n     assert resolved[\"api_mode\"] == \"chat_completions\"\n-    assert resolved[\"base_url\"] == \"https://api.minimax.io/v1\"\n \n \n def test_named_custom_provider_anthropic_api_mode(monkeypatch):\n"]}]},{"kind":"pr","number":2375,"title":"fix: MiniMax (/anthropic) auth gets overridden by Anthropic token refr","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#2388","number":2388}],"category":"merged_via","implication":"superseded"},"merged":false},{"kind":"pr","number":2377,"title":"fix(auth): gate Anthropic token refresh to native Anthropic endpoints only","url":null,"state":"closed","close_reason":{"category":"uncategorized","implication":"needs_llm"},"merged":false,"is_fix_pr":true,"fix_tier":"suggested","fix_detail_withheld":true},{"kind":"pr","number":2388,"title":"fix(provider): prevent Anthropic fallback from inheriting non-Anthropic base_url + fix(update): reset on stash conflict","url":null,"state":"merged","close_reason":{"category":"merged","implication":"superseded"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["agent/auxiliary_client.py","hermes_cli/main.py","hermes_cli/runtime_provider.py","tests/hermes_cli/test_update_autostash.py"],"fix_hunks":[{"file":"agent/auxiliary_client.py","hunks":["@@ -654,16 +654,20 @@ def _try_anthropic() -> Tuple[Optional[Any], Optional[str]]:\n     if not token:\n         return None, None\n \n-    # Allow base URL override from config.yaml model.base_url\n+    # Allow base URL override from config.yaml model.base_url, but only\n+    # when the configured provider is anthropic — otherwise a non-Anthropic\n+    # base_url (e.g. Codex endpoint) would leak into Anthropic requests.\n     base_url = _ANTHROPIC_DEFAULT_BASE_URL\n     try:\n         from hermes_cli.config import load_config\n         cfg = load_config()\n         model_cfg = cfg.get(\"model\")\n         if isinstance(model_cfg, dict):\n-            cfg_base_url = (model_cfg.get(\"base_url\") or \"\").strip().rstrip(\"/\")\n-            if cfg_base_url:\n-                base_url = cfg_base_url\n+            cfg_provider = str(model_cfg.get(\"provider\") or \"\").strip().lower()\n+            if cfg_provider == \"anthropic\":\n+                cfg_base_url = (model_cfg.get(\"base_url\") or \"\").strip().rstrip(\"/\")\n+                if cfg_base_url:\n+                    base_url = cfg_base_url\n     except Exception:\n         pass\n "]},{"file":"hermes_cli/main.py","hunks":["@@ -2559,12 +2559,29 @@ def _restore_stashed_changes(\n         capture_output=True,\n         text=True,\n     )\n-    if restore.returncode != 0:\n+\n+    # Check for unmerged (conflicted) files — can happen even when returncode is 0\n+    unmerged = subprocess.run(\n+        git_cmd + [\"diff\", \"--name-only\", \"--diff-filter=U\"],\n+        cwd=cwd,\n+        capture_output=True,\n+        text=True,\n+    )\n+    has_conflicts = bool(unmerged.stdout.strip())\n+\n+    if restore.returncode != 0 or has_conflicts:\n+        # Reset the working tree so Hermes is runnable with the updated code\n+        subprocess.run(\n+            git_cmd + [\"reset\", \"--hard\", \"HEAD\"],\n+            cwd=cwd,\n+            capture_output=True,\n+        )\n         print(\"✗ Update pulled new code, but restoring local changes failed.\")\n         if restore.stdout.strip():\n             print(restore.stdout.strip())\n         if restore.stderr.strip():\n             print(restore.stderr.strip())\n+        print(\"The working tree has been reset to a clean state.\")\n         print(\"Your changes are still preserved in git stash.\")\n         print(f\"Resolve manually with: git stash apply {stash_ref}\")\n         sys.exit(1)"]},{"file":"hermes_cli/runtime_provider.py","hunks":["@@ -359,9 +359,14 @@ def resolve_runtime_provider(\n                 \"No Anthropic credentials found. Set ANTHROPIC_TOKEN or ANTHROPIC_API_KEY, \"\n                 \"run 'claude setup-token', or authenticate with 'claude /login'.\"\n             )\n-        # Allow base URL override from config.yaml model.base_url\n+        # Allow base URL override from config.yaml model.base_url, but only\n+        # when the configured provider is anthropic — otherwise a non-Anthropic\n+        # base_url (e.g. Codex endpoint) would leak into Anthropic requests.\n         model_cfg = _get_model_config()\n-        cfg_base_url = (model_cfg.get(\"base_url\") or \"\").strip().rstrip(\"/\")\n+        cfg_provider = str(model_cfg.get(\"provider\") or \"\").strip().lower()\n+        cfg_base_url = \"\"\n+        if cfg_provider == \"anthropic\":\n+            cfg_base_url = (model_cfg.get(\"base_url\") or \"\").strip().rstrip(\"/\")\n         base_url = cfg_base_url or \"https://api.anthropic.com\"\n         return {\n             \"provider\": \"anthropic\","]},{"file":"tests/hermes_cli/test_update_autostash.py","hunks":["@@ -68,6 +68,8 @@ def fake_run(cmd, **kwargs):\n         calls.append((cmd, kwargs))\n         if cmd[1:3] == [\"stash\", \"apply\"]:\n             return SimpleNamespace(stdout=\"applied\\n\", stderr=\"\", returncode=0)\n+        if cmd[1:3] == [\"diff\", \"--name-only\"]:\n+            return SimpleNamespace(stdout=\"\", stderr=\"\", returncode=0)\n         if cmd[1:3] == [\"stash\", \"list\"]:\n             return SimpleNamespace(stdout=\"stash@{1} abc123\\n\", stderr=\"\", returncode=0)\n         if cmd[1:3] == [\"stash\", \"drop\"]:","@@ -81,8 +83,9 @@ def fake_run(cmd, **kwargs):\n \n     assert restored is True\n     assert calls[0][0] == [\"git\", \"stash\", \"apply\", \"abc123\"]\n-    assert calls[1][0] == [\"git\", \"stash\", \"list\", \"--format=%gd %H\"]\n-    assert calls[2][0] == [\"git\", \"stash\", \"drop\", \"stash@{1}\"]\n+    assert calls[1][0] == [\"git\", \"diff\", \"--name-only\", \"--diff-filter=U\"]\n+    assert calls[2][0] == [\"git\", \"stash\", \"list\", \"--format=%gd %H\"]\n+    assert calls[3][0] == [\"git\", \"stash\", \"drop\", \"stash@{1}\"]\n     out = capsys.readouterr().out\n     assert \"Restore local changes now? [Y/n]\" in out\n     assert \"restored on top of the updated codebase\" in out","@@ -117,6 +120,8 @@ def fake_run(cmd, **kwargs):\n         calls.append((cmd, kwargs))\n         if cmd[1:3] == [\"stash\", \"apply\"]:\n             return SimpleNamespace(stdout=\"applied\\n\", stderr=\"\", returncode=0)\n+        if cmd[1:3] == [\"diff\", \"--name-only\"]:\n+            return SimpleNamespace(stdout=\"\", stderr=\"\", returncode=0)\n         if cmd[1:3] == [\"stash\", \"list\"]:\n             return SimpleNamespace(stdout=\"stash@{0} abc123\\n\", stderr=\"\", returncode=0)\n         if cmd[1:3] == [\"stash\", \"drop\"]:","@@ -129,8 +134,9 @@ def fake_run(cmd, **kwargs):\n \n     assert restored is True\n     assert calls[0][0] == [\"git\", \"stash\", \"apply\", \"abc123\"]\n-    assert calls[1][0] == [\"git\", \"stash\", \"list\", \"--format=%gd %H\"]\n-    assert calls[2][0] == [\"git\", \"stash\", \"drop\", \"stash@{0}\"]\n+    assert calls[1][0] == [\"git\", \"diff\", \"--name-only\", \"--diff-filter=U\"]\n+    assert calls[2][0] == [\"git\", \"stash\", \"list\", \"--format=%gd %H\"]\n+    assert calls[3][0] == [\"git\", \"stash\", \"drop\", \"stash@{0}\"]\n     assert \"Restore local changes now?\" not in capsys.readouterr().out\n \n ","@@ -152,6 +158,8 @@ def fake_run(cmd, **kwargs):\n         calls.append((cmd, kwargs))\n         if cmd[1:3] == [\"stash\", \"apply\"]:\n             return SimpleNamespace(stdout=\"applied\\n\", stderr=\"\", returncode=0)\n+        if cmd[1:3] == [\"diff\", \"--name-only\"]:\n+            return SimpleNamespace(stdout=\"\", stderr=\"\", returncode=0)\n         if cmd[1:3] == [\"stash\", \"list\"]:\n             return SimpleNamespace(stdout=\"stash@{0} def456\\n\", stderr=\"\", returncode=0)\n         raise AssertionError(f\"unexpected command: {cmd}\")","@@ -161,10 +169,9 @@ def fake_run(cmd, **kwargs):\n     restored = hermes_main._restore_stashed_changes([\"git\"], tmp_path, \"abc123\", prompt_user=False)\n \n     assert restored is True\n-    assert calls == [\n-        ([\"git\", \"stash\", \"apply\", \"abc123\"], {\"cwd\": tmp_path, \"capture_output\": True, \"text\": True}),\n-        ([\"git\", \"stash\", \"list\", \"--format=%gd %H\"], {\"cwd\": tmp_path, \"capture_output\": True, \"text\": True, \"check\": True}),\n-    ]\n+    assert calls[0] == ([\"git\", \"stash\", \"apply\", \"abc123\"], {\"cwd\": tmp_path, \"capture_output\": True, \"text\": True})\n+    assert calls[1] == ([\"git\", \"diff\", \"--name-only\", \"--diff-filter=U\"], {\"cwd\": tmp_path, \"capture_output\": True, \"text\": True})\n+    assert calls[2] == ([\"git\", \"stash\", \"list\", \"--format=%gd %H\"], {\"cwd\": tmp_path, \"capture_output\": True, \"text\": True, \"check\": True})\n     out = capsys.readouterr().out\n     assert \"couldn't find the stash entry to drop\" in out\n     assert \"stash was left in place\" in out","@@ -181,6 +188,8 @@ def fake_run(cmd, **kwargs):\n         calls.append((cmd, kwargs))\n         if cmd[1:3] == [\"stash\", \"apply\"]:\n             return SimpleNamespace(stdout=\"applied\\n\", stderr=\"\", returncode=0)\n+        if cmd[1:3] == [\"diff\", \"--name-only\"]:\n+            return SimpleNamespace(stdout=\"\", stderr=\"\", returncode=0)\n         if cmd[1:3] == [\"stash\", \"list\"]:\n             return SimpleNamespace(stdout=\"stash@{0} abc123\\n\", stderr=\"\", returncode=0)\n         if cmd[1:3] == [\"stash\", \"drop\"]:","@@ -192,7 +201,7 @@ def fake_run(cmd, **kwargs):\n     restored = hermes_main._restore_stashed_changes([\"git\"], tmp_path, \"abc123\", prompt_user=False)\n \n     assert restored is True\n-    assert calls[2][0] == [\"git\", \"stash\", \"drop\", \"stash@{0}\"]\n+    assert calls[3][0] == [\"git\", \"stash\", \"drop\", \"stash@{0}\"]\n     out = capsys.readouterr().out\n     assert \"couldn't drop the saved stash entry\" in out\n     assert \"drop failed\" in out","@@ -208,6 +217,10 @@ def fake_run(cmd, **kwargs):\n         calls.append((cmd, kwargs))\n         if cmd[1:3] == [\"stash\", \"apply\"]:\n             return SimpleNamespace(stdout=\"conflict output\\n\", stderr=\"conflict stderr\\n\", returncode=1)\n+        if cmd[1:3] == [\"diff\", \"--name-only\"]:\n+            return SimpleNamespace(stdout=\"hermes_cli/main.py\\n\", stderr=\"\", returncode=0)\n+        if cmd[1:3] == [\"reset\", \"--hard\"]:\n+            return SimpleNamespace(stdout=\"\", stderr=\"\", returncode=0)\n         raise AssertionError(f\"unexpected command: {cmd}\")\n \n     monkeypatch.setattr(hermes_main.subprocess, \"run\", fake_run)","@@ -219,7 +232,34 @@ def fake_run(cmd, **kwargs):\n     out = capsys.readouterr().out\n     assert \"Your changes are still preserved in git stash.\" in out\n     assert \"git stash apply abc123\" in out\n-    assert calls == [([\"git\", \"stash\", \"apply\", \"abc123\"], {\"cwd\": tmp_path, \"capture_output\": True, \"text\": True})]\n+    assert \"working tree has been reset to a clean state\" in out\n+    # Verify reset --hard was called to clean up conflict markers\n+    reset_calls = [c for c, _ in calls if c[1:3] == [\"reset\", \"--hard\"]]\n+    assert len(reset_calls) == 1\n+\n+\n+def test_restore_stashed_changes_resets_when_unmerged_files_detected(monkeypatch, tmp_path, capsys):\n+    \"\"\"Even if stash apply returns 0, conflict markers must be cleaned up.\"\"\"\n+    calls = []\n+\n+    def fake_run(cmd, **kwargs):\n+        calls.append((cmd, kwargs))\n+        if cmd[1:3] == [\"stash\", \"apply\"]:\n+            return SimpleNamespace(stdout=\"applied\\n\", stderr=\"\", returncode=0)\n+        if cmd[1:3] == [\"diff\", \"--name-only\"]:\n+            return SimpleNamespace(stdout=\"cli.py\\n\", stderr=\"\", returncode=0)\n+        if cmd[1:3] == [\"reset\", \"--hard\"]:\n+            return SimpleNamespace(stdout=\"\", stderr=\"\", returncode=0)\n+        raise AssertionError(f\"unexpected command: {cmd}\")\n+\n+    monkeypatch.setattr(hermes_main.subprocess, \"run\", fake_run)\n+\n+    with pytest.raises(SystemExit, match=\"1\"):\n+        hermes_main._restore_stashed_changes([\"git\"], tmp_path, \"abc123\", prompt_user=False)\n+\n+    out = capsys.readouterr().out\n+    assert \"working tree has been reset to a clean state\" in out\n+    assert \"git stash apply abc123\" in out\n \n \n def test_stash_local_changes_if_needed_raises_when_stash_ref_missing(monkeypatch, tmp_path):\n"]}]},{"kind":"pr","number":2396,"title":"fix(auth): gate Anthropic token refresh to native Anthropic endpoints only","url":null,"state":"closed","close_reason":{"category":"uncategorized","implication":"needs_llm"},"merged":false,"is_fix_pr":true,"fix_tier":"suggested","fix_detail_withheld":true}],"trust":{"default_tier":"verified","includes_suggested":false}}