Runtime Event Bus
The runtime publishes session changes, store writes, automation activity, and config reloads through GET /api/events. Use these events to refresh data in your application.
Chat responses use a separate POST stream with text_delta, tool_call_start, and done messages. See Runtime Server. The event bus reports state changes across sessions; it does not replace authenticated data queries.
Subscribe
This browser example uses the current origin and its hosted session. A cross-origin or bearer-authenticated client needs an appropriate authenticated connection; native EventSource cannot set an Authorization header.
const events = new EventSource('/api/events');
const handleEvent = (message: MessageEvent<string>) => {
const event = JSON.parse(message.data);
if (event.type === 'session_created') {
console.log('Session created:', event.sessionId);
}
};
// Direct runtimes name SSE events, so register a named listener for each
// catalog type the view uses. The hosted event service uses message frames.
events.addEventListener('session_created', handleEvent);
events.addEventListener('message', handleEvent);Call events.close() when the view is disposed. The server sends a comment heartbeat every 15 seconds.
createLocalServer() mounts this route. An application using createServer() directly must opt in with mountEventsRoute: true. Hosted deployments provide their own event route.
Reconnect-and-resume
EventSource saves the SSE id and sends it as Last-Event-ID on reconnect. Treat this ID as an opaque cursor:
- A direct runtime uses a process-local sequence and retains 200 events by default. Its cursor and buffer reset when the process restarts.
- Hosted deployments routed through the event service use Redis stream IDs, with retention configured by the platform. Do not substitute the event payload's
seqfor this cursor.
The server replays retained events after the cursor, then streams live events. Missing events outside retention cannot be recovered from this subscription. Refresh the underlying data after a reconnect if your view needs a complete state. A gap in numeric seq can also come from filtered event types, so it is not proof of data loss.
Event catalog
Session events
| Type | Fields | When |
|---|---|---|
session_created | sessionId, agentId | A new session was created (chat, admin, automation). |
session_updated | sessionId, agentId, title?, status?, answeredBy? | A session was persisted after a message, title change, or metadata update. |
session_deleted | sessionId | A session was deleted via the API. |
Automation events
| Type | Fields | When |
|---|---|---|
automation_triggered | name, source | Automation run starting. source is "cron", "webhook", or "manual". |
automation_completed | name, durationMs | Automation finished successfully. |
automation_failed | name, error, durationMs | Automation threw during the agent loop. |
automation_started | name, intervalMs | A cron automation was registered or resumed by the platform. |
automation_stopped | name | A cron automation was paused. |
Delivery events
| Type | Fields | When |
|---|---|---|
delivery_succeeded | automation, targetType, targetUrl?, httpStatus?, durationMs | A delivery target accepted the payload. |
delivery_failed | automation, targetType, targetUrl?, httpStatus?, error, attempts | Delivery failed after retries. |
Store events
| Type | Fields | When |
|---|---|---|
store_updated | storeName, operation, count? | A document was written, deleted, or batch-written. operation is "put", "delete", or "batch". |
Config events
| Type | Fields | When |
|---|---|---|
manifest_changed | None | The agent manifest (connections, skills, automations) was reloaded after a source or deploy change. |
files_changed | path? | A file in the agent repo changed. Amodal uses this to refresh source-aware views. |
reload_failed | message | A bundle reload failed; the runtime keeps serving the previous bundle. |
Channel events
| Type | When |
|---|---|
channel_message_received | An inbound message arrived on a messaging channel. |
channel_reply_sent | The agent's reply was delivered back to the channel. |
channel_session_created | A channel conversation started a new session. |
channel_auth_rejected | A channel webhook failed authentication. |
Tool-call events
tool_call_started, tool_call_completed, and tool_call_failed report execution activity. The core runtime route excludes them by default; add ?include=tool_calls or individual type names to include them. The hosted routes do not apply this core-route filter.
Types
All events carry seq, timestamp, and type fields plus the event-specific payload. The React SDK exports AgentEvent, which accepts runtime event fields as unknown values. Narrow those fields before using them:
import type { AgentEvent } from '@amodalai/react';
function handleEvent(event: AgentEvent) {
if (event.type === 'session_updated' && typeof event['sessionId'] === 'string') {
console.log(event['sessionId'], event['status']);
}
}When to use events vs. polling
Use events to know when to refresh a session list, automation status, or store-backed view. Use the corresponding HTTP API to fetch the current data and enforce the caller's access.
Event delivery and data access have separate boundaries. Do not treat receipt of an event as permission to read the referenced session or store.