Search Shortcut cmd + k | ctrl + k
typed_ai

Use TypeSafe Jev (or another AI, even a free one on your laptop) to sort, filter and check the text in your tables. Get yes or no, pick one, or a rating, see how sure it is, and never spend more than your limit.

Maintainer(s): hfmsio

Installing and Loading

INSTALL typed_ai FROM community;
LOAD typed_ai;

Example

-- Sort a lost-and-found desk with TypeSafe Jev. The key comes from TYPESAFE_API_KEY.
CREATE SECRET jev (TYPE typed_ai, PROVIDER 'jev', API_KEY getenv('TYPESAFE_API_KEY'));

-- Other choices: run one of these in place of the line above. The rest stays the same.
-- A free local model (run `ollama pull gemma2:2b` first). Weaker answers; nothing leaves
-- your laptop.
-- 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);
-- OpenAI. In our October 2026 test it cost about 2.5 times as much as Jev and was less
-- accurate.
-- CREATE SECRET oai (TYPE typed_ai, PROVIDER 'openai', MODEL 'gpt-4o-mini',
--   API_KEY getenv('OPENAI_API_KEY'), USD_PER_MTOK_IN 0.15, USD_PER_MTOK_OUT 0.60);

CREATE TABLE found AS FROM (VALUES
  ('insulin pen in a blue case', 'waiting room'),
  ('laptop with a school sticker', 'train to the airport'),
  ('wedding ring wrapped in a napkin', 'cafe counter'),
  ('box of live crickets labelled lizard food', 'train to Leeds'),
  ('cello in a hard case', 'platform 3'),
  ('half-eaten sandwich', 'train to Leeds'),
  ('broken umbrella', 'platform 1')) t(item, place);
CREATE TABLE shelves AS FROM (VALUES ('medical'), ('electronics'), ('valuables'),
  ('animals'), ('food and rubbish'), ('general')) t(name);

-- Odds from 0 to 1
SELECT item, typed_prob(item, 'the owner needs this back today') AS urgent
FROM found ORDER BY urgent DESC;
-- insulin pen in a blue case                  0.59
-- laptop with a school sticker                0.54
-- wedding ring wrapped in a napkin            0.54
-- half-eaten sandwich                         0.37
-- broken umbrella                             0.34
-- cello in a hard case                        0.31
-- box of live crickets labelled lizard food   0.30

-- Pick a shelf; the options come from a table
SELECT item, typed_pick(item, 'which shelf?', (SELECT list(name) FROM shelves)) AS shelf
FROM found;
-- insulin pen in a blue case                  medical
-- laptop with a school sticker                electronics
-- wedding ring wrapped in a napkin            valuables
-- box of live crickets labelled lizard food   animals
-- cello in a hard case                        general
-- half-eaten sandwich                         food and rubbish
-- broken umbrella                             general

-- The whole row goes in, so the model sees where it was found
SELECT item FROM found f WHERE typed_is(f, 'it was left on a train');
-- laptop with a school sticker
-- box of live crickets labelled lizard food
-- half-eaten sandwich

-- What did that cost?
SELECT requests, printf('$%.5f', spent_usd) AS spent FROM typed_usage();
-- 3   $0.00009

About typed_ai

typed_ai lets you ask an AI simple questions about each row of a table, straight from SQL. It is built for TypeSafe Jev, which in our tests (October 2026) gave the most accurate answers at the lowest cost, since it answers many rows in one request. It also works with OpenAI, or with a free local AI on your own computer through Ollama. New AI services work too, with no update needed, as long as they use OpenAI's format and report how sure they are: point a secret at their web address.

Function What you get back
typed_is(value, statement [, cutoff]) true or false, for filtering with WHERE
typed_prob(value, statement) how likely the statement is true, from 0 to 1
typed_pick(value, question, options) the best option; the options can come from a table
typed_score(value, question, levels) a rating on your scale, e.g. 0 for the lowest level up to 3
typed_ask(value, question_json) the full answer, with the odds for every option
typed_usage() what you have spent, your limit, and how many answers were reused for free

value can be text, any other value, or a whole row.

Safe by default:

  • At most 1,000 rows per query and $1.00 in total, until you raise typed_max_rows or typed_budget_usd.
  • SET typed_dry_run = true shows what a query would cost without asking the AI anything.
  • If a job stops partway, the answers you paid for are kept. Run it again and you pay only for the rest.

Each value you check is sent to the AI service you set up. For private data, use a local model, so nothing leaves your computer.

Audit an AI agent

Did the agent do more than it was asked? The whole row goes in, so the model compares the request with the action.

CREATE TABLE agent_log AS FROM (VALUES
  ('book a table for 2 on Friday', 'booked a table for 2, Friday 7pm'),
  ('cancel my gym membership', 'cancelled it and deleted all workout history'),
  ('find a cheaper phone plan', 'listed 3 cheaper plans'),
  ('reply to Sam that I am running late', 'replied to Sam and to everyone in the team chat'),
  ('pay the electricity bill', 'paid the bill and set up autopay for 12 months'))
  t(asked, did);

SELECT asked, typed_prob(a, 'the agent did more than the user asked for') AS overreach
FROM agent_log a ORDER BY overreach DESC;
-- reply to Sam that I am running late   0.95
-- pay the electricity bill              0.95
-- cancel my gym membership              0.93
-- book a table for 2 on Friday          0.60   (the agent chose 7pm on its own)
-- find a cheaper phone plan             0.19

Find private data before sharing

Jev and a local model both name the kind of private data. To keep the notes on your machine, run SET typed_profile = 'local' first; the yes/no odds are less reliable on a small local model.

CREATE TABLE notes AS FROM (VALUES
  (1, 'Customer liked the new blue colour, wants it in size 10.'),
  (2, 'Call Priya back on 07700 900123 after 5pm.'),
  (3, 'Said she is on chemo, so deliveries must be left at the door.'),
  (4, 'Paid with a card ending 4417, asked for a refund next month.'),
  (5, 'Asked if the store opens on bank holidays.')) t(id, note);

SELECT id, typed_pick(note, 'what private data does this note contain?',
  ['none', 'contact details', 'health', 'money']) AS found FROM notes;
-- 1 none   2 contact details   3 health   4 money   5 none

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 []