test(tui): fix stale mocks + xdist flakes in TUI test suite
All 61 TUI-related tests green across 3 consecutive xdist runs.
tests/tui_gateway/test_protocol.py:
- rename `get_messages` → `get_messages_as_conversation` on mock DB (method
was renamed in the real backend, test was still stubbing the old name)
- update tool-message shape expectation: `{role, name, context}` matches
current `_history_to_messages` output, not the legacy `{role, text}`
tests/hermes_cli/test_tui_resume_flow.py:
- `cmd_chat` grew a first-run provider-gate that bailed to "Run: hermes
setup" before `_launch_tui` was ever reached; 3 tests stubbed
`_resolve_last_session` + `_launch_tui` but not the gate
- factored a `main_mod` fixture that stubs `_has_any_provider_configured`,
reused by all three tests
tests/test_tui_gateway_server.py:
- `test_config_set_personality_resets_history_and_returns_info` was flaky
under xdist because the real `_write_config_key` touches
`~/.hermes/config.yaml`, racing with any other worker that writes
config. Stub it in the test.
This commit is contained in:
@@ -78,6 +78,10 @@ QWEN_OAUTH_CLIENT_ID = "f0304373b74a44d2b584a3fb70ca9e56"
|
||||
QWEN_OAUTH_TOKEN_URL = "https://chat.qwen.ai/api/v1/oauth2/token"
|
||||
QWEN_ACCESS_TOKEN_REFRESH_SKEW_SECONDS = 120
|
||||
|
||||
# Google Gemini OAuth (google-gemini-cli provider, Cloud Code Assist backend)
|
||||
DEFAULT_GEMINI_CLOUDCODE_BASE_URL = "cloudcode-pa://google"
|
||||
GEMINI_OAUTH_ACCESS_TOKEN_REFRESH_SKEW_SECONDS = 60 # refresh 60s before expiry
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Provider Registry
|
||||
@@ -122,6 +126,12 @@ PROVIDER_REGISTRY: Dict[str, ProviderConfig] = {
|
||||
auth_type="oauth_external",
|
||||
inference_base_url=DEFAULT_QWEN_BASE_URL,
|
||||
),
|
||||
"google-gemini-cli": ProviderConfig(
|
||||
id="google-gemini-cli",
|
||||
name="Google Gemini (OAuth)",
|
||||
auth_type="oauth_external",
|
||||
inference_base_url=DEFAULT_GEMINI_CLOUDCODE_BASE_URL,
|
||||
),
|
||||
"copilot": ProviderConfig(
|
||||
id="copilot",
|
||||
name="GitHub Copilot",
|
||||
@@ -939,7 +949,7 @@ def resolve_provider(
|
||||
"github-copilot-acp": "copilot-acp", "copilot-acp-agent": "copilot-acp",
|
||||
"aigateway": "ai-gateway", "vercel": "ai-gateway", "vercel-ai-gateway": "ai-gateway",
|
||||
"opencode": "opencode-zen", "zen": "opencode-zen",
|
||||
"qwen-portal": "qwen-oauth", "qwen-cli": "qwen-oauth", "qwen-oauth": "qwen-oauth",
|
||||
"qwen-portal": "qwen-oauth", "qwen-cli": "qwen-oauth", "qwen-oauth": "qwen-oauth", "google-gemini-cli": "google-gemini-cli", "gemini-cli": "google-gemini-cli", "gemini-oauth": "google-gemini-cli",
|
||||
"hf": "huggingface", "hugging-face": "huggingface", "huggingface-hub": "huggingface",
|
||||
"mimo": "xiaomi", "xiaomi-mimo": "xiaomi",
|
||||
"aws": "bedrock", "aws-bedrock": "bedrock", "amazon-bedrock": "bedrock", "amazon": "bedrock",
|
||||
@@ -1251,6 +1261,83 @@ def get_qwen_auth_status() -> Dict[str, Any]:
|
||||
}
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Google Gemini OAuth (google-gemini-cli) — PKCE flow + Cloud Code Assist.
|
||||
#
|
||||
# Tokens live in ~/.hermes/auth/google_oauth.json (managed by agent.google_oauth).
|
||||
# The `base_url` here is the marker "cloudcode-pa://google" that run_agent.py
|
||||
# uses to construct a GeminiCloudCodeClient instead of the default OpenAI SDK.
|
||||
# Actual HTTP traffic goes to https://cloudcode-pa.googleapis.com/v1internal:*.
|
||||
# =============================================================================
|
||||
|
||||
def resolve_gemini_oauth_runtime_credentials(
|
||||
*,
|
||||
force_refresh: bool = False,
|
||||
) -> Dict[str, Any]:
|
||||
"""Resolve runtime OAuth creds for google-gemini-cli."""
|
||||
try:
|
||||
from agent.google_oauth import (
|
||||
GoogleOAuthError,
|
||||
_credentials_path,
|
||||
get_valid_access_token,
|
||||
load_credentials,
|
||||
)
|
||||
except ImportError as exc:
|
||||
raise AuthError(
|
||||
f"agent.google_oauth is not importable: {exc}",
|
||||
provider="google-gemini-cli",
|
||||
code="google_oauth_module_missing",
|
||||
) from exc
|
||||
|
||||
try:
|
||||
access_token = get_valid_access_token(force_refresh=force_refresh)
|
||||
except GoogleOAuthError as exc:
|
||||
raise AuthError(
|
||||
str(exc),
|
||||
provider="google-gemini-cli",
|
||||
code=exc.code,
|
||||
) from exc
|
||||
|
||||
creds = load_credentials()
|
||||
base_url = DEFAULT_GEMINI_CLOUDCODE_BASE_URL
|
||||
return {
|
||||
"provider": "google-gemini-cli",
|
||||
"base_url": base_url,
|
||||
"api_key": access_token,
|
||||
"source": "google-oauth",
|
||||
"expires_at_ms": (creds.expires_ms if creds else None),
|
||||
"auth_file": str(_credentials_path()),
|
||||
"email": (creds.email if creds else "") or "",
|
||||
"project_id": (creds.project_id if creds else "") or "",
|
||||
}
|
||||
|
||||
|
||||
def get_gemini_oauth_auth_status() -> Dict[str, Any]:
|
||||
"""Return a status dict for `hermes auth list` / `hermes status`."""
|
||||
try:
|
||||
from agent.google_oauth import _credentials_path, load_credentials
|
||||
except ImportError:
|
||||
return {"logged_in": False, "error": "agent.google_oauth unavailable"}
|
||||
auth_path = _credentials_path()
|
||||
creds = load_credentials()
|
||||
if creds is None or not creds.access_token:
|
||||
return {
|
||||
"logged_in": False,
|
||||
"auth_file": str(auth_path),
|
||||
"error": "not logged in",
|
||||
}
|
||||
return {
|
||||
"logged_in": True,
|
||||
"auth_file": str(auth_path),
|
||||
"source": "google-oauth",
|
||||
"api_key": creds.access_token,
|
||||
"expires_at_ms": creds.expires_ms,
|
||||
"email": creds.email,
|
||||
"project_id": creds.project_id,
|
||||
}
|
||||
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# SSH / remote session detection
|
||||
# =============================================================================
|
||||
@@ -2469,6 +2556,8 @@ def get_auth_status(provider_id: Optional[str] = None) -> Dict[str, Any]:
|
||||
return get_codex_auth_status()
|
||||
if target == "qwen-oauth":
|
||||
return get_qwen_auth_status()
|
||||
if target == "google-gemini-cli":
|
||||
return get_gemini_oauth_auth_status()
|
||||
if target == "copilot-acp":
|
||||
return get_external_process_provider_status(target)
|
||||
# API-key providers
|
||||
|
||||
@@ -33,7 +33,7 @@ from hermes_constants import OPENROUTER_BASE_URL
|
||||
|
||||
|
||||
# Providers that support OAuth login in addition to API keys.
|
||||
_OAUTH_CAPABLE_PROVIDERS = {"anthropic", "nous", "openai-codex", "qwen-oauth"}
|
||||
_OAUTH_CAPABLE_PROVIDERS = {"anthropic", "nous", "openai-codex", "qwen-oauth", "google-gemini-cli"}
|
||||
|
||||
|
||||
def _get_custom_provider_names() -> list:
|
||||
@@ -148,7 +148,7 @@ def auth_add_command(args) -> None:
|
||||
if provider.startswith(CUSTOM_POOL_PREFIX):
|
||||
requested_type = AUTH_TYPE_API_KEY
|
||||
else:
|
||||
requested_type = AUTH_TYPE_OAUTH if provider in {"anthropic", "nous", "openai-codex", "qwen-oauth"} else AUTH_TYPE_API_KEY
|
||||
requested_type = AUTH_TYPE_OAUTH if provider in {"anthropic", "nous", "openai-codex", "qwen-oauth", "google-gemini-cli"} else AUTH_TYPE_API_KEY
|
||||
|
||||
pool = load_pool(provider)
|
||||
|
||||
@@ -254,6 +254,27 @@ def auth_add_command(args) -> None:
|
||||
print(f'Added {provider} OAuth credential #{len(pool.entries())}: "{entry.label}"')
|
||||
return
|
||||
|
||||
if provider == "google-gemini-cli":
|
||||
from agent.google_oauth import run_gemini_oauth_login_pure
|
||||
|
||||
creds = run_gemini_oauth_login_pure()
|
||||
label = (getattr(args, "label", None) or "").strip() or (
|
||||
creds.get("email") or _oauth_default_label(provider, len(pool.entries()) + 1)
|
||||
)
|
||||
entry = PooledCredential(
|
||||
provider=provider,
|
||||
id=uuid.uuid4().hex[:6],
|
||||
label=label,
|
||||
auth_type=AUTH_TYPE_OAUTH,
|
||||
priority=0,
|
||||
source=f"{SOURCE_MANUAL}:google_pkce",
|
||||
access_token=creds["access_token"],
|
||||
refresh_token=creds.get("refresh_token"),
|
||||
)
|
||||
pool.add_entry(entry)
|
||||
print(f'Added {provider} OAuth credential #{len(pool.entries())}: "{entry.label}"')
|
||||
return
|
||||
|
||||
if provider == "qwen-oauth":
|
||||
creds = auth_mod.resolve_qwen_runtime_credentials(refresh_if_expiring=False)
|
||||
label = (getattr(args, "label", None) or "").strip() or label_from_token(
|
||||
|
||||
@@ -104,6 +104,7 @@ COMMAND_REGISTRY: list[CommandDef] = [
|
||||
CommandDef("model", "Switch model for this session", "Configuration", args_hint="[model] [--provider name] [--global]"),
|
||||
CommandDef("provider", "Show available providers and current provider",
|
||||
"Configuration"),
|
||||
CommandDef("gquota", "Show Google Gemini Code Assist quota usage", "Info"),
|
||||
|
||||
CommandDef("personality", "Set a predefined personality", "Configuration",
|
||||
args_hint="[name]"),
|
||||
|
||||
@@ -1002,6 +1002,30 @@ OPTIONAL_ENV_VARS = {
|
||||
"category": "provider",
|
||||
"advanced": True,
|
||||
},
|
||||
"HERMES_GEMINI_CLIENT_ID": {
|
||||
"description": "Google OAuth client ID for google-gemini-cli (optional; defaults to Google's public gemini-cli client)",
|
||||
"prompt": "Google OAuth client ID (optional — leave empty to use the public default)",
|
||||
"url": "https://console.cloud.google.com/apis/credentials",
|
||||
"password": False,
|
||||
"category": "provider",
|
||||
"advanced": True,
|
||||
},
|
||||
"HERMES_GEMINI_CLIENT_SECRET": {
|
||||
"description": "Google OAuth client secret for google-gemini-cli (optional)",
|
||||
"prompt": "Google OAuth client secret (optional)",
|
||||
"url": "https://console.cloud.google.com/apis/credentials",
|
||||
"password": True,
|
||||
"category": "provider",
|
||||
"advanced": True,
|
||||
},
|
||||
"HERMES_GEMINI_PROJECT_ID": {
|
||||
"description": "GCP project ID for paid Gemini tiers (free tier auto-provisions)",
|
||||
"prompt": "GCP project ID for Gemini OAuth (leave empty for free tier)",
|
||||
"url": None,
|
||||
"password": False,
|
||||
"category": "provider",
|
||||
"advanced": True,
|
||||
},
|
||||
"OPENCODE_ZEN_API_KEY": {
|
||||
"description": "OpenCode Zen API key (pay-as-you-go access to curated models)",
|
||||
"prompt": "OpenCode Zen API key",
|
||||
|
||||
@@ -373,7 +373,11 @@ def run_doctor(args):
|
||||
print(color("◆ Auth Providers", Colors.CYAN, Colors.BOLD))
|
||||
|
||||
try:
|
||||
from hermes_cli.auth import get_nous_auth_status, get_codex_auth_status
|
||||
from hermes_cli.auth import (
|
||||
get_nous_auth_status,
|
||||
get_codex_auth_status,
|
||||
get_gemini_oauth_auth_status,
|
||||
)
|
||||
|
||||
nous_status = get_nous_auth_status()
|
||||
if nous_status.get("logged_in"):
|
||||
@@ -388,6 +392,20 @@ def run_doctor(args):
|
||||
check_warn("OpenAI Codex auth", "(not logged in)")
|
||||
if codex_status.get("error"):
|
||||
check_info(codex_status["error"])
|
||||
|
||||
gemini_status = get_gemini_oauth_auth_status()
|
||||
if gemini_status.get("logged_in"):
|
||||
email = gemini_status.get("email") or ""
|
||||
project = gemini_status.get("project_id") or ""
|
||||
pieces = []
|
||||
if email:
|
||||
pieces.append(email)
|
||||
if project:
|
||||
pieces.append(f"project={project}")
|
||||
suffix = f" ({', '.join(pieces)})" if pieces else ""
|
||||
check_ok("Google Gemini OAuth", f"(logged in{suffix})")
|
||||
else:
|
||||
check_warn("Google Gemini OAuth", "(not logged in)")
|
||||
except Exception as e:
|
||||
check_warn("Auth provider status", f"(could not check: {e})")
|
||||
|
||||
|
||||
@@ -1405,6 +1405,8 @@ def select_provider_and_model(args=None):
|
||||
_model_flow_openai_codex(config, current_model)
|
||||
elif selected_provider == "qwen-oauth":
|
||||
_model_flow_qwen_oauth(config, current_model)
|
||||
elif selected_provider == "google-gemini-cli":
|
||||
_model_flow_google_gemini_cli(config, current_model)
|
||||
elif selected_provider == "copilot-acp":
|
||||
_model_flow_copilot_acp(config, current_model)
|
||||
elif selected_provider == "copilot":
|
||||
@@ -1807,6 +1809,76 @@ def _model_flow_qwen_oauth(_config, current_model=""):
|
||||
print("No change.")
|
||||
|
||||
|
||||
def _model_flow_google_gemini_cli(_config, current_model=""):
|
||||
"""Google Gemini OAuth (PKCE) via Cloud Code Assist — supports free AND paid tiers.
|
||||
|
||||
Flow:
|
||||
1. Show upfront warning about Google's ToS stance (per opencode-gemini-auth).
|
||||
2. If creds missing, run PKCE browser OAuth via agent.google_oauth.
|
||||
3. Resolve project context (env -> config -> auto-discover -> free tier).
|
||||
4. Prompt user to pick a model.
|
||||
5. Save to ~/.hermes/config.yaml.
|
||||
"""
|
||||
from hermes_cli.auth import (
|
||||
DEFAULT_GEMINI_CLOUDCODE_BASE_URL,
|
||||
get_gemini_oauth_auth_status,
|
||||
resolve_gemini_oauth_runtime_credentials,
|
||||
_prompt_model_selection,
|
||||
_save_model_choice,
|
||||
_update_config_for_provider,
|
||||
)
|
||||
from hermes_cli.models import _PROVIDER_MODELS
|
||||
|
||||
print()
|
||||
print("⚠ Google considers using the Gemini CLI OAuth client with third-party")
|
||||
print(" software a policy violation. Some users have reported account")
|
||||
print(" restrictions. You can use your own API key via 'gemini' provider")
|
||||
print(" for the lowest-risk experience.")
|
||||
print()
|
||||
try:
|
||||
proceed = input("Continue with OAuth login? [y/N]: ").strip().lower()
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
print("Cancelled.")
|
||||
return
|
||||
if proceed not in {"y", "yes"}:
|
||||
print("Cancelled.")
|
||||
return
|
||||
|
||||
status = get_gemini_oauth_auth_status()
|
||||
if not status.get("logged_in"):
|
||||
try:
|
||||
from agent.google_oauth import resolve_project_id_from_env, start_oauth_flow
|
||||
|
||||
env_project = resolve_project_id_from_env()
|
||||
start_oauth_flow(force_relogin=True, project_id=env_project)
|
||||
except Exception as exc:
|
||||
print(f"OAuth login failed: {exc}")
|
||||
return
|
||||
|
||||
# Verify creds resolve + trigger project discovery
|
||||
try:
|
||||
creds = resolve_gemini_oauth_runtime_credentials(force_refresh=False)
|
||||
project_id = creds.get("project_id", "")
|
||||
if project_id:
|
||||
print(f" Using GCP project: {project_id}")
|
||||
else:
|
||||
print(" No GCP project configured — free tier will be auto-provisioned on first request.")
|
||||
except Exception as exc:
|
||||
print(f"Failed to resolve Gemini credentials: {exc}")
|
||||
return
|
||||
|
||||
models = list(_PROVIDER_MODELS.get("google-gemini-cli") or [])
|
||||
default = current_model or (models[0] if models else "gemini-2.5-flash")
|
||||
selected = _prompt_model_selection(models, current_model=default)
|
||||
if selected:
|
||||
_save_model_choice(selected)
|
||||
_update_config_for_provider("google-gemini-cli", DEFAULT_GEMINI_CLOUDCODE_BASE_URL)
|
||||
print(f"Default model set to: {selected} (via Google Gemini OAuth / Code Assist)")
|
||||
else:
|
||||
print("No change.")
|
||||
|
||||
|
||||
|
||||
|
||||
def _model_flow_custom(config):
|
||||
"""Custom endpoint: collect URL, API key, and model name.
|
||||
|
||||
@@ -136,6 +136,11 @@ _PROVIDER_MODELS: dict[str, list[str]] = {
|
||||
"gemma-4-31b-it",
|
||||
"gemma-4-26b-it",
|
||||
],
|
||||
"google-gemini-cli": [
|
||||
"gemini-2.5-pro",
|
||||
"gemini-2.5-flash",
|
||||
"gemini-2.5-flash-lite",
|
||||
],
|
||||
"zai": [
|
||||
"glm-5.1",
|
||||
"glm-5",
|
||||
@@ -244,6 +249,7 @@ _PROVIDER_MODELS: dict[str, list[str]] = {
|
||||
"big-pickle",
|
||||
],
|
||||
"opencode-go": [
|
||||
"glm-5.1",
|
||||
"glm-5",
|
||||
"kimi-k2.5",
|
||||
"mimo-v2-pro",
|
||||
@@ -534,6 +540,7 @@ CANONICAL_PROVIDERS: list[ProviderEntry] = [
|
||||
ProviderEntry("copilot-acp", "GitHub Copilot ACP", "GitHub Copilot ACP (spawns `copilot --acp --stdio`)"),
|
||||
ProviderEntry("huggingface", "Hugging Face", "Hugging Face Inference Providers (20+ open models)"),
|
||||
ProviderEntry("gemini", "Google AI Studio", "Google AI Studio (Gemini models — OpenAI-compatible endpoint)"),
|
||||
ProviderEntry("google-gemini-cli", "Google Gemini (OAuth)", "Google Gemini via OAuth + Code Assist (free tier supported; no API key needed)"),
|
||||
ProviderEntry("deepseek", "DeepSeek", "DeepSeek (DeepSeek-V3, R1, coder — direct API)"),
|
||||
ProviderEntry("xai", "xAI", "xAI (Grok models — direct API)"),
|
||||
ProviderEntry("zai", "Z.AI / GLM", "Z.AI / GLM (Zhipu AI direct API)"),
|
||||
@@ -596,6 +603,8 @@ _PROVIDER_ALIASES = {
|
||||
"qwen": "alibaba",
|
||||
"alibaba-cloud": "alibaba",
|
||||
"qwen-portal": "qwen-oauth",
|
||||
"gemini-cli": "google-gemini-cli",
|
||||
"gemini-oauth": "google-gemini-cli",
|
||||
"hf": "huggingface",
|
||||
"hugging-face": "huggingface",
|
||||
"huggingface-hub": "huggingface",
|
||||
|
||||
@@ -64,6 +64,11 @@ HERMES_OVERLAYS: Dict[str, HermesOverlay] = {
|
||||
base_url_override="https://portal.qwen.ai/v1",
|
||||
base_url_env_var="HERMES_QWEN_BASE_URL",
|
||||
),
|
||||
"google-gemini-cli": HermesOverlay(
|
||||
transport="openai_chat",
|
||||
auth_type="oauth_external",
|
||||
base_url_override="cloudcode-pa://google",
|
||||
),
|
||||
"copilot-acp": HermesOverlay(
|
||||
transport="codex_responses",
|
||||
auth_type="external_process",
|
||||
@@ -232,6 +237,11 @@ ALIASES: Dict[str, str] = {
|
||||
"qwen": "alibaba",
|
||||
"alibaba-cloud": "alibaba",
|
||||
|
||||
# google-gemini-cli (OAuth + Code Assist)
|
||||
"gemini-cli": "google-gemini-cli",
|
||||
"gemini-oauth": "google-gemini-cli",
|
||||
|
||||
|
||||
# huggingface
|
||||
"hf": "huggingface",
|
||||
"hugging-face": "huggingface",
|
||||
|
||||
@@ -22,6 +22,7 @@ from hermes_cli.auth import (
|
||||
resolve_nous_runtime_credentials,
|
||||
resolve_codex_runtime_credentials,
|
||||
resolve_qwen_runtime_credentials,
|
||||
resolve_gemini_oauth_runtime_credentials,
|
||||
resolve_api_key_provider_credentials,
|
||||
resolve_external_process_provider_credentials,
|
||||
has_usable_secret,
|
||||
@@ -156,6 +157,9 @@ def _resolve_runtime_from_pool_entry(
|
||||
elif provider == "qwen-oauth":
|
||||
api_mode = "chat_completions"
|
||||
base_url = base_url or DEFAULT_QWEN_BASE_URL
|
||||
elif provider == "google-gemini-cli":
|
||||
api_mode = "chat_completions"
|
||||
base_url = base_url or "cloudcode-pa://google"
|
||||
elif provider == "anthropic":
|
||||
api_mode = "anthropic_messages"
|
||||
cfg_provider = str(model_cfg.get("provider") or "").strip().lower()
|
||||
@@ -804,6 +808,26 @@ def resolve_runtime_provider(
|
||||
logger.info("Qwen OAuth credentials failed; "
|
||||
"falling through to next provider.")
|
||||
|
||||
if provider == "google-gemini-cli":
|
||||
try:
|
||||
creds = resolve_gemini_oauth_runtime_credentials()
|
||||
return {
|
||||
"provider": "google-gemini-cli",
|
||||
"api_mode": "chat_completions",
|
||||
"base_url": creds.get("base_url", ""),
|
||||
"api_key": creds.get("api_key", ""),
|
||||
"source": creds.get("source", "google-oauth"),
|
||||
"expires_at_ms": creds.get("expires_at_ms"),
|
||||
"email": creds.get("email", ""),
|
||||
"project_id": creds.get("project_id", ""),
|
||||
"requested_provider": requested_provider,
|
||||
}
|
||||
except AuthError:
|
||||
if requested_provider != "auto":
|
||||
raise
|
||||
logger.info("Google Gemini OAuth credentials failed; "
|
||||
"falling through to next provider.")
|
||||
|
||||
if provider == "copilot-acp":
|
||||
creds = resolve_external_process_provider_credentials(provider)
|
||||
return {
|
||||
|
||||
@@ -102,7 +102,7 @@ _DEFAULT_PROVIDER_MODELS = {
|
||||
"ai-gateway": ["anthropic/claude-opus-4.6", "anthropic/claude-sonnet-4.6", "openai/gpt-5", "google/gemini-3-flash"],
|
||||
"kilocode": ["anthropic/claude-opus-4.6", "anthropic/claude-sonnet-4.6", "openai/gpt-5.4", "google/gemini-3-pro-preview", "google/gemini-3-flash-preview"],
|
||||
"opencode-zen": ["gpt-5.4", "gpt-5.3-codex", "claude-sonnet-4-6", "gemini-3-flash", "glm-5", "kimi-k2.5", "minimax-m2.7"],
|
||||
"opencode-go": ["glm-5", "kimi-k2.5", "mimo-v2-pro", "mimo-v2-omni", "minimax-m2.5", "minimax-m2.7"],
|
||||
"opencode-go": ["glm-5.1", "glm-5", "kimi-k2.5", "mimo-v2-pro", "mimo-v2-omni", "minimax-m2.5", "minimax-m2.7"],
|
||||
"huggingface": [
|
||||
"Qwen/Qwen3.5-397B-A17B", "Qwen/Qwen3-235B-A22B-Thinking-2507",
|
||||
"Qwen/Qwen3-Coder-480B-A35B-Instruct", "deepseek-ai/DeepSeek-R1-0528",
|
||||
|
||||
@@ -467,6 +467,7 @@ async def get_status():
|
||||
"latest_config_version": latest_ver,
|
||||
"gateway_running": gateway_running,
|
||||
"gateway_pid": gateway_pid,
|
||||
"gateway_health_url": _GATEWAY_HEALTH_URL,
|
||||
"gateway_state": gateway_state,
|
||||
"gateway_platforms": gateway_platforms,
|
||||
"gateway_exit_reason": gateway_exit_reason,
|
||||
|
||||
Reference in New Issue
Block a user