Describe the transform in plain language; OpexFlow writes it. The generator talks to any
OpenAI-compatible /chat/completions endpoint, is steered to emit DSL first (falling
back to JS when the rule isn’t expressible), and server-validates the output before
returning it.
ai:
enabled: true # master switch (default false)
base_url: "https://api.openai.com/v1" # any OpenAI-compatible base; plain http:// works (e.g. a local Ollama / stub)
model: "gpt-4o-mini"
api_key: "${OPEX_AI_API_KEY}" # required; read from the environment, never returned by the API
max_tokens: 4096 # output budget floor; edits of long scripts ask for more (cap 16384)| Key | Default | Meaning |
|---|---|---|
ai.enabled |
false |
Master switch. Off = the generator reports “not configured”. |
ai.base_url |
https://api.openai.com/v1 |
Base URL ending in /v1; /chat/completions is appended. |
ai.model |
gpt-4o-mini |
Model id sent to the endpoint. |
ai.api_key |
none | Bearer token (${OPEX_AI_API_KEY}). Required. |
ai.max_tokens |
4096 |
Floor for max output tokens. When editing, the request grows with the current script’s length (up to 16384), since the model returns the whole script. A reply that still runs out fails with stage truncated. |
GET /api/script/ai-status returns { configured, missing?, model?, base_url?, provider_host? } (never the key), so the editor can show a setup hint: missing lists ai.enabled / ai.api_key when they are not set.
In the flow editor, select a transform node and open Generate with AI under its script.
Describe the rule (e.g. “emit only when temp exceeds 80 or vibration crosses 5.0”), pick a
target language (auto prefers DSL) and hit Generate. The model maps your fields onto
metadata.* using a sample record (the last real record seen for the node’s source, unless you
pass one) and returns a runnable program; Replace script with this puts it into the node,
and Test with last record checks it before you Deploy.
Editing and iterating. When the node already has a script, your request is an instruction
to change it (“also drop records above 90 °C”): the model gets the current script and returns the
complete updated one, with explanation summarising what changed. The last ~6 turns of the
conversation are sent along so you can refine step by step.
Every answer is validated before you see it (sandboxed compile, then a dry run on the sample
record). A rejected answer is not hidden: ok:false with stage (validation, dry_run, …),
the error, and the rejected source, so you can ask for a fix.
POST /api/script/generate body: { instruction, current?: { backend, script }, history?: [{ role, content }], sample_record?, match?, target? }
(description is the older name of instruction). Response: { ok, backend, source, explanation, sample_used, sample_key } or
{ ok:false, stage, error, backend?, source?, explanation? }.