#!/usr/bin/env python3 """ Hermes API 调用测试 — 验证 daemon 到 hermes OpenAI-compatible API 的 HTTP 链路。 在 Ubuntu proot 或 Termux 环境内执行。 """ import subprocess, json, sys, os, time, urllib.request, urllib.error CONFIG_PATH = "config.json" REPORT = {"test": "hermes_api", "steps": {}, "overall": None} def log_step(name, ok, detail=""): status = "[OK]" if ok else "[FAIL]" print(f" {status} {name}") if detail: print(f" {detail}") REPORT["steps"][name] = {"ok": ok, "detail": detail} return ok def call_hermes_api(api_url, message, session_id, timeout=60): """Call hermes OpenAI-compatible API and parse SSE response.""" payload = json.dumps({ "model": "hermes-agent", "messages": [ {"role": "user", "content": message} ], "stream": True, "session_id": session_id }).encode("utf-8") req = urllib.request.Request( api_url, data=payload, headers={"Content-Type": "application/json", "Accept": "text/event-stream"}, method="POST" ) try: full_reply = [] with urllib.request.urlopen(req, timeout=timeout) as resp: buffer = "" for chunk in resp: chunk_str = chunk.decode("utf-8", errors="replace") buffer += chunk_str while "\n\n" in buffer: block, buffer = buffer.split("\n\n", 1) data_str = None for line in block.strip().split("\n"): if line.startswith("data:"): data_str = line[5:].strip() if data_str: if data_str == "[DONE]": break try: obj = json.loads(data_str) delta = obj.get("choices", [{}])[0].get("delta", {}) content = delta.get("content", "") if content: full_reply.append(content) except json.JSONDecodeError: pass return True, "".join(full_reply) except urllib.error.URLError as e: return False, f"URLError: {e}" except Exception as e: return False, str(e) def main(): print("=" * 60) print("Hermes API 调用测试 (OpenAI-compatible)") print("=" * 60) config = {} if os.path.exists(CONFIG_PATH): with open(CONFIG_PATH) as f: config = json.load(f) all_ok = True hermes_cfg = config.get("hermes", {}) api_url = hermes_cfg.get("api_url", "http://localhost:8642/v1/chat/completions") timeout = hermes_cfg.get("timeout_sec", 60) # Step 1: Check hermes server is reachable print("\n[Step 1] 检查 hermes 服务可达性") try: health_url = api_url.replace("/v1/chat/completions", "/health") req = urllib.request.Request(health_url, method="GET") with urllib.request.urlopen(req, timeout=5) as resp: health_ok = resp.status == 200 body = resp.read().decode("utf-8", errors="replace")[:100] except Exception as e: health_ok = False body = str(e) all_ok &= log_step("hermes_reachable", health_ok, body) if not health_ok: print("\n [提示] hermes 服务未启动或端口不对。请确认:") print(f" 1. hermes gateway 已启动 (python3 -m gateway.run)") print(f" 2. api_server 已启用 (config.yaml platforms.api_server.enabled=true)") print(f" 3. 监听端口与 {api_url} 一致") save_report() return 1 # Step 2: Send a test message print("\n[Step 2] 发送测试消息到 hermes") test_msg = "你好,这是一个来自 daemon 的测试消息。请回复一句简短的话。" session_id = f"test-{int(time.time())}" print(f" sessionId: {session_id}") print(f" message: {test_msg[:60]}") ok, result = call_hermes_api(api_url, test_msg, session_id, timeout) detail = f"回复: {result[:80]}" if result else f"错误: {result}" all_ok &= log_step("hermes_chat", ok, detail) # Step 3: Context persistence test (same session) if ok and result: print("\n[Step 3] 上下文持久化测试(同一 session)") followup = "刚才你说了什么?请重复一遍。" ok2, result2 = call_hermes_api(api_url, followup, session_id, timeout) has_context = ok2 and result2 and (result[:30] in result2 or "刚才" in result2 or "说了" in result2) all_ok &= log_step("context_persist", has_context, f"回复: {result2[:80] if result2 else 'None'}" if ok2 else f"失败: {result2}") # Summary REPORT["overall"] = "PASS" if all_ok else "FAIL" REPORT["timestamp"] = subprocess.check_output(["date", "-Iseconds"]).decode().strip() save_report() print("\n" + "=" * 60) print(f"结果: {REPORT['overall']}") print("=" * 60) print("\n详细报告: test_report_hermes_api.json") return 0 if all_ok else 1 def save_report(): with open("test_report_hermes_api.json", "w") as f: json.dump(REPORT, f, indent=2, ensure_ascii=False) if __name__ == "__main__": sys.exit(main())