Coverage for src/lilbee/server/handlers/agent_config.py: 100%

24 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-08-14 11:46 +0000

1"""Agent-client config handlers for the HTTP server.""" 

2 

3from __future__ import annotations 

4 

5import asyncio 

6 

7from lilbee.app.agent_configs.detect import detect_agent_clients 

8from lilbee.app.agent_configs.document import ( 

9 AgentClient, 

10 AgentConfigDocument, 

11 build_agent_config, 

12 client_serves_models, 

13) 

14from lilbee.app.models import installed_chat_model_refs 

15from lilbee.app.services import get_services 

16from lilbee.core.config import cfg 

17from lilbee.providers.model_ref import with_configured_remote_chat 

18from lilbee.server.auth import session_manager 

19from lilbee.server.models import AgentConfigIndexResponse, AgentConfigResponse 

20 

21 

22async def agent_config_index() -> AgentConfigIndexResponse: 

23 """Every supported client, with whether its CLI is installed on this machine.""" 

24 # Probing walks PATH and stats candidate directories; keep it off the loop. 

25 detections = await asyncio.to_thread(detect_agent_clients) 

26 return AgentConfigIndexResponse.from_detections(detections) 

27 

28 

29async def agent_config(client: AgentClient, base_url: str) -> AgentConfigResponse: 

30 """One client's config, carrying *base_url* and this server's current token.""" 

31 # The registry walk and the served-window probe both block. 

32 document = await asyncio.to_thread(_build_document, client, base_url) 

33 return AgentConfigResponse.from_document(document) 

34 

35 

36def _model_inputs(client: AgentClient) -> tuple[list[str] | None, int | None]: 

37 """The chat refs and served window to advertise, or ``None`` for an MCP-only client.""" 

38 if not client_serves_models(client): 

39 return None, None 

40 refs = with_configured_remote_chat(installed_chat_model_refs(), cfg.chat_model) 

41 return refs, get_services().provider.served_chat_ctx() 

42 

43 

44def _build_document(client: AgentClient, base_url: str) -> AgentConfigDocument: 

45 """Assemble *client*'s document from live server state.""" 

46 model_refs, chat_ctx = _model_inputs(client) 

47 return build_agent_config( 

48 client, 

49 base_url=base_url, 

50 # A server with auth disabled accepts an empty bearer, which is what a 

51 # client configured from it should send. 

52 api_key=session_manager.token or "", 

53 model_refs=model_refs, 

54 default_ref=str(cfg.chat_model) if model_refs is not None else None, 

55 chat_ctx=chat_ctx, 

56 )