--- warning: DO NOT CHANGE THIS MANUALLY, THIS IS GENERATED BY https://github.com/duckdb/community-extensions repository, check README there title: anofox_decide excerpt: | DuckDB Community Extensions Natural-language decisions on your data inside DuckDB — yes/no probabilities, one-of-N choices and ordinal scores with the answer sets written in the query, from hosted (TypeSafe Jev, Liquid AI D1, OpenAI Decisions), local-server and in-process ONNX decision models, plus calibration metrics extension: name: anofox_decide description: Natural-language decisions on your data inside DuckDB — yes/no probabilities, one-of-N choices and ordinal scores with the answer sets written in the query, from hosted (TypeSafe Jev, Liquid AI D1, OpenAI Decisions), local-server and in-process ONNX decision models, plus calibration metrics version: '2026.10.31' language: C++ build: cmake license: MIT maintainers: - sipemu - jrosskopf excluded_platforms: "wasm_mvp;wasm_eh;wasm_threads;windows_amd64_mingw;linux_amd64_musl;osx_amd64" repo: github: DataZooDE/anofox-decide ref: edf0fb28710f147cf2faa8bc93ea83d597ab7e32 variegata: edf0fb28710f147cf2faa8bc93ea83d597ab7e32 docs: hello_world: | -- Try the SQL with the built-in test model: no key, no network. It returns -- constants (0.5, the first option), so it can never pass for a real answer. SELECT decide_probability('The customer requests a refund.', 'A refund is requested.', model := 'stub') AS p; -- Real answers: register a hosted model, opt in to remote calls, and ask. -- (export LIQUID_API_KEY=... before starting DuckDB; a DuckDB secret overrides it) SET anofox_decide_allow_remote = true; -- your text goes to the provider SELECT decide_register_model('d1', 'liquid'); SET anofox_decide_model = 'd1'; SELECT id, decide_probability(text, 'A refund is requested.') AS p_refund, decide_choice(text, 'Which team owns this?', ['billing', 'defect', 'other']) AS team, decide_score(text, 'How frustrated is the writer?', ['calm', 'frustrated', 'angry']) AS frustration FROM (VALUES (1, 'I was charged twice for my March invoice, please refund the extra 49 EUR.'), (2, 'The app crashes every time I open the export dialog on version 3.2.')) t(id, text); -- Something not working? One row per check, with the fix for each problem. SELECT * FROM decide_doctor(); extended_description: | **anofox_decide** turns natural-language questions about text or structured data into SQL functions. Ask a yes/no question, choose one of the options *you* define, or rate a text on an ordered scale; purpose-built decision models answer with **calibrated probabilities**, so you choose the threshold and can measure how good the answers are. No training, no prompt engineering, no glue code: the questions and the answer sets are written in the query. ### Three kinds of question - **binary** — `decide_probability(state, 'A refund is requested.')` is the probability that a statement holds; `decide_decision(state, question, 0.7)` applies an explicit threshold (never guessed for you). - **choice** — `decide_choice(state, 'Which team owns this?', ['billing','defect','other'])` picks one option from a list you define at query time, with the probability of each. - **score** — `decide_score(state, 'How frustrated is the writer?', ['calm','frustrated','angry'])` rates a text on an ordered rubric of 2 to 10 levels and returns the expected level. Several questions about the same text go in one request with `decide_many` (JSON), `decide_table` (one row per question: probability, choice, score, per-option distribution) or `decide_answers` (the same rows as a list you `unnest`, which scores a whole table concurrently). ### Pick the model that fits One interface, several models, comparable in a single query: - **Hosted:** TypeSafe **Jev** (`typesafe`), Liquid AI **D1** (`liquid`) and Cloudflare **Clef** / **Clef-flash** (`cloudflare`, on Workers AI) and OpenAI **gpt-6-luna** (`openai`, the Decisions API; a refusal comes back as NULL). Calls send the text you score to the provider, so they sit behind an explicit opt-in (`anofox_decide_allow_remote`), off by default. - **Local servers:** [strands-decider](https://github.com/strands-labs/strands-decider) (`strands`, keyless, on loopback), Kev, or any System One compatible endpoint (`systemone`). - **In-process and offline:** **Laya** (multilingual or typed-decisions) and **Julia-1** on ONNX Runtime (`local`). `CALL decide_download('laya-multilingual')` fetches the upstream weights from Hugging Face once (about 0.7 GB, pinned and SHA-256 verified); after that it runs inside DuckDB with no Python and no network. Over-long text raises an error instead of being cut silently (`decide_token_count` shows what fits). - **`stub`:** a built-in test model that returns constants, so the SQL can be tried with no key. API keys come from environment variables or DuckDB secrets (`CREATE SECRET (TYPE anofox_decide, API_KEY '...', SCOPE 'api.liquid.ai')`); a secret always overrides the environment, and a key is only ever sent to the host it was configured for. **The extension ships no model weights**: local models download the upstream files on request. ### Built for many rows Scalar calls over a table evaluate a chunk of rows together: identical requests are sent once, up to `anofox_decide_max_concurrency` remote requests run at the same time (default 8 for hosted providers), connections are reused, and a rate limit makes the query back off. On the real Liquid D1 service, 8 tickets with three questions each took 176.7 s one at a time and 23.1 s this way. ### Know how good it is, and fix the cut-off `decide_accuracy`, `decide_brier_score` and `decide_ece` aggregate over `(probability, label)` pairs, so comparing models on your own labelled data is one query. A 200-ticket evaluation of every supported model on public data is in the repository (`docs/EVALUATION.md`). Some models rank well but are wrong at the 0.5 cut-off. `decide_fit_calibration(p, outcome)` fits Platt scaling to a labelled sample and returns a spec you register the model with (`MAP {'calibration': 'platt:1.92,-0.72'}`); the ranking never changes, and choice and score answers are untouched. `decide_choice_distribution` returns the probability of every option, so a low-confidence answer can be left undecided in plain SQL. ### Errors that say what to do Every error is `: . Fix: ` and echoes the value that caused it. `decide_doctor()` checks the whole setup, and `decide_models()` shows which models can be called right now and why not. ### Surface - `decide_probability` / `decide_decision` / `decide_choice` / `decide_choice_distribution` / `decide_score` — evaluate one question - `decide_many` / `decide_table` / `decide_answers` — several questions about one text, as JSON, rows, or a list to `unnest` - `decide_accuracy` / `decide_brier_score` / `decide_ece` / `decide_fit_calibration` — quality metrics and calibration (aggregates) - `decide_register_model` / `decide_unregister_model` / `decide_models` / `decide_doctor` — models and diagnostics - `decide_download` / `decide_token_count` — fetch a local model, count tokens for its window - `SET anofox_decide_*` settings (default model, remote opt-in, concurrency, timeout, retries) Every function is also available as `anofox_decide_*`. See the [project repository](https://github.com/DataZooDE/anofox-decide) for the full SQL API, examples and troubleshooting. extension_star_count: 3 extension_star_count_pretty: 3 extension_download_count: 874 extension_download_count_pretty: 874 image: '/images/community_extensions/social_preview/preview_community_extension_anofox_decide.png' layout: community_extension_doc --- ### Compatibility Matrix This table covers all DuckDB releases that have not reached [end-of-life](https://duckdb.org/release_calendar), including LTS releases, and shows the 2 most recent patch releases of each. Older patch releases are not listed, but the extension may be available for them as well.
| Platform | 1.4.4 | 1.4.5 | 1.5.5 | 1.5.6 | 2.0.0 | | :--- | :---: | :---: | :---: | :---: | :---: | | Linux AMD64 | ❌ | ❌ | ❌ | ✅ | ✅ | | Linux ARM64 | ❌ | ❌ | ❌ | ✅ | ✅ | | macOS AMD64 | ❌ | ❌ | ❌ | ❌ | ❌ | | macOS ARM64 | ❌ | ❌ | ❌ | ✅ | ✅ | | Windows AMD64 | ❌ | ❌ | ❌ | ✅ | ✅ | | Windows ARM64 | ❌ | ❌ | ❌ | ❌ | ❌ | | WebAssembly | ❌ | ❌ | ❌ | ❌ | ❌ | ### Installing and Loading ```sql INSTALL {{ page.extension.name }} FROM community; LOAD {{ page.extension.name }}; ``` {% if page.docs.hello_world %} ### Example ```sql {{ page.docs.hello_world }}``` {% endif %} {% if page.docs.extended_description %} ### About {{ page.extension.name }} {{ page.docs.extended_description }} {% endif %} ### Added Functions
| function_name | function_type | description | comment | examples | |------------------------------------|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | anofox_contract_version | scalar | Returns the version of the anofox integration contract (output schemas and duckdb_functions() tags) this extension implements. | NULL | [anofox_contract_version()] | | anofox_decide_accelerate | table | One call from installed to using the GPU: finds the GPU, downloads and verifies the matching plugin and checks that it loads. With nothing usable it says so and the CPU keeps serving. Takes effect in this session. Columns: step, status, detail. | NULL | [CALL decide_accelerate();] | | anofox_decide_accuracy | aggregate | Fraction of rows where thresholding the probability reproduces the outcome. The two-argument form uses the documented 0.5 boundary; the three-argument form takes an explicit threshold in [0, 1] (NaN or out-of-range thresholds raise an error). NULL inputs are skipped; empty input returns NULL. | NULL | [SELECT decide_accuracy(p, y) FROM labeled;] | | anofox_decide_accuracy | aggregate | Fraction of rows where thresholding the probability reproduces the outcome. The two-argument form uses the documented 0.5 boundary; the three-argument form takes an explicit threshold in [0, 1] (NaN or out-of-range thresholds raise an error). NULL inputs are skipped; empty input returns NULL. | NULL | [SELECT decide_accuracy(p, y, 0.7) FROM labeled;] | | anofox_decide_accuracy | aggregate | Fraction of rows where thresholding the probability reproduces the outcome. The two-argument form uses the documented 0.5 boundary; the three-argument form takes an explicit threshold in [0, 1] (NaN or out-of-range thresholds raise an error). NULL inputs are skipped; empty input returns NULL. | NULL | [SELECT decide_accuracy(p, y::BIGINT) FROM labeled;] | | anofox_decide_answers | scalar | Evaluate several questions against one `state` and return one row per question as a list of structs (question_id, kind, probability, choice, confidence, model, score, distribution), the same rows decide_table returns. `questions` is the JSON array decide_many takes. Use unnest(decide_answers(...), recursive := true) to get decide_table's columns for every row of a table. Unlike LATERAL decide_table, it runs in the scalar pipeline: the rows of a chunk are scored concurrently (anofox_decide_max_concurrency), identical rows are sent once and calibration applies. NULL state or questions returns NULL (no rows after unnest). | NULL | [-- uses the session default model: SET anofox_decide_model = '';
SELECT decide_answers('The bill is wrong.', '[{"id":"refund","kind":"binary","instruction":"A refund is requested."}]');] | | anofox_decide_answers | scalar | Evaluate several questions against one `state` and return one row per question as a list of structs (question_id, kind, probability, choice, confidence, model, score, distribution), the same rows decide_table returns. `questions` is the JSON array decide_many takes. Use unnest(decide_answers(...), recursive := true) to get decide_table's columns for every row of a table. Unlike LATERAL decide_table, it runs in the scalar pipeline: the rows of a chunk are scored concurrently (anofox_decide_max_concurrency), identical rows are sent once and calibration applies. NULL state or questions returns NULL (no rows after unnest). | NULL | [SELECT id, unnest(decide_answers(body, '[{"id":"refund","kind":"binary","instruction":"A refund is requested."}]', model := 'jev-latest'), recursive := true) FROM tickets;] | | anofox_decide_auc | aggregate | Area under the ROC curve of predicted probabilities against observed outcomes: the chance that a random positive gets a higher probability than a random negative, ties counting one half (scikit-learn roc_auc_score; higher is better, 0.5 is chance). NULL when only one outcome occurs. Rows with a NULL probability or outcome are skipped; empty input returns NULL. | NULL | [SELECT decide_auc(p, y) FROM labeled;] | | anofox_decide_auc | aggregate | Area under the ROC curve of predicted probabilities against observed outcomes: the chance that a random positive gets a higher probability than a random negative, ties counting one half (scikit-learn roc_auc_score; higher is better, 0.5 is chance). NULL when only one outcome occurs. Rows with a NULL probability or outcome are skipped; empty input returns NULL. | NULL | [SELECT decide_auc(p, y::BIGINT) FROM labeled;] | | anofox_decide_backends | table | Which device can serve which local model, and why not: one row per local model and discovered device. supported is NULL while the model is not downloaded. 'auto' only ever picks a device this function calls supported. Columns: model, device, supported, reason. | NULL | [SELECT * FROM decide_backends() WHERE NOT supported;] | | anofox_decide_brier_score | aggregate | Brier score of predicted probabilities against observed outcomes: mean squared difference between the probability and the 0/1 outcome (lower is better; 0 is perfect, 0.25 is a constant 0.5). Rows with a NULL probability or outcome are skipped; empty input returns NULL. | NULL | [SELECT decide_brier_score(p, y) FROM labeled;] | | anofox_decide_brier_score | aggregate | Brier score of predicted probabilities against observed outcomes: mean squared difference between the probability and the 0/1 outcome (lower is better; 0 is perfect, 0.25 is a constant 0.5). Rows with a NULL probability or outcome are skipped; empty input returns NULL. | NULL | [SELECT decide_brier_score(p, y::BIGINT) FROM labeled;] | | anofox_decide_calibration_curve_by | table_macro | Table macro: the calibration (reliability) curve of decide probabilities against observed outcomes, one per group of source (the anofox integration contract's `curve` schema, curve_type 'calibration', for anofox_plot). Probabilities fall in n_bins equal-width bins on P(yes) (default 10; decide_ece's edges); one row per non-empty bin: the group column, model_id (the group), series, curve_type, x (mean probability), y (fraction of positives), y_low / y_high (95% Wilson interval), threshold, weight (rows in the bin), n_censor, row_order (1-based, by bin). Rows with a NULL probability or outcome are skipped. | NULL | [SELECT * FROM decide_calibration_curve_by('scored', model, p, y, n_bins := 10)] | | anofox_decide_choice | scalar | Choose the single best answer for `question` from a runtime-defined list of `options` given `state`. Returns the winning option; the score distribution is available through decide_many and decide_table. An empty or NULL option list raises an actionable error. | NULL | [-- uses the session default model: SET anofox_decide_model = '';
SELECT decide_choice('Invoice charged twice', 'Primary issue?', ['billing','defect','other']);] | | anofox_decide_choice | scalar | Choose the single best answer for `question` from a runtime-defined list of `options` given `state`. Returns the winning option; the score distribution is available through decide_many and decide_table. An empty or NULL option list raises an actionable error. | NULL | [-- uses the session default model: SET anofox_decide_model = '';
SELECT decide_choice('Invoice charged twice', 'Primary issue?', ['billing','defect']);] | | anofox_decide_choice | scalar | Choose the single best answer for `question` from a runtime-defined list of `options` given `state`. Returns the winning option; the score distribution is available through decide_many and decide_table. An empty or NULL option list raises an actionable error. | NULL | [SELECT decide_choice('Invoice charged twice', 'Primary issue?', ['billing','defect'], model := 'stub');] | | anofox_decide_choice | scalar | Choose the single best answer for `question` from a runtime-defined list of `options` given `state`. Returns the winning option; the score distribution is available through decide_many and decide_table. An empty or NULL option list raises an actionable error. | NULL | [SELECT decide_choice(body, 'Which team owns this?', ['billing','defect','other'], model := 'jev-latest') FROM tickets;] | | anofox_decide_choice_distribution | scalar | Probability of every option for `question` given `state`, as MAP(VARCHAR, DOUBLE) (the probabilities sum to 1). Same arguments as decide_choice, which returns only the winner; use this to read the confidence, set a minimum probability and abstain, or compare models. An empty or NULL option list raises an actionable error. | NULL | [SELECT decide_choice_distribution('Invoice charged twice', 'Primary issue?', ['billing','defect','other']);] | | anofox_decide_choice_distribution | scalar | Probability of every option for `question` given `state`, as MAP(VARCHAR, DOUBLE) (the probabilities sum to 1). Same arguments as decide_choice, which returns only the winner; use this to read the confidence, set a minimum probability and abstain, or compare models. An empty or NULL option list raises an actionable error. | NULL | [SELECT decide_choice_distribution('Invoice charged twice', 'Primary issue?', ['billing','defect']);] | | anofox_decide_choice_distribution | scalar | Probability of every option for `question` given `state`, as MAP(VARCHAR, DOUBLE) (the probabilities sum to 1). Same arguments as decide_choice, which returns only the winner; use this to read the confidence, set a minimum probability and abstain, or compare models. An empty or NULL option list raises an actionable error. | NULL | [SELECT decide_choice_distribution('Invoice charged twice', 'Primary issue?', ['billing','defect'], model := 'stub');] | | anofox_decide_choice_distribution | scalar | Probability of every option for `question` given `state`, as MAP(VARCHAR, DOUBLE) (the probabilities sum to 1). Same arguments as decide_choice, which returns only the winner; use this to read the confidence, set a minimum probability and abstain, or compare models. An empty or NULL option list raises an actionable error. | NULL | [SELECT map_extract(decide_choice_distribution(body, 'Which team owns this?', ['billing','defect','other'], model := 'jev-latest'), 'billing')[1] AS p_billing FROM tickets;] | | anofox_decide_decision | scalar | Boolean decision: true when the probability that `question` holds for `state` reaches `threshold` (0 to 1, inclusive). NULL state or question returns NULL; NaN or out-of-range thresholds raise an error instead of clamping. | NULL | [-- uses the session default model: SET anofox_decide_model = '';
SELECT decide_decision('The customer requests a refund.', 'A refund is requested.', 0.7);] | | anofox_decide_decision | scalar | Boolean decision: true when the probability that `question` holds for `state` reaches `threshold` (0 to 1, inclusive). NULL state or question returns NULL; NaN or out-of-range thresholds raise an error instead of clamping. | NULL | [SELECT decide_decision(body, 'A refund is requested.', 0.7, model := 'jev-latest') FROM tickets;] | | anofox_decide_devices | table | List the devices this machine can score local models on: the cpu (always there) and any NVIDIA, AMD or Apple GPU found. usable = false names the reason. A GPU is only used after CALL decide_accelerate() has installed its plugin. Columns: device_id, backend, name, arch, vram_total, vram_free, driver, usable, reason. | NULL | [SELECT * FROM decide_devices();] | | anofox_decide_doctor | table | Check whether the setup is ready and say how to fix what is not: the default model, the registered models, the remote opt-in, one row per registered model (files readable, API key found and from where, endpoint) and the telemetry state. Columns: item, status (ok / warn / fail), detail, fix. Run it first when a call does not work. | NULL | [SELECT * FROM decide_doctor();] | | anofox_decide_download | table | Download a local model's weights from Hugging Face into the cache directory (anofox_decide_cache_dir, default ~/.cache/anofox-decide), then use it offline with model := ''. Models: julia-1 (0.6 GB), laya-multilingual (0.7 GB), laya-typed-decisions (0.85 GB). Files are verified (size, sha256) and a partial download resumes. Columns: model, file, bytes, status (cached / downloaded / resumed), path. | NULL | [CALL decide_download('laya-multilingual');] | | anofox_decide_download_runtime | table | Download the GPU plugin for 'cuda', 'rocm' or 'mlx' into anofox_decide_plugin_dir (default /plugins) and verify it against the sha256 published with the release before it is moved into place, and again on every later call of this function (a mismatch deletes it). CUDA also fetches the pinned ONNX Runtime GPU runtime. Refuses a platform nothing is published for before downloading. Columns: file, bytes, status (cached / downloaded). | NULL | [CALL decide_download_runtime('cuda');] | | anofox_decide_ece | aggregate | Expected calibration error over ten equal-width probability bins: the bin-weighted gap between average confidence and accuracy (lower is better). Rows with a NULL probability or outcome are skipped; empty input returns NULL. | NULL | [SELECT decide_ece(p, y) FROM labeled;] | | anofox_decide_ece | aggregate | Expected calibration error over ten equal-width probability bins: the bin-weighted gap between average confidence and accuracy (lower is better). Rows with a NULL probability or outcome are skipped; empty input returns NULL. | NULL | [SELECT decide_ece(p, y::BIGINT) FROM labeled;] | | anofox_decide_fit_calibration | aggregate | Fit Platt scaling from labelled data: given a model's yes/no probabilities and the true outcomes, returns the calibration spec 'platt:a,b' (p' = sigmoid(a * logit(p) + b), a > 0) to pass as MAP {'calibration': ...} to decide_register_model. It fixes a model whose cut-off is off (such as one that says yes too often at 0.5) without changing its ranking. Needs both outcomes and non-constant probabilities; rows with NULLs are skipped; empty input returns NULL. Fit on held-out labelled data, then check the result with decide_brier_score / decide_ece on another sample. | NULL | [SELECT decide_fit_calibration(p, y) FROM labeled;] | | anofox_decide_fit_calibration | aggregate | Fit Platt scaling from labelled data: given a model's yes/no probabilities and the true outcomes, returns the calibration spec 'platt:a,b' (p' = sigmoid(a * logit(p) + b), a > 0) to pass as MAP {'calibration': ...} to decide_register_model. It fixes a model whose cut-off is off (such as one that says yes too often at 0.5) without changing its ranking. Needs both outcomes and non-constant probabilities; rows with NULLs are skipped; empty input returns NULL. Fit on held-out labelled data, then check the result with decide_brier_score / decide_ece on another sample. | NULL | [SELECT decide_fit_calibration(p, y::BIGINT) FROM labeled;] | | anofox_decide_gpu_precompile | table | Compile a local model's shape buckets ahead of time on the ROCm (MIGraphX) backend, so no query stalls on a first-use compile. Each bucket takes 2-4 minutes once and leaves 0.6-1.7 GB in the cache (progress is printed while it runs); a cached bucket only loads. Compiles one row and a full batch for every token bucket (Laya: 256 and 1024; Julia-1: 256 to 8192), or only the bucket that holds `seq` tokens. Needs the model on a compile-per-shape GPU device (SET anofox_decide_device = 'rocm';). Columns: model, device, batch, seq, markers, seconds. | NULL | [CALL decide_gpu_precompile('laya-multilingual');] | | anofox_decide_log_loss | aggregate | Log loss (mean binary cross-entropy) of predicted probabilities against observed outcomes, with the probability clipped to [1e-15, 1 - 1e-15] as scikit-learn's log_loss (lower is better). Rows with a NULL probability or outcome are skipped; empty input returns NULL. | NULL | [SELECT decide_log_loss(p, y) FROM labeled;] | | anofox_decide_log_loss | aggregate | Log loss (mean binary cross-entropy) of predicted probabilities against observed outcomes, with the probability clipped to [1e-15, 1 - 1e-15] as scikit-learn's log_loss (lower is better). Rows with a NULL probability or outcome are skipped; empty input returns NULL. | NULL | [SELECT decide_log_loss(p, y::BIGINT) FROM labeled;] | | anofox_decide_many | scalar | Evaluate several questions against one `state` in a single provider call. `questions` is a JSON array of {id, kind: 'binary'\|'choice'\|'score', instruction[, options \| levels]} objects; returns a JSON object {model, results: [...]} with one answer per question, in order: id, kind and probability; a choice adds `choice` and the per-option `probabilities`; a score adds `score` (the expected 0-based level) and the per-level `probabilities`. Remote providers receive one request for the whole batch. | NULL | [-- uses the session default model: SET anofox_decide_model = '';
SELECT decide_many('The bill is wrong.', '[{"id":"refund","kind":"binary","instruction":"A refund is requested."}]');] | | anofox_decide_many | scalar | Evaluate several questions against one `state` in a single provider call. `questions` is a JSON array of {id, kind: 'binary'\|'choice'\|'score', instruction[, options \| levels]} objects; returns a JSON object {model, results: [...]} with one answer per question, in order: id, kind and probability; a choice adds `choice` and the per-option `probabilities`; a score adds `score` (the expected 0-based level) and the per-level `probabilities`. Remote providers receive one request for the whole batch. | NULL | [SELECT decide_many(body, '[{"id":"refund","kind":"binary","instruction":"A refund is requested."}]', model := 'jev-latest') FROM tickets;] | | anofox_decide_metrics_by | table_macro | Table macro: decide's quality metrics per group of source, one row per metric (the anofox integration contract's `summary` schema, for anofox_plot): the group column, model_id (the group), metric (accuracy at 0.5, auc, brier, ece, log_loss), value, conf_low, conf_high, row_order (1-based). A metric that is undefined for a group (auc with one outcome) is left out. Rows with a NULL probability or outcome are skipped. | NULL | [SELECT * FROM decide_metrics_by('scored', model, p, y)] | | anofox_decide_models | table | List the models registered on this database instance and whether each can be called now. Columns: model, provider, mode ('test' / 'local' / 'remote'), path, is_default, ready, hint (what to do when it is not ready), profile, endpoint, wire_model. The built-in 'stub' test model is always present; register more with decide_register_model. | NULL | [SELECT * FROM decide_models();] | | anofox_decide_probability | scalar | Probability (0 to 1) that the statement `question` holds for `state`, scored by the named model (`model :=`, or the anofox_decide_model setting; with neither the call fails and says how to choose one). NULL state or question returns NULL; unknown models, remote calls without opt-in and missing API keys raise errors that name the fixing call. | NULL | [-- uses the session default model: SET anofox_decide_model = '';
SELECT decide_probability('The customer requests a refund.', 'A refund is requested.');] | | anofox_decide_probability | scalar | Probability (0 to 1) that the statement `question` holds for `state`, scored by the named model (`model :=`, or the anofox_decide_model setting; with neither the call fails and says how to choose one). NULL state or question returns NULL; unknown models, remote calls without opt-in and missing API keys raise errors that name the fixing call. | NULL | [SELECT decide_probability(body, 'A refund is requested.', model := 'jev-latest') FROM tickets;] | | anofox_decide_register_model | scalar | Register a model id for this database instance and return true. Providers: 'stub' (deterministic), 'local' (ONNX graph and tokenizer paths, optional profile 'julia-1' or 'laya'), and the remote providers 'typesafe', 'liquid', 'cloudflare' (Clef on Workers AI: models 'clef' and 'clef-flash', account id from the account_id option or CLOUDFLARE_ACCOUNT_ID), 'openai' (OpenAI Decisions, model 'gpt-6-luna', key OPENAI_API_KEY; options input ('auto', 'text' or 'json': JSON state is sent as structured data) and prompt_cache_key; a refused answer is NULL), 'systemone' and 'strands' (optional options MAP with endpoint, path, model, key_env, criteria, account_id). The options MAP also takes calibration, 'platt:a,b', for any provider: it rescales that model's yes/no probabilities (fit a and b with decide_fit_calibration). Duplicate ids, unsupported providers and unreadable files raise actionable errors. | NULL | [SELECT decide_register_model('jev-latest', 'typesafe');] | | anofox_decide_register_model | scalar | Register a model id for this database instance and return true. Providers: 'stub' (deterministic), 'local' (ONNX graph and tokenizer paths, optional profile 'julia-1' or 'laya'), and the remote providers 'typesafe', 'liquid', 'cloudflare' (Clef on Workers AI: models 'clef' and 'clef-flash', account id from the account_id option or CLOUDFLARE_ACCOUNT_ID), 'openai' (OpenAI Decisions, model 'gpt-6-luna', key OPENAI_API_KEY; options input ('auto', 'text' or 'json': JSON state is sent as structured data) and prompt_cache_key; a refused answer is NULL), 'systemone' and 'strands' (optional options MAP with endpoint, path, model, key_env, criteria, account_id). The options MAP also takes calibration, 'platt:a,b', for any provider: it rescales that model's yes/no probabilities (fit a and b with decide_fit_calibration). Duplicate ids, unsupported providers and unreadable files raise actionable errors. | NULL | [SELECT decide_register_model('julia-1', 'local', '/models/julia1.onnx');] | | anofox_decide_register_model | scalar | Register a model id for this database instance and return true. Providers: 'stub' (deterministic), 'local' (ONNX graph and tokenizer paths, optional profile 'julia-1' or 'laya'), and the remote providers 'typesafe', 'liquid', 'cloudflare' (Clef on Workers AI: models 'clef' and 'clef-flash', account id from the account_id option or CLOUDFLARE_ACCOUNT_ID), 'openai' (OpenAI Decisions, model 'gpt-6-luna', key OPENAI_API_KEY; options input ('auto', 'text' or 'json': JSON state is sent as structured data) and prompt_cache_key; a refused answer is NULL), 'systemone' and 'strands' (optional options MAP with endpoint, path, model, key_env, criteria, account_id). The options MAP also takes calibration, 'platt:a,b', for any provider: it rescales that model's yes/no probabilities (fit a and b with decide_fit_calibration). Duplicate ids, unsupported providers and unreadable files raise actionable errors. | NULL | [SELECT decide_register_model('julia-1', 'local', '/models/julia1.onnx', '/models/tokenizer/tokenizer.json');] | | anofox_decide_register_model | scalar | Register a model id for this database instance and return true. Providers: 'stub' (deterministic), 'local' (ONNX graph and tokenizer paths, optional profile 'julia-1' or 'laya'), and the remote providers 'typesafe', 'liquid', 'cloudflare' (Clef on Workers AI: models 'clef' and 'clef-flash', account id from the account_id option or CLOUDFLARE_ACCOUNT_ID), 'openai' (OpenAI Decisions, model 'gpt-6-luna', key OPENAI_API_KEY; options input ('auto', 'text' or 'json': JSON state is sent as structured data) and prompt_cache_key; a refused answer is NULL), 'systemone' and 'strands' (optional options MAP with endpoint, path, model, key_env, criteria, account_id). The options MAP also takes calibration, 'platt:a,b', for any provider: it rescales that model's yes/no probabilities (fit a and b with decide_fit_calibration). Duplicate ids, unsupported providers and unreadable files raise actionable errors. | NULL | [SELECT decide_register_model('kev-latest', 'systemone', MAP {'endpoint': 'http://127.0.0.1:8009'});] | | anofox_decide_register_model | scalar | Register a model id for this database instance and return true. Providers: 'stub' (deterministic), 'local' (ONNX graph and tokenizer paths, optional profile 'julia-1' or 'laya'), and the remote providers 'typesafe', 'liquid', 'cloudflare' (Clef on Workers AI: models 'clef' and 'clef-flash', account id from the account_id option or CLOUDFLARE_ACCOUNT_ID), 'openai' (OpenAI Decisions, model 'gpt-6-luna', key OPENAI_API_KEY; options input ('auto', 'text' or 'json': JSON state is sent as structured data) and prompt_cache_key; a refused answer is NULL), 'systemone' and 'strands' (optional options MAP with endpoint, path, model, key_env, criteria, account_id). The options MAP also takes calibration, 'platt:a,b', for any provider: it rescales that model's yes/no probabilities (fit a and b with decide_fit_calibration). Duplicate ids, unsupported providers and unreadable files raise actionable errors. | NULL | [SELECT decide_register_model('laya', 'local', '/models/laya.onnx', '/models/tokenizer/tokenizer.json', 'laya');] | | anofox_decide_register_model | scalar | Register a model id for this database instance and return true. Providers: 'stub' (deterministic), 'local' (ONNX graph and tokenizer paths, optional profile 'julia-1' or 'laya'), and the remote providers 'typesafe', 'liquid', 'cloudflare' (Clef on Workers AI: models 'clef' and 'clef-flash', account id from the account_id option or CLOUDFLARE_ACCOUNT_ID), 'openai' (OpenAI Decisions, model 'gpt-6-luna', key OPENAI_API_KEY; options input ('auto', 'text' or 'json': JSON state is sent as structured data) and prompt_cache_key; a refused answer is NULL), 'systemone' and 'strands' (optional options MAP with endpoint, path, model, key_env, criteria, account_id). The options MAP also takes calibration, 'platt:a,b', for any provider: it rescales that model's yes/no probabilities (fit a and b with decide_fit_calibration). Duplicate ids, unsupported providers and unreadable files raise actionable errors. | NULL | [SELECT decide_register_model('laya', 'local', '/models/laya.onnx', '/models/tokenizer/tokenizer.json', 'laya', MAP {'calibration': 'platt:1.1,-0.3'});] | | anofox_decide_register_model | scalar | Register a model id for this database instance and return true. Providers: 'stub' (deterministic), 'local' (ONNX graph and tokenizer paths, optional profile 'julia-1' or 'laya'), and the remote providers 'typesafe', 'liquid', 'cloudflare' (Clef on Workers AI: models 'clef' and 'clef-flash', account id from the account_id option or CLOUDFLARE_ACCOUNT_ID), 'openai' (OpenAI Decisions, model 'gpt-6-luna', key OPENAI_API_KEY; options input ('auto', 'text' or 'json': JSON state is sent as structured data) and prompt_cache_key; a refused answer is NULL), 'systemone' and 'strands' (optional options MAP with endpoint, path, model, key_env, criteria, account_id). The options MAP also takes calibration, 'platt:a,b', for any provider: it rescales that model's yes/no probabilities (fit a and b with decide_fit_calibration). Duplicate ids, unsupported providers and unreadable files raise actionable errors. | NULL | [SELECT decide_register_model('my-stub');] | | anofox_decide_roc_curve_by | table_macro | Table macro: the ROC curve of decide probabilities against observed outcomes, one per group of source (scikit-learn roc_curve; the anofox integration contract's `curve` schema, curve_type 'roc', for anofox_plot). One row per point: the group column, model_id (the group), series, curve_type, x (false positive rate), y (true positive rate), y_low, y_high, threshold (the probability; +inf for the (0, 0) start), weight, n_censor, row_order (1-based, along the curve). Tied probabilities form one point; drop_intermediate (default true) drops the points on straight segments. Rows with a NULL probability or outcome are skipped; a group with only one outcome has no curve. | NULL | [SELECT * FROM decide_roc_curve_by('scored', model, p, y)] | | anofox_decide_score | scalar | Rate `state` on an ordered rubric of 2 to 10 level descriptions (lowest first) and return the expected level index (0-based) as a DOUBLE, e.g. 1.4 between 'frustrated' (1) and 'angry' (2). Per-level probabilities and confidence are available through decide_many and decide_table. NULL state, question or levels returns NULL; empty, repeated, NULL or out-of-range levels raise an actionable error. | NULL | [-- uses the session default model: SET anofox_decide_model = '';
SELECT decide_score('Help! My payouts failed for 3 days!', 'How frustrated is the writer?', ['calm','frustrated','angry']);] | | anofox_decide_score | scalar | Rate `state` on an ordered rubric of 2 to 10 level descriptions (lowest first) and return the expected level index (0-based) as a DOUBLE, e.g. 1.4 between 'frustrated' (1) and 'angry' (2). Per-level probabilities and confidence are available through decide_many and decide_table. NULL state, question or levels returns NULL; empty, repeated, NULL or out-of-range levels raise an actionable error. | NULL | [SELECT decide_score(body, 'How urgent is this?', ['can wait','this week','today'], model := 'jev-latest') FROM tickets;] | | anofox_decide_table | table | Score several questions against one state and return one row per answer (question id, kind, probability, choice, confidence, model, plus score and distribution). `questions` is a JSON array of {id, kind: 'binary'\|'choice'\|'score', instruction[, options \| levels]} objects. With constant arguments it is one request for all questions; in LATERAL over a table of states it scores every row, one request per row and one row at a time (for many rows use the scalar functions, which run concurrently). Name the model with `model :=` or the third argument. | NULL | [SELECT * FROM decide_table('The bill is wrong.', '[{"id":"refund","kind":"binary","instruction":"A refund is requested."}]', model := 'stub');] | | anofox_decide_table | table | Score several questions against one state and return one row per answer (question id, kind, probability, choice, confidence, model, plus score and distribution). `questions` is a JSON array of {id, kind: 'binary'\|'choice'\|'score', instruction[, options \| levels]} objects. With constant arguments it is one request for all questions; in LATERAL over a table of states it scores every row, one request per row and one row at a time (for many rows use the scalar functions, which run concurrently). Name the model with `model :=` or the third argument. | NULL | [SELECT * FROM tickets, LATERAL (SELECT * FROM decide_table(tickets.body, '[{"id":"refund","kind":"binary","instruction":"A refund is requested."}]', model := 'jev-latest')) dt;] | | anofox_decide_token_count | scalar | Number of tokens `text` has for a local model: what it costs against the model's window (anofox_decide_max_length for julia-1, the limit in rl_agent_config.json for Laya). A local model raises an error instead of silently cutting text that does not fit (anofox_decide_on_truncate), so use this to find the long rows first. Local models only: hosted services do not expose their tokenizer. NULL text returns NULL. | NULL | [-- uses the session default model: SET anofox_decide_model = '';
SELECT decide_token_count('The customer requests a refund.');] | | anofox_decide_token_count | scalar | Number of tokens `text` has for a local model: what it costs against the model's window (anofox_decide_max_length for julia-1, the limit in rl_agent_config.json for Laya). A local model raises an error instead of silently cutting text that does not fit (anofox_decide_on_truncate), so use this to find the long rows first. Local models only: hosted services do not expose their tokenizer. NULL text returns NULL. | NULL | [SELECT id, decide_token_count(body, model := 'julia-1') AS tokens FROM tickets ORDER BY tokens DESC;] | | anofox_decide_unregister_model | scalar | Remove a registered model by id and return true, e.g. to re-register it with different settings. The built-in 'stub' test model cannot be removed. An unknown id raises an error that suggests a close match. | NULL | [SELECT decide_unregister_model('my-model');] | | decide_accelerate | table | One call from installed to using the GPU: finds the GPU, downloads and verifies the matching plugin and checks that it loads. With nothing usable it says so and the CPU keeps serving. Takes effect in this session. Columns: step, status, detail. | NULL | [CALL decide_accelerate();] | | decide_accuracy | aggregate | Fraction of rows where thresholding the probability reproduces the outcome. The two-argument form uses the documented 0.5 boundary; the three-argument form takes an explicit threshold in [0, 1] (NaN or out-of-range thresholds raise an error). NULL inputs are skipped; empty input returns NULL. | NULL | [SELECT decide_accuracy(p, y) FROM labeled;] | | decide_accuracy | aggregate | Fraction of rows where thresholding the probability reproduces the outcome. The two-argument form uses the documented 0.5 boundary; the three-argument form takes an explicit threshold in [0, 1] (NaN or out-of-range thresholds raise an error). NULL inputs are skipped; empty input returns NULL. | NULL | [SELECT decide_accuracy(p, y, 0.7) FROM labeled;] | | decide_accuracy | aggregate | Fraction of rows where thresholding the probability reproduces the outcome. The two-argument form uses the documented 0.5 boundary; the three-argument form takes an explicit threshold in [0, 1] (NaN or out-of-range thresholds raise an error). NULL inputs are skipped; empty input returns NULL. | NULL | [SELECT decide_accuracy(p, y::BIGINT) FROM labeled;] | | decide_answers | scalar | Evaluate several questions against one `state` and return one row per question as a list of structs (question_id, kind, probability, choice, confidence, model, score, distribution), the same rows decide_table returns. `questions` is the JSON array decide_many takes. Use unnest(decide_answers(...), recursive := true) to get decide_table's columns for every row of a table. Unlike LATERAL decide_table, it runs in the scalar pipeline: the rows of a chunk are scored concurrently (anofox_decide_max_concurrency), identical rows are sent once and calibration applies. NULL state or questions returns NULL (no rows after unnest). | NULL | [-- uses the session default model: SET anofox_decide_model = '';
SELECT decide_answers('The bill is wrong.', '[{"id":"refund","kind":"binary","instruction":"A refund is requested."}]');] | | decide_answers | scalar | Evaluate several questions against one `state` and return one row per question as a list of structs (question_id, kind, probability, choice, confidence, model, score, distribution), the same rows decide_table returns. `questions` is the JSON array decide_many takes. Use unnest(decide_answers(...), recursive := true) to get decide_table's columns for every row of a table. Unlike LATERAL decide_table, it runs in the scalar pipeline: the rows of a chunk are scored concurrently (anofox_decide_max_concurrency), identical rows are sent once and calibration applies. NULL state or questions returns NULL (no rows after unnest). | NULL | [SELECT id, unnest(decide_answers(body, '[{"id":"refund","kind":"binary","instruction":"A refund is requested."}]', model := 'jev-latest'), recursive := true) FROM tickets;] | | decide_auc | aggregate | Area under the ROC curve of predicted probabilities against observed outcomes: the chance that a random positive gets a higher probability than a random negative, ties counting one half (scikit-learn roc_auc_score; higher is better, 0.5 is chance). NULL when only one outcome occurs. Rows with a NULL probability or outcome are skipped; empty input returns NULL. | NULL | [SELECT decide_auc(p, y) FROM labeled;] | | decide_auc | aggregate | Area under the ROC curve of predicted probabilities against observed outcomes: the chance that a random positive gets a higher probability than a random negative, ties counting one half (scikit-learn roc_auc_score; higher is better, 0.5 is chance). NULL when only one outcome occurs. Rows with a NULL probability or outcome are skipped; empty input returns NULL. | NULL | [SELECT decide_auc(p, y::BIGINT) FROM labeled;] | | decide_backends | table | Which device can serve which local model, and why not: one row per local model and discovered device. supported is NULL while the model is not downloaded. 'auto' only ever picks a device this function calls supported. Columns: model, device, supported, reason. | NULL | [SELECT * FROM decide_backends() WHERE NOT supported;] | | decide_brier_score | aggregate | Brier score of predicted probabilities against observed outcomes: mean squared difference between the probability and the 0/1 outcome (lower is better; 0 is perfect, 0.25 is a constant 0.5). Rows with a NULL probability or outcome are skipped; empty input returns NULL. | NULL | [SELECT decide_brier_score(p, y) FROM labeled;] | | decide_brier_score | aggregate | Brier score of predicted probabilities against observed outcomes: mean squared difference between the probability and the 0/1 outcome (lower is better; 0 is perfect, 0.25 is a constant 0.5). Rows with a NULL probability or outcome are skipped; empty input returns NULL. | NULL | [SELECT decide_brier_score(p, y::BIGINT) FROM labeled;] | | decide_calibration_curve_by | table_macro | Table macro: the calibration (reliability) curve of decide probabilities against observed outcomes, one per group of source (the anofox integration contract's `curve` schema, curve_type 'calibration', for anofox_plot). Probabilities fall in n_bins equal-width bins on P(yes) (default 10; decide_ece's edges); one row per non-empty bin: the group column, model_id (the group), series, curve_type, x (mean probability), y (fraction of positives), y_low / y_high (95% Wilson interval), threshold, weight (rows in the bin), n_censor, row_order (1-based, by bin). Rows with a NULL probability or outcome are skipped. | NULL | [SELECT * FROM decide_calibration_curve_by('scored', model, p, y, n_bins := 10)] | | decide_choice | scalar | Choose the single best answer for `question` from a runtime-defined list of `options` given `state`. Returns the winning option; the score distribution is available through decide_many and decide_table. An empty or NULL option list raises an actionable error. | NULL | [-- uses the session default model: SET anofox_decide_model = '';
SELECT decide_choice('Invoice charged twice', 'Primary issue?', ['billing','defect','other']);] | | decide_choice | scalar | Choose the single best answer for `question` from a runtime-defined list of `options` given `state`. Returns the winning option; the score distribution is available through decide_many and decide_table. An empty or NULL option list raises an actionable error. | NULL | [-- uses the session default model: SET anofox_decide_model = '';
SELECT decide_choice('Invoice charged twice', 'Primary issue?', ['billing','defect']);] | | decide_choice | scalar | Choose the single best answer for `question` from a runtime-defined list of `options` given `state`. Returns the winning option; the score distribution is available through decide_many and decide_table. An empty or NULL option list raises an actionable error. | NULL | [SELECT decide_choice('Invoice charged twice', 'Primary issue?', ['billing','defect'], model := 'stub');] | | decide_choice | scalar | Choose the single best answer for `question` from a runtime-defined list of `options` given `state`. Returns the winning option; the score distribution is available through decide_many and decide_table. An empty or NULL option list raises an actionable error. | NULL | [SELECT decide_choice(body, 'Which team owns this?', ['billing','defect','other'], model := 'jev-latest') FROM tickets;] | | decide_choice_distribution | scalar | Probability of every option for `question` given `state`, as MAP(VARCHAR, DOUBLE) (the probabilities sum to 1). Same arguments as decide_choice, which returns only the winner; use this to read the confidence, set a minimum probability and abstain, or compare models. An empty or NULL option list raises an actionable error. | NULL | [SELECT decide_choice_distribution('Invoice charged twice', 'Primary issue?', ['billing','defect','other']);] | | decide_choice_distribution | scalar | Probability of every option for `question` given `state`, as MAP(VARCHAR, DOUBLE) (the probabilities sum to 1). Same arguments as decide_choice, which returns only the winner; use this to read the confidence, set a minimum probability and abstain, or compare models. An empty or NULL option list raises an actionable error. | NULL | [SELECT decide_choice_distribution('Invoice charged twice', 'Primary issue?', ['billing','defect']);] | | decide_choice_distribution | scalar | Probability of every option for `question` given `state`, as MAP(VARCHAR, DOUBLE) (the probabilities sum to 1). Same arguments as decide_choice, which returns only the winner; use this to read the confidence, set a minimum probability and abstain, or compare models. An empty or NULL option list raises an actionable error. | NULL | [SELECT decide_choice_distribution('Invoice charged twice', 'Primary issue?', ['billing','defect'], model := 'stub');] | | decide_choice_distribution | scalar | Probability of every option for `question` given `state`, as MAP(VARCHAR, DOUBLE) (the probabilities sum to 1). Same arguments as decide_choice, which returns only the winner; use this to read the confidence, set a minimum probability and abstain, or compare models. An empty or NULL option list raises an actionable error. | NULL | [SELECT map_extract(decide_choice_distribution(body, 'Which team owns this?', ['billing','defect','other'], model := 'jev-latest'), 'billing')[1] AS p_billing FROM tickets;] | | decide_decision | scalar | Boolean decision: true when the probability that `question` holds for `state` reaches `threshold` (0 to 1, inclusive). NULL state or question returns NULL; NaN or out-of-range thresholds raise an error instead of clamping. | NULL | [-- uses the session default model: SET anofox_decide_model = '';
SELECT decide_decision('The customer requests a refund.', 'A refund is requested.', 0.7);] | | decide_decision | scalar | Boolean decision: true when the probability that `question` holds for `state` reaches `threshold` (0 to 1, inclusive). NULL state or question returns NULL; NaN or out-of-range thresholds raise an error instead of clamping. | NULL | [SELECT decide_decision(body, 'A refund is requested.', 0.7, model := 'jev-latest') FROM tickets;] | | decide_devices | table | List the devices this machine can score local models on: the cpu (always there) and any NVIDIA, AMD or Apple GPU found. usable = false names the reason. A GPU is only used after CALL decide_accelerate() has installed its plugin. Columns: device_id, backend, name, arch, vram_total, vram_free, driver, usable, reason. | NULL | [SELECT * FROM decide_devices();] | | decide_doctor | table | Check whether the setup is ready and say how to fix what is not: the default model, the registered models, the remote opt-in, one row per registered model (files readable, API key found and from where, endpoint) and the telemetry state. Columns: item, status (ok / warn / fail), detail, fix. Run it first when a call does not work. | NULL | [SELECT * FROM decide_doctor();] | | decide_download | table | Download a local model's weights from Hugging Face into the cache directory (anofox_decide_cache_dir, default ~/.cache/anofox-decide), then use it offline with model := ''. Models: julia-1 (0.6 GB), laya-multilingual (0.7 GB), laya-typed-decisions (0.85 GB). Files are verified (size, sha256) and a partial download resumes. Columns: model, file, bytes, status (cached / downloaded / resumed), path. | NULL | [CALL decide_download('laya-multilingual');] | | decide_download_runtime | table | Download the GPU plugin for 'cuda', 'rocm' or 'mlx' into anofox_decide_plugin_dir (default /plugins) and verify it against the sha256 published with the release before it is moved into place, and again on every later call of this function (a mismatch deletes it). CUDA also fetches the pinned ONNX Runtime GPU runtime. Refuses a platform nothing is published for before downloading. Columns: file, bytes, status (cached / downloaded). | NULL | [CALL decide_download_runtime('cuda');] | | decide_ece | aggregate | Expected calibration error over ten equal-width probability bins: the bin-weighted gap between average confidence and accuracy (lower is better). Rows with a NULL probability or outcome are skipped; empty input returns NULL. | NULL | [SELECT decide_ece(p, y) FROM labeled;] | | decide_ece | aggregate | Expected calibration error over ten equal-width probability bins: the bin-weighted gap between average confidence and accuracy (lower is better). Rows with a NULL probability or outcome are skipped; empty input returns NULL. | NULL | [SELECT decide_ece(p, y::BIGINT) FROM labeled;] | | decide_fit_calibration | aggregate | Fit Platt scaling from labelled data: given a model's yes/no probabilities and the true outcomes, returns the calibration spec 'platt:a,b' (p' = sigmoid(a * logit(p) + b), a > 0) to pass as MAP {'calibration': ...} to decide_register_model. It fixes a model whose cut-off is off (such as one that says yes too often at 0.5) without changing its ranking. Needs both outcomes and non-constant probabilities; rows with NULLs are skipped; empty input returns NULL. Fit on held-out labelled data, then check the result with decide_brier_score / decide_ece on another sample. | NULL | [SELECT decide_fit_calibration(p, y) FROM labeled;] | | decide_fit_calibration | aggregate | Fit Platt scaling from labelled data: given a model's yes/no probabilities and the true outcomes, returns the calibration spec 'platt:a,b' (p' = sigmoid(a * logit(p) + b), a > 0) to pass as MAP {'calibration': ...} to decide_register_model. It fixes a model whose cut-off is off (such as one that says yes too often at 0.5) without changing its ranking. Needs both outcomes and non-constant probabilities; rows with NULLs are skipped; empty input returns NULL. Fit on held-out labelled data, then check the result with decide_brier_score / decide_ece on another sample. | NULL | [SELECT decide_fit_calibration(p, y::BIGINT) FROM labeled;] | | decide_gpu_precompile | table | Compile a local model's shape buckets ahead of time on the ROCm (MIGraphX) backend, so no query stalls on a first-use compile. Each bucket takes 2-4 minutes once and leaves 0.6-1.7 GB in the cache (progress is printed while it runs); a cached bucket only loads. Compiles one row and a full batch for every token bucket (Laya: 256 and 1024; Julia-1: 256 to 8192), or only the bucket that holds `seq` tokens. Needs the model on a compile-per-shape GPU device (SET anofox_decide_device = 'rocm';). Columns: model, device, batch, seq, markers, seconds. | NULL | [CALL decide_gpu_precompile('laya-multilingual');] | | decide_log_loss | aggregate | Log loss (mean binary cross-entropy) of predicted probabilities against observed outcomes, with the probability clipped to [1e-15, 1 - 1e-15] as scikit-learn's log_loss (lower is better). Rows with a NULL probability or outcome are skipped; empty input returns NULL. | NULL | [SELECT decide_log_loss(p, y) FROM labeled;] | | decide_log_loss | aggregate | Log loss (mean binary cross-entropy) of predicted probabilities against observed outcomes, with the probability clipped to [1e-15, 1 - 1e-15] as scikit-learn's log_loss (lower is better). Rows with a NULL probability or outcome are skipped; empty input returns NULL. | NULL | [SELECT decide_log_loss(p, y::BIGINT) FROM labeled;] | | decide_many | scalar | Evaluate several questions against one `state` in a single provider call. `questions` is a JSON array of {id, kind: 'binary'\|'choice'\|'score', instruction[, options \| levels]} objects; returns a JSON object {model, results: [...]} with one answer per question, in order: id, kind and probability; a choice adds `choice` and the per-option `probabilities`; a score adds `score` (the expected 0-based level) and the per-level `probabilities`. Remote providers receive one request for the whole batch. | NULL | [-- uses the session default model: SET anofox_decide_model = '';
SELECT decide_many('The bill is wrong.', '[{"id":"refund","kind":"binary","instruction":"A refund is requested."}]');] | | decide_many | scalar | Evaluate several questions against one `state` in a single provider call. `questions` is a JSON array of {id, kind: 'binary'\|'choice'\|'score', instruction[, options \| levels]} objects; returns a JSON object {model, results: [...]} with one answer per question, in order: id, kind and probability; a choice adds `choice` and the per-option `probabilities`; a score adds `score` (the expected 0-based level) and the per-level `probabilities`. Remote providers receive one request for the whole batch. | NULL | [SELECT decide_many(body, '[{"id":"refund","kind":"binary","instruction":"A refund is requested."}]', model := 'jev-latest') FROM tickets;] | | decide_metrics_by | table_macro | Table macro: decide's quality metrics per group of source, one row per metric (the anofox integration contract's `summary` schema, for anofox_plot): the group column, model_id (the group), metric (accuracy at 0.5, auc, brier, ece, log_loss), value, conf_low, conf_high, row_order (1-based). A metric that is undefined for a group (auc with one outcome) is left out. Rows with a NULL probability or outcome are skipped. | NULL | [SELECT * FROM decide_metrics_by('scored', model, p, y)] | | decide_models | table | List the models registered on this database instance and whether each can be called now. Columns: model, provider, mode ('test' / 'local' / 'remote'), path, is_default, ready, hint (what to do when it is not ready), profile, endpoint, wire_model. The built-in 'stub' test model is always present; register more with decide_register_model. | NULL | [SELECT * FROM decide_models();] | | decide_probability | scalar | Probability (0 to 1) that the statement `question` holds for `state`, scored by the named model (`model :=`, or the anofox_decide_model setting; with neither the call fails and says how to choose one). NULL state or question returns NULL; unknown models, remote calls without opt-in and missing API keys raise errors that name the fixing call. | NULL | [-- uses the session default model: SET anofox_decide_model = '';
SELECT decide_probability('The customer requests a refund.', 'A refund is requested.');] | | decide_probability | scalar | Probability (0 to 1) that the statement `question` holds for `state`, scored by the named model (`model :=`, or the anofox_decide_model setting; with neither the call fails and says how to choose one). NULL state or question returns NULL; unknown models, remote calls without opt-in and missing API keys raise errors that name the fixing call. | NULL | [SELECT decide_probability(body, 'A refund is requested.', model := 'jev-latest') FROM tickets;] | | decide_register_model | scalar | Register a model id for this database instance and return true. Providers: 'stub' (deterministic), 'local' (ONNX graph and tokenizer paths, optional profile 'julia-1' or 'laya'), and the remote providers 'typesafe', 'liquid', 'cloudflare' (Clef on Workers AI: models 'clef' and 'clef-flash', account id from the account_id option or CLOUDFLARE_ACCOUNT_ID), 'openai' (OpenAI Decisions, model 'gpt-6-luna', key OPENAI_API_KEY; options input ('auto', 'text' or 'json': JSON state is sent as structured data) and prompt_cache_key; a refused answer is NULL), 'systemone' and 'strands' (optional options MAP with endpoint, path, model, key_env, criteria, account_id). The options MAP also takes calibration, 'platt:a,b', for any provider: it rescales that model's yes/no probabilities (fit a and b with decide_fit_calibration). Duplicate ids, unsupported providers and unreadable files raise actionable errors. | NULL | [SELECT decide_register_model('jev-latest', 'typesafe');] | | decide_register_model | scalar | Register a model id for this database instance and return true. Providers: 'stub' (deterministic), 'local' (ONNX graph and tokenizer paths, optional profile 'julia-1' or 'laya'), and the remote providers 'typesafe', 'liquid', 'cloudflare' (Clef on Workers AI: models 'clef' and 'clef-flash', account id from the account_id option or CLOUDFLARE_ACCOUNT_ID), 'openai' (OpenAI Decisions, model 'gpt-6-luna', key OPENAI_API_KEY; options input ('auto', 'text' or 'json': JSON state is sent as structured data) and prompt_cache_key; a refused answer is NULL), 'systemone' and 'strands' (optional options MAP with endpoint, path, model, key_env, criteria, account_id). The options MAP also takes calibration, 'platt:a,b', for any provider: it rescales that model's yes/no probabilities (fit a and b with decide_fit_calibration). Duplicate ids, unsupported providers and unreadable files raise actionable errors. | NULL | [SELECT decide_register_model('julia-1', 'local', '/models/julia1.onnx');] | | decide_register_model | scalar | Register a model id for this database instance and return true. Providers: 'stub' (deterministic), 'local' (ONNX graph and tokenizer paths, optional profile 'julia-1' or 'laya'), and the remote providers 'typesafe', 'liquid', 'cloudflare' (Clef on Workers AI: models 'clef' and 'clef-flash', account id from the account_id option or CLOUDFLARE_ACCOUNT_ID), 'openai' (OpenAI Decisions, model 'gpt-6-luna', key OPENAI_API_KEY; options input ('auto', 'text' or 'json': JSON state is sent as structured data) and prompt_cache_key; a refused answer is NULL), 'systemone' and 'strands' (optional options MAP with endpoint, path, model, key_env, criteria, account_id). The options MAP also takes calibration, 'platt:a,b', for any provider: it rescales that model's yes/no probabilities (fit a and b with decide_fit_calibration). Duplicate ids, unsupported providers and unreadable files raise actionable errors. | NULL | [SELECT decide_register_model('julia-1', 'local', '/models/julia1.onnx', '/models/tokenizer/tokenizer.json');] | | decide_register_model | scalar | Register a model id for this database instance and return true. Providers: 'stub' (deterministic), 'local' (ONNX graph and tokenizer paths, optional profile 'julia-1' or 'laya'), and the remote providers 'typesafe', 'liquid', 'cloudflare' (Clef on Workers AI: models 'clef' and 'clef-flash', account id from the account_id option or CLOUDFLARE_ACCOUNT_ID), 'openai' (OpenAI Decisions, model 'gpt-6-luna', key OPENAI_API_KEY; options input ('auto', 'text' or 'json': JSON state is sent as structured data) and prompt_cache_key; a refused answer is NULL), 'systemone' and 'strands' (optional options MAP with endpoint, path, model, key_env, criteria, account_id). The options MAP also takes calibration, 'platt:a,b', for any provider: it rescales that model's yes/no probabilities (fit a and b with decide_fit_calibration). Duplicate ids, unsupported providers and unreadable files raise actionable errors. | NULL | [SELECT decide_register_model('kev-latest', 'systemone', MAP {'endpoint': 'http://127.0.0.1:8009'});] | | decide_register_model | scalar | Register a model id for this database instance and return true. Providers: 'stub' (deterministic), 'local' (ONNX graph and tokenizer paths, optional profile 'julia-1' or 'laya'), and the remote providers 'typesafe', 'liquid', 'cloudflare' (Clef on Workers AI: models 'clef' and 'clef-flash', account id from the account_id option or CLOUDFLARE_ACCOUNT_ID), 'openai' (OpenAI Decisions, model 'gpt-6-luna', key OPENAI_API_KEY; options input ('auto', 'text' or 'json': JSON state is sent as structured data) and prompt_cache_key; a refused answer is NULL), 'systemone' and 'strands' (optional options MAP with endpoint, path, model, key_env, criteria, account_id). The options MAP also takes calibration, 'platt:a,b', for any provider: it rescales that model's yes/no probabilities (fit a and b with decide_fit_calibration). Duplicate ids, unsupported providers and unreadable files raise actionable errors. | NULL | [SELECT decide_register_model('laya', 'local', '/models/laya.onnx', '/models/tokenizer/tokenizer.json', 'laya');] | | decide_register_model | scalar | Register a model id for this database instance and return true. Providers: 'stub' (deterministic), 'local' (ONNX graph and tokenizer paths, optional profile 'julia-1' or 'laya'), and the remote providers 'typesafe', 'liquid', 'cloudflare' (Clef on Workers AI: models 'clef' and 'clef-flash', account id from the account_id option or CLOUDFLARE_ACCOUNT_ID), 'openai' (OpenAI Decisions, model 'gpt-6-luna', key OPENAI_API_KEY; options input ('auto', 'text' or 'json': JSON state is sent as structured data) and prompt_cache_key; a refused answer is NULL), 'systemone' and 'strands' (optional options MAP with endpoint, path, model, key_env, criteria, account_id). The options MAP also takes calibration, 'platt:a,b', for any provider: it rescales that model's yes/no probabilities (fit a and b with decide_fit_calibration). Duplicate ids, unsupported providers and unreadable files raise actionable errors. | NULL | [SELECT decide_register_model('laya', 'local', '/models/laya.onnx', '/models/tokenizer/tokenizer.json', 'laya', MAP {'calibration': 'platt:1.1,-0.3'});] | | decide_register_model | scalar | Register a model id for this database instance and return true. Providers: 'stub' (deterministic), 'local' (ONNX graph and tokenizer paths, optional profile 'julia-1' or 'laya'), and the remote providers 'typesafe', 'liquid', 'cloudflare' (Clef on Workers AI: models 'clef' and 'clef-flash', account id from the account_id option or CLOUDFLARE_ACCOUNT_ID), 'openai' (OpenAI Decisions, model 'gpt-6-luna', key OPENAI_API_KEY; options input ('auto', 'text' or 'json': JSON state is sent as structured data) and prompt_cache_key; a refused answer is NULL), 'systemone' and 'strands' (optional options MAP with endpoint, path, model, key_env, criteria, account_id). The options MAP also takes calibration, 'platt:a,b', for any provider: it rescales that model's yes/no probabilities (fit a and b with decide_fit_calibration). Duplicate ids, unsupported providers and unreadable files raise actionable errors. | NULL | [SELECT decide_register_model('my-stub');] | | decide_roc_curve_by | table_macro | Table macro: the ROC curve of decide probabilities against observed outcomes, one per group of source (scikit-learn roc_curve; the anofox integration contract's `curve` schema, curve_type 'roc', for anofox_plot). One row per point: the group column, model_id (the group), series, curve_type, x (false positive rate), y (true positive rate), y_low, y_high, threshold (the probability; +inf for the (0, 0) start), weight, n_censor, row_order (1-based, along the curve). Tied probabilities form one point; drop_intermediate (default true) drops the points on straight segments. Rows with a NULL probability or outcome are skipped; a group with only one outcome has no curve. | NULL | [SELECT * FROM decide_roc_curve_by('scored', model, p, y)] | | decide_score | scalar | Rate `state` on an ordered rubric of 2 to 10 level descriptions (lowest first) and return the expected level index (0-based) as a DOUBLE, e.g. 1.4 between 'frustrated' (1) and 'angry' (2). Per-level probabilities and confidence are available through decide_many and decide_table. NULL state, question or levels returns NULL; empty, repeated, NULL or out-of-range levels raise an actionable error. | NULL | [-- uses the session default model: SET anofox_decide_model = '';
SELECT decide_score('Help! My payouts failed for 3 days!', 'How frustrated is the writer?', ['calm','frustrated','angry']);] | | decide_score | scalar | Rate `state` on an ordered rubric of 2 to 10 level descriptions (lowest first) and return the expected level index (0-based) as a DOUBLE, e.g. 1.4 between 'frustrated' (1) and 'angry' (2). Per-level probabilities and confidence are available through decide_many and decide_table. NULL state, question or levels returns NULL; empty, repeated, NULL or out-of-range levels raise an actionable error. | NULL | [SELECT decide_score(body, 'How urgent is this?', ['can wait','this week','today'], model := 'jev-latest') FROM tickets;] | | decide_table | table | Score several questions against one state and return one row per answer (question id, kind, probability, choice, confidence, model, plus score and distribution). `questions` is a JSON array of {id, kind: 'binary'\|'choice'\|'score', instruction[, options \| levels]} objects. With constant arguments it is one request for all questions; in LATERAL over a table of states it scores every row, one request per row and one row at a time (for many rows use the scalar functions, which run concurrently). Name the model with `model :=` or the third argument. | NULL | [SELECT * FROM decide_table('The bill is wrong.', '[{"id":"refund","kind":"binary","instruction":"A refund is requested."}]', model := 'stub');] | | decide_table | table | Score several questions against one state and return one row per answer (question id, kind, probability, choice, confidence, model, plus score and distribution). `questions` is a JSON array of {id, kind: 'binary'\|'choice'\|'score', instruction[, options \| levels]} objects. With constant arguments it is one request for all questions; in LATERAL over a table of states it scores every row, one request per row and one row at a time (for many rows use the scalar functions, which run concurrently). Name the model with `model :=` or the third argument. | NULL | [SELECT * FROM tickets, LATERAL (SELECT * FROM decide_table(tickets.body, '[{"id":"refund","kind":"binary","instruction":"A refund is requested."}]', model := 'jev-latest')) dt;] | | decide_token_count | scalar | Number of tokens `text` has for a local model: what it costs against the model's window (anofox_decide_max_length for julia-1, the limit in rl_agent_config.json for Laya). A local model raises an error instead of silently cutting text that does not fit (anofox_decide_on_truncate), so use this to find the long rows first. Local models only: hosted services do not expose their tokenizer. NULL text returns NULL. | NULL | [-- uses the session default model: SET anofox_decide_model = '';
SELECT decide_token_count('The customer requests a refund.');] | | decide_token_count | scalar | Number of tokens `text` has for a local model: what it costs against the model's window (anofox_decide_max_length for julia-1, the limit in rl_agent_config.json for Laya). A local model raises an error instead of silently cutting text that does not fit (anofox_decide_on_truncate), so use this to find the long rows first. Local models only: hosted services do not expose their tokenizer. NULL text returns NULL. | NULL | [SELECT id, decide_token_count(body, model := 'julia-1') AS tokens FROM tickets ORDER BY tokens DESC;] | | decide_unregister_model | scalar | Remove a registered model by id and return true, e.g. to re-register it with different settings. The built-in 'stub' test model cannot be removed. An unknown id raises an error that suggests a close match. | NULL | [SELECT decide_unregister_model('my-model');] | ### 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_value | |-------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------|--------|---------|-------------------------------------------------| | anofox_decide_allow_remote | Off by default. When on, remote models (typesafe, liquid, cloudflare, openai, systemone, strands) may be called, which sends the text you score to their endpoints | BOOLEAN | GLOBAL | [] | false | | anofox_decide_api_key | Legacy API key for the typesafe provider, kept in plain text and readable with current_setting(); prefer CREATE SECRET (TYPE anofox_decide, API_KEY '...') or the TYPESAFE_API_KEY environment variable | VARCHAR | GLOBAL | [] | | | anofox_decide_batch_tokens | Local models: score the rows of a whole chunk together, in batches of at most this many padded tokens (batch size times padded length; 1024 to 131072). 0 (default) scores one text at a time. Results are the same either way; batching only pays on a GPU, on CPU it was measured to be slower | BIGINT | GLOBAL | [] | 0 | | anofox_decide_cache_dir | Where decide_download keeps the local models (empty: ~/.cache/anofox-decide) | VARCHAR | GLOBAL | [] | | | anofox_decide_device | Where local models run: 'auto' (default) uses a GPU only when its plugin is installed (CALL decide_accelerate()), the device is usable and the plugin serves the model, otherwise the CPU; 'cpu'; or 'cuda', 'rocm', 'mlx', which fail with the fix when that device cannot serve the model. SELECT * FROM decide_backends() shows the choice | VARCHAR | GLOBAL | [] | auto | | anofox_decide_endpoint | Legacy endpoint for the typesafe provider (default https://api.typesafe.ai); other remote providers take a per-model endpoint (the options MAP of decide_register_model) | VARCHAR | GLOBAL | [] | https://api.typesafe.ai | | anofox_decide_gpu_precision | Numeric precision of the GPU backends. Only 'fp32' in this release; other values are rejected rather than silently run in fp32 | VARCHAR | GLOBAL | [] | fp32 | | anofox_decide_head_length | Tokens reserved for the question and its options in local models (default 512); must stay below anofox_decide_max_length | BIGINT | GLOBAL | [] | 512 | | anofox_decide_max_concurrency | How many remote requests one query sends at the same time (0 to 64, default 0 = automatic: 8 for hosted providers, 1 for the local strands server). 1 sends them one after another. Lower it if the service rate limits you | BIGINT | GLOBAL | [] | 0 | | anofox_decide_max_length | Maximum tokens a julia-1 local model reads per question (default 8192); longer text is cut off. Laya models use the limit in their rl_agent_config.json instead | BIGINT | GLOBAL | [] | 8192 | | anofox_decide_max_questions | Maximum questions per decide_many / decide_table call (default 100, at most 1000) | BIGINT | GLOBAL | [] | 100 | | anofox_decide_max_retries | Retries after a rate limit (429), server error (5xx) or connection failure for remote calls (default 3, at most 10) | BIGINT | GLOBAL | [] | 3 | | anofox_decide_model | Model id used when a decide_* call names no model (must be registered, see decide_models()). Unset by default: name a model per call or SET it. 'stub' is a built-in test model that returns constants | VARCHAR | GLOBAL | [] | | | anofox_decide_on_truncate | What a local model does when the text, the question or an option does not fit its window: 'error' (default) raises an error that says how much would be cut, 'ignore' scores the shortened input. Check lengths with decide_token_count(text) | VARCHAR | GLOBAL | [] | error | | anofox_decide_plugin_dir | Where the GPU plugins are installed and loaded from (empty: the 'plugins' folder of anofox_decide_cache_dir). CALL decide_accelerate() fills it | VARCHAR | GLOBAL | [] | | | anofox_decide_timeout_ms | Per-request timeout for remote model calls, in milliseconds (default 30000) | BIGINT | GLOBAL | [] | 30000 | | anofox_telemetry_enabled | Enable or disable anonymous usage telemetry | BOOLEAN | GLOBAL | [] | false | | anofox_telemetry_key | PostHog API key for telemetry | VARCHAR | GLOBAL | [] | phc_t3wwRLtpyEmLHYaZCSszG0MqVr74J6wnCrj9D41zk2t | | datazoo_banner | Show the DataZoo feedback banner when an extension is loaded in an interactive terminal (at most once a day per extension). | BOOLEAN | GLOBAL | [] | true | | temp_directory | Set the directory to which temporary files are written. | VARCHAR | GLOBAL | [] | post.db.tmp |