LLMs are unreliable at math. Percentiles, weighted means, post-fetch reshaping — anything quantitative — should run in a deterministic engine, not in the model’s head. We route those snippets through Oracle’s Multilingual Engine (MLE) — JavaScript that runs inside the Oracle process, called via DBMS_MLE.
Oracle AI Database 26ai Free ships MLE with JavaScript. Python MLE is a separate package not enabled in this build, which surfaces as ORA-04101: Multilingual Engine does not support the language PYTHON. The agent doesn’t care which language we expose — it’ll happily emit JS for the kinds of computation we need (arithmetic, string formatting, JSON reshaping).
mle-js-oracledb. So the real trust boundary is AGENT_USER’s grants plus whatever the kernel enforces at SQL-execution time (DDS / VPD / audit / redaction — Part 8). If you care about defense-in-depth, narrow AGENT’s grants or push policy into the kernel.~/.ssh/.Nothing in Oracle itself — MLE is available out of the box on Oracle AI Database 26ai with the grants app/scripts/bootstrap.py already gave to AGENT:
EXECUTE ON DBMS_MLEEXECUTE DYNAMIC MLEDB_DEVELOPER_ROLEThis Part just defines the Python helper that calls DBMS_MLE.EVAL for us.
exec_js helperexec_js(code) wraps your JS in a try/catch + console.log capture, evaluates it inside a fresh MLE context, and returns:
{"stdout": "<captured console.log>", "stderr": "<error if thrown>", "ok": True/False}
The wrapper uses mle-js-bindings to export a result value, which the Python side imports via DBMS_MLE.IMPORT_FROM_MLE and parses as JSON.
The Part 7 system prompt has an explicit rule:
“For numeric work over fetched rows … you MUST fetch with
run_sqland then callexec_jsto compute.”
This pushes percentile / mean / max / unit-conversion / reshaping work through MLE rather than letting the model do arithmetic in its head or rely solely on SQL aggregation. Without that rule GPT-class models often skip the JS hop and answer from a single run_sql aggregate — convenient but harder to audit when the math gets non-trivial.
const totals = [199, 4999, 12999, 599, 8999, 24999, 1499, 89999, 3499, 599, 19999, 11999]
.slice().sort((a, b) => a - b);
const n = totals.length;
function pct(p) {
const k = (n - 1) * p;
const f = Math.floor(k);
return f === Math.min(f + 1, n - 1)
? totals[f]
: totals[f] + (totals[Math.min(f + 1, n - 1)] - totals[f]) * (k - f);
}
const sum = totals.reduce((a, b) => a + b, 0);
console.log("n=" + n + " mean=" + Math.floor(sum/n) +
" p50=" + Math.round(pct(0.50)) + " p95=" + Math.round(pct(0.95)));
The model emits this JS in response to “compute percentiles over these order totals”, exec_js runs it inside Oracle, and the result lands back in the agent’s context as deterministic, audit-traceable output.
run_sql. No subprocess, no network, no extra install.exec_js means the trace shows the JS source, the inputs, and the result — not a number the LLM claims is correct.ORA-04101: Multilingual Engine does not support the language PYTHON — Use JavaScript. Python MLE isn’t enabled on Free.
No stdout but ok: true — The snippet didn’t call console.log. Wrap your final value in console.log(...) to capture it.
stderr: "ReferenceError: require is not defined" — The wrapper imports require("mle-js-bindings"). If you’re running a snippet directly via DBMS_MLE.EVAL outside exec_js, you need to handle bindings yourself.
ORA-04036: PGA memory ... exceeds PGA_AGGREGATE_LIMIT — Raise pga_aggregate_limit. The pre-built setup raises it to 4 GiB; if you’re running outside the Codespace, do this once as SYSDBA against CDB$ROOT.