fix: add Grok OAuth provider catalog support

This commit is contained in:
Michael Lam
2026-05-18 19:49:54 -07:00
parent 718a4c7615
commit 1827ea3efd
4 changed files with 95 additions and 0 deletions

View File

@@ -2,6 +2,10 @@
## [Unreleased]
### Fixed
- **PR #2568** by @Michaelyklam (closes #2545) — Add the Hermes Agent `xai-oauth` provider to the WebUI's OAuth/provider catalogs so Grok OAuth accounts authenticated through the Hermes CLI appear in Settings → Providers and the model picker. The provider is treated as CLI-managed OAuth (not WebUI API-key configurable) and uses the live Hermes CLI model catalog when available with a Grok static fallback.
## [v0.51.91] — 2026-05-18 — Release BO (stage-384 — 5-PR full sweep batch — reasoning-replay history fix + archive-extract per-session inbox + fallback streaming warnings + sanitized custom-provider env hints + Slice 3c queue/goal adapter routing)
### Fixed

View File

@@ -692,6 +692,7 @@ _PROVIDER_DISPLAY = {
"anthropic": "Anthropic",
"openai": "OpenAI",
"openai-codex": "OpenAI Codex",
"xai-oauth": "xAI Grok OAuth",
"copilot": "GitHub Copilot",
"zai": "Z.AI / GLM",
"kimi-coding": "Kimi / Moonshot",
@@ -1209,6 +1210,9 @@ _PROVIDER_MODELS = {
"x-ai": [
{"id": "grok-4.20", "label": "Grok 4.20"},
],
"xai-oauth": [
{"id": "grok-4.20", "label": "Grok 4.20"},
],
}

View File

@@ -692,6 +692,7 @@ _OAUTH_PROVIDERS = frozenset({
"nous",
"openai-codex",
"qwen-oauth",
"xai-oauth",
})
# SECTION: Helper functions
@@ -1866,6 +1867,14 @@ def get_providers() -> dict[str, Any]:
if live_models:
models = live_models
models_total = len(models)
if pid == "xai-oauth":
live_models = _models_from_live_provider_ids(
pid,
_read_live_provider_model_ids("xai-oauth"),
)
if live_models:
models = live_models
models_total = len(models)
# Nous Portal: prefer the live catalog so the providers card matches
# the dropdown picker (#1538). Same fallback shape as the static-only
# case below — when hermes_cli is unavailable or its lookup raises,

View File

@@ -0,0 +1,78 @@
import copy
import api.config as config
import api.profiles as profiles
def _with_config(monkeypatch, tmp_path, cfg):
old_cfg = copy.deepcopy(config.cfg)
old_mtime = config._cfg_mtime
config.cfg.clear()
config.cfg.update(copy.deepcopy(cfg))
config._cfg_mtime = 0.0
config.invalidate_models_cache()
monkeypatch.setattr(profiles, "get_active_hermes_home", lambda: tmp_path)
def restore():
config.cfg.clear()
config.cfg.update(old_cfg)
config._cfg_mtime = old_mtime
config.invalidate_models_cache()
return restore
def test_xai_oauth_is_known_oauth_provider():
from api.providers import _OAUTH_PROVIDERS
from api.config import _PROVIDER_DISPLAY
assert "xai-oauth" in _OAUTH_PROVIDERS
assert _PROVIDER_DISPLAY["xai-oauth"] == "xAI Grok OAuth"
def test_xai_oauth_provider_card_uses_oauth_status_and_models(monkeypatch, tmp_path):
restore = _with_config(
monkeypatch,
tmp_path,
{
"model": {"provider": "xai-oauth", "default": "grok-4.20"},
"providers": {},
},
)
monkeypatch.setattr(config, "_read_live_provider_model_ids", lambda pid: ["grok-4.20"] if pid == "xai-oauth" else [])
try:
from api.providers import get_providers
import api.providers as providers
monkeypatch.setattr(providers, "_read_live_provider_model_ids", lambda pid: ["grok-4.20"] if pid == "xai-oauth" else [])
result = get_providers()
grok = next(p for p in result["providers"] if p["id"] == "xai-oauth")
assert grok["display_name"] == "xAI Grok OAuth"
assert grok["is_oauth"] is True
assert grok["configurable"] is False
assert grok["key_source"] == "oauth"
assert grok["models"] == [{"id": "grok-4.20", "label": "Grok 4.20"}]
assert grok["models_total"] == 1
finally:
restore()
def test_xai_oauth_model_picker_group_uses_live_catalog(monkeypatch, tmp_path):
restore = _with_config(
monkeypatch,
tmp_path,
{
"model": {"provider": "xai-oauth", "default": "grok-4.20"},
"providers": {"xai-oauth": {}},
},
)
monkeypatch.setattr(config, "_read_live_provider_model_ids", lambda pid: ["grok-4.20"] if pid == "xai-oauth" else [])
try:
result = config.get_available_models()
group = next(g for g in result["groups"] if g["provider_id"] == "xai-oauth")
assert group["provider"] == "xAI Grok OAuth"
assert group["models"] == [{"id": "grok-4.20", "label": "Grok 4.20"}]
assert result["active_provider"] == "xai-oauth"
finally:
restore()