AI
Reaching machine intelligence — models, versioned prompts, embeddings, and bounded agents, with cost and PII egress as first-class constraints.
AI is how your app calls machine intelligence: triage a ticket, embed a knowledge base, let an agent resolve a support case. Model calls differ from every other effect — they are nondeterministic, they cost money per call, and your data leaves the building — so prompts are versioned artifacts, not strings buried in a handler.
The one rule
The production model is declared, never guessed — there is no prod default. Development uses
mock for determinism, and sending PII to a third-party model fails the build unless you
explicitly acknowledge it.
Quick start
Declare a model and a prompt
The model is a logical binding (smart, fast); the prompt is a versioned artifact with a typed output:
import { ai } from "okengine";
import { z } from "zod";
export const smart = ai.model("smart", { provider: "anthropic", tier: "opus" });
export const triage = smart.prompt("ticket-triage", {
in: z.object({ subject: z.string(), body: z.string() }),
out: z.object({ urgency: z.enum(["low", "high"]), team: z.string(), summary: z.string() }),
version: 3,
budget: { maxCostPerCall: 0.02 },
});Ask it from a Flow
fx.ask routes the call through the declared model and validates the response against out:
do: async (input, fx) => {
const result = await fx.ask(triage, { subject: input.subject, body: input.body });
// result is typed by the prompt's `out` schema
};Gate regressions in CI
Point the prompt at an eval set and it becomes a CI check — a prompt change that degrades answers fails the build like a broken test:
export const triage = smart.prompt("ticket-triage", {
// …
evals: "./evals/triage.jsonl", // run with `oke eval`
});The four building blocks
| Declaration | Produces |
|---|---|
ai.model(name, opts) | Logical model binding — provider / tier / concrete model id |
model.prompt(name, opts) | Versioned prompt with typed in/out, evals, budget |
ai.embed(name, opts) | Embedding pipeline into a store.index (searched via fx.search) |
ai.agent(name, opts) | Bounded agent whose tools are your own flows |
Prompt options
| Option | Type | Meaning |
|---|---|---|
in / out | zod / Standard Schema | Input and output contracts — responses validated against out |
version | number | Artifact version — diffs and regressions tracked per version |
evals | string | Path to a .jsonl eval set, regression-gated via oke eval |
budget | object | maxCostPerCall — cost is a first-class dimension |
Agents with real guardrails
An agent's tools are your flows — each carrying its own gates, effects, and typed errors, so the agent can never do anything a flow couldn't:
export const support = ai.agent("support", {
model: smart,
tools: [getBooking, refundBooking], // flows, with their gates attached
maxSteps: 6,
budget: { maxCostPerRun: 0.25 },
});maxSteps bounds the loop; budget.maxCostPerRun bounds the spend. Both are declared, so "the agent ran away" is a violated contract, not a surprise.
PII cannot leak by accident
At build time, OKE checks which fields each fx.ask sends against your store classifications. If a PII field (.pii() in your schema) would reach a third-party model, the build fails:
build failed: flow "ticket-triage" sends pii field(s) [email] to a third-party model without allowPiiThe escape hatch is explicit acknowledgment — allowPii: true (or pii: "allow") on the flow — so egress is a decision that shows up in code review. The mock driver and local models are not third-party; the check targets external providers.
Nondeterminism is priced in
Because fx.ask is nondeterministic, the runtime adjusts around it: journaling is forced on (durable flows can replay), and auto-caching is disabled for the call. In development and tests the mock driver makes model calls deterministic — your suite never hits a network, and CI never flakes on a provider.
Per-environment drivers
| Driver | What it is |
|---|---|
mock | Deterministic fake — dev + test default |
anthropic | Anthropic API |
openai-compatible | Any OpenAI-compatible endpoint |
bedrock | AWS Bedrock |
vertex | Google Vertex AI |
ollama | Local models — counts as on-premise for the PII check |
There is deliberately no production default: prod must name a driver, which keeps the model choice visible in oke.config.ts where review can see it.
Troubleshooting
A flow sends a classified PII field to a third-party model. Either stop sending that field (drop it from the fx.ask input), or acknowledge the egress with allowPii: true on the flow — the error message names the exact fields.
The one you declared. There is no fallback or guess — if prod has no AI driver configured, that's a configuration gap to fix, not a silent default.
Attach evals: "./evals/<name>.jsonl" to the prompt and run oke eval in CI. The suite replays the eval cases and fails on regressions, per prompt version.
Bound it at declaration: maxSteps caps iterations, budget.maxCostPerRun caps spend. The Console's AI view shows cost per run so you can tune both against real numbers.
Learn more
- Flow —
fx.askandfx.searchinsidedo - Store —
store.index, the home of embeddings - Console · AI — prompts, versions, cost per run
Next
Channel
Reaching humans — email, SMS, WhatsApp, and push with consent, locale, receipts, and fallback chains built in.
Security Headers
Official plugin — the complete secure-headers set on every HTTP response, failures included. Full helmet.js parity with API-first defaults, a CSP builder with report-only mode, and live DB-driven config.