Files

1 line
11 KiB
JSON

{"repo": "briandilley/gilbert-plugins", "files": {"deepseek/tests/test_deepseek_ai.py": {"e51651974422a521c774c2966972ac2cc518f8e9": {"t": 1785747152.48653, "n": 5426, "h": "603e70f62d1c5269", "c": "\"\"\"Tests for DeepSeekAI backend — focuses on vendor-specific defaults and\nthe core request/response contract. Deep OpenAI-compat behaviour (tool-call\nreassembly, attachment ordering, slash-command splitting) is covered by\nthe qwen plugin's tests since the parsing logic is identical.\"\"\"\n\nfrom unittest.mock import AsyncMock, MagicMock\n\nimport pytest\nfrom gilbert_plugin_deepseek.deepseek_ai import DeepSeekAI\n\nfrom gilbert.interfaces.ai import (\n AIBackendError,\n AIRequest,\n Message,\n MessageRole,\n StopReason,\n)\nfrom gilbert.interfaces.tools import ToolParameterType\n\n\n@pytest.fixture\ndef backend() -> DeepSeekAI:\n return DeepSeekAI()\n\n\nasync def test_initialize_requires_api_key(backend: DeepSeekAI) -> None:\n with pytest.raises(ValueError, match=\"api_key\"):\n await backend.initialize({})\n\n\nasync def test_default_base_url_is_deepseek(backend: DeepSeekAI) -> None:\n await backend.initialize({\"api_key\": \"sk-test\"})\n assert backend._client is not None\n resolved = str(backend._client.build_request(\"POST\", \"/chat/completions\").url)\n assert resolved == \"https://api.deepseek.com/v1/chat/completions\"\n await backend.close()\n\n\nasync def test_default_model_is_deepseek_chat(backend: DeepSeekAI) -> None:\n await backend.initialize({\"api_key\": \"sk-test\"})\n assert backend._model == \"deepseek-chat\"\n await backend.close()\n\n\nasync def test_custom_base_url_joins_cleanly(backend: DeepSeekAI) -> None:\n await backend.initialize(\n {\"api_key\": \"sk-test\", \"base_url\": \"https://proxy.example/v1/\"}\n )\n assert backend._client is not None\n resolved = str(backend._client.build_request(\"POST\", \"/chat/completions\").url)\n assert resolved == \"https://proxy.example/v1/chat/completions\"\n await backend.close()\n\n\ndef test_capabilities_reports_streaming_and_attachments() -> None:\n caps = DeepSeekAI().capabilities()\n assert caps.streaming is True\n assert caps.attachments_user is True\n\n\ndef test_backend_name() -> None:\n assert DeepSeekAI.backend_name == \"deepseek\"\n\n\ndef test_backend_config_params_includes_enabled_toggle() -> None:\n params = DeepSeekAI.backend_config_params()\n enabled = next((p for p in params if p.key == \"enabled\"), None)\n assert enabled is not None\n assert enabled.type == ToolParameterType.BOOLEAN\n assert enabled.default is True\n\n\ndef test_build_request_body_uses_max_tokens() -> None:\n backend = DeepSeekAI()\n backend._model = \"deepseek-chat\"\n backend._max_tokens = 256\n backend._temperature = 0.3\n body = backend._build_request_body(\n AIRequest(\n messages=[Message(role=MessageRole.USER, content=\"hi\")],\n system_prompt=\"Be terse\",\n )\n )\n assert body[\"model\"] == \"deepseek-chat\"\n assert body[\"max_tokens\"] == 256\n assert \"max_completion_tokens\" not in body\n assert body[\"temperature\"] == 0.3\n assert body[\"messages\"][0] == {\"role\": \"system\", \"content\": \"Be terse\"}\n\n\ndef test_parse_text_response() -> None:\n backend = DeepSeekAI()\n data = {\n \"choices\": [\n {\n \"message\": {\"role\": \"assistant\", \"content\": \"Hello!\"},\n \"finish_reason\": \"stop\",\n }\n ],\n \"model\": \"deepseek-chat\",\n \"usage\": {\"prompt_tokens\": 10, \"completion_tokens\": 5},\n }\n response = backend._parse_response(data)\n assert response.message.content == \"Hello!\"\n assert response.stop_reason == StopReason.END_TURN\n assert response.model == \"deepseek-chat\"\n assert response.usage is not None\n assert response.usage.input_tokens == 10\n\n\nasync def test_generate_calls_chat_completions(backend: DeepSeekAI) -> None:\n await backend.initialize({\"api_key\": \"sk-test\"})\n mock_response = MagicMock()\n mock_response.is_error = False\n mock_response.json.return_value = {\n \"choices\": [\n {\n \"message\": {\"role\": \"assistant\", \"content\": \"hi\"},\n \"finish_reason\": \"stop\",\n }\n ],\n \"model\": \"deepseek-chat\",\n }\n assert backend._client is not None\n backend._client.post = AsyncMock(return_value=mock_response) # type: ignore[method-assign]\n await backend.generate(AIRequest(messages=[Message(role=MessageRole.USER, content=\"x\")]))\n backend._client.post.assert_called_once()\n assert backend._client.post.call_args[0][0] == \"/chat/completions\"\n await backend.close()\n\n\nasync def test_generate_raises_ai_backend_error_on_http_error(\n backend: DeepSeekAI,\n) -> None:\n await backend.initialize({\"api_key\": \"sk-test\"})\n mock_response = MagicMock()\n mock_response.is_error = True\n mock_response.status_code = 401\n mock_response.json.return_value = {\"error\": {\"message\": \"Invalid API key\"}}\n assert backend._client is not None\n backend._client.post = AsyncMock(return_value=mock_response) # type: ignore[method-assign]\n with pytest.raises(AIBackendError) as exc_info:\n await backend.generate(\n AIRequest(messages=[Message(role=MessageRole.USER, content=\"x\")])\n )\n assert exc_info.value.status == 401\n assert \"Invalid API key\" in str(exc_info.value)\n await backend.close()\n\n\nasync def test_generate_raises_when_not_initialized(backend: DeepSeekAI) -> None:\n with pytest.raises(RuntimeError, match=\"not initialized\"):\n await backend.generate(\n AIRequest(messages=[Message(role=MessageRole.USER, content=\"x\")])\n )\n"}, "87e934ac815539a9dbaad0db0fc3a5b61f0458c9": {"t": 1785770724.9599166, "n": 5426, "h": "603e70f62d1c5269", "c": "\"\"\"Tests for DeepSeekAI backend — focuses on vendor-specific defaults and\nthe core request/response contract. Deep OpenAI-compat behaviour (tool-call\nreassembly, attachment ordering, slash-command splitting) is covered by\nthe qwen plugin's tests since the parsing logic is identical.\"\"\"\n\nfrom unittest.mock import AsyncMock, MagicMock\n\nimport pytest\nfrom gilbert_plugin_deepseek.deepseek_ai import DeepSeekAI\n\nfrom gilbert.interfaces.ai import (\n AIBackendError,\n AIRequest,\n Message,\n MessageRole,\n StopReason,\n)\nfrom gilbert.interfaces.tools import ToolParameterType\n\n\n@pytest.fixture\ndef backend() -> DeepSeekAI:\n return DeepSeekAI()\n\n\nasync def test_initialize_requires_api_key(backend: DeepSeekAI) -> None:\n with pytest.raises(ValueError, match=\"api_key\"):\n await backend.initialize({})\n\n\nasync def test_default_base_url_is_deepseek(backend: DeepSeekAI) -> None:\n await backend.initialize({\"api_key\": \"sk-test\"})\n assert backend._client is not None\n resolved = str(backend._client.build_request(\"POST\", \"/chat/completions\").url)\n assert resolved == \"https://api.deepseek.com/v1/chat/completions\"\n await backend.close()\n\n\nasync def test_default_model_is_deepseek_chat(backend: DeepSeekAI) -> None:\n await backend.initialize({\"api_key\": \"sk-test\"})\n assert backend._model == \"deepseek-chat\"\n await backend.close()\n\n\nasync def test_custom_base_url_joins_cleanly(backend: DeepSeekAI) -> None:\n await backend.initialize(\n {\"api_key\": \"sk-test\", \"base_url\": \"https://proxy.example/v1/\"}\n )\n assert backend._client is not None\n resolved = str(backend._client.build_request(\"POST\", \"/chat/completions\").url)\n assert resolved == \"https://proxy.example/v1/chat/completions\"\n await backend.close()\n\n\ndef test_capabilities_reports_streaming_and_attachments() -> None:\n caps = DeepSeekAI().capabilities()\n assert caps.streaming is True\n assert caps.attachments_user is True\n\n\ndef test_backend_name() -> None:\n assert DeepSeekAI.backend_name == \"deepseek\"\n\n\ndef test_backend_config_params_includes_enabled_toggle() -> None:\n params = DeepSeekAI.backend_config_params()\n enabled = next((p for p in params if p.key == \"enabled\"), None)\n assert enabled is not None\n assert enabled.type == ToolParameterType.BOOLEAN\n assert enabled.default is True\n\n\ndef test_build_request_body_uses_max_tokens() -> None:\n backend = DeepSeekAI()\n backend._model = \"deepseek-chat\"\n backend._max_tokens = 256\n backend._temperature = 0.3\n body = backend._build_request_body(\n AIRequest(\n messages=[Message(role=MessageRole.USER, content=\"hi\")],\n system_prompt=\"Be terse\",\n )\n )\n assert body[\"model\"] == \"deepseek-chat\"\n assert body[\"max_tokens\"] == 256\n assert \"max_completion_tokens\" not in body\n assert body[\"temperature\"] == 0.3\n assert body[\"messages\"][0] == {\"role\": \"system\", \"content\": \"Be terse\"}\n\n\ndef test_parse_text_response() -> None:\n backend = DeepSeekAI()\n data = {\n \"choices\": [\n {\n \"message\": {\"role\": \"assistant\", \"content\": \"Hello!\"},\n \"finish_reason\": \"stop\",\n }\n ],\n \"model\": \"deepseek-chat\",\n \"usage\": {\"prompt_tokens\": 10, \"completion_tokens\": 5},\n }\n response = backend._parse_response(data)\n assert response.message.content == \"Hello!\"\n assert response.stop_reason == StopReason.END_TURN\n assert response.model == \"deepseek-chat\"\n assert response.usage is not None\n assert response.usage.input_tokens == 10\n\n\nasync def test_generate_calls_chat_completions(backend: DeepSeekAI) -> None:\n await backend.initialize({\"api_key\": \"sk-test\"})\n mock_response = MagicMock()\n mock_response.is_error = False\n mock_response.json.return_value = {\n \"choices\": [\n {\n \"message\": {\"role\": \"assistant\", \"content\": \"hi\"},\n \"finish_reason\": \"stop\",\n }\n ],\n \"model\": \"deepseek-chat\",\n }\n assert backend._client is not None\n backend._client.post = AsyncMock(return_value=mock_response) # type: ignore[method-assign]\n await backend.generate(AIRequest(messages=[Message(role=MessageRole.USER, content=\"x\")]))\n backend._client.post.assert_called_once()\n assert backend._client.post.call_args[0][0] == \"/chat/completions\"\n await backend.close()\n\n\nasync def test_generate_raises_ai_backend_error_on_http_error(\n backend: DeepSeekAI,\n) -> None:\n await backend.initialize({\"api_key\": \"sk-test\"})\n mock_response = MagicMock()\n mock_response.is_error = True\n mock_response.status_code = 401\n mock_response.json.return_value = {\"error\": {\"message\": \"Invalid API key\"}}\n assert backend._client is not None\n backend._client.post = AsyncMock(return_value=mock_response) # type: ignore[method-assign]\n with pytest.raises(AIBackendError) as exc_info:\n await backend.generate(\n AIRequest(messages=[Message(role=MessageRole.USER, content=\"x\")])\n )\n assert exc_info.value.status == 401\n assert \"Invalid API key\" in str(exc_info.value)\n await backend.close()\n\n\nasync def test_generate_raises_when_not_initialized(backend: DeepSeekAI) -> None:\n with pytest.raises(RuntimeError, match=\"not initialized\"):\n await backend.generate(\n AIRequest(messages=[Message(role=MessageRole.USER, content=\"x\")])\n )\n"}}}}