Functions

Tu agente no es un formulario.Es un archivo de tu repo.

Declara el agente y las herramientas que puede llamar en TypeScript. Despliega el directorio. Zavu lo construye, guarda los secretos, lo ejecuta con tus eventos o en horario, y reconcilia el agente en vivo con lo que dice el archivo.

Runtime
nodejs24
Se fija en el primer deploy y se mantiene, así ningún deploy posterior lo mueve por debajo.
Timeout
1–180 s
Por defecto 30. Qué techo manda depende del trigger.
Memoria
128 · 256 · 512 · 1024
MB por invocación. La mayoría de los handlers cabe en el más pequeño.
Código
200 archivos · 900.000 bytes
Los paquetes npm se declaran, no se suben.

01 — Escríbelo

Un directorio, un entrypoint y lo que importe.

El deploy arranca en el entrypoint y sigue los imports relativos. Lo que alcanza se sube; lo que nadie importa se queda en tu máquina.

Qué se sube de verdad

Elige un archivo. El panel dice si viaja con el deploy, y por qué.

order-bot/
Archivos subidos4 / 200
Bytes subidos1,355 / 900,000
index.tsEntrypoint
import { defineAgent, defineTool } from "@zavudev/functions"
import { formatOrder, lookupOrder } from "./lib/orders"
import { HOST_PROMPT } from "./prompts/host"

defineAgent({
  senderId: process.env.SENDER_ID!,
  name: "Bella",
  provider: "zavu",
  model: "openai/gpt-4o-mini",
  prompt: HOST_PROMPT,
})

defineTool({
  name: "lookup_order",
  description: "Get current status of an order. Use when the customer asks about one.",
  parameters: {
    type: "object",
    properties: { orderId: { type: "string" } },
    required: ["orderId"],
  },
  handler: async ({ orderId }, ctx) => {
    ctx.log("lookup", orderId)
    return formatOrder(await lookupOrder(orderId))
  },
})

El entrypoint. El deploy lo lee primero y desde aquí recorre sus imports relativos. Por defecto es index.ts — usa entrypoint por REST, o --source en la CLI, para nombrar otro.

Rutas rechazadas

../shared/x.tsnode_modules/package.json

La CLI y la API son la misma superficie.

Usa la que encaje con tu forma de trabajar. Nada de esto existe solo en una de las dos.

index.ts
npx zavudev fn init --name order-bot --template blank
import { defineAgent, defineTool } from "@zavudev/functions"

defineAgent({
  senderId: process.env.SENDER_ID!,
  name: "Bella",
  provider: "zavu",
  model: "openai/gpt-4o-mini",
  prompt: "You are Bella, host at the restaurant. Be brief.",
})

defineTool({
  name: "check_availability",
  description: "Get free reservation slots for a date.",
  parameters: {
    type: "object",
    properties: { date: { type: "string" }, partySize: { type: "number" } },
    required: ["date", "partySize"],
  },
  handler: async ({ date, partySize }) => {
    return { available: true, slots: ["19:00", "21:00"] }
  },
})

02 — Despliégalo

Un deploy es un registro que puedes mirar, y al que puedes volver.

Desplegar responde de inmediato con un id. Tú lo consultas. Cada versión se conserva, con la salida del build que la explica.

Ciclo de vida del deployment

Avanza paso a paso, o déjalo correr. Rompe un import para tomar el otro camino.

  1. supersededen lo que se convierte una versión cuando otra más nueva toma su lugar. Sigue legible, y volver a ella es una sola llamada.

DeploymentGET /v1/functions/deployments/{deploymentId}
{
  "id": "fnd_8c21ab5f",
  "functionId": "fn_4kq2m9x",
  "version": 7,
  "status": "pending",
  "sourceCodeBytes": 18432,
  "bundleBytes": null,
  "errorMessage": null,
  "deployedAt": null,
  "createdAt": "2026-03-14T09:41:12.000Z"
}

Consulta hasta que status sea active o failed. Ambos son terminales.

Rollback

Vuelves atrás nombrando un id de deployment. Su código, sus dependencias y su runtime se copian al draft y se despliegan de nuevo como una versión más, así que el historial solo crece. Los secretos no vuelven atrás: son actuales, no versionados.

$ npx zavudev fn rollback 4

Deploy desde GitHub

Enlaza un repositorio y un push a la rama lo despliega. Cómo se autentica el enlace lo decide el servidor, no tú: con la GitHub App de Zavu instalada, los repos privados funcionan y no hay nada que agregar al repositorio. Sin ella obtienes un enlace manual, y su secreto de webhook se imprime exactamente una vez. Enlazar no verifica el repositorio contra GitHub — un owner/repo que la instalación no puede ver se acepta y falla en el primer deploy.

connection
app o manual — lo elige el servidor
branch
solo los pushes aquí despliegan
rootDir
el subdirectorio, para monorepos
autoDeploy
en false conserva el enlace e ignora los pushes
lastStatus
deploying, deployed o failed
lastError
por qué no aterrizó el último push

03 — Ejecútalo

Con tus eventos, o con el reloj.

Un trigger suscribe la función a un tipo de evento, para un sender o para todos. El tipo especial cron la ejecuta en horario.

Constructor de triggers

Elige tipos de evento y senders. El request y los triggers que crea aparecen a la derecha, y una expresión cron se resuelve a sus próximas ejecuciones en UTC.

Tipos de evento

Senders

Agrega el tipo de evento cron arriba para ejecutar la función en horario en vez de suscribirla a un mensaje. Toma una expresión de cinco campos en UTC, y una función puede tener varias con horarios distintos.

RequestPOST /v1/functions/{functionId}/triggers
{
  "eventTypes": [
    "message.inbound"
  ],
  "senderIds": [
    null
  ]
}
Response201
{
  "added": 1,
  "skipped": 0,
  "triggers": [
    {
      "id": "fnt_0001",
      "eventType": "message.inbound",
      "senderId": null,
      "active": true
    }
  ]
}

Un trigger por tipo de evento × sender. Un trigger cron ignora el eje de senders, así que cuenta una vez sin importar cuántos elijas. Los duplicados vuelven como skipped, no se crean dos veces.

Vale la pena saberlo

El timeout que fijas no siempre es el techo que manda.

  • Ejecuciones por evento y por cron

    Asíncronas. Nadie espera la respuesta, así que un timeout largo solo acota lo que te cuesta una ejecución atascada.

  • Una herramienta en plena conversación

    Síncrona. La respuesta al cliente espera a tu handler, así que mantenlos bien por debajo del límite, no pegados a él.

  • Una función expuesta por HTTP

    Además la acota el tope de respuesta HTTP de la plataforma. Subir timeoutSec no sube ese.

04 — Opéralo

Secretos, logs y un endpoint cuando lo quieras.

01

Los secretos entran y no vuelven

Listarlos devuelve cada clave y los últimos cuatro caracteres de su valor, nunca el valor. Las claves van en mayúsculas estilo variable de entorno, y los prefijos AWS_ y LAMBDA_ están reservados. Definir uno marca la función como desincronizada en vez de reiniciarla por debajo; el siguiente deploy lo aplica.

02

Una API key que no tuviste que cablear

Crear una función aprovisiona una key de Zavu con alcance acotado y la inyecta como ZAVU_API_KEY, así un handler llama de vuelta a la API sin que administres credenciales. Para más alcance, crea tu propia key y ponla como secreto.

03

Logs, filtrados y paginados

Trae los logs de invocación acotados por ventana de tiempo o filtrados por patrón, y págilos con nextToken. La misma salida se sigue en vivo desde la CLI mientras trabajas.

04

Un endpoint HTTPS, con interruptor

Encender la URL pública aplica a la función ya desplegada — sin redeploy. Apagada, la URL guardada deja de servir y ya no se devuelve, así que publicUrl viene en null en vez de quedar obsoleta.

Escríbelo, despliégalo, mira los logs.

Empieza gratis, sin tarjeta. La CLI habla con la misma API que usará tu código.

Functions | Agentes y herramientas en TypeScript — Zavu | Zavu