Skip to main content
Updated Aug 4, 2026

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
ParamTypeDescription
objanyObject to access (null-safe)
pathstringDotted path (e.g. "a.b.c")
defaultanyValue 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!)
Null-check semantics

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
Replaces verbose patterns

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
Null-check semantics

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)
ParamTypeDescription
stranyValue to truncate (coerced to string, null returns "")
maxLennumberMaximum length of result (including suffix)
suffixstringAppended when truncated (default: "")
tip

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)
ParamTypeDescription
templatestringTemplate string with {key} placeholders
varsobjectObject 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)
Replaces conditional concatenation

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)
Building query strings

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)
FunctionDescriptionExample
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 mapsize("hello")5, size([1, 2, 3])3
split(str, sep)Split into arraysplit("a,b,c", ",")["a","b","c"]
lowerAscii(str)LowercaselowerAscii("HELLO")"hello"
upperAscii(str)UppercaseupperAscii("hello")"HELLO"
trim(str)Trim whitespacetrim(" hi ")"hi"
substring(str, start, end?)Extract substringsubstring("hello", 1, 4)"ell"
replace(str, old, new)Replace occurrencesreplace("aab", "a", "x")"xxb"
indexOf(str, sub)First index of substringindexOf("hello", "l")2
lastIndexOf(str, sub)Last index of substringlastIndexOf("hello", "l")3
charAt(str, index)Character at indexcharAt("hello", 0)"h"
join(list, sep?)Join array to stringjoin(["a","b"], ",")"a,b"

Math

FunctionDescriptionExample
math_add(a, b)Addmath_add(5, 3)8
math_subtract(a, b)Subtractmath_subtract(10, 3)7
math_multiply(a, b)Multiplymath_multiply(4, 3)12
math_divide(a, b)Dividemath_divide(10, 3)3.333...
math_round(n, decimals?)Roundmath_round(3.456, 2)3.46
math_floor(n)Floormath_floor(3.7)3
math_ceil(n)Ceilingmath_ceil(3.1)4
math_abs(n)Absolute valuemath_abs(-5)5
math_pow(base, exp)Powermath_pow(2, 3)8
math_sqrt(n)Square rootmath_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 nmath_exp(0)1
math_max(arr)Maximummath_max([1,5,3])5
math_min(arr)Minimummath_min([1,5,3])1
math_mean(arr)Averagemath_mean([1,2,3])2
math_median(arr)Medianmath_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 vectorsmath_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 rangemath_clamp(15, 0, 10)10
math_evaluate(expr)Evaluate a math expression stringmath_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

FunctionDescription
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

FunctionDescription
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.

FunctionDescription
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

FunctionDescription
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.