from __future__ import annotations from time import perf_counter from types import SimpleNamespace import pytest from starlette.requests import Request from app.gateway.routers import agents as agents_router from app.gateway.routers import skills as skills_router from deerflow.persistence.agents import MemoryAgentStore from deerflow.persistence.skills import MemorySkillStore from deerflow.persistence.tags import MemoryTagStore from deerflow.skills.types import SkillCategory def _request(path: str) -> Request: request = Request( { "type": "http", "method": "GET", "path": path, "headers": [], "query_string": b"", "server": ("test", 80), "client": ("127.0.0.1", 12345), "scheme": "http", "root_path": "", } ) request.scope["app"] = SimpleNamespace( state=SimpleNamespace( config=SimpleNamespace( concurrency=SimpleNamespace( redis=SimpleNamespace(enabled=False, url=None, password=None) ) ) ) ) request.state.user = SimpleNamespace(id="benchmark-user", system_role="user") return request @pytest.mark.asyncio async def test_catalog_endpoint_assembly_with_300_agents_and_300_skills(monkeypatch) -> None: agent_store = MemoryAgentStore() for index in range(300): await agent_store.ensure_builtin( { "id": f"benchmark-agent-{index:03d}", "name": f"Benchmark Agent {index:03d}", "description": "synthetic homepage benchmark record", "published": True, } ) agent_tags = MemoryTagStore() monkeypatch.setattr(agents_router, "_require_agents_api_enabled", lambda: None) monkeypatch.setattr(agents_router, "get_agent_store", lambda _request: agent_store) monkeypatch.setattr(agents_router, "get_tag_store", lambda _request: agent_tags) monkeypatch.setattr(agents_router, "get_skill_store", lambda _request: None) started = perf_counter() agents_response = await agents_router.list_agents( _request("/api/agents"), search=None, tag_ids=None, scope=None, page=None, page_size=20, sort="time_desc", owner=None, square=None, admin=False, hidden=None, ) agents_ms = (perf_counter() - started) * 1000 assert len(agents_response.agents) == 300 skill_store = MemorySkillStore() catalog = [] for index in range(300): name = f"benchmark-skill-{index:03d}" await skill_store.ensure_legacy({"name": name, "owner_user_id": None, "published": True}) catalog.append( { "name": name, "description": "synthetic homepage benchmark record", "license": None, "category": SkillCategory.PUBLIC.value, "enabled": True, "created_at": None, "last_activity_at": None, } ) monkeypatch.setattr(skills_router, "load_or_warm_skill_catalog_snapshot", lambda _config: _resolved(catalog)) monkeypatch.setattr(skills_router, "_list_skill_display_adapters", lambda _names: _resolved({})) started = perf_counter() skills_response = await skills_router.list_skills( _request("/api/skills"), config=SimpleNamespace(), skill_store=skill_store, tag_store=MemoryTagStore(), search=None, tag_ids=None, square=None, scope=None, sort="time_desc", admin=False, ) skills_ms = (perf_counter() - started) * 1000 assert len(skills_response.skills) == 300 assert agents_ms < 3_000 assert skills_ms < 3_000 print(f"synthetic 300+300 catalogue assembly: agents={agents_ms:.1f}ms skills={skills_ms:.1f}ms") async def _resolved(value): return value