// llm_anthropic: cliente HTTP minimal a Anthropic Claude API. // Sin deps externas (cURL via popen). // Ver issue 0080. #pragma once #include "data_table_logic.h" #include "tql_to_sql.h" #include #include namespace llm_anthropic { enum class OutputMode { TQL, SQL }; struct AskInput { std::string question; // pregunta NL std::string tql_current; // TQL actual (emitido) std::vector col_names; // schema input std::vector col_types; std::vector joinable_names; // tables disponibles para join OutputMode mode = OutputMode::TQL; std::string model; // empty -> default int max_tokens = 8192; }; struct AskResult { std::string code; // bloque ```lua o ```sql extraido (sin fences) std::string raw; // texto completo de la respuesta std::string error; // non-empty si fallo int tokens_in = 0; int tokens_out = 0; }; // Pure: construye el system prompt y user message JSON-escapado. // Devuelve el JSON body completo POST al endpoint /v1/messages. std::string build_request_body(const AskInput& in); // Pure: extrae primer ```\n ... \n``` bloque de `raw`. lang = "lua"|"sql". // Si no encuentra fence, retorna raw stripped. std::string extract_code_block(const std::string& raw, const std::string& lang); // Pure: extrae texto del JSON de respuesta Anthropic. // Busca `"content":[{"type":"text","text":"..."}]` y devuelve el text. std::string parse_response_text(const std::string& json_body); // Impure: lanza cURL via popen, posts `body` al endpoint Anthropic /v1/messages, // retorna response body (JSON crudo). API key leida de: // 1. parametro `api_key` si non-empty // 2. env FN_LLM_API_KEY // 3. `pass anthropic/api-key | head -n1` // Si FN_LLM_MOCK_RESPONSE env set, retorna su valor (test injection). std::string call_api(const std::string& body, const std::string& api_key, std::string& error_out); // Orchestrator: build prompt + POST + parse. Convenience wrapper. AskResult ask(const AskInput& in, const std::string& api_key = ""); } // namespace llm_anthropic