269 lines
12 KiB
Python
269 lines
12 KiB
Python
"""Hermes chat voice contracts."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from test_hermes_chat_support import (
|
|
HERMES,
|
|
ROOT,
|
|
SimpleNamespace,
|
|
VAULT,
|
|
_documents,
|
|
importlib,
|
|
sys,
|
|
yaml,
|
|
)
|
|
|
|
|
|
def test_webui_recovers_auth_and_labels_session_scoped_controls():
|
|
dockerfile = (ROOT / "dockerfiles" / "Dockerfile.hermes-webui").read_text()
|
|
|
|
assert "res.status===401||res.status===403" in dockerfile
|
|
assert "window.location.assign('/oauth2/start?rd='" in dockerfile
|
|
assert "childrenExpanded?'▾ ':'▸ '" in dockerfile
|
|
assert "'atlas/auto/maximum': 'Automatic · Maximum'" in dockerfile
|
|
assert "hermes-webui-telegram-project-patch.py" in dockerfile
|
|
telegram_project_patch = (
|
|
ROOT / "dockerfiles" / "hermes-webui-telegram-project-patch.py"
|
|
).read_text()
|
|
assert "TELEGRAM_PROJECT_NAME = 'Telegram'" in telegram_project_patch
|
|
assert "session_key.startswith('telegram-topic-')" in telegram_project_patch
|
|
|
|
router = (ROOT / "dockerfiles" / "hermes-webui-router.js").read_text()
|
|
assert "'atlas/auto/fast':'AUTO · Fast'" in router
|
|
assert "'atlas/manual/codex/sol':'Codex · SOL'" in router
|
|
assert "'atlas/manual/claude/opus':'Claude · Opus'" in router
|
|
assert "watchModelOptions('modelSelect')" in router
|
|
assert "watchModelOptions('settingsModel')" in router
|
|
|
|
def test_chat_voice_uses_private_jetson_services_and_shared_auto_route():
|
|
statefulset = _documents(HERMES / "chat-statefulset.yaml")[0]
|
|
containers = statefulset["spec"]["template"]["spec"]["containers"]
|
|
webui = next(item for item in containers if item["name"] == "webui")
|
|
env = {item["name"]: item["value"] for item in webui["env"]}
|
|
|
|
assert env["HERMES_STT_URL"] == (
|
|
"http://hermes-stt.hermes.svc.cluster.local:9000/v1/audio/transcriptions"
|
|
)
|
|
assert env["HERMES_WEBUI_ATLAS_TTS_URL"] == (
|
|
"http://hermes-tts.hermes.svc.cluster.local:9001/v1/audio/speech"
|
|
)
|
|
assert "hermes_stt_client.py" in env["HERMES_LOCAL_STT_COMMAND"]
|
|
|
|
configmap = _documents(HERMES / "chat-configmap.yaml")[0]
|
|
config = yaml.safe_load(configmap["data"]["config.yaml"])
|
|
assert config["stt"] == {
|
|
"enabled": True,
|
|
"provider": "local_command",
|
|
"local": {"model": "small", "language": "auto"},
|
|
}
|
|
|
|
dockerfile = (ROOT / "dockerfiles" / "Dockerfile.hermes-webui").read_text()
|
|
assert "hermes-webui-atlas-patch.py" in dockerfile
|
|
assert "hermes-webui-atlas-voice.js" in dockerfile
|
|
voice_script = (ROOT / "dockerfiles" / "hermes-webui-atlas-voice.js").read_text()
|
|
assert "/api/transcribe/capability" in voice_script
|
|
assert "/api/transcribe" in voice_script
|
|
assert "/api/tts" in voice_script
|
|
assert "speakResponse(generation)" in voice_script
|
|
assert "window._splitForTTS(text,280)" in voice_script
|
|
assert "pending=fetchSpeech(chunks[index+1])" in voice_script
|
|
assert "restartSoon(token,450)" in voice_script
|
|
assert "constraints.voiceIsolation=true" in voice_script
|
|
assert "highpass.frequency.value=140" in voice_script
|
|
assert "Math.max(0.04,noiseFloor*2.4+0.006)" in voice_script
|
|
assert "while(preRoll.length>3) preRoll.shift()" in voice_script
|
|
|
|
stt_server = (ROOT / "dockerfiles" / "hermes-jetson-stt-server.py").read_text()
|
|
assert "def _repetitive_token" in stt_server
|
|
assert "compression_ratio_threshold=2.0" in stt_server
|
|
assert "no_speech_threshold=0.5" in stt_server
|
|
|
|
def test_voice_transcript_filter_removes_fan_hallucinations(monkeypatch):
|
|
server_path = ROOT / "dockerfiles" / "hermes-jetson-stt-server.py"
|
|
spec = importlib.util.spec_from_file_location("hermes_jetson_stt_server", server_path)
|
|
assert spec and spec.loader
|
|
module = importlib.util.module_from_spec(spec)
|
|
monkeypatch.setitem(sys.modules, "cgi", SimpleNamespace())
|
|
monkeypatch.setitem(
|
|
sys.modules,
|
|
"torch",
|
|
SimpleNamespace(cuda=SimpleNamespace(is_available=lambda: False)),
|
|
)
|
|
monkeypatch.setitem(sys.modules, "whisper", SimpleNamespace())
|
|
spec.loader.exec_module(module)
|
|
|
|
result = {
|
|
"segments": [
|
|
{
|
|
"text": " ththththththththth Testing.",
|
|
"no_speech_prob": 0.12,
|
|
"avg_logprob": -0.2,
|
|
},
|
|
{
|
|
"text": " background hum",
|
|
"no_speech_prob": 0.82,
|
|
"avg_logprob": -0.9,
|
|
},
|
|
]
|
|
}
|
|
|
|
assert module._clean_transcript(result) == "Testing."
|
|
|
|
def test_voice_models_are_baked_and_runtime_has_no_public_egress():
|
|
stt_dockerfile = (ROOT / "dockerfiles" / "Dockerfile.hermes-jetson-stt").read_text()
|
|
tts_dockerfile = (ROOT / "dockerfiles" / "Dockerfile.hermes-jetson-tts").read_text()
|
|
assert "ADD --checksum=sha256:aff26ae4" in stt_dockerfile
|
|
assert "ADD --checksum=sha256:9ecf7799" in stt_dockerfile
|
|
assert "--chmod=0444" in stt_dockerfile
|
|
assert "chmod 0555 /opt/models /opt/models/whisper" in stt_dockerfile
|
|
assert "HERMES_STT_CACHE=/opt/models/whisper" in stt_dockerfile
|
|
assert "ADD --checksum=sha256:4cabf7c3" in tts_dockerfile
|
|
assert "ADD --checksum=sha256:db42b97d" in tts_dockerfile
|
|
assert tts_dockerfile.count("--chmod=0444") == 6
|
|
assert "chmod 0555 /opt/models /opt/models/piper" in tts_dockerfile
|
|
assert "HERMES_TTS_CACHE=/opt/models/piper" in tts_dockerfile
|
|
tts_server = (ROOT / "dockerfiles" / "hermes-jetson-tts-server.py").read_text()
|
|
assert "download_voice" not in tts_server
|
|
assert "baked Piper voice is missing" in tts_server
|
|
assert "session_options.intra_op_num_threads = ONNX_THREADS" in tts_server
|
|
|
|
policies = _documents(HERMES / "networkpolicy.yaml")
|
|
voice_policy = next(
|
|
item for item in policies if item["metadata"]["name"] == "hermes-private-voice"
|
|
)
|
|
assert voice_policy["spec"]["policyTypes"] == ["Ingress", "Egress"]
|
|
assert not any(
|
|
"ipBlock" in destination
|
|
for rule in voice_policy["spec"]["egress"]
|
|
for destination in rule.get("to", [])
|
|
)
|
|
|
|
def test_voice_workloads_have_deliberate_xavier_placement():
|
|
documents = _documents(HERMES / "voice-deployment.yaml")
|
|
deployments = {
|
|
item["metadata"]["name"]: item
|
|
for item in documents
|
|
if item["kind"] == "Deployment"
|
|
}
|
|
stt = deployments["hermes-stt"]["spec"]["template"]["spec"]
|
|
tts = deployments["hermes-tts"]["spec"]["template"]["spec"]
|
|
|
|
assert "@sha256:" in stt["containers"][0]["image"]
|
|
assert "@sha256:" in tts["containers"][0]["image"]
|
|
assert stt["nodeSelector"] == {"kubernetes.io/hostname": "titan-21"}
|
|
assert tts["nodeSelector"] == {"kubernetes.io/hostname": "titan-21"}
|
|
assert stt["automountServiceAccountToken"] is False
|
|
assert tts["automountServiceAccountToken"] is False
|
|
assert stt["enableServiceLinks"] is False
|
|
assert tts["enableServiceLinks"] is False
|
|
assert stt["runtimeClassName"] == "nvidia"
|
|
assert stt["securityContext"]["supplementalGroups"] == [44]
|
|
stt_resources = stt["containers"][0]["resources"]
|
|
stt_env = {
|
|
item["name"]: item["value"] for item in stt["containers"][0]["env"]
|
|
}
|
|
assert stt_env["NVIDIA_DRIVER_CAPABILITIES"] == "compute,utility"
|
|
assert stt_resources["requests"]["nvidia.com/gpu.shared"] == 1
|
|
assert stt_resources["limits"]["nvidia.com/gpu.shared"] == 1
|
|
assert "nvidia.com/gpu.shared" not in tts["containers"][0]["resources"]["requests"]
|
|
tts_env = {
|
|
item["name"]: item["value"] for item in tts["containers"][0]["env"]
|
|
}
|
|
assert tts_env["HERMES_TTS_VOICE"] == "en_US-lessac-medium"
|
|
assert tts_env["HERMES_TTS_ONNX_THREADS"] == "2"
|
|
assert tts["containers"][0]["resources"]["limits"]["cpu"] == "4"
|
|
assert all("hostPath" not in volume for volume in stt["volumes"])
|
|
assert all("hostPath" not in volume for volume in tts["volumes"])
|
|
|
|
def test_chat_image_generation_uses_private_owner_broker():
|
|
"""Family pods get image bytes without receiving the owner's OAuth file."""
|
|
configmap = _documents(HERMES / "chat-configmap.yaml")[0]
|
|
assert "shared desktop/Wolf lane" in configmap["data"]["SOUL.md"]
|
|
assert "local FLUX waits" in configmap["data"]["SOUL.md"]
|
|
assert "Use `image_generate_local`" in configmap["data"]["SOUL.md"]
|
|
assert "Use `image_generate_hosted`" in configmap["data"]["SOUL.md"]
|
|
assert "ComfyUI endpoint" in configmap["data"]["SOUL.md"]
|
|
assert "`MEDIA:` path" in configmap["data"]["SOUL.md"]
|
|
assert "`image_edit_latest`" in configmap["data"]["SOUL.md"]
|
|
assert "Preserve the most recently selected image lane" in configmap["data"]["SOUL.md"]
|
|
config = yaml.safe_load(configmap["data"]["config.yaml"])
|
|
assert config["image_gen"] == {
|
|
"provider": "atlas-broker",
|
|
"model": "atlas-image-auto-high",
|
|
}
|
|
assert config["plugins"]["enabled"] == ["atlas-broker", "auto-router"]
|
|
|
|
statefulset = _documents(HERMES / "chat-statefulset.yaml")[0]
|
|
pod = statefulset["spec"]["template"]["spec"]
|
|
hermes = next(item for item in pod["containers"] if item["name"] == "hermes")
|
|
mounts = {item["name"]: item for item in hermes["volumeMounts"]}
|
|
assert mounts["image-plugin"]["mountPath"] == (
|
|
"/opt/hermes/plugins/image_gen/atlas-broker"
|
|
)
|
|
assert mounts["runtime-access"]["mountPath"] == "/runtime-access"
|
|
assert "provider-auth" not in mounts
|
|
assert not any(mount["name"] == "home" and "agent" in str(mount) for mount in hermes["volumeMounts"])
|
|
env = {item["name"]: item["value"] for item in hermes["env"]}
|
|
assert env["HERMES_IMAGE_BROKER_URL"].startswith("http://hermes-image-broker.")
|
|
|
|
plugin = (HERMES / "plugins" / "image-gen-broker" / "__init__.py").read_text()
|
|
assert '"local": "flux-2-klein-4b-local"' in plugin
|
|
assert '"hosted": "gpt-image-2-high"' in plugin
|
|
assert 'name="image_generate_local"' in plugin
|
|
assert 'name="image_generate_hosted"' in plugin
|
|
assert '"name": "image_edit_latest"' in plugin
|
|
assert '"name": "image_edit_latest_local"' in plugin
|
|
assert '"name": "image_edit_latest_hosted"' in plugin
|
|
assert "def _latest_generated_image" in plugin
|
|
assert "newest MEDIA: path from the conversation" in plugin
|
|
assert 'candidate.upper().startswith("MEDIA:")' in plugin
|
|
assert "override=True" not in plugin
|
|
|
|
agent = _documents(HERMES / "agent-deployment.yaml")[0]
|
|
containers = agent["spec"]["template"]["spec"]["containers"]
|
|
broker = next(item for item in containers if item["name"] == "image-broker")
|
|
assert broker["ports"] == [
|
|
{"name": "image-broker", "containerPort": 9002, "protocol": "TCP"}
|
|
]
|
|
assert broker["securityContext"]["readOnlyRootFilesystem"] is True
|
|
assert broker["securityContext"]["runAsNonRoot"] is True
|
|
|
|
services = _documents(HERMES / "service.yaml")
|
|
service = next(
|
|
item for item in services if item["metadata"]["name"] == "hermes-image-broker"
|
|
)
|
|
assert service["spec"]["selector"] == {"app": "hermes-agent"}
|
|
|
|
oauth_store = _documents(HERMES / "oauth-session-store.yaml")
|
|
redis = next(item for item in oauth_store if item["kind"] == "Deployment")
|
|
assert redis["spec"]["strategy"]["type"] == "Recreate"
|
|
assert "--appendonly" in redis["spec"]["template"]["spec"]["containers"][0]["args"]
|
|
|
|
policies = _documents(HERMES / "networkpolicy.yaml")
|
|
agent_policy = next(
|
|
item for item in policies if item["metadata"]["name"] == "hermes-agent-isolation"
|
|
)
|
|
broker_ingress = next(
|
|
rule
|
|
for rule in agent_policy["spec"]["ingress"]
|
|
if {port["port"] for port in rule["ports"]} == {9002, 9003}
|
|
)
|
|
assert broker_ingress["from"][0]["podSelector"]["matchLabels"] == {
|
|
"app": "hermes-chat-tenant"
|
|
}
|
|
vault_policy = (VAULT / "scripts" / "vault_k8s_auth_configure.sh").read_text()
|
|
assert (
|
|
'"hermes/agent-oidc hermes/agent-tokens hermes/chat-telegram '
|
|
'hermes/developer-keycloak hermes/developer-harbor hermes/developer-jenkins '
|
|
'hermes/developer-ssh"'
|
|
in vault_policy
|
|
)
|
|
assert (
|
|
'write_policy_and_role "hermes-scm-broker" "hermes-scm" '
|
|
'"hermes-scm-broker"' in vault_policy
|
|
)
|
|
assert (
|
|
'write_policy_and_role "hermes-node-ssh" "hermes" '
|
|
'"hermes-node-ssh-access"' in vault_policy
|
|
)
|