Coverage for src/lilbee/server/handlers/agent_config.py: 100%
23 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-11-06 08:17 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-11-06 08:17 +0000
1"""Agent-client config handlers for the HTTP server."""
3from __future__ import annotations
5import asyncio
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, with_configured_chat
15from lilbee.app.services import get_services
16from lilbee.core.config import cfg
17from lilbee.server.auth import session_manager
18from lilbee.server.models import AgentConfigIndexResponse, AgentConfigResponse
21async def agent_config_index() -> AgentConfigIndexResponse:
22 """Every supported client, with whether its CLI is installed on this machine."""
23 # Probing walks PATH and stats candidate directories; keep it off the loop.
24 detections = await asyncio.to_thread(detect_agent_clients)
25 return AgentConfigIndexResponse.from_detections(detections)
28async def agent_config(client: AgentClient, base_url: str) -> AgentConfigResponse:
29 """One client's config, carrying *base_url* and this server's current token."""
30 # The registry walk and the served-window probe both block.
31 document = await asyncio.to_thread(_build_document, client, base_url)
32 return AgentConfigResponse.from_document(document)
35def _model_inputs(client: AgentClient) -> tuple[list[str] | None, int | None]:
36 """The chat refs and served window to advertise, or ``None`` for an MCP-only client."""
37 if not client_serves_models(client):
38 return None, None
39 refs = with_configured_chat(installed_chat_model_refs(), cfg.chat_model)
40 return refs, get_services().provider.served_chat_ctx()
43def _build_document(client: AgentClient, base_url: str) -> AgentConfigDocument:
44 """Assemble *client*'s document from live server state."""
45 model_refs, chat_ctx = _model_inputs(client)
46 return build_agent_config(
47 client,
48 base_url=base_url,
49 # A server with auth disabled accepts an empty bearer, which is what a
50 # client configured from it should send.
51 api_key=session_manager.token or "",
52 model_refs=model_refs,
53 default_ref=str(cfg.chat_model) if model_refs is not None else None,
54 chat_ctx=chat_ctx,
55 )