Referencia de Funciones CEL
Referencia de las funciones y los operadores integrados disponibles en las expresiones CEL de AutoTalk, organizados por categoría.
Entran en ese alcance dos conjuntos de nombres, y ambos están en esta página. La
biblioteca estándar de CEL — operadores, macros de lista, funciones de
string, conversiones de tipo y los getters de timestamp — viene del registro CEL
compartido en AutoTalk Commons (src/functions/cel/index.ts), el mismo registro
del que se proyecta el panel Explorer del editor CEL, así que
todo lo que el Explorer ofrece está documentado aquí. Además, AutoTalk añade sus
propios auxiliares — get, coalesce, pluck, la familia math_*, los
auxiliares de fecha, los auxiliares de workflow step_* — que existen solo
aquí.
Core
get(obj, path, default?)
Accede de forma segura a una propiedad anidada a través de una ruta con puntos.
get(contact, "address.city") // "São Paulo"
get(contact, "address.zip", "00000-000") // retorna el predeterminado si falta
get(null, "name") // null
get(step(0), "data.results.0.title") // ruta profunda con índice de array
| Param | Tipo | Descripción |
|---|---|---|
obj | any | Objeto a acceder (seguro para null) |
path | string | Ruta con puntos (ej.: "a.b.c") |
default | any | Valor retornado si la ruta no existe (predeterminado: null) |
has(obj, path?)
Verifica si un valor o una ruta anidada existe y no es null/undefined.
has(contact, "platformId") // true si contact.platformId está definido
has(myVar) // true si myVar no es null/undefined
has(obj, "a.b.c") // true si la ruta completa resuelve a no-null
coalesce(...vals)
Retorna el primer valor no-null y no-undefined. Variádica — acepta hasta 5 argumentos. Si necesitas más, anida las llamadas: coalesce(a, b, c, d, coalesce(e, f)).
coalesce(get(contact, "customAttributes.nickname"), contact.name, "Guest") // el primer no-null gana
coalesce(0, 42) // 0 (no es null!)
coalesce(false, true) // false (no es null!)
coalesce("", "fallback") // "" (no es null!)
coalesce() solo omite null y undefined. Valores como 0, false y "" son válidos y se retornan.
now(tz?)
Retorna la fecha/hora actual como una string ISO 8601.
now() // "2024-01-15T14:30:00.000Z"
format_datetime(now(), "YYYY-MM-DD") // "2024-01-15"
El resultado siempre se expresa en UTC (sufijo Z), incluso cuando se pasa el argumento opcional de zona horaria. Para mostrar la hora actual en una zona horaria específica, formatéala — ej.: format_datetime(now(), "HH:mm", "America/Sao_Paulo").
present(val)
Verifica si un valor está significativamente presente. Retorna false para null, undefined, strings vacías/solo espacios y arrays vacíos. Los números y booleanos siempre se consideran presentes.
present(contact.platformId) // true si es una string no vacía
present("") // false
present(" ") // false (solo espacios)
present(0) // true
present([]) // false
present([1, 2]) // true
present(x) reemplaza el patrón común size(trim(coalesce(x, ""))) > 0.
blank(val)
Inverso de present(). Retorna true para null, undefined, strings vacías/solo espacios y arrays vacíos.
blank(contact.platformId) // true si es null o vacío
blank("hello") // false
blank(0) // false
Utilidades
pluck(arr, path)
Extrae una propiedad de cada objeto de un array.
pluck(contacts, "name") // ["Alice", "Bob", "Carol"]
pluck(tools, "tool.function.name") // ruta profunda soportada
slice(arr, start, end?)
Corta un array de forma segura. Retorna [] para entradas que no son arrays. Admite índices negativos.
slice(results, 0, 5) // primeros 5 elementos
slice(results, -3) // últimos 3 elementos
slice(results, 1, -1) // todos excepto el primero y el último
slice(null, 0, 2) // [] (seguro para no-arrays)
defaults(obj, fallbacks)
Fusiona valores de respaldo en un objeto para las claves que son null/undefined. Fusión superficial.
defaults(response, {"status": "unknown", "retryable": false})
// Completa status y retryable solo si son null/undefined en response
Como coalesce(), solo se reemplazan los valores null/undefined. 0, false y "" se mantienen.
url_params(base, params)
Construye una URL con parámetros de query. Omite los valores null y vacíos. Codifica automáticamente.
url_params("https://api.example.com/search", {"q": query, "page": 1, "lang": null})
// "https://api.example.com/search?q=hello&page=1" (lang omitido)
truncate(str, maxLen, suffix?)
Trunca una string a una longitud máxima con un sufijo opcional.
truncate("Hello World", 5) // "Hello"
truncate("Hello World", 8, "...") // "Hello..."
truncate(null, 10) // "" (seguro para null)
truncate("Hi", 100) // "Hi" (sin necesidad de truncar)
| Param | Tipo | Descripción |
|---|---|---|
str | any | Valor a truncar (convertido a string, null retorna "") |
maxLen | number | Longitud máxima del resultado (incluyendo el sufijo) |
suffix | string | Se agrega al truncar (predeterminado: "") |
El sufijo se incluye dentro de maxLen: truncate("Hello World", 8, "...") retorna "Hello..." (8 caracteres).
tpl(template, vars)
Interpolación simple de strings. Reemplaza los marcadores {key} con valores de un objeto.
tpl("Hello {name}!", {"name": "Alice"}) // "Hello Alice!"
tpl("*{title}*\n{domain}\n{url}", article) // texto formateado del artículo
tpl("{address.city}, {address.country}", contact) // soporte de ruta con puntos
tpl("Hi {name}", {"name": null}) // "Hi " (null → vacío)
| Param | Tipo | Descripción |
|---|---|---|
template | string | String de plantilla con marcadores {key} |
vars | object | Objeto con valores para interpolar |
join_present(separator, ...values)
Une valores con un separador, omitiendo los valores en blanco. Usa las mismas reglas que present(): null, strings vacías/solo espacios y arrays vacíos se omiten. 0 y false se mantienen. Acepta como máximo 5 argumentos en total — el separador más hasta 4 valores.
join_present(", ", "Alice", "Bob", "Carol") // "Alice, Bob, Carol"
join_present(" - ", title, null, author) // "Title - Author" (null omitido)
join_present(" ", "Hello", "", "World") // "Hello World" (vacío omitido)
join_present(" | ", 0, false, "text") // "0 | false | text" (0/false mantenidos)
join_present(" - ", prefix, text) reemplaza el patrón (present(prefix) ? prefix + " - " : "") + text.
encode_uri(str)
Codifica una string para URL. Los caracteres reservados de URI (&, =, ?, /, #) no se escapan, así que solo es adecuada para codificar una URL completa — no para valores individuales de parámetros de query.
encode_uri("hello world") // "hello%20world"
encode_uri("a&b=c") // "a&b=c" (caracteres reservados preservados)
Para agregar parámetros de query a una URL de forma segura, usa url_params() — codifica cada valor de parámetro por ti.
format_currency(currency, locale, amount)
Formatea un número como moneda. Los tres argumentos son obligatorios, en este orden: código de moneda, locale y, por último, el importe.
format_currency("USD", "en-US", 1234.5) // "$1,234.50"
format_currency("BRL", "pt-BR", 99.9) // "R$ 99,90"
Operadores
| Operador | Qué hace | Ejemplo |
|---|---|---|
! | NO lógico | !step_ok(0) |
&& | Y lógico, con cortocircuito | step_ok(0) && present(step_data(0, "id")) |
|| | O lógico, con cortocircuito | blank(contact.name) || contact.name == "-" |
==, != | Igualdad y desigualdad | step_data(0, "status") == "open" |
<, <=, >, >= | Comparación | size(step_data(0, "items")) > 0 |
+ | Suma. También une dos strings, concatena dos listas y suma una duración a un timestamp | [1, 2] + [3] → [1, 2, 3] |
-, *, /, % | Resta, multiplicación, división, resto | (total - paid) % 2 == 0 |
in | Pertenencia: ¿está este elemento en la lista, o esta clave en el mapa? | "vip" in contact.tags → true |
in es el que más se pasa por alto. Ahorra un bucle entero cuando solo necesitas
saber si un valor está presente, y se combina con el map de abajo:
"open" in step_data(0, "items").map(r, r.status)
Listas y macros
Las macros ejecutan una expresión sobre cada elemento de una lista. Se escriben en estilo receptor — la lista primero — y su primer argumento da nombre a la variable del bucle, que existe solo dentro de esa macro.
| Macro | Qué hace | Ejemplo |
|---|---|---|
list.all(x, pred) | Verdadero cuando todos los elementos coinciden. Verdadero para una lista vacía | rows.all(x, x.total > 0) |
list.exists(x, pred) | Verdadero cuando al menos un elemento coincide. Falso para una lista vacía | rows.exists(x, x.status == "open") |
list.exists_one(x, pred) | Verdadero cuando coincide exactamente un elemento | rows.exists_one(x, x.primary) |
list.map(x, expr) | Una nueva lista, con expr aplicada a cada elemento | rows.map(x, x.email) |
list.map(x, pred, expr) | Lo mismo, pero solo sobre los elementos que coinciden con pred | rows.map(x, x.status == "open", x.id) |
list.filter(x, pred) | Una nueva lista que contiene solo los elementos que coinciden | rows.filter(x, x.status == "open") |
Este es el camino más corto para "cuántas de las filas que devolvió un paso de búsqueda siguen abiertas" — sin necesidad de un paso Ejecutar Código:
size(step_data(0, "items").filter(r, r.status == "open"))
step_data(0, "items").map(r, r.status == "open", r.name) // nombres de las abiertas
step_data(0, "items").all(r, present(r.email)) // ¿toda fila es utilizable?
Conversión de tipos
| Función | Qué hace | Ejemplo |
|---|---|---|
int(v) | A número entero. Trunca un decimal hacia cero; un timestamp pasa a segundos de época, y una duración a segundos enteros | int("42") → 42, int(4.9) → 4 |
uint(v) | A número entero sin signo. Vuelve como un valor envuelto, no como un número simple — mira abajo | uint("42") |
double(v) | A número decimal | double("3.14") → 3.14 |
bool(v) | A booleano, desde "true", "false", "1" o "0" | bool("true") → true |
bytes(v) | Una string a bytes crudos | bytes("hi") |
string(v) | Cualquier cosa a su forma textual. Un timestamp pasa a una string ISO 8601, y una duración a segundos con una s | string(123) → "123" |
timestamp(v) | Una string ISO 8601 completa, o milisegundos de época, a un timestamp | timestamp("2024-01-15T00:00:00Z") |
duration(v) | Una string de duración — "90m", "1h30m", "3600s" — a una duración | duration("48h") |
type(v) | El tipo de un valor | type(1) |
dyn(v) | Pasa un valor tal cual, como tipo dinámico | dyn(v) |
Cinco cosas que conviene saber antes de poner una de estas en un campo:
-
Una conversión que no puede salir bien no solo vuelve vacía — se lleva la expresión entera consigo, y ninguna protección puede atraparla.
int("abc"),bool("yes"),uint("abc"),duration("abc")ytimestamp("2024-01-15")(sin la parte de hora) no producen nada, y tampoco lo hace nada construido a su alrededor:int("abc") > 5queda vacío en vez defalse,"n=" + string(int("abc"))queda vacío en vez de"n=", ypresent,blank,coalescey? :también quedan vacíos —present(int("abc"))no esfalseycoalesce(int("abc"), 0)no es0. Este es el único punto donde el fallo no se parece al de una ruta de paso inexistente, dondepresentsí respondefalse: una condición escrita como!present(int(step_data(0, "qty")))para decir "la cantidad no era un número" nunca se dispara. Comprueba el valor crudo antes de convertir, para que la conversión solo se ejecute sobre algo que puede aceptar:qty.matches("^-?[0-9]+$") ? int(qty) : 0 // 0 cuando qty es "abc" -
doublefalla de otra manera, y todavía más callada.double("abc")esNaN:presentlo da por presente,blanklo da por no vacío,string()lo renderiza como"NaN", y toda comparación contra él esfalse— tantodouble("abc") > 5comodouble("abc") <= 5. La protección conmatchesde arriba también sirve aquí. -
uint()devuelve un valor envuelto, no un número.uint("42")compara bien (uint("42") == 42estrue) pero no hace aritmética —uint("42") + 1queda vacío — y un campo guarda la envoltura en vez de42. Usaint()salvo que necesites de verdad el tipo sin signo, o desenvuélvelo:int(uint(v)),string(uint(v)). -
timestampydurationno son valores que un campo pueda guardar. Son útiles dentro de una expresión — comparando, sumando, alimentando un getter. Para obtener algo que un campo pueda almacenar, envuélvelos:string(timestamp(x) + duration("48h"))es una string ISO, eint(duration("90m"))es5400. -
type()tampoco sobrevive hasta un campo, y sus comparaciones no funcionan aquí. Usapresent/blankpara preguntar si un valor está, y compara contra el propio valor en vez de contra su tipo.
String
CEL incluye funciones de string integradas. La mayoría funciona tanto en estilo receptor como en estilo función:
"hello".contains("ell") // true (estilo receptor)
contains("hello", "ell") // true (estilo función)
| Función | Descripción | Ejemplo |
|---|---|---|
contains(str, sub) | Verifica si la string contiene la substring | "hello".contains("ell") |
startsWith(str, prefix) | Verifica el prefijo | "hello".startsWith("he") |
endsWith(str, suffix) | Verifica el sufijo | "hello".endsWith("lo") |
matches(str, pattern) | Coincidencia por expresión regular | "abc123".matches("^abc[0-9]+$") → true |
size(x) | Longitud de una string, lista o mapa | size("hello") → 5, size([1, 2, 3]) → 3 |
split(str, sep) | Divide en array | split("a,b,c", ",") → ["a","b","c"] |
lowerAscii(str) | Minúsculas | lowerAscii("HELLO") → "hello" |
upperAscii(str) | Mayúsculas | upperAscii("hello") → "HELLO" |
trim(str) | Elimina espacios | trim(" hi ") → "hi" |
substring(str, start, end?) | Extrae substring | substring("hello", 1, 4) → "ell" |
replace(str, old, new) | Reemplaza ocurrencias | replace("aab", "a", "x") → "xxb" |
indexOf(str, sub) | Primer índice de la substring | indexOf("hello", "l") → 2 |
lastIndexOf(str, sub) | Último índice de la substring | lastIndexOf("hello", "l") → 3 |
charAt(str, index) | Carácter en el índice | charAt("hello", 0) → "h" |
join(list, sep?) | Une un array en una string | join(["a","b"], ",") → "a,b" |
format(str, args) | Rellena los marcadores %s / %d desde una lista | "%d open".format([2]) → "2 open" |
strings.quote(str) | Envuelve entre comillas y escapa el contenido | strings.quote("a b") → "\"a b\"" |
Math
| Función | Descripción | Ejemplo |
|---|---|---|
math_add(a, b) | Suma | math_add(5, 3) → 8 |
math_subtract(a, b) | Resta | math_subtract(10, 3) → 7 |
math_multiply(a, b) | Multiplicación | math_multiply(4, 3) → 12 |
math_divide(a, b) | División | math_divide(10, 3) → 3.333... |
math_round(n, decimals?) | Redondeo | math_round(3.456, 2) → 3.46 |
math_floor(n) | Piso | math_floor(3.7) → 3 |
math_ceil(n) | Techo | math_ceil(3.1) → 4 |
math_abs(n) | Valor absoluto | math_abs(-5) → 5 |
math_pow(base, exp) | Potencia | math_pow(2, 3) → 8 |
math_sqrt(n) | Raíz cuadrada | math_sqrt(16) → 4 |
math_sin(n) | Seno (radianes) | math_sin(0) → 0 |
math_cos(n) | Coseno (radianes) | math_cos(0) → 1 |
math_tan(n) | Tangente (radianes) | math_tan(0) → 0 |
math_log(n, base?) | Logaritmo (natural por defecto) | math_log(8, 2) → 3 |
math_exp(n) | e elevado a la potencia n | math_exp(0) → 1 |
math_max(arr) | Máximo | math_max([1,5,3]) → 5 |
math_min(arr) | Mínimo | math_min([1,5,3]) → 1 |
math_mean(arr) | Promedio | math_mean([1,2,3]) → 2 |
math_median(arr) | Mediana | math_median([1,2,10]) → 2 |
math_std(arr) | Desviación estándar (muestral) | math_std([2,4,6]) → 2 |
math_variance(arr) | Varianza (muestral) | math_variance([2,4,6]) → 4 |
math_dot(a, b) | Producto punto de dos vectores | math_dot([1,2,3], [4,5,6]) → 32 |
math_norm(arr) | Norma euclidiana (longitud del vector) | math_norm([3,4]) → 5 |
math_clamp(val, min, max) | Restringe al rango | math_clamp(15, 0, 10) → 10 |
math_evaluate(expr) | Evalúa una string con una expresión matemática | math_evaluate("2 + 3 * 4") → 14 |
math_clamp(val, min, max)
Restringe un número dentro de un rango.
math_clamp(page, 1, 100) // asegura que page esté entre 1 y 100
math_clamp(-5, 0, 10) // 0 (por debajo del mínimo)
math_clamp(15, 0, 10) // 10 (por encima del máximo)
DateTime
| Función | Descripción |
|---|---|
now(tz?) | Fecha/hora actual como una string ISO 8601 (siempre expresada en UTC) |
format_datetime(d, fmt, tz?, locale?) | Formatea una fecha/hora. Acepta cualquier string de formato de dayjs — ej.: "DD/MM/YYYY", "YYYY-MM-DD HH:mm:ss", "HH:mm" — más una zona horaria y un locale opcionales ("en", "pt-BR", "es") |
add_datetime(d, n, unit) | Agrega tiempo. Unidades: "years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds" |
diff_datetime(d1, d2, unit) | Diferencia entre dos fechas/horas |
zoned_datetime(dateStr, timeStr, tz, format?) | Construye una fecha/hora con zona horaria a partir de strings separadas de fecha y hora, ej.: zoned_datetime("2024-01-15", "14:30", "America/Sao_Paulo"). Para convertir o mostrar una fecha/hora ya existente, usa format_datetime |
is_before(d1, d2) | ¿d1 antes de d2? |
is_after(d1, d2) | ¿d1 después de d2? |
is_between(d, start, end) | ¿d entre start y end? |
is_same_date(d1, d2, unit?, tz?) | ¿d1 y d2 son iguales en la unidad dada? (unidad predeterminada: "millisecond") — ej.: is_same_date(a, b, "day") verifica el mismo día calendario |
is_same_or_before(d1, d2, unit?, tz?) | ¿d1 igual o antes que d2? |
is_same_or_after(d1, d2, unit?, tz?) | ¿d1 igual o después que d2? |
Getters de timestamp y duración
Estos leen una parte de un timestamp o de una duration. Funcionan tanto en
estilo receptor — timestamp(x).getFullYear() — como en estilo función —
getFullYear(timestamp(x)) — y todo getter de timestamp acepta una zona horaria
IANA opcional como último argumento. Sin ella, leen el valor en UTC.
| Getter | En un timestamp | En una duración |
|---|---|---|
getFullYear(t, tz?) | Año de cuatro dígitos | — |
getMonth(t, tz?) | Mes, 0–11 — enero es 0 | — |
getDate(t, tz?) | Día del mes, 1–31 | — |
getDayOfMonth(t, tz?) | Día del mes, empezando en 0 — el día 15 es 14 | — |
getDayOfWeek(t, tz?) | Día de la semana, 0–6, domingo es 0 | — |
getDayOfYear(t, tz?) | Día del año, empezando en 0 — el 1 de enero es 0 | — |
getHours(v, tz?) | Hora, 0–23 | Horas enteras de la duración |
getMinutes(v, tz?) | Minuto, 0–59 | Minutos totales — duration("1h30m") da 90, no 30 |
getSeconds(v, tz?) | Segundo, 0–59 | Segundos totales |
getMilliseconds(v, tz?) | Milisegundo, 0–999 | La parte por debajo de un segundo, es decir 0 para cualquier duración en segundos enteros |
timestamp(step_data(0, "createdAt")).getDayOfWeek("America/Sao_Paulo") == 0 // cayó en domingo, hora local
getMonth(timestamp(now())) + 1 // mes como 1-12
Dos de estos son fáciles de equivocar: getDate cuenta desde 1 mientras que
getDayOfMonth cuenta desde 0, y getMonth cuenta desde 0. Cuando quieres una
fecha para mostrar a alguien, y no un número para comparar, format_datetime de
arriba es la mejor herramienta.
JSON
| Función | Descripción |
|---|---|
json_parse(str) | Convierte una string JSON en un objeto |
json_stringify(obj) | Serializa un objeto en una string JSON |
TOON
TOON es un formato de serialización de datos compacto y legible para humanos.
| Función | Descripción |
|---|---|
toon_encode(value) | Codifica un valor a una string TOON |
toon_decode(str) | Parsea una string TOON de vuelta a un valor |
toon_encode({"name": "Alice", "age": 30}) // "name: Alice\nage: 30"
toon_decode("name: Alice\nage: 30") // {"name": "Alice", "age": 30}
BSON / ObjectId
| Función | Descripción |
|---|---|
object_id(value?) | Crea o normaliza una instancia de ObjectId (una nueva si no hay argumento). Usa object_id_to_string() para obtener la string hexadecimal |
object_id_is_valid(id) | Verifica si la string es un ObjectId válido |
object_id_to_string(id) | Convierte un ObjectId a su string hexadecimal |
bson_serialize(value, encoding?) | Serializa un valor a bytes BSON, devueltos como una string base64 (predeterminado) o "hex" |
bson_deserialize(str, encoding?) | Decodifica una string BSON en base64 (predeterminado) o "hex" de vuelta a un valor |
ejson_stringify(value, relaxed?) | Serializa un valor a una string de MongoDB Extended JSON (modo relaxed por defecto) |
ejson_parse(str, relaxed?) | Parsea una string de MongoDB Extended JSON a un valor |
bson_serialize({"a": 1}) // "DAAAABBhAAEAAAAA" (base64)
bson_serialize({"a": 1}, "hex") // "0c0000001061000100000000"
bson_deserialize("DAAAABBhAAEAAAAA") // {"a": 1}
ejson_stringify({"a": 1}) // "{\"a\":1}"
Específicas de Workflow
Estas funciones solo están disponibles en las expresiones de workflow y de agentes (no en el CEL de formularios).
step(N)
Accede a la salida del paso N del workflow (indexado desde 0).
step(0) // objeto completo de salida del paso
step(0).data // payload de datos del paso
step(0).status // código de estado HTTP (para pasos HTTP)
step_ok(N)
Verifica si el paso N se completó exitosamente. Retorna true cuando executionContext.status es "completed" Y el estado HTTP es 200 (o null para pasos no-HTTP).
// Antes: verboso
get(step(0), "executionContext.status") == "completed" && (get(step(0), "status") == null || get(step(0), "status") == 200)
// Después: una llamada a función
step_ok(0)
step_data(N, path?, default?)
Obtiene datos del paso N en una ruta con puntos opcional. Retorna el predeterminado (o null) si no existe.
La ruta es relativa al data del paso — step_data(0, "title") lee step(0).data.title. No repitas data en la ruta: step_data(0, "data.title") busca step(0).data.data.title, falla en silencio y devuelve el valor por defecto — indistinguible de que el campo esté vacío. (step_data(0, "data.x") solo es correcto cuando el propio cuerpo de la respuesta tiene una clave data en el nivel superior, como en respuestas JSON:API.)
// Antes
get(step(0), "data.title", null)
// Después
step_data(0, "title")
step_data(0, "results.0.name", "Unknown")
step_data(1, "choices.0.message.content")
Acciones que publican en la raíz del paso
La mayoría de las acciones pone su salida bajo data, y por eso la ruta es
relativa a él. Veinte no lo hacen — declaran sus salidas en la raíz del paso
y no tienen ningún objeto data. No es un caso marginal:
actions/ai/llm/chat/generate está en la lista, y su choices es la salida de
paso que los workflows recorren más a menudo.
| Acción | Salidas en la raíz |
|---|---|
actions/ai/agent/send | messages |
actions/ai/llm/chat/generate | choices |
actions/agent/lifecycle/session/set_reply_delay | replyDelayMs |
actions/ai/text/speakable | text, model |
actions/data/company/resource/count | count |
actions/mcp/connect | url, toolCount |
actions/mcp/connect/autotalk-mcp | url, toolCount |
actions/media/audio/synthesize | file, bucket, fullPath, size, contentType, format, cache, billedMeter, billedMs |
actions/media/audio/transcribe | jobId, jobStatus, enginePath, providerType, diarized |
actions/media/document/generate | file, bucket, fullPath, fileName, size, contentType, format |
actions/media/read | text, supported, truncated, reason, mediaKind, mimeType, fileName, size |
actions/media/storage/delete | deleted, existed, bucket, fullPath |
actions/media/storage/probe | durationSeconds, width, height, formatName, videoCodec, audioCodec, hasAudio, sizeBytes, contentType, cached |
actions/media/storage/signed-url | signedUrl, contentType, size, mediaKind, bucket, fullPath, name, expiresAt |
actions/media/storage/upload | file, signedUrl, contentType, size |
actions/media/transform | jobId, jobStatus, preset |
actions/monitors/cancel | monitorId, monitorState |
actions/monitors/create | monitorId, monitorState, expiresAtIso |
actions/network/http/download-to-storage | status, file, signedUrl, contentType, size |
actions/security/auth/jwt/generate | jwt |
Lee esas salidas con get(step(N), "field"):
get(step(0), "count") > 0 // resource/count
get(step(1), "choices.0.message.content") // llm/chat/generate
get(step(2), "mediaKind") == "pdf" // media/read
step_data también resuelve contra la raíz en estos casos — un paso que no tiene
ni data ni result recae sobre el propio objeto del paso — así que
step_data(0, "count") también funciona. Ese fallback es deliberadamente estrecho
y no se aplica a un paso que sí tiene data: en
actions/network/http/request/send, step_data(N, "status") sigue devolviendo tu
valor por defecto en lugar del código de estado HTTP, porque status es hermano
de data en la raíz, no un campo dentro de él. (En
actions/network/http/download-to-storage, que sí tiene la forma de raíz,
status es una salida del paso, así que step_data(N, "status") sí lo devuelve
— la regla es la misma, lo que cambia es la forma de la acción.) Las claves que
pertenecen al envoltorio de ejecución (executionContext, actionContext,
safeError, safeResult, conditionPassed, aclInfo) nunca son alcanzables
por step_data en ningún paso.
Existe un tercer formato, y hoy hay exactamente una acción en él. Ejecutar
Código publica su valor de retorno como un result en el nivel superior y no
tiene data, así que step_data y step_has_content resuelven dentro de ese
valor: step_data(0, "count") lee step(0).result.count, que normalmente es lo
que quieres. Sus hermanos en la raíz del paso — files, logs,
executionTimeMs — no son alcanzables por esa vía y hay que leerlos con
get(step(N), "files"). Esto vale incluso cuando el código no devolvió nada,
porque entonces result es null, lo que ya basta para tomar esa rama. Por eso
la tabla de arriba no tiene una fila para actions/code/execute: no tiene ni la
forma data ni la forma de raíz.
Sea cual sea la forma que uses, una ruta que no existe devuelve el valor por
defecto en silencio — step_ok(N) sigue siendo true. Nunca confíes en una
lista recordada de memoria: comprueba las salidas declaradas de la acción
(get_action_definition(actionType), cuya pista STEP OUTPUTS se deriva de esas
salidas, o la referencia de la acción) antes de escribir la ruta.
step_error(N)
Obtiene la información de error de un paso fallido. Retorna {code, user_message, retryable} o null.
// Antes
coalesce(get(step(0), "executionContext.safeError.code"), "UNKNOWN")
// Después
step_error(0) // {code: "TIMEOUT", user_message: "...", retryable: true}
get(step_error(0), "code", "UNKNOWN") // "TIMEOUT"
step_has_content(N, path)
Verifica si el paso N se completó exitosamente Y tiene datos presentes (no-null, no-vacío) en la ruta dada. Combina step_ok(N) && present(step_data(N, path)) en una sola llamada.
// Antes: dos verificaciones
step_ok(0) && present(step_data(0, "articles"))
// Después: una llamada a función
step_has_content(0, "articles")
La ruta sigue exactamente la misma regla que step_data: relativa a data o —
en las acciones que publican en la raíz — relativa a la
raíz del paso.
getContext()
Obtiene el objeto de contexto de ejecución del workflow.
getTool()
Obtiene el objeto de contexto de la herramienta que se está ejecutando actualmente — el mismo contexto del que leen los auxiliares step(N). No toma argumentos; cualquier argumento que se pase se ignora.
getRoot()
Obtiene el contexto raíz del workflow.