Events
Events are the core communication protocol in Everruns. They provide real-time visibility into session execution via Server-Sent Events (SSE) streaming.
Overview
Section titled “Overview”Every action during a session - from user messages to LLM responses to tool executions - emits events. This enables:
- Real-time UI updates: Stream agent responses as they’re generated
- Observability: Track every step of agent execution
- Debugging: Full visibility into LLM calls, tool execution, and errors
- Integration: Build custom UIs or monitoring tools on the event stream
Quick Start
Section titled “Quick Start”SSE Streaming
Section titled “SSE Streaming”Subscribe to real-time events via Server-Sent Events:
curl -N "https://api.everruns.com/v1/sessions/{session_id}/sse" \ -H "Authorization: Bearer $API_KEY"Polling
Section titled “Polling”Alternatively, poll for events with pagination:
curl "https://api.everruns.com/v1/sessions/{session_id}/events?since_id={last_event_id}" \ -H "Authorization: Bearer $API_KEY"SSE Connection Management
Section titled “SSE Connection Management”Connection Lifecycle Events
Section titled “Connection Lifecycle Events”SSE streams include special lifecycle events for connection management:
| Event | Description |
|---|---|
connected | Sent immediately when the stream is established |
disconnecting | Sent before the server gracefully closes the connection |
Connection Cycling
Section titled “Connection Cycling”To prevent stale connections through proxies and load balancers, SSE connections are automatically cycled:
| Stream Type | Cycle Interval |
|---|---|
| Session events | 5 minutes |
| Durable monitoring | 10 minutes |
Before closing, the server sends a disconnecting event:
{ "event": "disconnecting", "data": "{\"reason\":\"connection_cycle\",\"retry_ms\":100}"}Clients should reconnect immediately using the since_id of the last received event. This ensures no events are missed during the transition.
Retry Hints
Section titled “Retry Hints”Each SSE event includes a retry: field that hints how long clients should wait before reconnecting if the connection is unexpectedly lost:
| Situation | Retry Hint |
|---|---|
| Active streaming (new events) | 100ms |
| Idle (no new events) | Increases with backoff up to 500ms |
After disconnecting event | 100ms (immediate reconnect) |
The EventSource API automatically uses this hint for reconnection timing.
Resuming Streams
Section titled “Resuming Streams”Use the since_id query parameter to resume from the last received event:
curl -N "https://api.everruns.com/v1/sessions/{session_id}/sse?since_id={last_event_id}" \ -H "Authorization: Bearer $API_KEY"Event IDs are UUID v7 (monotonically increasing by timestamp), ensuring reliable ordering and no duplicate events on reconnection.
JavaScript Example
Section titled “JavaScript Example”function connectSSE(sessionId, lastEventId) { const url = new URL(`/v1/sessions/${sessionId}/sse`, API_BASE); if (lastEventId) { url.searchParams.set('since_id', lastEventId); }
const eventSource = new EventSource(url, { withCredentials: true });
eventSource.addEventListener('connected', () => { console.log('SSE connected'); });
eventSource.addEventListener('disconnecting', (event) => { const data = JSON.parse(event.data); console.log('SSE disconnecting, reconnecting in', data.retry_ms, 'ms'); eventSource.close(); setTimeout(() => connectSSE(sessionId, lastEventId), data.retry_ms); });
eventSource.addEventListener('input.message', (event) => { const eventData = JSON.parse(event.data); lastEventId = eventData.id; // Handle event... });
// Handle other event types...
eventSource.onerror = () => { eventSource.close(); setTimeout(() => connectSSE(sessionId, lastEventId), 2000); };}Event Categories
Section titled “Event Categories”Events are organized into categories based on what they represent:
| Category | Events | Description |
|---|---|---|
| Input | input.message | User messages submitted to the session |
| Output | output.message.* | Agent response lifecycle (started, delta, completed) |
| Turn | turn.* | Turn lifecycle (started, completed, failed, cancelled) |
| Thinking | reason.thinking.* | Extended thinking content (for Claude models) |
| Atom | reason.*, act.*, tool.* | Internal execution phases |
| LLM | llm.generation | Full LLM API call details |
| Session | session.* | Session state changes |
Event Structure
Section titled “Event Structure”Every event follows this schema:
{ "id": "event_01933b5a00007000800000000000001", "type": "turn.completed", "ts": "2024-01-15T10:30:00.000Z", "session_id": "session_01933b5a00007000800000000000002", "sequence": 42, "context": { "turn_id": "turn_01933b5a00007000800000000000003", "input_message_id": "message_01933b5a00007000800000000000004", "trace_id": "turn_01933b5a00007000800000000000003", "span_id": "abc123", "parent_span_id": "def456" }, "data": { /* type-specific payload */ }}Core Fields
Section titled “Core Fields”| Field | Type | Description |
|---|---|---|
id | string | Unique event ID (UUIDv7 with event_ prefix) |
type | string | Event type in dot notation |
ts | string | ISO 8601 timestamp with millisecond precision |
session_id | string | Session this event belongs to |
sequence | integer | Monotonic sequence within session (for ordering) |
context | object | Correlation context for tracing |
data | object | Event-specific payload |
Event Context
Section titled “Event Context”The context object provides correlation IDs for tracing:
| Field | Description |
|---|---|
turn_id | Turn this event belongs to |
input_message_id | User message that triggered the turn |
exec_id | Atom execution identifier |
trace_id | OpenTelemetry-style trace ID |
span_id | This event’s span ID |
parent_span_id | Parent span for hierarchy |
Common Patterns
Section titled “Common Patterns”Started-Completed-Failed Pattern
Section titled “Started-Completed-Failed Pattern”Long-running operations follow a lifecycle pattern:
turn.started → turn.completed ↘ turn.failed ↘ turn.cancelledThis provides clear boundaries for UI state management and error handling.
Delta Pattern for Streaming
Section titled “Delta Pattern for Streaming”Streaming content uses delta events with accumulated state:
{ "type": "output.message.delta", "data": { "turn_id": "turn_...", "delta": "Hello", // New content since last delta "accumulated": "Hello" // Total content so far }}Delta events are batched (~100ms) to reduce volume while maintaining real-time feel.
Forward Compatibility
Section titled “Forward Compatibility”Events follow semantic versioning. The contract is defined in specs/events-contract.md.
What Won’t Break
Section titled “What Won’t Break”- Adding new event types
- Adding optional fields to existing events
- Adding new enum values
Consumer Guidelines
Section titled “Consumer Guidelines”- Ignore unknown fields: Your deserializer should not fail on unknown fields
- Handle optional fields: Check for presence before accessing
- Don’t rely on field ordering: JSON field order is not guaranteed
All events in API responses are well-defined types. The server filters out any internal or unsupported events before transmission.
OpenAPI Schema
Section titled “OpenAPI Schema”Full event schemas are documented in the OpenAPI specification:
Related Resources
Section titled “Related Resources”- Event Reference - Complete reference for all event types
- specs/events.md - Internal specification
- specs/events-contract.md - Contract specification