feat(plugins): add inject_message interface for remote message injection (#3778)
This commit is contained in:
5
cli.py
5
cli.py
@@ -6210,6 +6210,11 @@ class HermesCLI:
|
|||||||
self._interrupt_queue = queue.Queue() # For messages typed while agent is running
|
self._interrupt_queue = queue.Queue() # For messages typed while agent is running
|
||||||
self._should_exit = False
|
self._should_exit = False
|
||||||
self._last_ctrl_c_time = 0 # Track double Ctrl+C for force exit
|
self._last_ctrl_c_time = 0 # Track double Ctrl+C for force exit
|
||||||
|
|
||||||
|
# Give plugin manager a CLI reference so plugins can inject messages
|
||||||
|
from hermes_cli.plugins import get_plugin_manager
|
||||||
|
get_plugin_manager()._cli_ref = self
|
||||||
|
|
||||||
# Config file watcher — detect mcp_servers changes and auto-reload
|
# Config file watcher — detect mcp_servers changes and auto-reload
|
||||||
from hermes_cli.config import get_config_path as _get_config_path
|
from hermes_cli.config import get_config_path as _get_config_path
|
||||||
_cfg_path = _get_config_path()
|
_cfg_path = _get_config_path()
|
||||||
|
|||||||
@@ -152,6 +152,34 @@ class PluginContext:
|
|||||||
self._manager._plugin_tool_names.add(name)
|
self._manager._plugin_tool_names.add(name)
|
||||||
logger.debug("Plugin %s registered tool: %s", self.manifest.name, name)
|
logger.debug("Plugin %s registered tool: %s", self.manifest.name, name)
|
||||||
|
|
||||||
|
# -- message injection --------------------------------------------------
|
||||||
|
|
||||||
|
def inject_message(self, content: str, role: str = "user") -> bool:
|
||||||
|
"""Inject a message into the active conversation.
|
||||||
|
|
||||||
|
If the agent is idle (waiting for user input), this starts a new turn.
|
||||||
|
If the agent is running, this interrupts and injects the message.
|
||||||
|
|
||||||
|
This enables plugins (e.g. remote control viewers, messaging bridges)
|
||||||
|
to send messages into the conversation from external sources.
|
||||||
|
|
||||||
|
Returns True if the message was queued successfully.
|
||||||
|
"""
|
||||||
|
cli = self._manager._cli_ref
|
||||||
|
if cli is None:
|
||||||
|
logger.warning("inject_message: no CLI reference (not available in gateway mode)")
|
||||||
|
return False
|
||||||
|
|
||||||
|
msg = content if role == "user" else f"[{role}] {content}"
|
||||||
|
|
||||||
|
if getattr(cli, "_agent_running", False):
|
||||||
|
# Agent is mid-turn — interrupt with the message
|
||||||
|
cli._interrupt_queue.put(msg)
|
||||||
|
else:
|
||||||
|
# Agent is idle — queue as next input
|
||||||
|
cli._pending_input.put(msg)
|
||||||
|
return True
|
||||||
|
|
||||||
# -- hook registration --------------------------------------------------
|
# -- hook registration --------------------------------------------------
|
||||||
|
|
||||||
def register_hook(self, hook_name: str, callback: Callable) -> None:
|
def register_hook(self, hook_name: str, callback: Callable) -> None:
|
||||||
@@ -184,6 +212,7 @@ class PluginManager:
|
|||||||
self._hooks: Dict[str, List[Callable]] = {}
|
self._hooks: Dict[str, List[Callable]] = {}
|
||||||
self._plugin_tool_names: Set[str] = set()
|
self._plugin_tool_names: Set[str] = set()
|
||||||
self._discovered: bool = False
|
self._discovered: bool = False
|
||||||
|
self._cli_ref = None # Set by CLI after plugin discovery
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
# Public
|
# Public
|
||||||
|
|||||||
Reference in New Issue
Block a user