mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-11-06 05:17:15 +00:00
The messaging gateway already owns /plan /learn /init /initiate-setup /moa /blueprint /egress (idle-path ``_hm_cmd_<name>`` turn rewrites) and /goal /subgoal /loop /heartbeat /review /refine /debug (``_command_handler_table``). A local session is a real gateway session (Platform.LOCAL, LOCAL adapter), so slash.exec now admits them and runs those same handlers, under the session's profile scope and cwd, instead of refusing them (``unsupported_command``). What a handler would have SENT outside its return value is captured for the local call (gateway/session_command_sink.py): the ack line (``_send_command_ack``) and a next turn pushed onto the adapter FIFO (/goal's kickoff, ``_enqueue_goal_turn``). Both come back as one ``send`` directive (notice + message + display) that the client submits with its own durable input id -- the existing prompt-directive rule; the gateway never admits it itself. /curator had no gateway handler: ``_handle_curator_command`` runs main's ``hermes curator`` handler set (status by default) in the executor and returns its printed report. A /loop wake on a LOCAL route now commits through local_automation_v1 on the live session's source (the messaging branch borrows a committed native envelope a local route never has), as heartbeats already did. Red: tests/gateway/test_session_authoring_commands.py (real daemon, loopback model) answered ``unsupported_command`` for /plan on the PR head.
38 lines
1.2 KiB
Python
38 lines
1.2 KiB
Python
"""What a messaging command handler would have SENT, captured for a local ``slash.exec``.
|
|
|
|
The messaging gateway's handlers deliver two things outside their return value: an ack line
|
|
(``_send_command_ack``) and a next turn pushed onto the adapter FIFO (``/goal``'s kickoff,
|
|
``_enqueue_goal_turn``). A local session's adapter has no transport and no FIFO reader: its turns
|
|
are client-submitted admissions with the client's own durable input id. So while ``slash.exec``
|
|
runs a handler for a local session, both are captured here and returned to the client as one
|
|
``send`` directive (``notice`` + ``message``); the client submits it, the gateway never does.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from contextlib import contextmanager
|
|
from contextvars import ContextVar
|
|
from dataclasses import dataclass, field
|
|
|
|
_SINK: ContextVar = ContextVar('local_command_sink', default=None)
|
|
|
|
|
|
@dataclass
|
|
class CommandSink:
|
|
notices: list[str] = field(default_factory=list)
|
|
prompt: str | None = None
|
|
display: str | None = None
|
|
|
|
|
|
def active_sink() -> CommandSink | None:
|
|
return _SINK.get()
|
|
|
|
|
|
@contextmanager
|
|
def capture():
|
|
sink = CommandSink()
|
|
token = _SINK.set(sink)
|
|
try:
|
|
yield sink
|
|
finally:
|
|
_SINK.reset(token)
|