CEL Functions Reference
Complete reference for all built-in functions available in AutoTalk CEL expressions. Functions are organized by category.
Core
get(obj, path, default?)
Safely access a nested property via a dotted path.
get(contact, "address.city") // "São Paulo"
get(contact, "address.zip", "00000-000") // returns default if missing
get(null, "name") // null
get(step(0), "data.results.0.title") // deep path with array index
| Param | Type | Description |
|---|---|---|
obj | any | Object to access (null-safe) |
path | string | Dotted path (e.g. "a.b.c") |
default | any | Value returned if path missing (default: null) |
has(obj, path?)
Check if a value or nested path exists and is not null/undefined.
has(contact, "platformId") // true if contact.platformId is set
has(myVar) // true if myVar is not null/undefined
has(obj, "a.b.c") // true if full path resolves to non-null
coalesce(...vals)
Return the first non-null, non-undefined value. Variadic — accepts up to 5 arguments. If you need more, nest calls: coalesce(a, b, c, d, coalesce(e, f)).
coalesce(get(contact, "customAttributes.nickname"), contact.name, "Guest") // first non-null wins
coalesce(0, 42) // 0 (not null!)
coalesce(false, true) // false (not null!)
coalesce("", "fallback") // "" (not null!)
coalesce() only skips null and undefined. Values like 0, false, and "" are valid and returned.
now(tz?)
Returns the current date/time as an ISO 8601 string.
now() // "2024-01-15T14:30:00.000Z"
format_datetime(now(), "YYYY-MM-DD") // "2024-01-15"
The result is always expressed in UTC (Z suffix), even when the optional timezone argument is passed. To display the current time in a specific timezone, format it — e.g. format_datetime(now(), "HH:mm", "America/Sao_Paulo").
present(val)
Check if a value is meaningfully present. Returns false for null, undefined, empty/whitespace strings, and empty arrays. Numbers and booleans are always present.
present(contact.platformId) // true if non-empty string
present("") // false
present(" ") // false (whitespace only)
present(0) // true
present([]) // false
present([1, 2]) // true
present(x) replaces the common pattern size(trim(coalesce(x, ""))) > 0.
blank(val)
Inverse of present(). Returns true for null, undefined, empty/whitespace strings, and empty arrays.
blank(contact.platformId) // true if null or empty
blank("hello") // false
blank(0) // false
Utility
pluck(arr, path)
Extract a property from each object in an array.
pluck(contacts, "name") // ["Alice", "Bob", "Carol"]
pluck(tools, "tool.function.name") // deep path supported
slice(arr, start, end?)
Safely slice an array. Returns [] for non-array inputs. Supports negative indices.
slice(results, 0, 5) // first 5 items
slice(results, -3) // last 3 items
slice(results, 1, -1) // all except first and last
slice(null, 0, 2) // [] (safe for non-arrays)
defaults(obj, fallbacks)
Merge fallback values into an object for keys that are null/undefined. Shallow merge.
defaults(response, {"status": "unknown", "retryable": false})
// Fills in status and retryable only if they are null/undefined in response
Like coalesce(), only null/undefined values are replaced. 0, false, and "" are kept.
url_params(base, params)
Build a URL with query parameters. Skips null and empty values. Auto-encodes.
url_params("https://api.example.com/search", {"q": query, "page": 1, "lang": null})
// "https://api.example.com/search?q=hello&page=1" (lang skipped)
truncate(str, maxLen, suffix?)
Truncate a string to a maximum length with an optional suffix.
truncate("Hello World", 5) // "Hello"
truncate("Hello World", 8, "...") // "Hello..."
truncate(null, 10) // "" (null-safe)
truncate("Hi", 100) // "Hi" (no truncation needed)
| Param | Type | Description |
|---|---|---|
str | any | Value to truncate (coerced to string, null returns "") |
maxLen | number | Maximum length of result (including suffix) |
suffix | string | Appended when truncated (default: "") |
The suffix is included within maxLen: truncate("Hello World", 8, "...") returns "Hello..." (8 chars).
tpl(template, vars)
Simple string interpolation. Replaces {key} placeholders with values from an object.
tpl("Hello {name}!", {"name": "Alice"}) // "Hello Alice!"
tpl("*{title}*\n{domain}\n{url}", article) // formatted article text
tpl("{address.city}, {address.country}", contact) // dotted path support
tpl("Hi {name}", {"name": null}) // "Hi " (null → empty)
| Param | Type | Description |
|---|---|---|
template | string | Template string with {key} placeholders |
vars | object | Object with values to interpolate |
join_present(separator, ...values)
Join values with a separator, skipping blank values. Uses the same rules as present(): null, empty/whitespace strings, and empty arrays are skipped. 0 and false are kept. Accepts at most 5 arguments in total — the separator plus up to 4 values.
join_present(", ", "Alice", "Bob", "Carol") // "Alice, Bob, Carol"
join_present(" - ", title, null, author) // "Title - Author" (null skipped)
join_present(" ", "Hello", "", "World") // "Hello World" (empty skipped)
join_present(" | ", 0, false, "text") // "0 | false | text" (0/false kept)
join_present(" - ", prefix, text) replaces the pattern (present(prefix) ? prefix + " - " : "") + text.
encode_uri(str)
URL-encode a string. Reserved URI characters (&, =, ?, /, #) are not escaped, so it is only suitable for encoding a whole URL — not for individual query-parameter values.
encode_uri("hello world") // "hello%20world"
encode_uri("a&b=c") // "a&b=c" (reserved characters preserved)
To add query parameters to a URL safely, use url_params() — it encodes each parameter value for you.
format_currency(currency, locale, amount)
Format a number as currency. All three arguments are required, in this order: currency code, locale, then amount.
format_currency("USD", "en-US", 1234.5) // "$1,234.50"
format_currency("BRL", "pt-BR", 99.9) // "R$ 99,90"
String
CEL includes built-in string functions. Most work as both receiver-style and function-style:
"hello".contains("ell") // true (receiver-style)
contains("hello", "ell") // true (function-style)
| Function | Description | Example |
|---|---|---|
contains(str, sub) | Check if string contains substring | "hello".contains("ell") |
startsWith(str, prefix) | Check prefix | "hello".startsWith("he") |
endsWith(str, suffix) | Check suffix | "hello".endsWith("lo") |
matches(str, pattern) | Regular-expression match | "abc123".matches("^abc[0-9]+$") → true |
size(x) | Length of a string, list, or map | size("hello") → 5, size([1, 2, 3]) → 3 |
split(str, sep) | Split into array | split("a,b,c", ",") → ["a","b","c"] |
lowerAscii(str) | Lowercase | lowerAscii("HELLO") → "hello" |
upperAscii(str) | Uppercase | upperAscii("hello") → "HELLO" |
trim(str) | Trim whitespace | trim(" hi ") → "hi" |
substring(str, start, end?) | Extract substring | substring("hello", 1, 4) → "ell" |
replace(str, old, new) | Replace occurrences | replace("aab", "a", "x") → "xxb" |
indexOf(str, sub) | First index of substring | indexOf("hello", "l") → 2 |
lastIndexOf(str, sub) | Last index of substring | lastIndexOf("hello", "l") → 3 |
charAt(str, index) | Character at index | charAt("hello", 0) → "h" |
join(list, sep?) | Join array to string | join(["a","b"], ",") → "a,b" |
Math
| Function | Description | Example |
|---|---|---|
math_add(a, b) | Add | math_add(5, 3) → 8 |
math_subtract(a, b) | Subtract | math_subtract(10, 3) → 7 |
math_multiply(a, b) | Multiply | math_multiply(4, 3) → 12 |
math_divide(a, b) | Divide | math_divide(10, 3) → 3.333... |
math_round(n, decimals?) | Round | math_round(3.456, 2) → 3.46 |
math_floor(n) | Floor | math_floor(3.7) → 3 |
math_ceil(n) | Ceiling | math_ceil(3.1) → 4 |
math_abs(n) | Absolute value | math_abs(-5) → 5 |
math_pow(base, exp) | Power | math_pow(2, 3) → 8 |
math_sqrt(n) | Square root | math_sqrt(16) → 4 |
math_sin(n) | Sine (radians) | math_sin(0) → 0 |
math_cos(n) | Cosine (radians) | math_cos(0) → 1 |
math_tan(n) | Tangent (radians) | math_tan(0) → 0 |
math_log(n, base?) | Logarithm (natural log by default) | math_log(8, 2) → 3 |
math_exp(n) | e raised to the power n | math_exp(0) → 1 |
math_max(arr) | Maximum | math_max([1,5,3]) → 5 |
math_min(arr) | Minimum | math_min([1,5,3]) → 1 |
math_mean(arr) | Average | math_mean([1,2,3]) → 2 |
math_median(arr) | Median | math_median([1,2,10]) → 2 |
math_std(arr) | Standard deviation (sample) | math_std([2,4,6]) → 2 |
math_variance(arr) | Variance (sample) | math_variance([2,4,6]) → 4 |
math_dot(a, b) | Dot product of two vectors | math_dot([1,2,3], [4,5,6]) → 32 |
math_norm(arr) | Euclidean norm (vector length) | math_norm([3,4]) → 5 |
math_clamp(val, min, max) | Constrain to range | math_clamp(15, 0, 10) → 10 |
math_evaluate(expr) | Evaluate a math expression string | math_evaluate("2 + 3 * 4") → 14 |
math_clamp(val, min, max)
Constrain a number within a range.
math_clamp(page, 1, 100) // ensure page is between 1 and 100
math_clamp(-5, 0, 10) // 0 (below min)
math_clamp(15, 0, 10) // 10 (above max)
DateTime
| Function | Description |
|---|---|
now(tz?) | Current date/time as an ISO 8601 string (always expressed in UTC) |
format_datetime(d, fmt, tz?, locale?) | Format a datetime. Accepts any dayjs format string — e.g. "DD/MM/YYYY", "YYYY-MM-DD HH:mm:ss", "HH:mm" — plus an optional timezone and locale ("en", "pt-BR", "es") |
add_datetime(d, n, unit) | Add time. Units: "years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds" |
diff_datetime(d1, d2, unit) | Difference between two datetimes |
zoned_datetime(dateStr, timeStr, tz, format?) | Build a timezone-aware datetime from separate date and time strings, e.g. zoned_datetime("2024-01-15", "14:30", "America/Sao_Paulo"). To convert or display an existing datetime, use format_datetime instead |
is_before(d1, d2) | d1 before d2? |
is_after(d1, d2) | d1 after d2? |
is_between(d, start, end) | d between start and end? |
is_same_date(d1, d2, unit?, tz?) | d1 and d2 equal at the given unit? (default unit: "millisecond") — e.g. is_same_date(a, b, "day") checks same calendar day |
is_same_or_before(d1, d2, unit?, tz?) | d1 same as or before d2? |
is_same_or_after(d1, d2, unit?, tz?) | d1 same as or after d2? |
JSON
| Function | Description |
|---|---|
json_parse(str) | Parse JSON string to object |
json_stringify(obj) | Serialize object to JSON string |
TOON
TOON is a compact, human-readable data serialization format.
| Function | Description |
|---|---|
toon_encode(value) | Encode a value to a TOON string |
toon_decode(str) | Parse a TOON string back into a value |
toon_encode({"name": "Alice", "age": 30}) // "name: Alice\nage: 30"
toon_decode("name: Alice\nage: 30") // {"name": "Alice", "age": 30}
BSON / ObjectId
| Function | Description |
|---|---|
object_id(value?) | Create or normalize an ObjectId instance (new one if no argument). Wrap with object_id_to_string() for the hex string |
object_id_is_valid(id) | Check if string is valid ObjectId |
object_id_to_string(id) | Convert an ObjectId to its hex string |
bson_serialize(value, encoding?) | Serialize a value to BSON bytes, returned as a base64 (default) or "hex" string |
bson_deserialize(str, encoding?) | Decode a base64 (default) or "hex" BSON string back into a value |
ejson_stringify(value, relaxed?) | Serialize a value to a MongoDB Extended JSON string (relaxed mode by default) |
ejson_parse(str, relaxed?) | Parse a MongoDB Extended JSON string into a value |
bson_serialize({"a": 1}) // "DAAAABBhAAEAAAAA" (base64)
bson_serialize({"a": 1}, "hex") // "0c0000001061000100000000"
bson_deserialize("DAAAABBhAAEAAAAA") // {"a": 1}
ejson_stringify({"a": 1}) // "{\"a\":1}"
Workflow-Specific
These functions are available only in workflow and agent expressions (not in form CEL).
step(N)
Access output from workflow step N (0-indexed).
step(0) // full step output object
step(0).data // the step's data payload
step(0).status // HTTP status code (for HTTP steps)
step_ok(N)
Check if step N completed successfully. Returns true when executionContext.status is "completed" AND HTTP status is 200 (or null for non-HTTP steps).
// Before: verbose
get(step(0), "executionContext.status") == "completed" && (get(step(0), "status") == null || get(step(0), "status") == 200)
// After: one function call
step_ok(0)
step_data(N, path?, default?)
Get data from step N at an optional dotted path. Returns default (or null) if missing.
// Before
get(step(0), "data.title", null)
// After
step_data(0, "title")
step_data(0, "results.0.name", "Unknown")
step_data(1, "choices.0.message.content")
step_error(N)
Get error info from a failed step. Returns {code, user_message, retryable} or null.
// Before
coalesce(get(step(0), "executionContext.safeError.code"), "UNKNOWN")
// After
step_error(0) // {code: "TIMEOUT", user_message: "...", retryable: true}
get(step_error(0), "code", "UNKNOWN") // "TIMEOUT"
step_has_content(N, path)
Check if step N completed successfully AND has present (non-null, non-empty) data at the given path. Combines step_ok(N) && present(step_data(N, path)) into one call.
// Before: two checks
step_ok(0) && present(step_data(0, "articles"))
// After: one function call
step_has_content(0, "articles")
getContext()
Get the workflow execution context object.
getTool()
Get the context object of the currently running tool — the same context the step(N) helpers read from. Takes no arguments; any arguments passed are ignored.
getRoot()
Get the root workflow context.