|
|
@@ -9,7 +9,7 @@ from pathlib import Path
|
|
|
|
|
|
import pytest
|
|
|
|
|
|
-from deepseek_harness import DeepSeekHarness, HarnessClient, HarnessConfig, Notification
|
|
|
+from deepseek_harness import DeepSeekHarness, HarnessClient, HarnessConfig, Notification, SdkProtocolError
|
|
|
|
|
|
|
|
|
def test_high_level_sdk_runs_turn_and_collects_final_response(tmp_path: Path) -> None:
|
|
|
@@ -69,6 +69,17 @@ for line in sys.stdin:
|
|
|
},
|
|
|
},
|
|
|
}), flush=True)
|
|
|
+ print(json.dumps({
|
|
|
+ "jsonrpc": "2.0",
|
|
|
+ "method": "session.event",
|
|
|
+ "params": {
|
|
|
+ "sessionId": params["sessionId"],
|
|
|
+ "event": {
|
|
|
+ "type": "turn/end",
|
|
|
+ "data": {"turn": 2, "reason": {"kind": "max-tokens"}},
|
|
|
+ },
|
|
|
+ },
|
|
|
+ }), flush=True)
|
|
|
print(json.dumps({
|
|
|
"jsonrpc": "2.0",
|
|
|
"method": "session.status",
|
|
|
@@ -97,7 +108,7 @@ for line in sys.stdin:
|
|
|
result = harness.run("say hello", session_id="main")
|
|
|
|
|
|
assert result.final_response == "hello from runtime"
|
|
|
- assert result.finish_reason == "completed"
|
|
|
+ assert result.finish_reason == "max-tokens"
|
|
|
assert result.events[-1]["type"] == "turn/end"
|
|
|
dumped_env = json.loads(env_dump.read_text())
|
|
|
assert dumped_env["DEEPSEEK_API_KEY"] == "env-key"
|
|
|
@@ -152,6 +163,41 @@ for line in sys.stdin:
|
|
|
assert result.finish_reason is None
|
|
|
|
|
|
|
|
|
+def test_high_level_sdk_rejects_turn_end_without_reason_kind(tmp_path: Path) -> None:
|
|
|
+ script = tmp_path / "fake_runtime.py"
|
|
|
+ script.write_text(
|
|
|
+ """
|
|
|
+import json
|
|
|
+import sys
|
|
|
+
|
|
|
+for line in sys.stdin:
|
|
|
+ msg = json.loads(line)
|
|
|
+ method = msg.get("method")
|
|
|
+ if method == "initialize":
|
|
|
+ print(json.dumps({"jsonrpc": "2.0", "id": msg["id"], "result": {"serverInfo": {"name": "fake-runtime"}}}), flush=True)
|
|
|
+ elif method == "session/prompt":
|
|
|
+ params = msg.get("params") or {}
|
|
|
+ print(json.dumps({"jsonrpc": "2.0", "method": "session.event", "params": {"sessionId": params["sessionId"], "event": {"type": "agent/inbox/spliced", "data": {"target": "next-turn", "start": 0, "inserted": [{"id": "message-1"}]}}}}), flush=True)
|
|
|
+ print(json.dumps({"jsonrpc": "2.0", "id": msg["id"], "result": {"messageId": "message-1"}}), flush=True)
|
|
|
+ print(json.dumps({"jsonrpc": "2.0", "method": "session.event", "params": {"sessionId": params["sessionId"], "event": {"type": "turn/end", "data": {"turn": 1, "reason": {}}}}}), flush=True)
|
|
|
+ print(json.dumps({"jsonrpc": "2.0", "method": "session.status", "params": {"sessionId": params["sessionId"], "status": "idle"}}), flush=True)
|
|
|
+ elif method == "shutdown":
|
|
|
+ print(json.dumps({"jsonrpc": "2.0", "id": msg["id"], "result": {}}), flush=True)
|
|
|
+ break
|
|
|
+""".strip()
|
|
|
+ )
|
|
|
+
|
|
|
+ with DeepSeekHarness(
|
|
|
+ launch_args_override=(sys.executable, str(script)),
|
|
|
+ cwd=str(tmp_path),
|
|
|
+ ) as harness:
|
|
|
+ with pytest.raises(
|
|
|
+ SdkProtocolError,
|
|
|
+ match=r"turn/end event requires a string data\.reason\.kind",
|
|
|
+ ):
|
|
|
+ harness.run("reject malformed turn ending", session_id="main")
|
|
|
+
|
|
|
+
|
|
|
def test_relative_cwd_is_absolute_in_process_environment_and_wire(
|
|
|
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
|
) -> None:
|