"""Gateway slash-command routing for Telegram and other headless surfaces.""" from __future__ import annotations import io import logging from typing import Any from unittest.mock import MagicMock import pytest from rich.console import Console from core.agent_harness.session import SessionCore from core.agent_harness.session.persistence.memory import InMemorySessionStorage from core.agent_harness.tools.action_tools import get_action_tool from gateway.turn_handler import GatewayTurnHandler from tests.core.agent.orchestration.cross_surface_parity_harness import RecordingGatewaySink def _gateway_console() -> Console: return Console(file=io.StringIO(), force_terminal=False, highlight=False, width=100) def _run_gateway_slash(message: str) -> RecordingGatewaySink: session = SessionCore(storage=InMemorySessionStorage()) sink = RecordingGatewaySink() handler = GatewayTurnHandler(console=_gateway_console()) handler(message, session, sink, logging.getLogger("test.gateway.slash")) return sink def test_gateway_registers_slash_invoke_tool() -> None: """Harness adapters wired at gateway boot must expose slash_invoke to action turns.""" slash = get_action_tool("slash_invoke") assert slash is not None assert slash.name == "slash_invoke" def test_gateway_status_slash_is_not_swallowed() -> None: """Literal /status must route through slash_invoke and return session diagnostics.""" sink = _run_gateway_slash("/status") assert sink.finalized is not None assert "I didn't have anything to add for that." not in sink.finalized assert "interactions" in sink.finalized.lower() def test_gateway_investigate_slash_dispatches(monkeypatch: pytest.MonkeyPatch) -> None: """Literal /investigate