Files
2026-07-13 13:12:33 +08:00

183 lines
5.9 KiB
Python

"""Tests for the /meta gateway slash command (list + run)."""
from __future__ import annotations
import io
from typing import Any
import pytest
from rich.console import Console
from opensquilla.cli.repl.session_state import ChatSessionState
from opensquilla.cli.repl.stream import TurnResult
class _FakeGatewayClient:
"""Records generic RPC ``call`` invocations and returns canned payloads."""
def __init__(self, responses: dict[str, Any] | None = None) -> None:
self.calls: list[tuple[str, dict[str, Any] | None]] = []
self.responses = responses or {}
async def call(self, method: str, params: dict | None = None) -> Any:
self.calls.append((method, params))
return self.responses.get(method, {})
def _make_console() -> tuple[Console, io.StringIO]:
buffer = io.StringIO()
console = Console(file=buffer, force_terminal=False, width=100, highlight=False, no_color=True)
return console, buffer
@pytest.mark.asyncio
async def test_meta_no_arg_lists_skills(monkeypatch: pytest.MonkeyPatch) -> None:
from opensquilla.cli.repl import slash_adapter
from opensquilla.cli.repl.slash_adapter import (
GatewaySlashContext,
handle_gateway_slash_command,
)
console, buffer = _make_console()
monkeypatch.setattr(slash_adapter, "console", console)
client = _FakeGatewayClient(
responses={
"meta.list": {
"skills": [
{"name": "meta-tiny", "description": "A tiny meta-skill."},
{"name": "meta-plan", "description": "Plan things."},
]
}
}
)
state = ChatSessionState(session_key="agent:main:test", model="local/test")
handled = await handle_gateway_slash_command(
"/meta",
GatewaySlashContext(state=state, client=client, elevated_state={"mode": None}),
)
assert handled is True
assert client.calls == [("meta.list", {})]
rendered = buffer.getvalue()
assert "meta-tiny" in rendered
assert "meta-plan" in rendered
@pytest.mark.asyncio
async def test_meta_no_arg_disabled_prints_notice(monkeypatch: pytest.MonkeyPatch) -> None:
from opensquilla.cli.repl import slash_adapter
from opensquilla.cli.repl.slash_adapter import (
GatewaySlashContext,
handle_gateway_slash_command,
)
console, buffer = _make_console()
monkeypatch.setattr(slash_adapter, "console", console)
client = _FakeGatewayClient(responses={"meta.list": {"disabled": True}})
state = ChatSessionState(session_key="agent:main:test", model="local/test")
handled = await handle_gateway_slash_command(
"/meta",
GatewaySlashContext(state=state, client=client, elevated_state={"mode": None}),
)
assert handled is True
assert client.calls == [("meta.list", {})]
assert "disabled" in buffer.getvalue().lower()
@pytest.mark.asyncio
async def test_meta_run_ok_triggers_turn(monkeypatch: pytest.MonkeyPatch) -> None:
from opensquilla.cli.repl import slash_adapter
from opensquilla.cli.repl.slash_adapter import (
GatewaySlashContext,
handle_gateway_slash_command,
)
console, _buffer = _make_console()
monkeypatch.setattr(slash_adapter, "console", console)
captured: dict[str, Any] = {}
async def fake_stream_response_gateway(
gateway_client: object,
session_key: str,
message: str,
elevated_state: dict[str, str | None],
attachments: list[dict[str, Any]] | None = None,
*,
tui_output: object | None = None,
) -> TurnResult:
captured.update(
{
"client": gateway_client,
"session_key": session_key,
"message": message,
"elevated_state": elevated_state,
}
)
return TurnResult(text="launched")
monkeypatch.setattr(slash_adapter, "stream_response_gateway", fake_stream_response_gateway)
client = _FakeGatewayClient(responses={"meta.run": {"ok": True}})
state = ChatSessionState(session_key="agent:main:test", model="local/test")
handled = await handle_gateway_slash_command(
"/meta meta-tiny",
GatewaySlashContext(state=state, client=client, elevated_state={"mode": "on"}),
)
assert handled is True
assert client.calls == [
("meta.run", {"name": "meta-tiny", "sessionKey": "agent:main:test"}),
]
# A turn was triggered through the same path /image uses.
assert captured["session_key"] == "agent:main:test"
assert captured["message"] == "/meta meta-tiny"
assert captured["elevated_state"] == {"mode": "on"}
assert state.transcript.to_markdown()
@pytest.mark.asyncio
async def test_meta_run_not_ok_prints_error_and_skips_turn(
monkeypatch: pytest.MonkeyPatch,
) -> None:
from opensquilla.cli.repl import slash_adapter
from opensquilla.cli.repl.slash_adapter import (
GatewaySlashContext,
handle_gateway_slash_command,
)
console, buffer = _make_console()
monkeypatch.setattr(slash_adapter, "console", console)
stream_calls: list[str] = []
async def fake_stream_response_gateway(*args: Any, **kwargs: Any) -> TurnResult:
stream_calls.append("called")
return TurnResult(text="should-not-happen")
monkeypatch.setattr(slash_adapter, "stream_response_gateway", fake_stream_response_gateway)
client = _FakeGatewayClient(
responses={"meta.run": {"ok": False, "error": "unknown meta-skill: bad"}}
)
state = ChatSessionState(session_key="agent:main:test", model="local/test")
handled = await handle_gateway_slash_command(
"/meta bad",
GatewaySlashContext(state=state, client=client, elevated_state={"mode": None}),
)
assert handled is True
assert client.calls == [
("meta.run", {"name": "bad", "sessionKey": "agent:main:test"}),
]
# No turn fired.
assert stream_calls == []
assert "unknown meta-skill: bad" in buffer.getvalue()