fix(chat): support Hermes clarify batches
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
"""Adapt Hermes batch clarify callbacks to the bridge's per-question UI."""
|
||||
from __future__ import annotations
|
||||
|
||||
import queue
|
||||
import uuid
|
||||
|
||||
|
||||
def make_clarify_callback(pool, session_id, legacy_callback):
|
||||
def callback(questions, choices=None):
|
||||
# Older Hermes versions call callback(question, choices) and expect text.
|
||||
if not isinstance(questions, list):
|
||||
return legacy_callback(questions, choices)
|
||||
|
||||
answers = {}
|
||||
for index, item in enumerate(questions):
|
||||
if not isinstance(item, dict):
|
||||
raise ValueError('invalid clarify question')
|
||||
question_id = str(item.get('qid') or f'q{index}')
|
||||
clarify_id = uuid.uuid4().hex
|
||||
response_queue = queue.Queue(maxsize=1)
|
||||
with pool._lock:
|
||||
pool._clarify_requests[clarify_id] = response_queue
|
||||
try:
|
||||
pool._append_event(session_id, {
|
||||
'event': 'clarify.requested',
|
||||
'clarify_id': clarify_id,
|
||||
'question': str(item.get('question') or ''),
|
||||
'choices': item.get('choices') or None,
|
||||
'multi_select': bool(item.get('multi_select')),
|
||||
'timeout_ms': 300_000,
|
||||
})
|
||||
try:
|
||||
response = response_queue.get(timeout=300)
|
||||
except queue.Empty:
|
||||
return {'answers': answers, 'outcome': 'timed_out'}
|
||||
answers[question_id] = response or None
|
||||
finally:
|
||||
with pool._lock:
|
||||
pool._clarify_requests.pop(clarify_id, None)
|
||||
return {'answers': answers, 'outcome': 'submitted'}
|
||||
return callback
|
||||
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Launch the read-only vendored bridge with local compatibility adapters."""
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
compat_dir = Path(__file__).resolve().parent
|
||||
sys.path.insert(0, str(compat_dir))
|
||||
sys.path.insert(0, str(compat_dir.parent / 'python'))
|
||||
|
||||
import hermes_bridge as bridge
|
||||
from clarify_compat import make_clarify_callback
|
||||
|
||||
original_callback = bridge.AgentPool._clarify_callback
|
||||
|
||||
|
||||
def clarify_callback(self, session_id):
|
||||
return make_clarify_callback(self, session_id, original_callback(self, session_id))
|
||||
|
||||
|
||||
bridge.AgentPool._clarify_callback = clarify_callback
|
||||
# Workers must launch this same compatibility entrypoint, not the vendored one.
|
||||
bridge._transport.__file__ = __file__
|
||||
|
||||
if __name__ == '__main__':
|
||||
raise SystemExit(bridge.main())
|
||||
@@ -332,11 +332,11 @@ export function buildAgentBridgeLaunchArgs(command: BridgeCommand, script: strin
|
||||
|
||||
function bridgeScriptPath(): string {
|
||||
const candidates = [
|
||||
// Built server: dist/server/index.js -> dist/server/agent-bridge/python/hermes_bridge.py
|
||||
resolve(__dirname, 'agent-bridge', 'python', 'hermes_bridge.py'),
|
||||
// Built server: dist/server/index.js -> dist/server/agent-bridge/compat/hermes_bridge.py
|
||||
resolve(__dirname, 'agent-bridge', 'compat', 'hermes_bridge.py'),
|
||||
// ts-node/dev source tree.
|
||||
resolve(__dirname, 'services/hermes/agent-bridge/python/hermes_bridge.py'),
|
||||
resolve(process.cwd(), 'packages/server/src/services/hermes/agent-bridge/python/hermes_bridge.py'),
|
||||
resolve(__dirname, 'services/hermes/agent-bridge/compat/hermes_bridge.py'),
|
||||
resolve(process.cwd(), 'packages/server/src/services/hermes/agent-bridge/compat/hermes_bridge.py'),
|
||||
]
|
||||
const found = candidates.find(candidate => existsSync(candidate))
|
||||
if (!found) {
|
||||
|
||||
@@ -1202,6 +1202,7 @@ async function applyBridgeChunkAsync(
|
||||
clarify_id: ev.clarify_id,
|
||||
question: ev.question,
|
||||
choices: Array.isArray(ev.choices) ? ev.choices : null,
|
||||
multi_select: Boolean(ev.multi_select),
|
||||
timeout_ms: ev.timeout_ms,
|
||||
}
|
||||
replaceState(sessionMap, sessionId, 'clarify.requested', payload)
|
||||
|
||||
Reference in New Issue
Block a user