{"repo":"NousResearch/hermes-agent","public_id":"18681","display_label":"Gateway api_key config reading for custom providers","summary":"These issues and PRs address a bug where the gateway's /model command and model listing probes fail to read api_key credentials from config when using custom endpoints or providers. Fixes involve using the credential pool and passing config api keys through the relevant handlers.","subsystem":"gateway","counts":{"members":5,"open_issues":0,"open_issues_distinct":0,"open_prs":1,"closed_issues":1,"merged_prs":1,"attempt_prs":3},"landed_fix":{"status":"merged_to_main","basis":"structural","pr":22842,"merged_at":"2026-05-10T00:54:59+00:00"},"resolution":{"state":"unresolved","by":null},"freshness":{"state":"verified","last_verified_at":"2026-05-10T00:54:59+00:00","is_stale":false},"grouping":{"backbone":"STRUCTURAL_SPANNING","link_density":0.4},"fix_edges":[{"issue_number":18681,"pr_number":22842,"tier":"verified","basis":"superseded_ref","confidence":0.9,"recoverable_from_timeline":false,"pr_merged_at":"2026-05-10T00:54:59+00:00"}],"members":[{"kind":"issue","number":18681,"title":"fix(gateway): /model command fails on custom providers — api_key not read from config","url":null,"state":"closed"},{"kind":"pr","number":18685,"title":"fix(gateway): pass config api key to model switch","url":null,"state":"open","close_reason":{"category":"uncategorized","implication":"needs_llm"},"merged":false},{"kind":"pr","number":19683,"title":"fix(gateway): read api_key from model config in /model command handler","url":null,"state":"closed","close_reason":{"refs":[{"kind":"commit","value":"f24db23458fdb2e0a14be4881d6eda5cfbf50991","number":0},{"kind":"pr","value":"#18685","number":18685}],"category":"implemented_elsewhere","implication":"superseded"},"merged":false,"is_fix_pr":true,"fix_tier":"suggested","fix_detail_withheld":true},{"kind":"pr","number":22810,"title":"fix: use credential_pool for custom endpoint model listing probes","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#22842","number":22842}],"category":"merged_via","implication":"superseded"},"merged":false},{"kind":"pr","number":22842,"title":"fix: use credential_pool for custom endpoint model listing probes (salvage #22810)","url":null,"state":"merged","close_reason":{"category":"merged"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["hermes_cli/model_switch.py","hermes_cli/runtime_provider.py","scripts/release.py"],"fix_hunks":[{"file":"hermes_cli/model_switch.py","hunks":["@@ -889,10 +889,9 @@ def switch_model(\n             # \"ollama-launch\" that resolve_runtime_provider doesn't know), keep existing\n             # credentials. Otherwise use the resolved values (picks up credential rotation,\n             # base_url adjustments for OpenCode, etc.).\n-            if runtime.get(\"provider\") != \"custom\":\n-                api_key = runtime.get(\"api_key\", \"\")\n-                base_url = runtime.get(\"base_url\", \"\")\n-                api_mode = runtime.get(\"api_mode\", \"\")\n+            api_key = runtime.get(\"api_key\", \"\")\n+            base_url = runtime.get(\"base_url\", \"\")\n+            api_mode = runtime.get(\"api_mode\", \"\")\n         except Exception:\n             pass\n "]},{"file":"hermes_cli/runtime_provider.py","hunks":["@@ -492,6 +492,13 @@ def _resolve_named_custom_runtime(\n     requested_norm = (requested_provider or \"\").strip().lower()\n     if requested_norm == \"custom\" and explicit_base_url:\n         base_url = explicit_base_url.strip().rstrip(\"/\")\n+        # Check credential pool first — mirrors the named-custom-provider path\n+        # so bare `provider: custom` with a configured custom_providers entry\n+        # also gets its api_key from the pool instead of env var fallbacks.\n+        pool_result = _try_resolve_from_custom_pool(base_url, \"custom\", None)\n+        if pool_result:\n+            pool_result[\"source\"] = \"direct-alias\"\n+            return pool_result\n         api_key_candidates = [\n             (explicit_api_key or \"\").strip(),\n             os.getenv(\"OPENAI_API_KEY\", \"\").strip(),"]},{"file":"scripts/release.py","hunks":["@@ -66,6 +66,7 @@\n     \"[redacted:email]\": \"qWaitCrypto\",\n     \"44045911+kidonng@users.noreply.github.com\": \"kidonng\",\n     \"[redacted:email]\": \"DanielLSM\",\n+    \"264291321+v1b3coder@users.noreply.github.com\": \"v1b3coder\",\n     \"[redacted:email]\": \"Qwinty\",\n     \"[redacted:email]\": \"CalmProton\",\n     \"308068+mbac@users.noreply.github.com\": \"mbac\",\n"]}]}],"trust":{"default_tier":"verified","includes_suggested":false}}