Function

O bloco Function executa seu próprio código JavaScript, Python ou Shell como uma etapa do workflow. Use-o para remodelar um valor, fazer um cálculo, chamar uma CLI ou adicionar uma lógica que nenhum outro block cobre.

Configuração

Código

JavaScript é o padrão. O campo de linguagem faz parte do workflow salvo e nunca é removido quando a configuração do Sandbox muda. Python continua disponível como opção de linguagem; Shell e os controles de Sandbox personalizado aparecem quando um provedor remoto de sandbox de Function está habilitado. Referencie uma saída anterior diretamente, sem aspas em volta da tag, e leia uma variável de ambiente com {{VAR}}:

const data = <api.data>;
return data.items.filter((i) => i.active).map((i) => i.id);
data = <api.data>
__studio_result__ = [item["id"] for item in data["items"] if item["active"]]
set -euo pipefail
active_ids=$(printf '%s' <api.data> | jq -c '[.items[] | select(.active) | .id]')
printf '__STUDIO_RESULT__=%s\n' "$active_ids"

Em JavaScript, retorne um valor com return. Python é executado como um módulo normal: atribua a __studio_result__ o valor que os blocks seguintes vão consumir. Um script completo com funções, imports e uma guarda if __name__ == '__main__': funciona como está escrito; snippets antigos com um return de nível superior continuam suportados. print() é log e vai para o stdout em vez de se tornar o resultado.

O Shell retorna dados estruturados imprimindo uma linha que começa com __STUDIO_RESULT__=. Um payload JSON válido se torna um objeto, array, número, booleano ou string; um payload que não é JSON se torna uma string. A linha do marcador é removida do stdout. As outras saídas do comando continuam disponíveis no stdout.

Placeholders de segredos no código

Quando uma variável de ambiente é a expressão JavaScript ou Python completa, prefira a forma sem aspas:

const apiKey = {{API_KEY}};

As formas existentes com aspas e embutidas também são suportadas, incluindo "{{API_KEY}}", "Bearer {{API_KEY}}" e placeholders em template literals. O código de Function e de Custom Tool usa o mesmo compilador no limite de execução. Ele vincula o segredo separadamente do fonte, em vez de colar o texto puro no seu código, então aspas, barras invertidas, quebras de linha e valores string como "123" e "true" preservam seu conteúdo exato e não se tornam literais JavaScript ou Python de outro tipo.

Placeholders são sempre strings

Um placeholder é vinculado como valor, nunca interpretado como código-fonte. É isso que impede um segredo de ser executado como código — mas também significa que {{KEY}} sempre resulta em uma string, não importa a aparência do valor. Converta-o quando seu código precisar de outro tipo:

const retries = Number({{MAX_RETRIES}});
const enabled = {{FEATURE_ON}} === 'true';
const patterns = JSON.parse({{PATTERN_LIST}});

Em Python, use int(), == "true" e json.loads() da mesma forma.

Dois casos passam batido com facilidade:

  • Booleanos. Um if ({{FEATURE_ON}}) puro é sempre verdadeiro, porque a string "false" é truthy. Compare com 'true' em vez disso.
  • Listas e objetos. Guarde o valor como JSON para poder desserializá-lo depois. ["^[A-Z]{2}-\\d{4}$", "^\\d{7,15}$"] se torna um array; um array JavaScript de literais de regex não. Ele chega como uma única string longa, e iterar sobre ela percorre caractere por caractere.

Os blocks Condition diferem em um ponto: lá, um valor numérico, booleano ou null é comparado como literal, então {{MAX_RETRIES}} === 3 é verdadeiro. Todos os outros valores são strings, exatamente como aqui.

Literais de regex em JavaScript podem conter um placeholder:

const matcher = /^{{PATH_PATTERN}}$/i;

O valor é interpretado como texto bruto de padrão regex e as flags do literal são preservadas. Se você precisa que o valor seja comparado literalmente, e não como padrão, escape os metacaracteres de regex antes de construir a expressão.

No Shell, use a mesma sintaxe {{KEY}} e escreva "{{KEY}}" quando o valor deve permanecer um único argumento escalar. Placeholders sem aspas continuam suportados para workflows existentes e mantêm o comportamento nativo do Bash sem aspas, incluindo divisão em palavras e semântica de padrão regex. Placeholders também funcionam dentro de heredocs com delimitador entre aspas, sem habilitar expansões de shell não relacionadas:

cat > /tmp/request.txt <<'REQUEST'
Authorization: Bearer {{API_KEY}}
Home remains literal: $HOME
REQUEST

O Studio fornece o heredoc renderizado de forma privada, preservando o comportamento literal de $VAR, backticks e substituição de comando do delimitador entre aspas.

Saídas

SaídaO que é
<function.result>O valor que seu código retorna (objeto, array, string, número, …)
<function.stdout>Tudo que foi impresso com console.log() ou print()

Linguagem

JavaScript sem imports é executado em um sandbox local rápido. JavaScript com import ou require, Python e Shell são executados no provedor de sandbox remoto configurado.

JavaScriptPythonShell
ExecuçãoLocal quando não há imports; remota com importsSempre remotaSempre remota
Retornar um valorreturn { … }Atribuir __studio_result__ = { … }Imprimir __STUDIO_RESULT__={…}
Requisições HTTPfetch() embutidorequests ou httpxcurl ou uma CLI instalada
Melhor paratransformações rápidas e JSONscripts, ciência de dados, gráficos, matemática complexafluxos com CLI e utilitários de sistema

Python e Shell exigem um sandbox remoto. Eles vêm habilitados por padrão no agent-studio.seeyu.ai; em uma instância auto-hospedada, construa e configure primeiro a base de Function dedicada do provedor. Qualquer figura que você gerar em Python é capturada como imagem automaticamente.

Se nenhum provedor remoto estiver configurado, JavaScript sem import ou require continua a ser executado na VM isolada local do Studio. A falta de configuração de E2B ou Daytona não desabilita esse caminho. Código exclusivamente remoto falha com um erro de configuração explícito; o Studio não reinterpreta Python ou Shell como JavaScript.

A base de Function dedicada tem o mesmo runtime e o mesmo contrato universal de pacotes no E2B e no Daytona. Ela inclui esta stack de ciência de dados; use um sandbox do workspace quando outra dependência precisar estar presente:

  • Dados e gráficos: pandas, numpy, scipy, xarray, numba, networkx
  • ML e NLP: scikit-learn, gensim, nltk, spacy, textblob
  • Plots e imagens: matplotlib, seaborn, plotly, bokeh, kaleido, pillow, opencv-python, scikit-image, imageio, tifffile
  • Áudio: librosa, soundfile
  • Web, parsing e arquivos: requests, beautifulsoup4, lxml, openpyxl, xlrd, python-docx, xmltodict, PyYAML, tomlkit, simplejson, orjson, SQLAlchemy
  • Matemática: sympy
  • Auxiliares de aplicação: rich, typer, click, tqdm, Jinja2, pydantic, python-dateutil, pytz, psutil, filetype, python-slugify, parsedatetime, pytimeparse
  • CLIs genéricas: jq, yq, csvkit, zx, xmlstarlet, httpie, ripgrep, fd, bat, sqlite3, tar, gzip, bzip2, ZIP/XZ/7z, ferramentas de mídia/imagem e utilitários de rede padrão

CLIs de fornecedores e serviços, como AWS CLI e GitHub CLI, não fazem parte da base universal. Adicione-as pelo catálogo gerenciado. Clientes de banco de dados como PostgreSQL, MySQL e Redis podem ser adicionados como pacotes de sistema quando estiverem disponíveis nos repositórios Debian configurados.

Sandboxes

Um sandbox é um ambiente nomeado que seu workspace mantém: uma linguagem, uma lista de dependências pip ou npm, pacotes de sistema Debian/APT opcionais e ferramentas de CLI gerenciadas opcionais. Selecione um em um block Function e o código dele pode importar as dependências e executar os comandos que declara. Deixe a seleção vazia para usar a base de Function dedicada.

Crie e edite sandboxes em Settings → Sandboxes. Só administradores do workspace podem criar ou editar sandboxes. No agent-studio.seeyu.ai eles exigem um plano Max ou Enterprise ativo; implantações auto-hospedadas os habilitam com SANDBOXES_ENABLED (veja enterprise auto-hospedado). A seção só fica utilizável quando a implantação também tem um provedor remoto e uma base de Function imutável configurados. O block Function esconde seu seletor de Sandbox personalizado quando esse runtime está indisponível.

  1. Nomeie o sandbox — bigquery-etl, scraping, o que descrever o trabalho.
  2. Escolha a linguagem. Isso define se a lista de dependências usa pip ou npm. Blocks Python e JavaScript listam os sandboxes correspondentes; Shell pode usar qualquer um dos dois tipos.
  3. Cole suas dependências, uma por linha. Fixar versões é opcional.
  4. Adicione pacotes de sistema pela coordenada do pacote Debian/APT, um por linha. Use isso para utilitários de linha de comando comuns, como jq e ffmpeg.
  5. Selecione as ferramentas de CLI gerenciadas que exigem um instalador especializado e verificado. O catálogo pesquisável é agrupado por nuvem, Kubernetes, infraestrutura, deploy, dados e armazenamento, e segurança. Cada entrada usa um artefato do fornecedor fixado e com integridade verificada.

Dependências:

google-cloud-bigquery==3.25.0
pyairtable>=3.0
pandas

Pacotes de sistema:

shellcheck
pandoc
graphviz

Depois abra as opções avançadas do block e escolha o sandbox em Sandbox.

O comportamento padrão e o personalizado são deliberadamente explícitos:

  • JavaScript sem imports permanece no runtime isolado local, por velocidade, e ignora a seleção de sandbox.
  • JavaScript com import ou require é executado remotamente. Sem seleção, usa a base de Function; com um sandbox, recebe os pacotes npm, os pacotes de sistema e as ferramentas de CLI gerenciadas daquele sandbox.
  • Python e Shell sempre são executados remotamente. Sem seleção, recebem apenas a base de Function; com um sandbox, recebem suas dependências, pacotes de sistema e ferramentas de CLI gerenciadas.

Na próxima vez que um block Function carregar suas opções de sandbox, uma consulta bem-sucedida que confirme que o sandbox selecionado foi excluído limpa essa seleção. Falhas de busca ou de autenticação deixam o workflow inalterado.

Dois sandboxes com a mesma linguagem, a mesma lista de dependências, os mesmos pacotes de sistema e as mesmas ferramentas de CLI gerenciadas compartilham um único build, então duplicar um conjunto não custa nada. Editar qualquer parte dessa especificação de instalação inicia um novo build. Execuções já em andamento continuam usando o build antigo. Excluir um sandbox libera seu build quando nada mais o usa.

Status do build

No agent-studio.seeyu.ai, cada especificação de sandbox é pré-construída em uma imagem reutilizável, então as execuções não pagam custo de instalação. A linha de status em Settings mostra Queued, Building, Ready ou Failed. Um build que falha informa o que deu errado — um pacote que não existe, uma versão sem correspondência, um conflito do resolvedor — com o log do instalador atrás de um detalhe expansível.

Executar um block antes de o sandbox estar Ready interrompe a execução e mostra o status. Um build que falhou é repetido periodicamente por conta própria. Para tentar imediatamente, abra o menu de três pontos ao final da linha de status com falha e escolha Retry build. Salve ou descarte as edições não salvas do sandbox antes, para que a nova tentativa sempre use a especificação visível.

Em uma implantação auto-hospedada com Daytona, dependências, pacotes de sistema e ferramentas de CLI gerenciadas são instalados dentro do sandbox no início de cada execução, o que adiciona tempo de inicialização por execução. Imagens pré-construídas exigem E2B.

Pacotes de sistema, CLIs gerenciadas e instalações pontuais

Use System packages para CLIs disponíveis nos repositórios Debian/APT do sandbox. As entradas podem incluir uma arquitetura ou uma versão exata, como pacote:arquitetura=versão. Elas são validadas, deduplicadas e instaladas quando o sandbox é construído ou preparado.

O seletor Managed CLI tools cobre CLIs que precisam de mais do que uma instalação APT normal, como um arquivo fixado do fornecedor, configuração de PATH ou verificação de comando. CLIs de serviços e fornecedores são deliberadamente deixadas fora da base universal de Function. Por exemplo, depois de adicionar Google Cloud CLI a um sandbox, uma Function Shell pode executar bq diretamente:

set -euo pipefail
bq query --use_legacy_sql=false --format=json 'SELECT CURRENT_DATE() AS today'

Para um comando necessário apenas uma vez, instale-o no início do script Shell. O sandbox remoto é efêmero, então a instalação vale só para aquela chamada da Function e soma ao tempo de execução dela:

set -euo pipefail
python -m pip install --quiet csvkit
csvcut -n /tmp/input.csv

Use um sandbox personalizado quando reprodutibilidade ou tempo de inicialização importarem. Coloque utilitários Debian comuns em System packages; use o seletor gerenciado apenas quando precisar de um de seus instaladores especializados. Comandos de instalação arbitrários não são salvos na especificação de um sandbox.

O que é permitido

Os campos de dependências aceitam apenas nomes de pacotes e especificadores de versão. URLs, referências git+, -e, caminhos locais, --index-url e aliases npm são rejeitados, com o número da linha problemática informado.

Pacotes de sistema usam coordenadas Debian no formato pacote[:arquitetura][=versão]. Flags, URLs, caminhos, espaços em branco, globs e sintaxe de shell são rejeitados. Um sandbox pode declarar até 50 dependências, 50 pacotes de sistema e 10 ferramentas de CLI gerenciadas.

Limitar segredos para ferramentas de agente

Quando um block Function é usado como ferramenta de um Agent, seu código pode ler todos os segredos do workspace por padrão — tanto {{MY_SECRET}} quanto environmentVariables['MY_SECRET']. Use {{MY_SECRET}} quando o valor puder aparecer nos logs de execução: uma substituição bem-sucedida de chaves duplas ativa o mascaramento do trace de execução, enquanto o acesso direto via environmentVariables['MY_SECRET'] sozinho não ativa.

Para restringir isso, defina Secret access como Selected secrets na configuração de ferramenta do block e escolha os nomes que o código pode ler. Duas coisas mudam:

  • Só esses segredos são injetados. {{OTHER_SECRET}} também deixa de resolver.
  • Os nomes selecionados são adicionados à descrição da ferramenta, para que o modelo saiba o que pode referenciar. Os valores são vinculados apenas no servidor, quando a Function é executada; eles não vão na requisição ao modelo. Se um resultado de Function contiver um valor de segredo exato, o modelo do Agent recebe {{NAME}} no lugar. O resultado bruto em tempo de execução e os efeitos colaterais locais não são reescritos.

Manter o padrão (All secrets) resolve a lista no momento da execução, então um segredo adicionado no mês que vem é incluído automaticamente.

Exemplos

Remodelar a resposta de uma API

A Function lê <api.data>, retorna apenas o campo de que o resto do workflow precisa e o expõe como <extract.result>.

Validar a entrada antes de gravar

A Function sanitiza a entrada do formulário e retorna o valor limpo, que o block API envia como corpo da requisição.

Um exemplo prático: pontuação de fidelidade

loyalty-calculator.js
const { purchaseHistory, accountAge, supportTickets } = <agent>;

const totalSpent = purchaseHistory.reduce((sum, p) => sum + p.amount, 0);
const purchaseFrequency = purchaseHistory.length / (accountAge / 365);
const ticketRatio = supportTickets.resolved / supportTickets.total;

const spendScore = Math.min((totalSpent / 1000) * 30, 30);
const frequencyScore = Math.min(purchaseFrequency * 20, 40);
const supportScore = ticketRatio * 30;
const loyaltyScore = Math.round(spendScore + frequencyScore + supportScore);

return {
  customer: <agent.name>,
  loyaltyScore,
  loyaltyTier: loyaltyScore >= 80 ? 'Platinum' : loyaltyScore >= 60 ? 'Gold' : 'Silver',
};
loyalty-calculator.py
def calculate_loyalty(data):
    purchase_history = data["purchaseHistory"]
    account_age = data["accountAge"]
    support_tickets = data["supportTickets"]

    total_spent = sum(p["amount"] for p in purchase_history)
    purchase_frequency = len(purchase_history) / (account_age / 365)
    ticket_ratio = support_tickets["resolved"] / support_tickets["total"]

    spend_score = min(total_spent / 1000 * 30, 30)
    frequency_score = min(purchase_frequency * 20, 40)
    support_score = ticket_ratio * 30
    loyalty_score = round(spend_score + frequency_score + support_score)
    tier = "Platinum" if loyalty_score >= 80 else "Gold" if loyalty_score >= 60 else "Silver"

    return {
        "customer": data["name"],
        "loyaltyScore": loyalty_score,
        "loyaltyTier": tier,
    }


if __name__ == "__main__":
    __studio_result__ = calculate_loyalty(<agent>)

Entradas grandes

O Studio entrega ao block Function seu código, seus parâmetros e suas referências resolvidas em uma única requisição, então valores muito grandes são mantidos por referência em vez de embutidos.

Prefira uma referência estreita a um valor grande inteiro: use <api.data.id> em vez de <api.data>. Se uma função JavaScript sem imports realmente referenciar um valor grande inteiro, o Studio a reescreve automaticamente para uma leitura lazy no servidor.

Arquivos vêm primeiro como metadados: ler <file.name> ou <file.url> não carrega o conteúdo do arquivo. Leia o conteúdo sob demanda com os auxiliares studio.files (somente em JavaScript sem imports):

const file = <readfile.file>;
const text = await studio.files.readText(file);
const chunk = await studio.files.readTextChunk(file, { offset: 0, length: 1024 * 1024 });
const bytes = await studio.files.readBase64Chunk(file, { offset: 0, length: 1024 * 1024 });

studio.files.readText, readBase64 e as variantes …Chunk fazem streaming a partir do armazenamento de execução, respeitando limites de memória. studio.values.read(ref) e studio.values.readArray(ref) leem referências de valores e arrays grandes. O offset e o length dos chunks são baseados em bytes, então para parsing exato de Unicode prefira referências estruturadas menores. Para grandes volumes de dados gerados, escreva o resultado em um arquivo ou tabela com outputPath, outputSandboxPath ou outputTable em vez de retornar o payload inteiro embutido.

Os auxiliares lazy studio.files e studio.values estão disponíveis apenas em funções JavaScript sem imports. JavaScript com imports, Python e Shell ainda não os suportam.

Boas práticas

  • Mantenha cada função focada. Uma transformação por block é mais fácil de ler, testar e depurar.
  • Trate os erros. Envolva código arriscado em try/catch e retorne uma mensagem clara, ou deixe a exceção seguir para o caminho de erro.
  • Referencie apenas o que você precisa. Puxe um campo estreito em vez de um objeto grande inteiro, para manter os valores fora do corpo da requisição.
  • Use o stdout para depurar. console.log(), print() e a saída comum do shell chegam a <function.stdout> e aos logs da execução.

Common Questions

JavaScript, Python e Shell. JavaScript é o padrão. Python continua sendo uma opção de linguagem estável e salva; Shell e os controles de Sandbox personalizado aparecem quando um provedor remoto de sandbox está habilitado. A execução de Python e Shell exige esse provedor.
JavaScript sem imports externos é executado em um sandbox isolado local, por velocidade. JavaScript que usa import ou require, Python e Shell são executados no sandbox remoto configurado.
Sim. JavaScript sem import ou require é executado na VM isolada local do Studio e não exige um provedor remoto. JavaScript com imports externos, Python, Shell e Sandboxes personalizados exigem E2B ou Daytona e falham explicitamente quando isso não está disponível.
Use a sintaxe de sinais de menor e maior diretamente, como <agent.content> ou <api.data>, sem aspas em volta da tag — o Studio a substitui pelo valor real antes da execução. Para variáveis de ambiente, use chaves duplas: {{API_KEY}}.
Duas saídas: result e stdout. Use return em JavaScript, atribua __studio_result__ em Python ou imprima um marcador __STUDIO_RESULT__= em Shell para definir result. A saída comum de console, print e comandos vai para stdout.
Sim. fetch() está disponível em JavaScript com async/await. Em Python, use requests ou httpx. Em Shell, use curl ou uma CLI disponível no sandbox selecionado.
Sim, um tempo limite de execução configurável. Se seu código o exceder, a execução é encerrada e o block reporta um erro. Tenha isso em mente em chamadas externas ou processamento pesado.