Skip to main content
aiField adds a field that FrogBot fills in with AI. You name the fields it reads and write a prompt. When one of those fields changes, FrogBot asks the model in the background and saves the answer. The admin panel shows when a value is being generated, when it failed, and when someone wrote it by hand.
The value is a Text field, or a Select field when you pass options (see Select output). aiField returns a row holding the value and two state fields, _summary_status and _summary_error (see Stored value). Put it in a collection’s fields like any other field.

Config options

With options, these Select options are also accepted, and minLength and maxLength are not: required isn’t supported: a generated value is empty until its first run finishes, and an empty answer is allowed. FrogBot stores the value and shows it to everyone who can read the record, so virtual and hidden aren’t supported either. A text AI field also holds one value, so hasMany, minRows and maxRows are not accepted without options. TypeScript rejects all of them, and from JavaScript they fail when the config is built, as do invalid options:

Admin options

AI fields support the standard field admin options. admin.position applies to the whole row, so the value and its status move to the sidebar together. Every other option applies to the value field. admin.readOnly stops hand edits but keeps Generate and Regenerate for users who may update the record. Text output also accepts the Text admin options: Select output accepts the Select admin options: FrogBot stores the field’s inputs, prompt and model in admin.custom.frogbot.kind. Your own admin.custom keys, and other keys under admin.custom.frogbot, are kept.
admin.custom is sent to the browser, so anyone who can open the admin panel can read the prompt. Don’t put secrets in it.

Display and editing

List

The List cell shows the value with its state: The buttons need update access to the record. Without it, the cell shows the value, the spinner and the warning only. Generating cells update on their own: while any are visible, the page re-reads them in one request every 3 seconds, and stops once none are generating. If the collection sets admin.enableListViewSelectAPI, the List shows the plain value, with no state and no buttons.

Board and Calendar

Board cards and Calendar events show the value, dimmed while generating, and a warning icon after a failure. They have no buttons. Board can group by an AI select field.

Document view

The document view shows a line under the input: Generate, Regenerate and Retry need update access to the record, and the line is hidden while creating a record. While the value is generating, the view checks for the result every 3 seconds. A result that arrives while the form is open fills the input, unless you have already changed it. A Regenerate is refused while another user is editing the record, and the error appears as a message. On a collection with drafts, it is also refused when the record was saved as a draft or published, or started generating, after the view loaded, so it never publishes a newer draft:
Typing in the input and saving keeps your value. See The manual-edit rule.

Runs

When runs happen

A save queues a run when it:
  • creates a record with at least one input set;
  • changes an input of a record that wasn’t edited by hand;
  • sets the status to pending (Regenerate).
The run happens in the background, after the save has finished. A save that fails, or a transaction that rolls back, queues nothing. An AI field can be an input of another AI field: when the first one is saved, the second one runs. FrogBot refuses to start if AI fields form a cycle.

What the model sees

The prompt is the model’s instructions, and the message is a JSON object of the input values keyed by field name, in inputs order:
Values are read as stored: relationships are IDs and rich text is its stored JSON. The model has no tools, and the answer is saved with surrounding whitespace removed.

The manual-edit rule

Writing a value by hand, from the admin panel or any API, marks the field as edited by hand. FrogBot then keeps that value: input changes no longer regenerate it, until someone regenerates it. A hand edit made while a run is in progress wins, and the run’s answer is discarded. Clearing a generated value by hand also counts as an edit.

Regenerate

Generate, Regenerate and Retry all set the status to pending, which queues a run and clears the edited-by-hand state. You can do the same from the REST API, the Local API or an agent tool:
This needs update access to the record. Any other status you write is ignored. To regenerate many records at once, see Regenerate many records.

Quick edits

Quick edits leave at most one waiting run per record, field and locale, and it uses the latest inputs. A run that has already started finishes first. An answer generated from inputs that have changed since is never saved. See Jobs.

Who a run belongs to

A run belongs to the user who made the save, and its usage is recorded for that user. It follows the AI access rules for that user, including their budget and allowed models with the AI policy plugin. A run that a policy refuses is saved as a failure. A user’s run reads only the inputs that user can read, so two users can get different answers for the same record. A save with no user, such as a Local API call or a seed, runs with no per-user limits and reads every input. The answer is visible to anyone who can read the AI field, so it can reveal inputs they can’t read. Use the field’s access.read when that matters. If the user is deleted before the run, or can no longer read the record, the run fails with one of these errors:
A run’s save sets updatedBy to the user who started the run.

Failures

A failed run, such as a provider error, a refused policy or an answer that fails validation, sets the status to error and saves the first 200 characters of the message. The full error is written to the server log. Failed runs are not retried automatically; use Retry or Regenerate.

Locales and drafts

A localized AI field runs per locale: a save in fr regenerates only the fr value, from the fr inputs. On a collection with drafts, a run reads and writes the latest version. A draft’s run saves to the draft and leaves the published version unchanged. If someone saves a newer draft of a published record while the run is in progress, the answer goes to that draft, and the draft stays unpublished.

The job runner

Runs are jobs on the default queue. The web server checks for waiting runs once a minute; a worker can check more often. If web autorun is turned off and no worker runs, values stay generating.

Regenerate many records

The List’s … menu has a Regenerate <label>… entry for each AI field, such as Regenerate Summary…. It’s shown to users who can update the collection, and not in the trash or in a relationship drawer. The entry covers the selected rows. With nothing selected, or after Select all, it covers every record that matches the List’s filters and search.
A view’s filter isn’t applied, so All in view and Select all can include records that the view hides. Add the condition as a List filter to leave them out.
The entry opens a dialog that asks which records to run: No choice runs records that are generating or whose inputs are all empty. The dialog doesn’t count records in advance; choose Regenerate to queue the runs, or Cancel to change nothing. When the runs are queued, the dialog closes and a message reports the result:
A record is skipped when its inputs are all empty, you can’t update it, another user is editing it, or its status changed after you chose. The selection is cleared, and the queued rows show a spinner and fill in as their runs finish. If queueing stops partway, for example after a network error, the message gives the error and how many runs were already queued; those runs still happen. Each record is regenerated as a single Regenerate would do it:
  • Drafts stay drafts, and published records stay published.
  • The runs use the List’s locale.
  • The runs belong to you and follow your AI access rules, such as your budget and allowed models. See Who a run belongs to. A record your policy refuses, for example after your budget runs out partway, shows the failed state. Choose Only failed later to retry it.
Runs go at the job runner’s pace. With the defaults, the web server checks once a minute and runs up to 10 waiting runs, so 500 records take roughly an hour. To go faster, run a worker with a shorter --cron and a higher --limit. From the REST API, the same result is a normal update that writes pending to the status field of every record matching a filter. This retries every failed summary:
On a collection with drafts, add draft=true and update drafts and published records separately, with a _status condition in the filter. For published records, also send "_status": "published" so they stay published. A plain update without draft=true publishes over any newer draft.

Select output

Pass options to have the model pick from a list:
The model is asked for a structured answer and sees the option values, not the labels, so use values that explain themselves. With hasMany: true it can pick any number, and duplicates are dropped in the model’s order. An empty answer is allowed and saved as no value. An answer that isn’t an option, or that isn’t a structured answer at all, fails the run with Retry. The model needs to support structured output. Changing the options regenerates nothing. A record whose stored value was removed from the options behaves as it would on any Select field: every save, including Regenerate, fails with “This field has an invalid selection” until the value is changed by hand. AI select values appear as option pills in List cells and on cards, coloured when the options have colours.

Placement and inputs

An AI field must be a top-level field of a collection. Rows, collapsibles, unnamed groups and unnamed tabs are fine; arrays, blocks, named groups and named tabs are not. Inputs follow the same rule. FrogBot checks AI fields at startup and refuses to start with an error such as:

Stored value

The value is stored like a Text or Select field. Next to it, FrogBot keeps two state fields: Both are returned by the REST API, the Local API and agent tools, and they’re kept out of admin forms, List columns and filters. FrogBot sets them; the only write it accepts is the status pending. They are localized with the value.

Agents and generated types

An AI field describes itself to agents using FrogBot’s MCP tools and in generated types. The value’s text names the inputs:
The state fields have their own:
With a string admin.description, or a translated one with an en entry, the AI text is added after it in parentheses. The admin panel still shows only your description. A function admin.description isn’t copied, so the AI text stands alone. The text is English only. To change the value’s text, add your own jsonSchema entry. It runs after the AI field’s entry, so it can adjust or replace the description.

Custom components

The AI cell and input are AICell and AIField from @frogbotai/ui/admin. Your own admin.components.Cell or admin.components.Field replaces them, and other components such as Label, Description, Error, beforeInput and afterInput work as they do on a Text or Select field. A custom Cell can draw the standard AI display inside its own markup with FieldCell. As with any custom Cell, it appears only in the List view. frogbot/fields exports aiFieldPaths(name), which returns the state field names, isAIFieldInputSet(value), and the AIFieldStatus and AIKind types. It is safe to use in browser code.