refactor(backend): update API routes and service layer
- Update agent router/service/repository with new endpoints - Update auth routes with phone-based authentication - Update users service with new phone lookup - Update schedule_items with new schemas - Update message schemas with visibility support - Update settings with new automation scheduler config - Update CLI with new commands - Update tests to match new API contracts
This commit is contained in:
@@ -20,6 +20,7 @@ class _FakeRepository:
|
||||
def __init__(self) -> None:
|
||||
self.committed = False
|
||||
self.persisted_user_messages: list[dict[str, object]] = []
|
||||
self.created_session_calls = 0
|
||||
|
||||
async def get_session_owner(self, *, session_id: str) -> str:
|
||||
if session_id == "00000000-0000-0000-0000-000000000001":
|
||||
@@ -30,6 +31,7 @@ class _FakeRepository:
|
||||
self, *, user_id: str, session_id: str | None = None
|
||||
) -> str:
|
||||
del user_id
|
||||
self.created_session_calls += 1
|
||||
return session_id or "00000000-0000-0000-0000-000000000999"
|
||||
|
||||
async def commit(self) -> None:
|
||||
@@ -39,9 +41,13 @@ class _FakeRepository:
|
||||
return None
|
||||
|
||||
async def get_history_day(
|
||||
self, *, session_id: str, before: date | None
|
||||
self,
|
||||
*,
|
||||
session_id: str,
|
||||
before: date | None,
|
||||
visibility_mask: int | None = None,
|
||||
) -> dict[str, object] | None:
|
||||
del session_id, before
|
||||
del session_id, before, visibility_mask
|
||||
return None
|
||||
|
||||
async def get_latest_session_id_for_user(self, *, user_id: str) -> str | None:
|
||||
@@ -54,15 +60,42 @@ class _FakeRepository:
|
||||
session_id: str,
|
||||
content: str,
|
||||
metadata: AgentChatMessageMetadata | None,
|
||||
visibility_mask: int,
|
||||
) -> None:
|
||||
self.persisted_user_messages.append(
|
||||
{
|
||||
"session_id": session_id,
|
||||
"content": content,
|
||||
"metadata": metadata,
|
||||
"visibility_mask": visibility_mask,
|
||||
}
|
||||
)
|
||||
|
||||
async def get_system_agent_config(
|
||||
self, *, agent_type: str
|
||||
) -> dict[str, object] | None:
|
||||
normalized = agent_type.strip().lower()
|
||||
mapping = {
|
||||
"router": 16,
|
||||
"worker": 17,
|
||||
"memory": 18,
|
||||
}
|
||||
bit = mapping.get(normalized)
|
||||
if bit is None:
|
||||
return None
|
||||
return {
|
||||
"agent_type": normalized,
|
||||
"status": "active",
|
||||
"config": {
|
||||
"temperature": 0.7,
|
||||
"max_tokens": None,
|
||||
"timeout_seconds": 30,
|
||||
"visibility_consumer_bit": bit,
|
||||
"context_messages": {"mode": "number", "count": 20},
|
||||
"enabled_tools": [],
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class _FakeQueue:
|
||||
def __init__(self) -> None:
|
||||
@@ -122,11 +155,11 @@ class _FakeAttachmentStorage:
|
||||
def _user() -> CurrentUser:
|
||||
return CurrentUser(
|
||||
id=UUID("00000000-0000-0000-0000-000000000001"),
|
||||
email="user@example.com",
|
||||
phone="+8613812345678",
|
||||
)
|
||||
|
||||
|
||||
def _build_run_input(*, urls: list[str]) -> RunAgentInput:
|
||||
def _build_run_input(*, urls: list[str], agent_type: str = "worker") -> RunAgentInput:
|
||||
content: list[dict[str, str]] = [{"type": "text", "text": "hello"}]
|
||||
for url in urls:
|
||||
content.append({"type": "binary", "mimeType": "image/png", "url": url})
|
||||
@@ -144,7 +177,7 @@ def _build_run_input(*, urls: list[str]) -> RunAgentInput:
|
||||
],
|
||||
"tools": [],
|
||||
"context": [],
|
||||
"forwardedProps": {},
|
||||
"forwardedProps": {"agent_type": agent_type},
|
||||
}
|
||||
)
|
||||
|
||||
@@ -222,6 +255,68 @@ async def test_enqueue_run_persists_attachment_and_queue_without_user_token(
|
||||
assert run_input["runId"] == "run-1"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_enqueue_run_rejects_unknown_agent_type(monkeypatch) -> None:
|
||||
monkeypatch.setattr(
|
||||
agent_service_module.config.storage, "bucket", "agent-test-bucket"
|
||||
)
|
||||
service = AgentService(
|
||||
repository=_FakeRepository(),
|
||||
queue=_FakeQueue(),
|
||||
stream=_FakeStream(),
|
||||
attachment_storage=_FakeAttachmentStorage(),
|
||||
)
|
||||
base_url = str(config.supabase.url).rstrip("/")
|
||||
safe_path = quote(
|
||||
"agent-inputs/00000000-0000-0000-0000-000000000001/"
|
||||
"00000000-0000-0000-0000-000000000001/uploads/a.png"
|
||||
)
|
||||
run_input = _build_run_input(
|
||||
urls=[
|
||||
f"{base_url}/storage/v1/object/sign/agent-test-bucket/{safe_path}?token=1"
|
||||
],
|
||||
agent_type="planner",
|
||||
)
|
||||
|
||||
with pytest.raises(HTTPException) as exc_info:
|
||||
await service.enqueue_run(run_input=run_input, current_user=_user())
|
||||
|
||||
assert exc_info.value.status_code == 422
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_enqueue_run_rejects_memory_mode_for_api(monkeypatch) -> None:
|
||||
monkeypatch.setattr(
|
||||
agent_service_module.config.storage, "bucket", "agent-test-bucket"
|
||||
)
|
||||
repository = _FakeRepository()
|
||||
service = AgentService(
|
||||
repository=repository,
|
||||
queue=_FakeQueue(),
|
||||
stream=_FakeStream(),
|
||||
attachment_storage=_FakeAttachmentStorage(),
|
||||
)
|
||||
base_url = str(config.supabase.url).rstrip("/")
|
||||
safe_path = quote(
|
||||
"agent-inputs/00000000-0000-0000-0000-000000000001/"
|
||||
"00000000-0000-0000-0000-000000000001/uploads/a.png"
|
||||
)
|
||||
run_input = _build_run_input(
|
||||
urls=[
|
||||
f"{base_url}/storage/v1/object/sign/agent-test-bucket/{safe_path}?token=1"
|
||||
],
|
||||
agent_type="memory",
|
||||
)
|
||||
|
||||
with pytest.raises(HTTPException) as exc_info:
|
||||
await service.enqueue_run(run_input=run_input, current_user=_user())
|
||||
|
||||
assert exc_info.value.status_code == 422
|
||||
assert exc_info.value.detail == "memory mode is automation-only"
|
||||
assert repository.created_session_calls == 0
|
||||
assert repository.persisted_user_messages == []
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_attachment_signed_url_returns_url(monkeypatch) -> None:
|
||||
monkeypatch.setattr(
|
||||
@@ -317,9 +412,13 @@ async def test_enqueue_run_rejects_too_many_attachments(monkeypatch) -> None:
|
||||
async def test_get_history_snapshot_filters_out_tool_messages() -> None:
|
||||
class _HistoryRepository(_FakeRepository):
|
||||
async def get_history_day(
|
||||
self, *, session_id: str, before: date | None
|
||||
self,
|
||||
*,
|
||||
session_id: str,
|
||||
before: date | None,
|
||||
visibility_mask: int | None = None,
|
||||
) -> dict[str, object] | None:
|
||||
del session_id, before
|
||||
del session_id, before, visibility_mask
|
||||
return {
|
||||
"day": "2026-03-17",
|
||||
"hasMore": False,
|
||||
|
||||
Reference in New Issue
Block a user