manual_sdk_agent_smoke.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. """Drive the repo-source dsh SDK profile through the SDK and a keyless mock SSE server.
  2. Requires ``pnpm install`` but no build. This manual test is not collected by
  3. pytest; run ``python tests/manual_sdk_agent_smoke.py``.
  4. """
  5. from __future__ import annotations
  6. import argparse
  7. import json
  8. import shutil
  9. import tempfile
  10. import threading
  11. from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
  12. from pathlib import Path
  13. from typing import Any
  14. from deepseek_harness import DeepSeekHarness
  15. class MockCompletionHandler(BaseHTTPRequestHandler):
  16. requests: list[dict[str, Any]] = []
  17. def do_POST(self) -> None:
  18. length = int(self.headers.get("content-length", "0"))
  19. body = self.rfile.read(length).decode("utf-8")
  20. self.requests.append({
  21. "path": self.path,
  22. "authorization": self.headers.get("authorization"),
  23. "body": json.loads(body),
  24. })
  25. self.send_response(200)
  26. self.send_header("content-type", "text/event-stream")
  27. self.end_headers()
  28. self.wfile.write(b'data: {"choices":[{"delta":{"role":"assistant","content":null,"reasoning_content":""}}]}\n\n')
  29. self.wfile.write(b'data: {"choices":[{"delta":{"content":"SDK runtime reached the configured HTTP model endpoint."}}]}\n\n')
  30. self.wfile.write(b'data: {"choices":[{"delta":{"content":""},"finish_reason":"stop"}],"usage":{"prompt_tokens":7,"completion_tokens":9}}\n\n')
  31. self.wfile.write(b"data: [DONE]\n\n")
  32. def log_message(self, _format: str, *_args: object) -> None:
  33. return
  34. def run_smoke(repo_root: Path, keep_sessions: bool) -> None:
  35. dsh_home = Path(tempfile.mkdtemp(prefix="dsh-sdk-smoke-home-"))
  36. session_root = dsh_home / "sessions"
  37. runtime_entry = repo_root / "apps/cli/src/bin.ts"
  38. server = ThreadingHTTPServer(("127.0.0.1", 0), MockCompletionHandler)
  39. thread = threading.Thread(target=server.serve_forever, name="mock-openai-compatible-server", daemon=True)
  40. thread.start()
  41. base_url = f"http://127.0.0.1:{server.server_address[1]}"
  42. print(f"repo_root={repo_root}")
  43. print(f"dsh_home={dsh_home}")
  44. print(f"mock_base_url={base_url}")
  45. try:
  46. with DeepSeekHarness(
  47. model="sdk-smoke-model",
  48. cwd=str(repo_root / "python/sdk"),
  49. runtime_cwd=str(repo_root),
  50. _launch_args=(
  51. "node",
  52. "--import",
  53. "tsx",
  54. str(runtime_entry),
  55. "--profile",
  56. "sdk",
  57. ),
  58. env={
  59. "DSH_HOME": str(dsh_home),
  60. "DSH_PERMISSION_MODE": "danger-full-access",
  61. "DSH_TELEMETRY_DISABLED": "1",
  62. "DEEPSEEK_BASE_URL": base_url,
  63. "DEEPSEEK_API_KEY": "sdk-smoke-key",
  64. },
  65. request_timeout_seconds=20,
  66. shutdown_timeout_seconds=2,
  67. ) as harness:
  68. result = harness.run(
  69. "Please reply with a short confirmation and do not call tools.",
  70. session_id="sdk-smoke-main",
  71. )
  72. print(f"final_response={result.final_response}")
  73. assert "configured HTTP model endpoint" in result.final_response
  74. assert len(MockCompletionHandler.requests) == 1
  75. request = MockCompletionHandler.requests[0]
  76. print(json.dumps(request, ensure_ascii=False, indent=2)[:4000])
  77. assert request["authorization"] == "Bearer sdk-smoke-key"
  78. assert request["body"]["model"] == "sdk-smoke-model"
  79. jsonl_files = sorted(session_root.rglob("*.jsonl.zstd"))
  80. assert jsonl_files, f"no Zstandard JSONL sessions were written under {session_root}"
  81. print("session_jsonl_zstd_files:")
  82. for path in jsonl_files:
  83. print(f" {path} bytes={path.stat().st_size}")
  84. assert path.read_bytes().startswith(bytes.fromhex("28b52ffd"))
  85. finally:
  86. server.shutdown()
  87. server.server_close()
  88. if keep_sessions:
  89. print(f"kept_dsh_home={dsh_home}")
  90. else:
  91. shutil.rmtree(dsh_home)
  92. print("removed temporary dsh home")
  93. def main() -> None:
  94. parser = argparse.ArgumentParser()
  95. parser.add_argument(
  96. "--repo-root",
  97. type=Path,
  98. default=Path(__file__).resolve().parents[3],
  99. help="Path to the deepseek-harness checkout.",
  100. )
  101. parser.add_argument("--keep-sessions", action="store_true")
  102. args = parser.parse_args()
  103. run_smoke(args.repo_root.resolve(), args.keep_sessions)
  104. if __name__ == "__main__":
  105. main()