Files
local-rig/tests/test_rig_real_agent.py
hermes-mac13 93758f3720 feat: 从 tutti-selfhost 拆出 local_rig 独立仓
- local_rig/ 完整包(7 源文件 + ui.html + CHANGELOG)
- tests/test_local_rig.py + test_rig_real_agent.py(纯 local_rig 测试)
- scripts/15-criterion4-live.sh(判据④活环境门)
- README.md(定位/快速开始/与 tutti-selfhost 的关系)
- requirements.txt(唯一外部依赖 pyyaml)
- .gitignore

来源: figmar/tutti-selfhost @ 3b23853 (2026-10-06)
原 PR #43 已合入 tutti-selfhost main
2026-10-06 13:36:14 +08:00

100 lines
4.5 KiB
Python

#!/usr/bin/env python3
"""**真 hermes CLI** 的端到端验证(默认跳过;`RIG_REAL=1` 才跑)。
为什么单独一个开关:它会**真调用本机 agent 与模型 API**(有网络/配额成本、耗时数十秒),
所以不进常规 CI。2026-10-05 实测已通过:入队 → 真子进程 → done → result="好的"。
同时钉住两个实测缺口(都曾让链路静默失效):
① `--agent` 不存在于 hermes CLI ⇒ 拼进去会被 argparse 当子命令名报错;
② 不传 `-m/--model` ⇒ 服务端 `HTTP 400: supported API model names are …, but you passed .`
"""
import os
import shutil
import sys
import tempfile
import time
import unittest
from pathlib import Path
_HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, os.path.dirname(_HERE))
from local_rig.daemon import RigDaemon # noqa: E402
from local_rig.rig_schema import Member # noqa: E402
HERMES_BIN = os.path.expanduser(
"~/Library/Application Support/cn.org.hermesagent.desktop/runtime/desktop-bin/hermes")
YAML = ('version: "0.1"\nname: real\npods:\n - id: dev\n label: D\n members:\n'
' - id: hermes\n runtime: hermes-cli\n target: hermes\n edges: []\n')
def _daemon():
cfg = Path(tempfile.mkdtemp()) / "rig.yaml"
cfg.write_text(YAML, encoding="utf-8")
return RigDaemon(cfg, db_path=str(Path(tempfile.mkdtemp()) / "q.db"))
class TestModelFlagIsPlumbed(unittest.TestCase):
"""静态可验的部分(不需要真跑):model 字段存在、命令里带 -m、不再带 --agent。"""
def test_member_has_model_default(self):
self.assertEqual(Member(id="x", runtime="hermes-cli", target="t").model, "deepseek-flash")
def test_yaml_can_override_model(self):
from local_rig.rig_schema import parse_rig
cfg = Path(tempfile.mkdtemp()) / "r.yaml"
cfg.write_text(YAML.replace("target: hermes\n", "target: hermes\n model: deepseek-v4-pro\n"),
encoding="utf-8")
rig = parse_rig(cfg)
self.assertEqual(rig.all_members()["dev.hermes"].model, "deepseek-v4-pro")
def test_no_bogus_agent_flag_in_sources(self):
for f in ("local_rig/daemon.py", "local_rig/runtime_hermes.py"):
src = Path(_HERE).parent.joinpath(f).read_text(encoding="utf-8")
code = "\n".join(l for l in src.splitlines() if not l.strip().startswith("#"))
self.assertNotIn('"--agent"', code, f"{f}: 仍把 --agent 传给 hermes CLI(它没有这个全局参数)")
@unittest.skipUnless(os.environ.get("RIG_REAL") == "1", "设 RIG_REAL=1 才真调 agent")
@unittest.skipUnless(shutil.which("hermes") or Path(HERMES_BIN).exists(), "本机没有 hermes CLI")
class TestRealAgentEndToEnd(unittest.TestCase):
def test_real_agent_answers_and_result_flows_to_bridge_event(self):
d = _daemon()
if not shutil.which("hermes"):
d.hermes_rt.hermes_bin = HERMES_BIN
d.enqueue("hermes", "只回两个字:好的", task_id="real-e2e", idem_key="idem-real-e2e")
row = None
for _ in range(60):
time.sleep(2)
row = d.queue.get("real-e2e")
if row and row.status in ("done", "failed"):
break
self.assertIsNotNone(row)
self.assertEqual(row.status, "done", f"真执行未达终态: {row.error}")
self.assertTrue((row.result or "").strip(), "真 agent 应有非空产出")
self.assertNotIn("HTTP 400", row.result or "", "不该再把模型名传错")
from bridge.rig import RigResultSource
import json
class _Local:
def __call__(self, req, timeout=None):
tk = d.queue.get(req.full_url.rsplit("/", 1)[-1])
class R:
def __enter__(self): return self
def __exit__(self, *a): return False
def read(self):
return json.dumps({"id": tk.id, "status": tk.status,
"result": tk.result, "error": tk.error}).encode()
return R()
s = RigResultSource(); s._open = _Local()
s.watch({"task_id": "real-e2e", "rig_task_id": "real-e2e"})
evs = s.poll()
self.assertEqual([e.contract_status for e in evs], ["succeeded"], "真产出应经接通件变成 succeeded 事件")
self.assertTrue(evs[0].summary.strip(), "事件里要带上 agent 的真实文本,房间才有内容可看")
if __name__ == "__main__":
unittest.main()