hermes(agent): recognize CLI runtime and shorten restarts
All checks were successful
Tests / Declarative: Post Actions passed: 229
All checks were successful
Tests / Declarative: Post Actions passed: 229
This commit is contained in:
parent
e277e43633
commit
04bd50ca74
@ -131,7 +131,29 @@ spec:
|
||||
upsert_env GIT_ASKPASS /opt/coordinator/gitea_askpass.sh
|
||||
upsert_env GIT_TERMINAL_PROMPT 0
|
||||
chmod 0600 "${env_file}"
|
||||
chown -R 10000:10000 /opt/data
|
||||
# Existing owner data is already written as uid/gid 10000. A
|
||||
# recursive chown made every routine rollout walk the full 20Gi
|
||||
# workspace while the dashboard had no endpoint. Own only the
|
||||
# paths this init container creates or updates.
|
||||
chown 10000:10000 \
|
||||
/opt/data \
|
||||
/opt/data/home \
|
||||
/opt/data/home/.claude \
|
||||
/opt/data/home/.codex \
|
||||
/opt/data/home/.kube \
|
||||
/opt/data/cli-lanes \
|
||||
/opt/data/logs \
|
||||
/opt/data/tools \
|
||||
/opt/data/tools/bin \
|
||||
/opt/data/workspace \
|
||||
/opt/data/workspace/coordinator \
|
||||
/opt/data/workspace/projects \
|
||||
/opt/data/workspace/skills \
|
||||
/opt/data/config.yaml \
|
||||
/opt/data/SOUL.md \
|
||||
/opt/data/workspace/AGENTS.md \
|
||||
/opt/data/workspace/START-HERE.md \
|
||||
"${env_file}"
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
runAsUser: 0
|
||||
|
||||
@ -6,6 +6,8 @@ from __future__ import annotations
|
||||
import copy
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Any, Iterable
|
||||
@ -262,6 +264,28 @@ def _existing_model(config: dict[str, Any], provider: str, default: str) -> str:
|
||||
return default
|
||||
|
||||
|
||||
def codex_cli_authenticated() -> bool:
|
||||
"""Return whether the installed Codex CLI has a usable local login."""
|
||||
codex = shutil.which("codex")
|
||||
if codex:
|
||||
try:
|
||||
status = subprocess.run(
|
||||
[codex, "login", "status"],
|
||||
capture_output=True,
|
||||
check=False,
|
||||
text=True,
|
||||
timeout=10,
|
||||
)
|
||||
detail = f"{status.stdout}\n{status.stderr}".lower()
|
||||
if status.returncode == 0 and (
|
||||
"logged in" in detail or "authenticated" in detail
|
||||
):
|
||||
return True
|
||||
except (OSError, subprocess.SubprocessError):
|
||||
pass
|
||||
return False
|
||||
|
||||
|
||||
def discover_codex_models() -> Catalog:
|
||||
"""Use the authenticated Codex endpoint; catalogs are status-only fallback."""
|
||||
token = ""
|
||||
@ -288,6 +312,20 @@ def discover_codex_models() -> Catalog:
|
||||
known = _unique_models(provider_model_ids("openai-codex", force_refresh=True))
|
||||
except Exception:
|
||||
known = []
|
||||
# The owner agent deliberately uses the local Codex app-server and the
|
||||
# Codex CLI's ChatGPT login. That credential is not exported into Hermes'
|
||||
# bearer-token store, so API discovery above may be empty even though the
|
||||
# runtime is fully authenticated. Treat a successful CLI status check as a
|
||||
# connected, degraded catalog: routing may use Codex while retaining the
|
||||
# last-known working model names until app-server discovery is available.
|
||||
if codex_cli_authenticated():
|
||||
return Catalog(
|
||||
"openai-codex",
|
||||
known,
|
||||
False,
|
||||
True,
|
||||
"connected-cli",
|
||||
)
|
||||
state = "degraded" if token else "not-configured"
|
||||
return Catalog("openai-codex", known, False, bool(token), state)
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ from __future__ import annotations
|
||||
|
||||
import importlib.util
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
@ -64,6 +65,23 @@ def test_empty_catalog_retains_current_models():
|
||||
assert routing.choose_claude_model([], "claude-opus-5") == "claude-opus-5"
|
||||
|
||||
|
||||
def test_codex_cli_login_counts_as_connected_runtime(monkeypatch):
|
||||
"""AUTO routing must recognize the authenticated app-server CLI lane."""
|
||||
monkeypatch.setattr(routing.shutil, "which", lambda name: "/usr/bin/codex")
|
||||
monkeypatch.setattr(
|
||||
routing.subprocess,
|
||||
"run",
|
||||
lambda *args, **kwargs: subprocess.CompletedProcess(
|
||||
args[0],
|
||||
0,
|
||||
stdout="Logged in using ChatGPT\n",
|
||||
stderr="",
|
||||
),
|
||||
)
|
||||
|
||||
assert routing.codex_cli_authenticated() is True
|
||||
|
||||
|
||||
def test_configure_routes_builds_cross_provider_fallback_profiles(tmp_path: Path):
|
||||
(tmp_path / "config.yaml").write_text(
|
||||
yaml.safe_dump(_base_config()), encoding="utf-8"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user