import { execFileSync } from 'node:child_process' import { describe, it } from 'vitest' describe('Hermes clarify bridge compatibility', () => { it('supports legacy callbacks, batches, multi-select, timeouts, and worker entrypoints', () => { const script = String.raw` import importlib.util, json, queue, sys, threading from pathlib import Path root = Path('packages/server/src/services/hermes/agent-bridge/compat').resolve() sys.path.insert(0, str(root)) from clarify_compat import make_clarify_callback class Pool: def __init__(self, replies): self._lock = threading.RLock() self._clarify_requests = {} self.events = [] self.replies = iter(replies) def _append_event(self, session, event): self.events.append((session, event)) self._clarify_requests[event['clarify_id']].put_nowait(next(self.replies)) pool = Pool(['first', json.dumps(['A', 'Other']), '']) callback = make_clarify_callback(pool, 'session-1', lambda q, c: f'legacy:{q}:{c[0]}') assert callback('old question', ['old choice']) == 'legacy:old question:old choice' result = callback([ {'qid': 'q0', 'question': 'First?', 'choices': ['first', 'second']}, {'qid': 'q1', 'question': 'Pick several', 'choices': ['A', 'B'], 'multi_select': True}, {'qid': 'q2', 'question': 'Optional question'}, ]) assert result == {'answers': {'q0': 'first', 'q1': '["A", "Other"]', 'q2': None}, 'outcome': 'submitted'} assert [event['question'] for _, event in pool.events] == ['First?', 'Pick several', 'Optional question'] assert [event['multi_select'] for _, event in pool.events] == [False, True, False] assert not pool._clarify_requests class TimeoutQueue: def __init__(self, maxsize): pass def get(self, timeout): raise queue.Empty() pool = Pool([]) pool._append_event = lambda session, event: None import clarify_compat clarify_compat.queue.Queue = TimeoutQueue assert make_clarify_callback(pool, 's', lambda *a: None)([{'qid': 'q0', 'question': 'timeout'}]) == {'answers': {}, 'outcome': 'timed_out'} assert not pool._clarify_requests spec = importlib.util.spec_from_file_location('compat_entry', root / 'hermes_bridge.py') entry = importlib.util.module_from_spec(spec) spec.loader.exec_module(entry) assert Path(entry.bridge._transport.__file__).resolve() == root / 'hermes_bridge.py' assert entry.bridge.AgentPool._clarify_callback is entry.clarify_callback ` execFileSync('python3', ['-c', script], { cwd: process.cwd(), encoding: 'utf8', stdio: 'pipe' }) }) it('starts a broker and profile worker through the compatibility entrypoint', () => { const script = String.raw` import json, os, socket, subprocess, sys, tempfile, time from pathlib import Path entry = Path('packages/server/src/services/hermes/agent-bridge/compat/hermes_bridge.py').resolve() with tempfile.TemporaryDirectory(prefix='clarify-bridge-test-') as temp: root = Path(temp) (root / 'run_agent.py').write_text('') endpoint = 'ipc://' + str(root / 'broker.sock') env = dict(os.environ, HERMES_HOME=str(root / 'home'), HERMES_AGENT_ROOT=str(root), PYTHONDONTWRITEBYTECODE='1') proc = subprocess.Popen([sys.executable, str(entry), '--endpoint', endpoint, '--agent-root', str(root), '--hermes-home', str(root / 'home')], env=env, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) try: deadline = time.monotonic() + 15 while not (root / 'broker.sock').exists(): if proc.poll() is not None or time.monotonic() > deadline: raise RuntimeError('compatibility broker failed to start') time.sleep(0.05) with socket.socket(socket.AF_UNIX) as client: client.settimeout(20) client.connect(str(root / 'broker.sock')) client.sendall(b'{"action":"worker_ping","profile":"default"}\n') with client.makefile('rb') as response: result = json.loads(response.readline()) assert result.get('ok') and result.get('pong') and result.get('worker_profile') == 'default', result finally: proc.terminate() try: proc.wait(timeout=10) except subprocess.TimeoutExpired: proc.kill() proc.wait(timeout=5) ` execFileSync('python3', ['-c', script], { cwd: process.cwd(), encoding: 'utf8', stdio: 'pipe', timeout: 30_000 }) }) })