mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-12 03:42:08 +00:00
feat(teams-pipeline): add plugin runtime and operator cli
Third slice of the Microsoft Teams meeting pipeline stack, salvaged onto current main. Adds the standalone teams_pipeline plugin that consumes Graph change notifications from the webhook listener, resolves meeting artifacts (transcript first, recording + STT fallback later), persists job state in a durable store, and exposes an operator CLI for inspection, replay, subscription management, and validation. Design choices follow maintainer review feedback on PR #19815: - Standalone plugin rather than bolted-on core surface (plugins/teams_pipeline/, kind: standalone in plugin.yaml). - Zero new model tools. The agent drives the pipeline by invoking the operator CLI via the terminal tool, guided by the skill that ships with a follow-up PR. - Reuses the existing msgraph_webhook gateway platform for Graph ingress. Pipeline runtime is wired in via bind_gateway_runtime and gated on plugins.enabled so gateways that don't run the plugin boot cleanly. Additions: - plugins/teams_pipeline/: runtime (gateway wiring + config builder), pipeline core, durable SQLite store, subscription maintenance helpers, Graph artifact resolution, operator CLI (list, show, run/replay, fetch dry-run, subscriptions list, subscribe, renew-subscription, delete-subscription, maintain-subscriptions, token-health, validate). - hermes_cli/main.py: second-pass plugin CLI discovery so any standalone plugin registered via ctx.register_cli_command() outside the memory-plugin convention path gets its subcommand wired into argparse without touching core. - gateway/run.py: _teams_pipeline_plugin_enabled() config gate, _wire_teams_pipeline_runtime() binding after adapter setup, and the two runner attributes used by the runtime. Credit to @dlkakbs for the entire plugin implementation.
This commit is contained in:
parent
ea86714cc0
commit
07bbd93337
14 changed files with 3332 additions and 1 deletions
|
|
@ -847,6 +847,15 @@ def _platform_config_key(platform: "Platform") -> str:
|
|||
return "cli" if platform == Platform.LOCAL else platform.value
|
||||
|
||||
|
||||
def _teams_pipeline_plugin_enabled() -> bool:
|
||||
"""Return True when the standalone Teams pipeline plugin is enabled."""
|
||||
config = _load_gateway_config()
|
||||
enabled = cfg_get(config, "plugins", "enabled", default=[])
|
||||
if not isinstance(enabled, list):
|
||||
return False
|
||||
return "teams_pipeline" in enabled or "teams-pipeline" in enabled
|
||||
|
||||
|
||||
def _load_gateway_config() -> dict:
|
||||
"""Load and parse ~/.hermes/config.yaml, returning {} on any error.
|
||||
|
||||
|
|
@ -1154,6 +1163,9 @@ class GatewayRunner:
|
|||
# Per-session reasoning effort overrides from /reasoning.
|
||||
# Key: session_key, Value: parsed reasoning config dict.
|
||||
self._session_reasoning_overrides: Dict[str, Dict[str, Any]] = {}
|
||||
# Teams meeting pipeline runtime (bound later when msgraph_webhook adapter exists).
|
||||
self._teams_pipeline_runtime = None
|
||||
self._teams_pipeline_runtime_error: Optional[str] = None
|
||||
# Track pending exec approvals per session
|
||||
# Key: session_key, Value: {"command": str, "pattern_key": str, ...}
|
||||
self._pending_approvals: Dict[str, Dict[str, Any]] = {}
|
||||
|
|
@ -1251,6 +1263,37 @@ class GatewayRunner:
|
|||
self._background_tasks: set = set()
|
||||
|
||||
|
||||
def _wire_teams_pipeline_runtime(self) -> None:
|
||||
"""Bind the Teams meeting pipeline runtime to Graph webhook ingress.
|
||||
|
||||
No-op when the msgraph_webhook adapter isn't running or the
|
||||
teams_pipeline plugin isn't enabled — lets the gateway start cleanly
|
||||
whether or not the user has opted into the pipeline.
|
||||
"""
|
||||
if Platform.MSGRAPH_WEBHOOK not in self.adapters:
|
||||
return
|
||||
if not _teams_pipeline_plugin_enabled():
|
||||
logger.debug("Teams pipeline plugin is disabled; skipping runtime wiring")
|
||||
return
|
||||
try:
|
||||
from plugins.teams_pipeline.runtime import bind_gateway_runtime
|
||||
except Exception as exc:
|
||||
logger.warning("Teams pipeline runtime import failed: %s", exc)
|
||||
return
|
||||
try:
|
||||
bound = bind_gateway_runtime(self)
|
||||
except Exception as exc:
|
||||
logger.warning("Teams pipeline runtime wiring failed: %s", exc)
|
||||
return
|
||||
if bound:
|
||||
logger.info("Teams pipeline runtime bound to msgraph webhook ingress")
|
||||
elif self._teams_pipeline_runtime_error:
|
||||
logger.warning(
|
||||
"Teams pipeline runtime unavailable: %s",
|
||||
self._teams_pipeline_runtime_error,
|
||||
)
|
||||
|
||||
|
||||
def _warn_if_docker_media_delivery_is_risky(self) -> None:
|
||||
"""Warn when Docker-backed gateways lack an explicit export mount.
|
||||
|
||||
|
|
@ -3304,7 +3347,8 @@ class GatewayRunner:
|
|||
|
||||
# Update delivery router with adapters
|
||||
self.delivery_router.adapters = self.adapters
|
||||
|
||||
self._wire_teams_pipeline_runtime()
|
||||
|
||||
self._running = True
|
||||
self._update_runtime_status("running")
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue