feat: add worker HTTP client
This commit is contained in:
@@ -0,0 +1,47 @@
|
|||||||
|
import httpx
|
||||||
|
|
||||||
|
from src.backend.config import settings
|
||||||
|
|
||||||
|
|
||||||
|
class WorkerClient:
|
||||||
|
def __init__(self):
|
||||||
|
self.base_url = settings.worker_url
|
||||||
|
|
||||||
|
async def process(
|
||||||
|
self,
|
||||||
|
prompt: str,
|
||||||
|
system_prompt: str,
|
||||||
|
model: str,
|
||||||
|
session_id: str | None = None,
|
||||||
|
) -> dict:
|
||||||
|
async with httpx.AsyncClient(timeout=300.0) as client:
|
||||||
|
resp = await client.post(
|
||||||
|
f"{self.base_url}/process",
|
||||||
|
json={
|
||||||
|
"prompt": prompt,
|
||||||
|
"system_prompt": system_prompt,
|
||||||
|
"model": model,
|
||||||
|
"session_id": session_id,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return resp.json()
|
||||||
|
|
||||||
|
async def summarize(
|
||||||
|
self,
|
||||||
|
exchanges: list[dict],
|
||||||
|
mode: str = "incremental",
|
||||||
|
) -> dict:
|
||||||
|
async with httpx.AsyncClient(timeout=300.0) as client:
|
||||||
|
resp = await client.post(
|
||||||
|
f"{self.base_url}/summarize",
|
||||||
|
json={"exchanges": exchanges, "mode": mode},
|
||||||
|
)
|
||||||
|
return resp.json()
|
||||||
|
|
||||||
|
async def health(self) -> bool:
|
||||||
|
try:
|
||||||
|
async with httpx.AsyncClient(timeout=5.0) as client:
|
||||||
|
resp = await client.get(f"{self.base_url}/health")
|
||||||
|
return resp.status_code == 200
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
from src.backend.config import settings
|
from src.backend.config import settings
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from unittest.mock import AsyncMock, MagicMock, patch
|
||||||
|
|
||||||
|
|
||||||
def test_settings_loads_api_key():
|
def test_settings_loads_api_key():
|
||||||
@@ -109,3 +110,80 @@ def test_envelope_fail():
|
|||||||
result = fail("NOT_FOUND", "Resource not found")
|
result = fail("NOT_FOUND", "Resource not found")
|
||||||
assert result["success"] is False
|
assert result["success"] is False
|
||||||
assert result["error"]["code"] == "NOT_FOUND"
|
assert result["error"]["code"] == "NOT_FOUND"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_worker_client_process():
|
||||||
|
from src.backend.services.worker_client import WorkerClient
|
||||||
|
|
||||||
|
mock_response = MagicMock()
|
||||||
|
mock_response.status_code = 200
|
||||||
|
mock_response.json.return_value = {
|
||||||
|
"success": True,
|
||||||
|
"result": "The answer is 42.",
|
||||||
|
"session_id": "sess-123",
|
||||||
|
}
|
||||||
|
|
||||||
|
with patch("src.backend.services.worker_client.httpx.AsyncClient") as MockClient:
|
||||||
|
mock_client_instance = AsyncMock()
|
||||||
|
mock_client_instance.post.return_value = mock_response
|
||||||
|
mock_client_instance.__aenter__ = AsyncMock(return_value=mock_client_instance)
|
||||||
|
mock_client_instance.__aexit__ = AsyncMock(return_value=False)
|
||||||
|
MockClient.return_value = mock_client_instance
|
||||||
|
|
||||||
|
client = WorkerClient()
|
||||||
|
result = await client.process(
|
||||||
|
prompt="What is the answer?",
|
||||||
|
system_prompt="You know everything.",
|
||||||
|
model="claude-sonnet-4-6",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["success"] is True
|
||||||
|
assert result["result"] == "The answer is 42."
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_worker_client_summarize():
|
||||||
|
from src.backend.services.worker_client import WorkerClient
|
||||||
|
|
||||||
|
mock_response = MagicMock()
|
||||||
|
mock_response.status_code = 200
|
||||||
|
mock_response.json.return_value = {
|
||||||
|
"success": True,
|
||||||
|
"summary": "[2026-05-25] Discussed the meaning of life.",
|
||||||
|
}
|
||||||
|
|
||||||
|
with patch("src.backend.services.worker_client.httpx.AsyncClient") as MockClient:
|
||||||
|
mock_client_instance = AsyncMock()
|
||||||
|
mock_client_instance.post.return_value = mock_response
|
||||||
|
mock_client_instance.__aenter__ = AsyncMock(return_value=mock_client_instance)
|
||||||
|
mock_client_instance.__aexit__ = AsyncMock(return_value=False)
|
||||||
|
MockClient.return_value = mock_client_instance
|
||||||
|
|
||||||
|
client = WorkerClient()
|
||||||
|
result = await client.summarize(
|
||||||
|
exchanges=[{"prompt": "What?", "result": "42."}],
|
||||||
|
mode="incremental",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["success"] is True
|
||||||
|
assert "Discussed" in result["summary"]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_worker_client_health():
|
||||||
|
from src.backend.services.worker_client import WorkerClient
|
||||||
|
|
||||||
|
mock_response = AsyncMock()
|
||||||
|
mock_response.status_code = 200
|
||||||
|
|
||||||
|
with patch("src.backend.services.worker_client.httpx.AsyncClient") as MockClient:
|
||||||
|
mock_client_instance = AsyncMock()
|
||||||
|
mock_client_instance.get.return_value = mock_response
|
||||||
|
mock_client_instance.__aenter__ = AsyncMock(return_value=mock_client_instance)
|
||||||
|
mock_client_instance.__aexit__ = AsyncMock(return_value=False)
|
||||||
|
MockClient.return_value = mock_client_instance
|
||||||
|
|
||||||
|
client = WorkerClient()
|
||||||
|
is_healthy = await client.health()
|
||||||
|
assert is_healthy is True
|
||||||
|
|||||||
Reference in New Issue
Block a user