"""Step 3 (SPEC L-13, L-16): the LLM turns the question into an `AgentLogQuery`. It never sees the logs.""" from dataclasses import dataclass from datetime import datetime from pydantic import ValidationError from app.agent.log_query import AgentLogQuery, json_schema from app.llm.provider import ChatMessage, JsonSchema, LLMProvider SCHEMA = JsonSchema(name="log_query", schema=json_schema()) @dataclass(frozen=True) class Plan: query: AgentLogQuery | None # None — the reply didn't pass validation error: str tokens: int def system_prompt(template: str, containers: list[str], default: str, now: datetime) -> str: # str.replace, not format: the template contains JSON braces return ( template.replace("{containers}", ", ".join(containers)) .replace("{default}", default) .replace("{now}", now.strftime("%Y-%m-%d %H:%M")) ) async def plan( llm: LLMProvider, template: str, prompt: str, containers: list[str], default: str, now: datetime ) -> Plan: messages = [ChatMessage("system", system_prompt(template, containers, default, now)), ChatMessage("user", prompt)] result = await llm.complete(messages, SCHEMA) if result.data is None: return Plan(None, "not JSON", result.tokens) try: query = AgentLogQuery.model_validate(result.data, context={"containers": containers}) except ValidationError as e: return Plan( None, "; ".join(f"{'.'.join(map(str, err['loc']))}: {err['msg']}" for err in e.errors())[:300], result.tokens, ) return Plan(query, "", result.tokens)