hermes(agent): recognize CLI runtime and shorten restarts
All checks were successful
Tests / Declarative: Post Actions passed: 229

This commit is contained in:
jenkins 2026-08-10 23:28:35 -03:00
parent e277e43633
commit 04bd50ca74
3 changed files with 79 additions and 1 deletions

View File

@ -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

View File

@ -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)

View File

@ -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"