fix(chat): route OpenClaw chat through Ollama lane
This commit is contained in:
105
apps/api/tests/test_chat_manager_ollama_routing.py
Normal file
105
apps/api/tests/test_chat_manager_ollama_routing.py
Normal file
@@ -0,0 +1,105 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
from src.services import chat_manager as chat_module
|
||||
from src.services.chat_manager import ChatManager
|
||||
|
||||
|
||||
class _FakeResponse:
|
||||
def __init__(self, content: str = "老闆,系統目前穩定。") -> None:
|
||||
self._content = content
|
||||
|
||||
def raise_for_status(self) -> None:
|
||||
return None
|
||||
|
||||
def json(self) -> dict[str, Any]:
|
||||
return {
|
||||
"message": {"content": self._content},
|
||||
"prompt_eval_count": 11,
|
||||
"eval_count": 13,
|
||||
}
|
||||
|
||||
|
||||
class _FakeAsyncClient:
|
||||
posted: list[tuple[str, dict[str, Any]]] = []
|
||||
|
||||
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
|
||||
async def __aenter__(self) -> _FakeAsyncClient:
|
||||
return self
|
||||
|
||||
async def __aexit__(self, *args: Any) -> None:
|
||||
return None
|
||||
|
||||
async def post(self, url: str, *, json: dict[str, Any]) -> _FakeResponse:
|
||||
self.posted.append((url, json))
|
||||
return _FakeResponse()
|
||||
|
||||
|
||||
def _settings() -> SimpleNamespace:
|
||||
return SimpleNamespace(OPENCLAW_DEFAULT_MODEL="qwen3:14b")
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _reset_fake_client() -> None:
|
||||
_FakeAsyncClient.posted = []
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_openclaw_chat_uses_ollama_interactive_lane(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
monkeypatch.setattr(chat_module.httpx, "AsyncClient", _FakeAsyncClient)
|
||||
monkeypatch.setattr(chat_module, "get_settings", _settings)
|
||||
monkeypatch.setattr(
|
||||
chat_module,
|
||||
"resolve_ollama_endpoint",
|
||||
lambda workload_type: "http://gcp-a:11435",
|
||||
)
|
||||
|
||||
result = await ChatManager()._call_openclaw("system context", "幫我看狀態")
|
||||
|
||||
assert result is not None
|
||||
assert "qwen3:14b" in result
|
||||
assert "免費" in result
|
||||
|
||||
assert len(_FakeAsyncClient.posted) == 1
|
||||
url, payload = _FakeAsyncClient.posted[0]
|
||||
assert url == "http://gcp-a:11435/api/chat"
|
||||
assert payload["model"] == "qwen3:14b"
|
||||
assert payload["messages"][0]["role"] == "system"
|
||||
assert payload["messages"][1] == {"role": "user", "content": "幫我看狀態"}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_nemoclaw_chat_uses_resolved_interactive_lane(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
monkeypatch.setattr(chat_module.httpx, "AsyncClient", _FakeAsyncClient)
|
||||
monkeypatch.setattr(
|
||||
chat_module,
|
||||
"resolve_ollama_endpoint",
|
||||
lambda workload_type: "http://gcp-a:11435",
|
||||
)
|
||||
|
||||
result = await ChatManager()._call_nemotron("system context", "補充觀點")
|
||||
|
||||
assert result is not None
|
||||
url, payload = _FakeAsyncClient.posted[0]
|
||||
assert url == "http://gcp-a:11435/api/chat"
|
||||
assert payload["model"] == "deepseek-r1:14b"
|
||||
|
||||
|
||||
def test_chat_manager_has_no_direct_gemini_generation_path() -> None:
|
||||
source_path = Path(chat_module.__file__).resolve()
|
||||
source = source_path.read_text(encoding="utf-8")
|
||||
|
||||
assert "generativelanguage.googleapis.com" not in source
|
||||
assert "GEMINI_API_KEY" not in source
|
||||
Reference in New Issue
Block a user