Expand description
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);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: ephemeralbreakpoint 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:
- Explicit values on the struct.
- Environment variables (
SQLRITE_LLM_*). - Built-in defaults (model =
claude-sonnet-4-6, max_tokens = 1024, cache TTL = 5 min).
Re-exports§
pub use provider::anthropic::AnthropicProvider;pub use provider::Provider;pub use provider::Request;pub use provider::Response;pub use provider::Usage;
Modules§
- prompt
- Prompt construction — turn a schema dump + a natural-language question into the request shape Anthropic expects.
- provider
- LLM provider abstraction.
Structs§
- AskConfig
- Knobs for an
ask()call. Construct directly, or viaAskConfig::from_envto pull defaults from the environment. - AskResponse
- Result returned from a successful [
ask] call.
Enums§
- AskError
- Errors
ask()can return. Includes every failure mode along the path: config / network / API / parsing. - Cache
Ttl - Cache-TTL knob exposed on
AskConfig. - Provider
Kind - Which LLM provider [
ask] talks to. Anthropic-only in 7g.1; the enum is here so adding OpenAI/Ollama later doesn’t break theAskConfigshape.
Constants§
- DEFAULT_
MAX_ TOKENS - Default
max_tokens. SQL generation rarely needs more than ~500 output tokens (single-statement queries + a one-sentence explanation). 1024 leaves headroom; under the SDK timeout cap so we don’t have to stream. - DEFAULT_
MODEL - Default model — Sonnet 4.6 hits the cost-quality sweet spot for
NL→SQL. Override via
AskConfig::modelor theSQLRITE_LLM_MODELenv var. Seedocs/phase-7-plan.mdfor the model-choice rationale.
Functions§
- ask_
with_ schema - One-shot natural-language → SQL.
- ask_
with_ schema_ and_ provider - Lower-level entry point — same flow as
ask_with_schema, but you supply the provider directly. - parse_
response - Pull
sqlandexplanationout of the model’s reply.