feat(session): add /handoff command for cross-platform session transfer

Adds /handoff <platform> CLI command that queues the current session for
resume on the configured home channel of any messaging platform.

CLI side:
- /handoff telegram — marks session in shared DB, sends summary to
  the Telegram home channel via send_message
- /handoff discord — same for Discord
- Supports telegram, discord, slack, whatsapp, signal, matrix

Gateway side:
- On new session creation, checks for pending handoffs for the
  incoming message's platform
- If found, loads the CLI session's full conversation history and
  injects it into the context prompt as a handoff transcript
- Agent continues the conversation seamlessly

Files:
- hermes_state.py: handoff_pending, handoff_platform columns + helpers
- cli.py: _handle_handoff_command dispatch + handler
- hermes_cli/commands.py: CommandDef entry
- gateway/run.py: handoff detection in _handle_message_with_agent
- tests/hermes_cli/test_session_handoff.py: 8 tests
This commit is contained in:
kshitijk4poor 2026-05-09 23:17:32 +05:30 committed by Teknium
parent 6e5c49bdc4
commit 878611a79d
5 changed files with 294 additions and 0 deletions

View file

@ -6648,6 +6648,46 @@ class GatewayRunner:
# Build the context prompt to inject
context_prompt = build_session_context_prompt(context, redact_pii=_redact_pii)
# Check for pending CLI handoff
if _is_new_session and self._session_db:
try:
platform_key = source.platform.value if source.platform else ""
handoff = self._session_db.find_pending_handoff(platform_key)
if handoff:
cli_session_id = handoff["id"]
cli_messages = self._session_db.get_messages(cli_session_id)
if cli_messages:
# Cap to last 200 messages to avoid context blowup
cli_messages = cli_messages[-200:]
transcript = []
for msg in cli_messages:
role = msg.get("role", "unknown")
content = str(msg.get("content") or "")
if content.strip():
label = {"user": "User", "assistant": "Assistant",
"system": "System", "tool": "Tool"}.get(role, role.title())
transcript.append(f"{label}: {content}")
if transcript:
handoff_title = handoff.get("title") or "untitled"
handoff_context = (
f"[Handoff from CLI session '{handoff_title}'. "
f"Continue the conversation below where it left off.]"
)
context_prompt = (
handoff_context
+ "\n\n--- Previous conversation ---\n"
+ "\n\n".join(transcript)
+ "\n--- End of previous conversation ---\n\n"
+ context_prompt
)
self._session_db.clear_handoff_pending(cli_session_id)
logger.info(
"Handoff: CLI session %s handed off to %s chat %s",
cli_session_id, platform_key, source.chat_id,
)
except Exception:
logger.debug("Handoff check failed", exc_info=True)
# If the previous session expired and was auto-reset, prepend a notice
# so the agent knows this is a fresh conversation (not an intentional /reset).