Skip to main content
A Trigger binds a function to an event. When the event occurs (HTTP request, queue message, cron schedule, etc.), the iii-engine invokes the function automatically.

What is a Trigger?

A trigger consists of:
  1. Type: The event type (http, queue, pubsub, cron)
  2. Function ID: The function to invoke when the event occurs
  3. Config: Type-specific configuration (route, topic, schedule, etc.)
Triggers are registered after functions. You can’t trigger a function that doesn’t exist.

Trigger Types

AgentOS supports four types of triggers:

HTTP

Invoke function via HTTP request (REST API)

Queue

Invoke function when message arrives in queue topic

PubSub

Invoke function when message published to topic

Cron

Invoke function on schedule (cron expression)

HTTP Triggers

HTTP triggers expose functions as REST API endpoints.
// From src/agent-core.ts:924-928
registerTrigger({
  type: "http",
  function_id: "api::chat_completions",
  config: {
    api_path: "v1/chat/completions",
    http_method: "POST"
  }
});
This creates an endpoint at http://localhost:3111/v1/chat/completions that invokes api::chat_completions.

HTTP Configuration

FieldTypeDescription
api_pathstringURL path (without leading /)
http_methodstringHTTP method: GET, POST, PUT, DELETE, OPTIONS

HTTP Configuration from config.yaml

The REST API module is configured in config.yaml:
# From config.yaml:4-13
modules:
  - class: modules::api::RestApiModule
    config:
      port: 3111
      host: 0.0.0.0
      default_timeout: 300000
      concurrency_request_limit: 2048
      cors:
        allowed_origins: ['*']
        allowed_methods: [GET, POST, PUT, DELETE, OPTIONS]
        allowed_headers: ['*']
HTTP triggers are served on port 3111 (from config). The main WebSocket connection is on port 49134.

Queue Triggers

Queue triggers invoke functions when messages arrive in a queue topic.
// From src/agent-core.ts:924-928
registerTrigger({
  type: "queue",
  function_id: "agent::chat",
  config: { topic: "agent.inbox" }
});
Now when a message is pushed to agent.inbox, the agent::chat function is invoked with the message data.

Queue Configuration

FieldTypeDescription
topicstringQueue topic name to subscribe to

Queue Module Configuration

# From config.yaml:33-36
modules:
  - class: modules::queue::QueueModule
    config:
      adapter:
        class: modules::queue::BuiltinQueueAdapter

Sending Messages to Queue

Push messages to the queue using trigger("queue::push", ...):
await trigger("queue::push", {
  topic: "agent.inbox",
  data: {
    agentId: "agent-123",
    message: "Hello!",
    sessionId: "sess-456"
  }
});

PubSub Triggers

PubSub triggers invoke functions when messages are published to a topic.
registerTrigger({
  type: "pubsub",
  function_id: "audit::log",
  config: { topic: "audit" }
});

PubSub vs Queue

FeatureQueuePubSub
DeliveryOne consumer receives each messageAll subscribers receive each message
OrderingFIFO (first in, first out)No ordering guarantee
Use CaseTask distribution, load balancingEvents, notifications, logging

PubSub Module Configuration

# From config.yaml:38-41
modules:
  - class: modules::pubsub::PubSubModule
    config:
      adapter:
        class: modules::pubsub::LocalAdapter

Publishing Messages

Publish messages using trigger("publish", ...) or triggerVoid("publish", ...):
// From src/agent-core.ts:873-876
triggerVoid("publish", {
  topic: "agent.lifecycle",
  data: { type: "created", agentId }
});
Real example from Rust:
// From crates/agent-core/src/main.rs:85-88
let _ = iii.trigger_void("publish", json!({
    "topic": "agent.lifecycle",
    "data": { "type": "deleted", "agentId": agent_id },
}));

Cron Triggers

Cron triggers invoke functions on a schedule.
registerTrigger({
  type: "cron",
  function_id: "cleanup::old_sessions",
  config: {
    schedule: "0 2 * * *"  // Every day at 2 AM
  }
});

Cron Configuration

FieldTypeDescription
schedulestringCron expression (5-field format)

Cron Expression Format

┌───────────── minute (0 - 59)
│ ┌───────────── hour (0 - 23)
│ │ ┌───────────── day of month (1 - 31)
│ │ │ ┌───────────── month (1 - 12)
│ │ │ │ ┌───────────── day of week (0 - 6) (Sunday to Saturday)
│ │ │ │ │
│ │ │ │ │
* * * * *

Common Cron Patterns

ExpressionDescription
*/5 * * * *Every 5 minutes
0 * * * *Every hour
0 0 * * *Every day at midnight
0 2 * * *Every day at 2 AM
0 0 * * 0Every Sunday at midnight
0 0 1 * *First day of every month

Cron Module Configuration

# From config.yaml:43-46
modules:
  - class: modules::cron::CronModule
    config:
      adapter:
        class: modules::cron::KvCronAdapter

Real-World Examples

Agent Inbox Queue Trigger

The agent-core worker registers a queue trigger to process chat messages:
// From crates/agent-core/src/main.rs:95
iii.register_trigger("queue", "agent::chat", json!({
    "topic": "agent.inbox"
}))?;

Audit Event PubSub Trigger

Publishing audit events that multiple subscribers can consume:
// From src/agent-core.ts:503-511
try {
  await triggerVoid("publish", {
    topic: "audit",
    data: {
      type: "tool_execution",
      agentId,
      tools: currentResponse.toolCalls.map((tc: ToolCall) => tc.id),
      iteration: iterations,
    },
  });
} catch (err: any) {
  console.warn("Audit publish failed", { agentId, error: err?.message });
}

Lifecycle Events

Publishing agent lifecycle events:
// From src/agent-core.ts:873-876
triggerVoid("publish", {
  topic: "agent.lifecycle",
  data: { type: "created", agentId },
});

Trigger Registration Patterns

Register All Triggers at Startup

// Register functions first
registerFunction({ id: "agent::chat", description: "..." }, handler);
registerFunction({ id: "agent::create", description: "..." }, handler);

// Then register triggers
registerTrigger({ type: "queue", function_id: "agent::chat", config: { topic: "agent.inbox" } });
registerTrigger({ type: "http", function_id: "agent::create", config: { api_path: "agents", http_method: "POST" } });

Multiple Triggers per Function

A single function can have multiple triggers:
registerFunction({ id: "notify::send", description: "Send notification" }, handler);

// Trigger via HTTP
registerTrigger({ type: "http", function_id: "notify::send", config: { api_path: "notify", http_method: "POST" } });

// Trigger via queue
registerTrigger({ type: "queue", function_id: "notify::send", config: { topic: "notifications" } });

// Trigger via pubsub
registerTrigger({ type: "pubsub", function_id: "notify::send", config: { topic: "alerts" } });

Managing Triggers at Runtime

Create triggers dynamically using the engine API:
// Create cron trigger via API
await trigger("engine::triggers::create", {
  type: "cron",
  function_id: "cleanup::sessions",
  config: { schedule: "0 3 * * *" }
});

// List all triggers
const triggers = await trigger("engine::triggers::list", {});

// Delete trigger
await trigger("engine::triggers::delete", { triggerId: "trigger-123" });

Best Practices

Register After Functions

Always register functions before their triggers. The engine can’t trigger a function that doesn’t exist.

Use Queue for Tasks

Use queue triggers for task distribution and load balancing across workers.

Use PubSub for Events

Use pubsub triggers for events that multiple subscribers need to process.

Descriptive Topics

Use namespaced topic names: agent.lifecycle, audit.security, task.completed

Handle Failures

Queue and pubsub handlers should handle errors gracefully - failed messages may be retried.

Idempotent Handlers

Design handlers to be safely retried. Don’t assume messages are delivered exactly once.

Trigger Flow Diagram

Complete Example: Agent System

Here’s how triggers work together in the agent system:
// 1. Register chat function
registerFunction(
  { id: "agent::chat", description: "Process chat message" },
  async (input) => {
    // Process message
    const response = await trigger("llm::complete", { ... });
    
    // Publish lifecycle event
    triggerVoid("publish", {
      topic: "agent.lifecycle",
      data: { type: "message_processed", agentId: input.agentId }
    });
    
    return response;
  }
);

// 2. Register HTTP trigger for direct API calls
registerTrigger({
  type: "http",
  function_id: "agent::chat",
  config: { api_path: "v1/chat/completions", http_method: "POST" }
});

// 3. Register queue trigger for async processing
registerTrigger({
  type: "queue",
  function_id: "agent::chat",
  config: { topic: "agent.inbox" }
});

// 4. Register audit logger for lifecycle events
registerFunction(
  { id: "audit::log", description: "Log audit events" },
  async (event) => {
    await trigger("state::append", {
      scope: "audit",
      key: "lifecycle",
      value: event
    });
  }
);

registerTrigger({
  type: "pubsub",
  function_id: "audit::log",
  config: { topic: "agent.lifecycle" }
});

// 5. Register cleanup cron
registerFunction(
  { id: "cleanup::sessions", description: "Clean old sessions" },
  async () => {
    const cutoff = Date.now() - 7 * 24 * 60 * 60 * 1000; // 7 days
    await trigger("memory::cleanup", { before: cutoff });
  }
);

registerTrigger({
  type: "cron",
  function_id: "cleanup::sessions",
  config: { schedule: "0 3 * * *" } // 3 AM daily
});

Next Steps

Architecture

See how all components work together in the system architecture

Workers

Learn more about creating and managing workers

Build docs developers (and LLMs) love