Skip to main content

Agents

Apps can define AI agents that execute autonomously in response to events, cron schedules, or manual triggers. Agents run in the same sandboxed environment as server routes but are driven by an AI model that can call tools.

Key Concepts

Agents are defined in informer.yaml and deployed alongside the app. Each agent has:

  • Instructions — a system prompt guiding the AI's behavior
  • Tools — app-scoped tools from the tools/ directory
  • Toolkits — external toolkit integrations (e.g., custom toolkits)
  • Assistants — Informer assistants whose instructions are merged into the agent's system prompt
  • Triggers — events, cron schedules, or manual invocation

Runs are individual executions of an agent. Each run tracks status, steps, token usage, and errors.

Events are the primary trigger mechanism. Server route handlers or other agents can emit events via emit(), and agents listening for those events execute automatically.

Agent API Endpoints

GET /api/apps/{id}/agents

List all agents for an app.

Authentication: Required

Permissions Required: Member+ role (write permission)

Response:

[
{
"id": "agent-uuid",
"appId": "app-uuid",
"name": "order-processor",
"description": "Processes new orders and sends confirmations",
"instructions": "You process incoming orders...",
"model": "go_everyday",
"tools": ["send-email", "update-inventory"],
"toolkits": ["admin:crm-toolkit"],
"assistants": ["assistant-uuid"],
"triggers": {
"on": ["order_created"]
},
"status": "active",
"nextRunAt": null,
"createdAt": "2025-03-01T10:00:00.000Z",
"updatedAt": "2025-03-01T10:00:00.000Z"
}
]

GET /api/apps/{id}/agents/{agentId}

Get a single agent's details.

Authentication: Required

Permissions Required: Member+ role (write permission)

Response: Same shape as the array item above, plus instructionsOverride if set.


PUT /api/apps/{id}/agents/{agentId}

Update an agent's runtime settings. Only certain fields can be changed via API — the core definition comes from informer.yaml on deploy.

Authentication: Required

Permissions Required: Member+ role (write permission)

Payload:

FieldTypeDescription
instructionsOverridestring | nullOverride the YAML-defined instructions (set to null to revert)
statusstring"active" or "stopped"
modelstringAI model slug (e.g., "go_everyday")

GET /api/apps/{id}/agents/{agentId}/runs

List execution history for an agent.

Authentication: Required

Permissions Required: Member+ role (write permission)

Query Parameters:

ParameterTypeDefaultDescription
limitnumber20Max results
offsetnumber0Pagination offset

Response:

[
{
"id": "run-uuid",
"agentId": "agent-uuid",
"trigger": "order_created",
"status": "completed",
"tokens": 1250,
"cost": 0,
"steps": [
{
"index": 0,
"type": "tool_call",
"toolCalls": [
{
"name": "update-inventory",
"args": { "productId": "SKU-123", "quantity": -1 },
"result": { "success": true }
}
]
},
{
"index": 1,
"type": "text",
"text": "Order processed successfully. Inventory updated and confirmation sent."
}
],
"context": { "orderId": "ORD-456" },
"error": null,
"completedAt": "2025-03-01T10:00:05.000Z",
"createdAt": "2025-03-01T10:00:00.000Z"
}
]

GET /api/apps/{id}/agents/{agentId}/runs/{runId}

Get details for a single run.

Authentication: Required

Permissions Required: Member+ role (write permission)


POST /api/apps/{id}/agents/{agentId}/_trigger

Manually trigger an agent. Useful for testing or one-off executions.

Authentication: Required

Permissions Required: Member+ role (write permission)

Payload:

{
"event": "manual",
"payload": { "orderId": "ORD-789" }
}
FieldTypeRequiredDescription
eventstringNoEvent name (default: "manual")
payloadobjectNoData passed to the agent as trigger context

Response:

Returns the created run record (status will be "running" initially).


Defining Agents in informer.yaml

Agents are declared in the agents section of informer.yaml:

agents:
order-processor:
description: Processes new orders
instructions: |
You are an order processing agent. When triggered by an order_created event,
verify the order details, update inventory, and send a confirmation email.
tools:
- send-email
- update-inventory
on: order_created
model: go_everyday

daily-report:
description: Generates daily summary
instructions: Generate a summary of today's orders and email it to the team.
tools:
- send-email
cron: "0 17 * * 1-5"
model: go_everyday

smart-assistant:
description: Customer support agent with toolkit and assistant tools
instructions: Help customers with their questions using CRM data.
toolkits:
- admin:crm-toolkit
assistants:
- admin:support-persona
on: support_request
webSearch: true

Agent Fields

FieldTypeRequiredDescription
descriptionstringNoHuman-readable description
instructionsstringNoSystem prompt for the AI
toolsstring[]NoApp tool names (from tools/ directory)
toolkitsstring[]NoToolkit natural IDs to attach
assistantsstring[]NoAssistant natural IDs — instructions are merged into the agent's system prompt
onstring | string[]NoEvent name(s) that trigger this agent
cronstringNoCron schedule (5-field format: min hour dom mon dow)
webSearchbooleanNoEnable web search tool
modelstringNoAI model slug (default: "go_everyday")

Trigger Types

Agents can be triggered in three ways (any combination):

  1. Events (on) — fires when the named event is emitted via emit() in a server route or webhook handler
  2. Cron (cron) — fires on a schedule (e.g., "0 3 * * *" for 3 AM daily)
  3. Manual — via POST /agents/{agentId}/_trigger

App Tools

Agents can call tools defined in the app's tools/ directory. Each tool is a JavaScript file that exports a handler:

// tools/send-email.js
export const description = 'Send an email to a recipient';
export const schema = {
properties: {
to: { type: 'string', description: 'Recipient email' },
subject: { type: 'string', description: 'Email subject' },
body: { type: 'string', description: 'Email body' }
},
required: ['to', 'subject', 'body']
};

export default async function ({ to, subject, body }, { query, fetch, emit, crypto, markdown, log }) {
const result = await fetch('integrations/sendgrid/request', {
method: 'POST',
body: {
url: '/v3/mail/send',
method: 'POST',
data: { to, subject, body }
}
});
return { sent: result.status === 202 };
}

Tools are bundled with esbuild during deploy and executed in V8 isolates. They have access to the same query, fetch, emit, crypto, markdown, and log callbacks as server routes.

Toolkit Integration

Agents can reference external toolkits that provide additional tool definitions. Toolkits are resolved during deploy — the app creates junction rows in app_toolkit linking the app to each referenced toolkit.

At execution time, the agent executor:

  1. Loads the app's toolkit references from app_toolkit
  2. Calls toolkit.getToolDefinitions() for each toolkit
  3. Merges toolkit tools into the agent's available tools
  4. Appends toolkit.getSystemInstructions() to the system prompt
agents:
crm-agent:
description: Handles CRM operations
instructions: Use CRM tools to look up and update customer records.
toolkits:
- admin:crm-toolkit
on: customer_update

If a referenced toolkit doesn't exist, deploy fails with a 400 error.

Assistant Integration

Agents can reference Informer assistants to inherit their instructions. Each referenced assistant's system prompt is merged into the agent's own instructions, allowing you to compose agent behavior from reusable assistant personas.

agents:
support-agent:
description: Handles customer support with a specialized persona
instructions: Process support tickets and escalate as needed.
assistants:
- admin:support-persona
on: support_request

Assistant references are resolved at deploy time — if a referenced assistant doesn't exist, deploy fails with a 400 error. Use either the assistant's naturalId (owner:slug) or UUID.

At execution time, the agent executor:

  1. Loads each referenced assistant by ID
  2. Collects the assistant's instructions field
  3. Appends assistant instructions to the agent's system prompt (before toolkit instructions)

Events

Events are the glue between server routes and agents. Declare event types in informer.yaml:

events:
order_created:
description: Fired when a new order is submitted
order_shipped:
description: Fired when an order ships

agents:
order-processor:
instructions: Process new orders.
on: order_created

Emit events from server routes:

// server/orders/index.js
export async function POST({ query, emit, request }) {
const [order] = await query(
'INSERT INTO orders (customer, total) VALUES ($1, $2) RETURNING *',
[request.body.customer, request.body.total]
);

// This triggers the order-processor agent
await emit('order_created', { orderId: order.id, total: order.total });

return { status: 201, body: order };
}

Event Dispatch

Events are dispatched in two ways:

  • Real-time — a Redis pub/sub listener picks up events immediately
  • Sweep — a periodic scan (every 10 seconds) catches any missed events

Events use atomic claiming (FOR UPDATE SKIP LOCKED) to prevent duplicate execution in clustered environments.

Execution Model

When an agent is triggered:

  1. A run record is created with status "running"
  2. A workspace database connection is acquired
  3. The AI model is resolved (default: go_everyday)
  4. App tools are loaded from bundled code in _bundles/tools/
  5. Assistant instructions are loaded and merged into the system prompt
  6. Toolkit tools are loaded from the app's toolkit references
  7. The AI loop runs with stepCountIs(20) as the stop condition
  8. Each tool call executes in a V8 isolate with query, fetch, and emit callbacks
  9. The run record is updated with status, steps, and token usage

Tool callbacks available to agents:

CallbackDescription
query(sql, params)Execute SQL against the app's workspace
fetch(path, options)Make authenticated API calls (whitelist enforced)
emit(event, payload)Create app events (can chain-trigger other agents)
crypto.hmac(algorithm, key, data, encoding?)HMAC digest computation
markdown(text)Convert markdown to HTML
log(message, data?)Structured logging (also log.info, log.warn, log.error, log.debug)