sqlrite-ask 0.1.23

Natural-language → SQL adapter for sqlrite-engine. Anthropic-first; OpenAI / Ollama follow-ups.
Documentation

sqlrite-ask — natural-language → SQL adapter for SQLRite.

Phase 7g.2 made this crate pure — it no longer depends on sqlrite-engine. The canonical API takes a &str schema dump (built however you like — see sqlrite::ConnectionAskExt::ask for the engine-side helper that wraps it):

use sqlrite_ask::{ask_with_schema, AskConfig};

let schema = "\
CREATE TABLE users (\n  id INTEGER PRIMARY KEY,\n  name TEXT NOT NULL\n);\n";
let cfg  = AskConfig::from_env()?;          // reads SQLRITE_LLM_API_KEY etc.
let resp = ask_with_schema(schema, "How many users?", &cfg)?;
println!("{}", resp.sql);
# Ok::<(), sqlrite_ask::AskError>(())

For the engine-integrated form (conn.ask("...", &cfg)), enable the sqlrite-engine crate's ask feature and bring its ConnectionAskExt trait into scope:

use sqlrite::{Connection, ConnectionAskExt};
use sqlrite_ask::AskConfig;

let conn = Connection::open("foo.sqlrite")?;
let cfg  = AskConfig::from_env()?;
let resp = conn.ask("How many users?", &cfg)?;

Why the split (Phase 7g.2 retro)

Wiring the REPL's .ask meta-command would have required the engine binary to depend on sqlrite-ask, but sqlrite-ask already depended on sqlrite-engine (for Connection, Database, Table). Cargo's static cycle detection rejects that shape even with optional = true. Solution: keep this crate pure over &str inputs, move the engine integration (schema dump + ConnectionAskExt) into sqlrite-engine itself behind an ask feature. Now there's one direction of dep flow: engine → sqlrite-ask, never the other way.

What this crate is

  • Provider adapters (Anthropic now; OpenAI / Ollama later) that POST one HTTP request to a chat-completion endpoint per ask() call.
  • Prompt construction with a cache_control: ephemeral breakpoint on the schema block, so repeat calls against the same schema served from Anthropic's prompt cache.
  • Output parsing tolerant to fenced JSON / leading prose / strict JSON (model output drifts even with strict instructions).
  • AskConfig (env vars + explicit overrides), AskResponse { sql, explanation, usage }, AskError.

What this crate is NOT

  • Not an executor. The caller decides whether to run the generated SQL. SDK convenience wrappers (Python.Connection .ask_run, Node.db.askRun, etc.) layer that on top.
  • Not multi-turn. Stateless — every call is a fresh prompt.
  • Not engine-coupled. Schema introspection lives on the engine side as of v0.1.19 — see sqlrite::ConnectionAskExt.

Configuration

[AskConfig] resolves in this priority order:

  1. Explicit values on the struct.
  2. Environment variables (SQLRITE_LLM_*).
  3. Built-in defaults (model = claude-sonnet-4-6, max_tokens = 1024, cache TTL = 5 min).