Search Shortcut cmd + k | ctrl + k
typed_ai

Ask a model yes/no, pick-one and score questions about your rows, with real probabilities and spending capped by default

Maintainer(s): hfmsio

Installing and Loading

INSTALL typed_ai FROM community;
LOAD typed_ai;

Example

-- Audit a chatbot: did each answer stick to its source? Needs TYPESAFE_API_KEY, or a local model profile.
CREATE SECRET jev (TYPE typed_ai, PROVIDER 'jev', API_KEY getenv('TYPESAFE_API_KEY'));
-- No key? A free local model works too (weaker answers):
-- CREATE SECRET local (TYPE typed_ai, PROVIDER 'openai', MODEL 'gemma2:2b',
--   URL 'http://localhost:11434/v1/chat/completions', USD_PER_MTOK_IN 0, USD_PER_MTOK_OUT 0);
CREATE TABLE bot_answers AS SELECT * FROM (VALUES
  ('Can I take photos?', 'Photography without flash is allowed in all galleries.', 'Yes, flash is fine everywhere.'),
  ('How heavy is the meteorite?', 'The Ashford meteorite weighs 412 kilograms.', 'It weighs about 412 kg.')
) t(question, source, answer);
CREATE TABLE topics AS SELECT * FROM (VALUES ('visiting rules'), ('science'), ('history')) t(name);

-- Price it first: no calls, no cost
SET typed_dry_run = true;
SELECT typed_prob(b, 'the answer is fully supported by the source') FROM bot_answers b;
SELECT dry_run_usd FROM typed_usage();
SET typed_dry_run = false;

-- The whole row goes in, so the model compares answer and source
SELECT answer, typed_prob(b, 'the answer is fully supported by the source') AS supported FROM bot_answers b;

-- Options can come from a table
SELECT question, typed_pick(question, 'what is the visitor asking about?', (SELECT list(name) FROM topics)) FROM bot_answers;

About typed_ai

typed_ai asks a model typed questions about rows and returns the model's own odds as probabilities. It works with TypeSafe Jev and with any OpenAI-compatible server that returns logprobs, including a local Ollama or vLLM.

Function Returns
typed_is(input, statement [, threshold]) BOOLEAN, for WHERE
typed_prob(input, statement) probability of yes, 0 to 1
typed_pick(input, question, options) the option the model rates highest; options can come from a table
typed_score(input, question, levels) probability-weighted level
typed_ask(input, question_json) the full answer as JSON
typed_usage() spend, budget, requests, cache and breaker state

Spending is capped from the first query: 1,000 rows per query and $1.00 per database until you raise typed_max_rows or typed_budget_usd. typed_dry_run prices a query without calling anything. A job that stops partway keeps every answer it paid for, so running it again costs only the missing rows.

Every value you judge is sent to the provider named in your profile (a DuckDB secret), over https unless that server runs on your own machine; keep private data on a local model. HTTP goes through httpfs, loaded on first use.

Added Functions

function_name function_type description comment examples
typed_ask scalar NULL NULL  
typed_is scalar NULL NULL  
typed_pick scalar NULL NULL  
typed_prob scalar NULL NULL  
typed_score scalar NULL NULL  
typed_usage table NULL NULL  

Overloaded Functions

This extension does not add any function overloads.

Added Types

This extension does not add any types.

Added Settings

name description input_type scope aliases
typed_batch_size Rows per request, up to the provider's limit BIGINT GLOBAL []
typed_budget_usd Most dollars this database may spend, counted since the extension loaded DOUBLE GLOBAL []
typed_cache_mb Memory for saved answers BIGINT GLOBAL []
typed_concurrency Requests in flight across the whole process BIGINT GLOBAL []
typed_dry_run Price queries and call nothing; results are NULL BOOLEAN GLOBAL []
typed_fail_after Failed requests in a row that stop calls for the rest of the query; 0 is off BIGINT GLOBAL []
typed_max_input_chars Longest input value, in characters; longer values are refused, never cut BIGINT GLOBAL []
typed_max_retries Extra attempts after a 408, 429, 5xx or dropped connection BIGINT GLOBAL []
typed_max_rows Most rows one query may send to the model; cached rows are free BIGINT GLOBAL []
typed_on_stop What a stopped job shows: 'error', 'null' or 'row' ({value, error} pairs) VARCHAR GLOBAL []
typed_profile Name of the typed_ai secret to use; empty picks the only one, or Jev from TYPESAFE_API_KEY VARCHAR GLOBAL []
typed_timeout_s Seconds per HTTP attempt BIGINT GLOBAL []