Computed Columns
A computed column is an AutessaDB column whose value is produced by an AutessaScript instead of being written directly. The script reads the row's other columns as variables, returns one value with response.setResponse(...), and the platform converts that value to the column's type and merges it into the row. Same language, same sandbox — but a slimmer execution context than a script tool.
See AutessaDB Tables for creating tables and columns; this page covers what your script sees once it's attached to a column.
When the script runs
Computed columns are recomputed asynchronously, in the background, after the row write that triggers them:
- On insert, every computed column in the table runs.
- On update, a computed column runs only when one of its declared dependencies (see below) is among the updated columns. If an update writes a computed column directly, that column is not recomputed over your explicit value in the same update.
Because computation is asynchronous, the insert or update returns immediately — with the row's computation status reported as COMPUTING — and the computed value appears in the row shortly after, once the script finishes. Scripts read a snapshot of the row as it was written; they never block the write itself.
When several computed columns exist, they run in dependency order: a computed column that depends on another computed column sees the freshly computed value, not the stale one. A circular dependency between computed columns is rejected and none of them compute.
Variables: the row, natively typed
The variables binding contains the row's columns, keyed by column name. Unlike tool executions — where every variable is a string — computed columns receive native types per the column's type:
| Column type | JavaScript value |
|---|---|
SHORT_TEXT, LONG_TEXT, SINGLE_SELECT | string |
MULTI_SELECT | string (the selections in their combined string form) |
INTEGER | number |
FLOAT | number |
BOOLEAN | boolean |
FILE, IMAGE, VIDEO, AUDIO | string (the stored file path) |
Details that matter in practice:
- Empty columns are absent, not null. A column with no value doesn't appear in
variablesat all — guard withvariables.has("name")before reading. - Built-in fields are included:
id(number),created_atandupdated_at(strings). DATETIMEcolumns don't cross the boundary — they are neither passed in as variables nor writable as a computed result. Store timestamps asSHORT_TEXTUTC strings if a computed column needs them.- Other computed columns' values are available too: previously stored values on update, and freshly computed values for columns earlier in the dependency order.
Declaring dependencies
A computed column's configuration includes a dependsOn list — the column names your script reads. It does three jobs:
- Update triggering. After an update, only computed columns whose
dependsOnintersects the updated columns are recomputed. A script that reads a column it doesn't declare will silently go stale on updates. - Ordering. Dependencies on other computed columns put your column later in the computation order.
- Validation. A missing dependency is logged; a dependency cycle fails the whole computation pass.
Declare every column the script reads. There is no automatic detection.
Returning the value
Call response.setResponse(...) with a string; the platform converts it to the column's type:
| Column type | Conversion |
|---|---|
SHORT_TEXT, LONG_TEXT, SINGLE_SELECT | stored as-is |
MULTI_SELECT | parsed from the combined multi-select string form |
INTEGER | parsed as an integer — must be a plain integer string like "42" |
FLOAT | parsed as a float |
BOOLEAN | "true" (case-insensitive) becomes true; anything else false |
FILE, IMAGE, VIDEO, AUDIO | stored as the file path |
If the string doesn't parse (say, "42.5" into an INTEGER column), the conversion fails and no value is written. The same happens when the script throws or never calls response.setResponse — the column is simply left unset. One failing computed column doesn't stop the others.
Failures are silent from the table's point of view: there is no error cell, just an empty column and a server-side log you can't see. Develop and debug the script as a script tool first — where the test window shows you logs and errors — then attach it to the column.
What's missing compared to tool execution
The script runs in the same sandbox with the same helpers bound, but the context is slimmer:
- No tool arguments. There are no
@@{name}placeholders — the variables are the row's columns, nothing else. - No platform context.
AUTESSA_COMPANY_ID,AUTESSA_TOOL_NAME, and the otherAUTESSA_*variables from tool execution are absent. As a consequence, company-scoped helpers refuse to run:tools.invokeByIdreturnsMISSING_COMPANY_IDandconnector.*returnsNO_COMPANY_CONTEXT. - No
responseStream. Computed columns never stream; referencingresponseStreamthrows aReferenceError. See Global bindings. api,llm,mathUtils, andwaitUtilswork normally.
Keep computed-column scripts small, fast, and deterministic — derive from the row, return a value. Side effects and orchestration belong in script tools.
Example: derive a display name
A SHORT_TEXT column full_name with dependsOn: ["first_name", "last_name"]:
const first = variables.has("first_name") ? variables.get("first_name") : "";
const last = variables.has("last_name") ? variables.get("last_name") : "";
const full = (first + " " + last).trim();
if (full !== "") {
response.setResponse(full);
}
// If both inputs are empty, setResponse is never called and the column stays unset.
Example: numeric derivation
A FLOAT column margin_percent with dependsOn: ["revenue", "cost"]. Numeric columns arrive as real numbers — no parseFloat needed:
if (variables.has("revenue") && variables.has("cost")) {
const revenue = variables.get("revenue"); // number
const cost = variables.get("cost"); // number
if (revenue > 0) {
const margin = ((revenue - cost) / revenue) * 100;
response.setResponse(margin.toFixed(2)); // "23.50" parses cleanly as FLOAT
}
}