Files
deepseek-harness/python/sdk/tests/test_commands.py
T

139 lines
6.6 KiB
Python

"""Explicit command transport, results, and ordinary prompt compatibility."""
from __future__ import annotations
import json
import sys
from pathlib import Path
import pytest
from pydantic import ValidationError
from deepseek_harness import CommandErrorResult, CommandExecution, CommandSuccessResult, DeepSeekHarness
from deepseek_harness.errors import JsonRpcError, SdkProtocolError
@pytest.fixture
def peer(tmp_path: Path) -> Path:
script = tmp_path / "commands.py"
script.write_text('''import json
import os
import sys
def send(frame):
print(json.dumps({"jsonrpc": "2.0", **frame}), flush=True)
for line in sys.stdin:
frame = json.loads(line)
with open(os.environ["REQUEST_LOG"], "a", encoding="utf-8") as log:
log.write(line)
method = frame["method"]
params = frame.get("params") or {}
if method == "initialize":
send({"id": frame["id"], "result": {"serverInfo": {"name": "command-peer"}}})
elif method == "session/command":
for event_type in ("command/run", "command/done"):
send({"method": "session.event", "params": {"sessionId": params["sessionId"],
"event": {"type": event_type, "data": {"commandId": "command-1"}}}})
send({"id": frame["id"], **json.loads(os.environ["COMMAND_RESPONSE"])})
elif method == "session/prompt":
session = params["sessionId"]
send({"id": frame["id"], "result": {"messageId": "input-1"}})
events = [
{"type": "agent/inbox/spliced", "data": {"inserted": [{"id": "input-1"}]}},
{"type": "assistant/message", "data": {"message": {"content": [{"type": "text", "text": "ordinary prompt"}]}}},
{"type": "turn/end", "data": {"turn": 1, "reason": {"kind": "completed"}}},
]
for event in events:
send({"method": "session.event", "params": {"sessionId": session, "event": event}})
send({"method": "session.status", "params": {"sessionId": session, "status": "idle"}})
elif method == "shutdown":
send({"id": frame["id"], "result": {}})
break
else:
raise AssertionError(method)
''', encoding="utf-8")
return script
def harness(peer: Path, tmp_path: Path, response: dict) -> DeepSeekHarness:
return DeepSeekHarness(
cwd=str(tmp_path),
dsh_home=str(tmp_path / "home"),
request_timeout_seconds=5,
_launch_args=(sys.executable, str(peer)),
env={"REQUEST_LOG": str(tmp_path / "requests.jsonl"), "COMMAND_RESPONSE": json.dumps(response)},
)
def frames(tmp_path: Path) -> list[dict]:
return [json.loads(line) for line in (tmp_path / "requests.jsonl").read_text(encoding="utf-8").splitlines()]
@pytest.mark.parametrize("result", [
{"kind": "success"},
{"kind": "success", "text": "Compacted.", "sourceEventSeq": 0},
{"kind": "success", "sourceEventSeq": 2**53 - 1},
{"kind": "error", "text": "The agent is busy."},
{"kind": "error", "text": " The agent is busy.\n"},
])
def test_command_returns_without_turn_or_idle_and_preserves_events(peer: Path, tmp_path: Path, result: dict) -> None:
response = {"commandId": "command-1", "result": result}
with harness(peer, tmp_path, {"result": response}) as sdk:
session = sdk.start_session("main")
with sdk.client.subscribe_session_notifications(session.id) as subscription:
execution = sdk.client.session_command(session.id, "/compact")
notifications = []
subscription.drain(notifications.append)
assert isinstance(execution, CommandExecution)
assert execution.command_id == "command-1"
assert isinstance(execution.result, CommandSuccessResult if result["kind"] == "success" else CommandErrorResult)
assert execution.model_dump(by_alias=True, exclude_none=True) == response
assert [item.payload["event"]["type"] for item in notifications] == ["command/run", "command/done"]
sent = frames(tmp_path)
assert [frame["method"] for frame in sent] == ["initialize", "session/command", "shutdown"]
assert sent[1]["params"] == {"sessionId": "main", "line": "/compact"}
def test_low_level_command_preserves_the_line(peer: Path, tmp_path: Path) -> None:
with harness(peer, tmp_path, {"result": {"commandId": "command-1", "result": {"kind": "success"}}}) as sdk:
assert sdk.client.session_command("other", "/compact \t").result.kind == "success"
assert frames(tmp_path)[1]["params"] == {"sessionId": "other", "line": "/compact \t"}
def test_command_rpc_rejection_does_not_fall_back_to_prompt(peer: Path, tmp_path: Path) -> None:
with harness(peer, tmp_path, {"error": {"code": -32602, "message": "unsupported command"}}) as sdk:
with pytest.raises(JsonRpcError, match="unsupported command") as raised:
sdk.client.session_command("main", "/model")
assert raised.value.code == -32602
assert [frame["method"] for frame in frames(tmp_path)] == ["initialize", "session/command", "shutdown"]
@pytest.mark.parametrize("response", [
{},
{"commandId": "command-1"},
{"commandId": "", "result": {"kind": "success"}},
{"commandId": "command-1", "result": {"kind": "unknown"}},
{"commandId": "command-1", "result": {"kind": "error"}},
{"commandId": "command-1", "result": {"kind": "error", "text": ""}},
{"commandId": "command-1", "result": {"kind": "error", "text": " \t\n"}},
{"commandId": "command-1", "result": {"kind": "success", "text": None}},
{"commandId": "command-1", "result": {"kind": "success", "sourceEventSeq": None}},
{"commandId": "command-1", "result": {"kind": "success", "sourceEventSeq": "4"}},
{"commandId": "command-1", "result": {"kind": "success", "sourceEventSeq": True}},
{"commandId": "command-1", "result": {"kind": "success", "sourceEventSeq": -1}},
{"commandId": "command-1", "result": {"kind": "success", "sourceEventSeq": 2**53}},
])
def test_command_rejects_malformed_results(peer: Path, tmp_path: Path, response: dict) -> None:
with harness(peer, tmp_path, {"result": response}) as sdk:
with pytest.raises(SdkProtocolError) as raised:
sdk.client.session_command("main", "/compact")
assert isinstance(raised.value.__cause__, ValidationError)
def test_low_level_prompt_keeps_slash_text_as_an_ordinary_prompt(peer: Path, tmp_path: Path) -> None:
with harness(peer, tmp_path, {"result": {}}) as sdk:
assert sdk.client.session_prompt("main", [{"type": "text", "text": "/compact"}]) == "input-1"
sent = frames(tmp_path)
assert [frame["method"] for frame in sent] == ["initialize", "session/prompt", "shutdown"]
assert sent[1]["params"] == {"sessionId": "main", "contentBlocks": [{"type": "text", "text": "/compact"}]}