Pular para o conteúdo principal
Atualizado em Sep 17, 2026

Referência de Funções CEL

Referência das funções e operadores integrados disponíveis nas expressões CEL do AutoTalk, organizados por categoria.

Dois conjuntos de nomes entram nesse escopo, e ambos estão nesta página. A biblioteca padrão do CEL — operadores, macros de lista, funções de string, conversões de tipo e os getters de timestamp — vem do registro CEL compartilhado no AutoTalk Commons (src/functions/cel/index.ts), o mesmo registro do qual o painel Explorer do editor CEL é projetado, então tudo o que o Explorer oferece está documentado aqui. Além disso, o AutoTalk adiciona os próprios auxiliares — get, coalesce, pluck, a família math_*, os auxiliares de data, os auxiliares de workflow step_* — que existem apenas aqui.


Core

get(obj, path, default?)

Acessa com segurança uma propriedade aninhada através de um caminho pontilhado.

get(contact, "address.city") // "São Paulo"
get(contact, "address.zip", "00000-000") // retorna o padrão se ausente
get(null, "name") // null
get(step(0), "data.results.0.title") // caminho profundo com índice de array
ParamTipoDescrição
objanyObjeto a acessar (seguro para null)
pathstringCaminho pontilhado (ex: "a.b.c")
defaultanyValor retornado se o caminho estiver ausente (padrão: null)

has(obj, path?)

Verifica se um valor ou caminho aninhado existe e não é null/undefined.

has(contact, "platformId") // true se contact.platformId estiver definido
has(myVar) // true se myVar não for null/undefined
has(obj, "a.b.c") // true se o caminho completo resolver para não-null

coalesce(...vals)

Retorna o primeiro valor não-null e não-undefined. Variádica — aceita até 5 argumentos. Se precisar de mais, aninhe as chamadas: coalesce(a, b, c, d, coalesce(e, f)).

coalesce(get(contact, "customAttributes.nickname"), contact.name, "Guest") // o primeiro não-null vence
coalesce(0, 42) // 0 (não é null!)
coalesce(false, true) // false (não é null!)
coalesce("", "fallback") // "" (não é null!)
Semântica de verificação de null

coalesce() ignora apenas null e undefined. Valores como 0, false e "" são válidos e retornados.

now(tz?)

Retorna a data/hora atual como uma string ISO 8601.

now() // "2024-01-15T14:30:00.000Z"
format_datetime(now(), "YYYY-MM-DD") // "2024-01-15"

O resultado é sempre expresso em UTC (sufixo Z), mesmo quando o argumento opcional de fuso horário é passado. Para exibir a hora atual em um fuso horário específico, formate-a — ex.: format_datetime(now(), "HH:mm", "America/Sao_Paulo").

present(val)

Verifica se um valor está significativamente presente. Retorna false para null, undefined, strings vazias/somente espaços e arrays vazios. Números e booleanos são sempre considerados presentes.

present(contact.platformId) // true se for string não vazia
present("") // false
present(" ") // false (somente espaços)
present(0) // true
present([]) // false
present([1, 2]) // true
Substitui padrões verbosos

present(x) substitui o padrão comum size(trim(coalesce(x, ""))) > 0.

blank(val)

Inverso de present(). Retorna true para null, undefined, strings vazias/somente espaços e arrays vazios.

blank(contact.platformId) // true se for null ou vazio
blank("hello") // false
blank(0) // false

Utilitários

pluck(arr, path)

Extrai uma propriedade de cada objeto em um array.

pluck(contacts, "name") // ["Alice", "Bob", "Carol"]
pluck(tools, "tool.function.name") // caminho profundo suportado

slice(arr, start, end?)

Fatia um array com segurança. Retorna [] para entradas que não são arrays. Suporta índices negativos.

slice(results, 0, 5) // primeiros 5 itens
slice(results, -3) // últimos 3 itens
slice(results, 1, -1) // todos exceto o primeiro e o último
slice(null, 0, 2) // [] (seguro para não-arrays)

defaults(obj, fallbacks)

Mescla valores de fallback em um objeto para chaves que são null/undefined. Mesclagem superficial.

defaults(response, {"status": "unknown", "retryable": false})
// Preenche status e retryable somente se forem null/undefined em response
Semântica de verificação de null

Assim como coalesce(), apenas valores null/undefined são substituídos. 0, false e "" são mantidos.

url_params(base, params)

Constrói uma URL com parâmetros de query. Ignora valores null e vazios. Codifica automaticamente.

url_params("https://api.example.com/search", {"q": query, "page": 1, "lang": null})
// "https://api.example.com/search?q=hello&page=1" (lang ignorado)

truncate(str, maxLen, suffix?)

Trunca uma string até um comprimento máximo com um sufixo opcional.

truncate("Hello World", 5) // "Hello"
truncate("Hello World", 8, "...") // "Hello..."
truncate(null, 10) // "" (seguro para null)
truncate("Hi", 100) // "Hi" (sem necessidade de truncar)
ParamTipoDescrição
stranyValor a truncar (convertido para string, null retorna "")
maxLennumberComprimento máximo do resultado (incluindo o sufixo)
suffixstringAdicionado quando truncado (padrão: "")
dica

O sufixo é incluído dentro de maxLen: truncate("Hello World", 8, "...") retorna "Hello..." (8 caracteres).

tpl(template, vars)

Interpolação simples de string. Substitui marcadores {key} por valores de um objeto.

tpl("Hello {name}!", {"name": "Alice"}) // "Hello Alice!"
tpl("*{title}*\n{domain}\n{url}", article) // texto formatado do artigo
tpl("{address.city}, {address.country}", contact) // suporte a caminho pontilhado
tpl("Hi {name}", {"name": null}) // "Hi " (null → vazio)
ParamTipoDescrição
templatestringString de template com marcadores {key}
varsobjectObjeto com valores para interpolar

join_present(separator, ...values)

Junta valores com um separador, ignorando valores em branco. Usa as mesmas regras de present(): null, strings vazias/somente espaços e arrays vazios são ignorados. 0 e false são mantidos. Aceita no máximo 5 argumentos no total — o separador mais até 4 valores.

join_present(", ", "Alice", "Bob", "Carol") // "Alice, Bob, Carol"
join_present(" - ", title, null, author) // "Title - Author" (null ignorado)
join_present(" ", "Hello", "", "World") // "Hello World" (vazio ignorado)
join_present(" | ", 0, false, "text") // "0 | false | text" (0/false mantidos)
Substitui concatenação condicional

join_present(" - ", prefix, text) substitui o padrão (present(prefix) ? prefix + " - " : "") + text.

encode_uri(str)

Codifica uma string para URL. Caracteres URI reservados (&, =, ?, /, #) não são escapados, então ela só é adequada para codificar uma URL inteira — não valores individuais de parâmetros de query.

encode_uri("hello world") // "hello%20world"
encode_uri("a&b=c") // "a&b=c" (caracteres reservados preservados)
Construindo query strings

Para adicionar parâmetros de query a uma URL com segurança, use url_params() — ela codifica cada valor de parâmetro para você.

format_currency(currency, locale, amount)

Formata um número como moeda. Os três argumentos são obrigatórios, nesta ordem: código da moeda, locale e, por fim, o valor.

format_currency("USD", "en-US", 1234.5) // "$1,234.50"
format_currency("BRL", "pt-BR", 99.9) // "R$ 99,90"

Operadores

OperadorO que fazExemplo
!NÃO lógico!step_ok(0)
&&E lógico, com curto-circuitostep_ok(0) && present(step_data(0, "id"))
||OU lógico, com curto-circuitoblank(contact.name) || contact.name == "-"
==, !=Igualdade e desigualdadestep_data(0, "status") == "open"
<, <=, >, >=Comparaçãosize(step_data(0, "items")) > 0
+Soma. Também junta duas strings, concatena duas listas e soma uma duração a um timestamp[1, 2] + [3][1, 2, 3]
-, *, /, %Subtração, multiplicação, divisão, resto(total - paid) % 2 == 0
inPertencimento: este elemento está na lista, ou esta chave está no mapa?"vip" in contact.tagstrue

in é o que mais passa despercebido. Ele evita um laço inteiro quando você só precisa saber se um valor está presente, e combina com o map abaixo:

"open" in step_data(0, "items").map(r, r.status)

Listas e macros

As macros executam uma expressão sobre cada elemento de uma lista. Elas são escritas no estilo receptor — a lista primeiro — e o primeiro argumento dá nome à variável do laço, que existe apenas dentro daquela macro.

MacroO que fazExemplo
list.all(x, pred)Verdadeiro quando todos os elementos correspondem. Verdadeiro para uma lista vaziarows.all(x, x.total > 0)
list.exists(x, pred)Verdadeiro quando ao menos um elemento corresponde. Falso para uma lista vaziarows.exists(x, x.status == "open")
list.exists_one(x, pred)Verdadeiro quando exatamente um elemento corresponderows.exists_one(x, x.primary)
list.map(x, expr)Uma nova lista, com expr aplicada a cada elementorows.map(x, x.email)
list.map(x, pred, expr)O mesmo, mas apenas sobre os elementos que correspondem a predrows.map(x, x.status == "open", x.id)
list.filter(x, pred)Uma nova lista contendo apenas os elementos correspondentesrows.filter(x, x.status == "open")

Este é o caminho mais curto para "quantas das linhas devolvidas por uma etapa de pesquisa ainda estão abertas" — sem precisar de uma etapa Executar Código:

size(step_data(0, "items").filter(r, r.status == "open"))
step_data(0, "items").map(r, r.status == "open", r.name) // nomes das abertas
step_data(0, "items").all(r, present(r.email)) // toda linha é utilizável?

Conversão de tipos

FunçãoO que fazExemplo
int(v)Para número inteiro. Trunca um decimal em direção a zero; um timestamp vira segundos de época, e uma duração vira segundos inteirosint("42")42, int(4.9)4
uint(v)Para número inteiro sem sinal. Volta como um valor encapsulado, e não como um número simples — veja abaixouint("42")
double(v)Para número decimaldouble("3.14")3.14
bool(v)Para booleano, a partir de "true", "false", "1" ou "0"bool("true")true
bytes(v)Uma string para bytes brutosbytes("hi")
string(v)Qualquer coisa para sua forma textual. Um timestamp vira uma string ISO 8601, e uma duração vira segundos com um sstring(123)"123"
timestamp(v)Uma string ISO 8601 completa, ou milissegundos de época, para um timestamptimestamp("2024-01-15T00:00:00Z")
duration(v)Uma string de duração — "90m", "1h30m", "3600s" — para uma duraçãoduration("48h")
type(v)O tipo de um valortype(1)
dyn(v)Passa um valor adiante, como tipo dinâmicodyn(v)

Cinco coisas para saber antes de colocar uma destas em um campo:

  • Uma conversão que não pode dar certo não apenas volta vazia — ela leva a expressão inteira junto, e nenhuma proteção consegue capturar isso. int("abc"), bool("yes"), uint("abc"), duration("abc") e timestamp("2024-01-15") (sem a parte de hora) não produzem nada, e tudo o que for construído em volta delas também não: int("abc") > 5 fica vazio em vez de false, "n=" + string(int("abc")) fica vazio em vez de "n=", e present, blank, coalesce e ? : também ficam vazios — present(int("abc")) não é false e coalesce(int("abc"), 0) não é 0. Este é o único ponto em que a falha não é igual à de um caminho de etapa inexistente, onde present realmente responde false: uma condição escrita como !present(int(step_data(0, "qty"))) para significar "a quantidade não era um número" nunca dispara. Teste o valor bruto antes de converter, para que a conversão só rode em algo que ela aceita:

    qty.matches("^-?[0-9]+$") ? int(qty) : 0 // 0 quando qty é "abc"
  • double falha de outro jeito, e ainda mais silenciosamente. double("abc") é NaN: present o considera presente, blank o considera não vazio, string() o renderiza como "NaN", e toda comparação com ele é false — tanto double("abc") > 5 quanto double("abc") <= 5. A proteção com matches acima também resolve aqui.

  • uint() devolve um valor encapsulado, e não um número. uint("42") compara corretamente (uint("42") == 42 é true), mas não faz aritmética — uint("42") + 1 fica vazio — e um campo guarda o encapsulamento em vez de 42. Use int() a menos que você precise mesmo do tipo sem sinal, ou desembrulhe: int(uint(v)), string(uint(v)).

  • timestamp e duration não são valores que um campo consegue guardar. Eles são úteis dentro de uma expressão — comparando, somando, alimentando um getter. Para obter algo que um campo possa armazenar, envolva-os: string(timestamp(x) + duration("48h")) é uma string ISO, e int(duration("90m")) é 5400.

  • type() também não sobrevive até um campo, e suas comparações não funcionam aqui. Use present / blank para perguntar se um valor existe, e compare com o próprio valor em vez do tipo dele.


String

CEL inclui funções de string integradas. A maioria funciona tanto no estilo receptor quanto no estilo função:

"hello".contains("ell") // true (estilo receptor)
contains("hello", "ell") // true (estilo função)
FunçãoDescriçãoExemplo
contains(str, sub)Verifica se a string contém a substring"hello".contains("ell")
startsWith(str, prefix)Verifica prefixo"hello".startsWith("he")
endsWith(str, suffix)Verifica sufixo"hello".endsWith("lo")
matches(str, pattern)Correspondência por expressão regular"abc123".matches("^abc[0-9]+$")true
size(x)Comprimento de uma string, lista ou mapsize("hello")5, size([1, 2, 3])3
split(str, sep)Divide em arraysplit("a,b,c", ",")["a","b","c"]
lowerAscii(str)MinúsculaslowerAscii("HELLO")"hello"
upperAscii(str)MaiúsculasupperAscii("hello")"HELLO"
trim(str)Remove espaçostrim(" hi ")"hi"
substring(str, start, end?)Extrai substringsubstring("hello", 1, 4)"ell"
replace(str, old, new)Substitui ocorrênciasreplace("aab", "a", "x")"xxb"
indexOf(str, sub)Primeiro índice da substringindexOf("hello", "l")2
lastIndexOf(str, sub)Último índice da substringlastIndexOf("hello", "l")3
charAt(str, index)Caractere no índicecharAt("hello", 0)"h"
join(list, sep?)Junta array em stringjoin(["a","b"], ",")"a,b"
format(str, args)Preenche os marcadores %s / %d a partir de uma lista"%d open".format([2])"2 open"
strings.quote(str)Envolve em aspas e escapa o conteúdostrings.quote("a b")"\"a b\""

Math

FunçãoDescriçãoExemplo
math_add(a, b)Adiçãomath_add(5, 3)8
math_subtract(a, b)Subtraçãomath_subtract(10, 3)7
math_multiply(a, b)Multiplicaçãomath_multiply(4, 3)12
math_divide(a, b)Divisãomath_divide(10, 3)3.333...
math_round(n, decimals?)Arredondamentomath_round(3.456, 2)3.46
math_floor(n)Pisomath_floor(3.7)3
math_ceil(n)Tetomath_ceil(3.1)4
math_abs(n)Valor absolutomath_abs(-5)5
math_pow(base, exp)Potênciamath_pow(2, 3)8
math_sqrt(n)Raiz quadradamath_sqrt(16)4
math_sin(n)Seno (radianos)math_sin(0)0
math_cos(n)Cosseno (radianos)math_cos(0)1
math_tan(n)Tangente (radianos)math_tan(0)0
math_log(n, base?)Logaritmo (natural por padrão)math_log(8, 2)3
math_exp(n)e elevado à potência nmath_exp(0)1
math_max(arr)Máximomath_max([1,5,3])5
math_min(arr)Mínimomath_min([1,5,3])1
math_mean(arr)Médiamath_mean([1,2,3])2
math_median(arr)Medianamath_median([1,2,10])2
math_std(arr)Desvio padrão (amostral)math_std([2,4,6])2
math_variance(arr)Variância (amostral)math_variance([2,4,6])4
math_dot(a, b)Produto escalar de dois vetoresmath_dot([1,2,3], [4,5,6])32
math_norm(arr)Norma euclidiana (comprimento do vetor)math_norm([3,4])5
math_clamp(val, min, max)Restringe ao intervalomath_clamp(15, 0, 10)10
math_evaluate(expr)Avalia uma string de expressão matemáticamath_evaluate("2 + 3 * 4")14

math_clamp(val, min, max)

Restringe um número dentro de um intervalo.

math_clamp(page, 1, 100) // garante que page está entre 1 e 100
math_clamp(-5, 0, 10) // 0 (abaixo do mínimo)
math_clamp(15, 0, 10) // 10 (acima do máximo)

DateTime

FunçãoDescrição
now(tz?)Data/hora atual como uma string ISO 8601 (sempre expressa em UTC)
format_datetime(d, fmt, tz?, locale?)Formata uma data/hora. Aceita qualquer string de formato do dayjs — ex.: "DD/MM/YYYY", "YYYY-MM-DD HH:mm:ss", "HH:mm" — mais um fuso horário e locale opcionais ("en", "pt-BR", "es")
add_datetime(d, n, unit)Adiciona tempo. Unidades: "years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds"
diff_datetime(d1, d2, unit)Diferença entre duas datas/horas
zoned_datetime(dateStr, timeStr, tz, format?)Constrói uma data/hora com fuso horário a partir de strings separadas de data e hora, ex.: zoned_datetime("2024-01-15", "14:30", "America/Sao_Paulo"). Para converter ou exibir uma data/hora já existente, use format_datetime
is_before(d1, d2)d1 antes de d2?
is_after(d1, d2)d1 depois de d2?
is_between(d, start, end)d entre start e end?
is_same_date(d1, d2, unit?, tz?)d1 e d2 iguais na unidade dada? (unidade padrão: "millisecond") — ex.: is_same_date(a, b, "day") verifica o mesmo dia do calendário
is_same_or_before(d1, d2, unit?, tz?)d1 igual ou anterior a d2?
is_same_or_after(d1, d2, unit?, tz?)d1 igual ou posterior a d2?

Getters de timestamp e duração

Estes leem uma parte de um timestamp ou de uma duration. Funcionam tanto no estilo receptor — timestamp(x).getFullYear() — quanto no estilo função — getFullYear(timestamp(x)) — e todo getter de timestamp aceita um fuso horário IANA opcional como último argumento. Sem ele, leem o valor em UTC.

GetterEm um timestampEm uma duração
getFullYear(t, tz?)Ano com quatro dígitos
getMonth(t, tz?)Mês, 0–11 — janeiro é 0
getDate(t, tz?)Dia do mês, 1–31
getDayOfMonth(t, tz?)Dia do mês, começando em 0 — o dia 15 é 14
getDayOfWeek(t, tz?)Dia da semana, 06, domingo é 0
getDayOfYear(t, tz?)Dia do ano, começando em 0 — 1º de janeiro é 0
getHours(v, tz?)Hora, 0–23Horas inteiras na duração
getMinutes(v, tz?)Minuto, 0–59Minutos totaisduration("1h30m")90, não 30
getSeconds(v, tz?)Segundo, 0–59Segundos totais
getMilliseconds(v, tz?)Milissegundo, 0–999A parte abaixo de um segundo, ou seja 0 para qualquer duração em segundos inteiros
timestamp(step_data(0, "createdAt")).getDayOfWeek("America/Sao_Paulo") == 0 // caiu num domingo, hora local
getMonth(timestamp(now())) + 1 // mês como 1-12

Dois destes são fáceis de errar: getDate conta a partir de 1 enquanto getDayOfMonth conta a partir de 0, e getMonth conta a partir de 0. Quando você quer uma data para mostrar a alguém, e não um número para comparar, format_datetime acima é a ferramenta melhor.


JSON

FunçãoDescrição
json_parse(str)Converte string JSON em objeto
json_stringify(obj)Serializa objeto em string JSON

TOON

TOON é um formato de serialização de dados compacto e legível por humanos.

FunçãoDescrição
toon_encode(value)Codifica um valor em uma string TOON
toon_decode(str)Faz o parse de uma string TOON de volta em um valor
toon_encode({"name": "Alice", "age": 30}) // "name: Alice\nage: 30"
toon_decode("name: Alice\nage: 30") // {"name": "Alice", "age": 30}

BSON / ObjectId

FunçãoDescrição
object_id(value?)Cria ou normaliza uma instância de ObjectId (uma nova se não houver argumento). Use object_id_to_string() para obter a string hexadecimal
object_id_is_valid(id)Verifica se a string é um ObjectId válido
object_id_to_string(id)Converte um ObjectId em sua string hexadecimal
bson_serialize(value, encoding?)Serializa um valor em bytes BSON, retornados como uma string base64 (padrão) ou "hex"
bson_deserialize(str, encoding?)Decodifica uma string BSON base64 (padrão) ou "hex" de volta em um valor
ejson_stringify(value, relaxed?)Serializa um valor em uma string Extended JSON do MongoDB (modo relaxado por padrão)
ejson_parse(str, relaxed?)Faz o parse de uma string Extended JSON do MongoDB em um 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 funções estão disponíveis apenas em expressões de workflow e agentes (não em CEL de formulários).

step(N)

Acessa a saída do passo N do workflow (indexado a partir de 0).

step(0) // objeto completo de saída do passo
step(0).data // payload de dados do passo
step(0).status // código de status HTTP (para passos HTTP)

step_ok(N)

Verifica se o passo N foi concluído com sucesso. Retorna true quando executionContext.status é "completed" E o status HTTP é 200 (ou null para passos não-HTTP).

// Antes: verboso
get(step(0), "executionContext.status") == "completed" && (get(step(0), "status") == null || get(step(0), "status") == 200)

// Depois: uma chamada de função
step_ok(0)

step_data(N, path?, default?)

Obtém dados do passo N em um caminho pontilhado opcional. Retorna o padrão (ou null) se ausente.

O caminho é relativo ao data do passostep_data(0, "title")step(0).data.title. Não repita data no caminho: step_data(0, "data.title") procura step(0).data.data.title, erra em silêncio e devolve o valor padrão — indistinguível do campo estar vazio. (step_data(0, "data.x") só está correto quando o corpo da resposta tem, ele próprio, uma chave data no topo, como em respostas JSON:API.)

// Antes
get(step(0), "data.title", null)

// Depois
step_data(0, "title")
step_data(0, "results.0.name", "Unknown")
step_data(1, "choices.0.message.content")

Ações que publicam na raiz da etapa

A maioria das ações coloca sua saída sob data, e é por isso que o caminho é relativo a ele. Vinte não fazem isso — elas declaram suas saídas na raiz da etapa e não têm objeto data nenhum. Esse não é um caso raro: actions/ai/llm/chat/generate está na lista, e o choices dela é a saída de etapa que os workflows mais percorrem.

AçãoSaídas na raiz
actions/ai/agent/sendmessages
actions/ai/llm/chat/generatechoices
actions/agent/lifecycle/session/set_reply_delayreplyDelayMs
actions/ai/text/speakabletext, model
actions/data/company/resource/countcount
actions/mcp/connecturl, toolCount
actions/mcp/connect/autotalk-mcpurl, toolCount
actions/media/audio/synthesizefile, bucket, fullPath, size, contentType, format, cache, billedMeter, billedMs
actions/media/audio/transcribejobId, jobStatus, enginePath, providerType, diarized
actions/media/document/generatefile, bucket, fullPath, fileName, size, contentType, format
actions/media/readtext, supported, truncated, reason, mediaKind, mimeType, fileName, size
actions/media/storage/deletedeleted, existed, bucket, fullPath
actions/media/storage/probedurationSeconds, width, height, formatName, videoCodec, audioCodec, hasAudio, sizeBytes, contentType, cached
actions/media/storage/signed-urlsignedUrl, contentType, size, mediaKind, bucket, fullPath, name, expiresAt
actions/media/storage/uploadfile, signedUrl, contentType, size
actions/media/transformjobId, jobStatus, preset
actions/monitors/cancelmonitorId, monitorState
actions/monitors/createmonitorId, monitorState, expiresAtIso
actions/network/http/download-to-storagestatus, file, signedUrl, contentType, size
actions/security/auth/jwt/generatejwt

Leia essas saídas com 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 também resolve contra a raiz nesses casos — uma etapa que não tem nem data nem result recai sobre o próprio objeto da etapa — então step_data(0, "count") também funciona. Esse fallback é deliberadamente estreito e não se aplica a uma etapa que de fato tem data: em actions/network/http/request/send, step_data(N, "status") continua devolvendo o seu valor padrão em vez do código de status HTTP, porque status é irmão de data na raiz, e não um campo dentro dele. (Na actions/network/http/download-to-storage, que é da forma raiz, status é uma saída da etapa, então step_data(N, "status") devolve o valor — a regra é a mesma, o formato da ação é que é diferente.) Chaves que pertencem ao envelope de execução (executionContext, actionContext, safeError, safeResult, conditionPassed, aclInfo) nunca são alcançáveis por step_data em nenhuma etapa.

Existe um terceiro formato, e exatamente uma ação está nele hoje. Executar Código publica seu valor de retorno como um result no topo e não tem data, então step_data e step_has_content resolvem dentro daquele valor: step_data(0, "count")step(0).result.count, que normalmente é o que você quer. Os irmãos dele na raiz da etapa — files, logs, executionTimeMsnão são alcançáveis por esse caminho e precisam ser lidos com get(step(N), "files"). Isso vale mesmo quando o código não retornou nada, porque aí result é null, o que já basta para tomar esse ramo. É por isso que a tabela acima não tem uma linha para actions/code/execute: ele não tem nem o formato data nem o formato de raiz.

Seja qual for a forma que você use, um caminho que não existe devolve o valor padrão em silênciostep_ok(N) continua true. Nunca confie em uma lista lembrada de cor: verifique as saídas declaradas da ação (get_action_definition(actionType), cuja dica STEP OUTPUTS é derivada dessas saídas, ou a referência da ação) antes de escrever o caminho.

step_error(N)

Obtém informações de erro de um passo que falhou. Retorna {code, user_message, retryable} ou null.

// Antes
coalesce(get(step(0), "executionContext.safeError.code"), "UNKNOWN")

// Depois
step_error(0) // {code: "TIMEOUT", user_message: "...", retryable: true}
get(step_error(0), "code", "UNKNOWN") // "TIMEOUT"

step_has_content(N, path)

Verifica se o passo N foi concluído com sucesso E possui dados presentes (não-null, não-vazio) no caminho dado. Combina step_ok(N) && present(step_data(N, path)) em uma única chamada.

// Antes: duas verificações
step_ok(0) && present(step_data(0, "articles"))

// Depois: uma chamada de função
step_has_content(0, "articles")

O caminho segue exatamente a mesma regra de step_data: relativo a data ou — nas ações que publicam na raiz — relativo à raiz da etapa.

getContext()

Obtém o objeto de contexto de execução do workflow.

getTool()

Obtém o objeto de contexto da ferramenta em execução no momento — o mesmo contexto que os auxiliares step(N) leem. Não recebe argumentos; quaisquer argumentos passados são ignorados.

getRoot()

Obtém o contexto raiz do workflow.