OpenMAIC Streaming Interface Event Types: Complete SSE Reference Guide
OpenMAIC emits 25 distinct Server-Sent Events (SSE) through its streaming interface, aggregating host lifecycle signals, legacy compatibility frames, and Pi-AI runtime messages into the WORKBENCH_EVENT_TYPES array consumed by the React frontend.
The THU-MAIC/OpenMAIC repository delivers live AI workbench updates via a Server-Sent Events stream, where each named frame type must be explicitly registered to prevent silent data loss. Understanding the complete taxonomy of OpenMAIC streaming interface event types is essential for debugging session flows, replaying historic logs, and building responsive UI components that react to real-time agent state changes.
The Three Categories of OpenMAIC Streaming Events
The SSE client defined in lib/workbench/use-workbench-session.ts concatenates three distinct source arrays to build the definitive WORKBENCH_EVENT_TYPES constant. Missing any entry from this aggregate list results in the EventSource API silently dropping those frames before they reach your application code.
Host Lifecycle Events
Defined in lib/agent-runtime/lifecycle.ts, these events track high-level session state and user interactions within the OpenMAIC workbench:
session_start,session_resumed,checkpoint,session_end,session_interrupteduser_message,trace,thinking_endmaterial_extraction,user_question,stage_linklibrary_changed,media_ready
These constants represent the primary lifecycle signals emitted by the host runtime during an AI-assisted session.
Legacy Compatibility Events
Maintained in lib/workbench/use-workbench-session.ts to ensure backward compatibility with archived session logs:
course_linkactive_stage_changed
These legacy names prevent data loss when replaying historic sessions recorded before lifecycle constants were renamed.
Pi-AI Runtime Events
Raw message types emitted directly by the Pi-AI agent, also defined in lib/workbench/use-workbench-session.ts:
message_start,message_update,message_endtool_execution_start,tool_execution_update,tool_execution_endturn_start,turn_end,agent_start,agent_end
These low-level events correspond to the granular "assistant" message stream and are folded into the chat UI by the workbench reducer.
Event Registration and the EventSource API
The frontend constructs the complete event taxonomy by spreading the three source arrays into WORKBENCH_EVENT_TYPES:
// lib/workbench/use-workbench-session.ts
export const LEGACY_WORKBENCH_EVENT_TYPES = [
'course_link',
'active_stage_changed',
] as const;
export const WORKBENCH_EVENT_TYPES = [
...Object.values(LIFECYCLE), // host lifecycle (lib/agent-runtime/lifecycle.ts)
...LEGACY_WORKBENCH_EVENT_TYPES,
...PI_EVENT_TYPES, // raw Pi-AI messages
];
The useWorkbenchStream hook iterates over this array to register a dedicated listener for each type:
const source = new EventSource(
`/api/agent/sessions/${encodeURIComponent(sessionId)}/events?lastEventId=${from}`
);
for (const type of WORKBENCH_EVENT_TYPES) {
source.addEventListener(type, onAny as EventListener);
}
Critical implementation detail: The EventSource API only dispatches frames to listeners registered for the exact event: name. Early versions of OpenMAIC omitted user_question from the aggregate list, causing a subtle bug where question cards were silently dropped before any UI code could process them (see the comment at lines 66-71 of use-workbench-session.ts).
Practical Implementation: Consuming OpenMAIC SSE Events
Attaching to a Session Stream
The following pattern establishes the connection and prepares the event routing infrastructure:
// lib/workbench/use-workbench-session.ts (excerpt)
export function useWorkbenchStream(sessionId: string | null): void {
const applyEvent = useWorkbenchStore(s => s.applyEvent);
const setAttached = useWorkbenchStore(s => s.setAttached);
const source = new EventSource(
`/api/agent/sessions/${encodeURIComponent(sessionId)}/events?lastEventId=${from}`
);
for (const type of WORKBENCH_EVENT_TYPES) {
source.addEventListener(type, onAny as EventListener);
}
// Handler implementation omitted for brevity
}
Dispatching Events by Type
Within the onAny callback, parse the event data and route based on the type discriminator:
// Inside the onAny callback from lib/workbench/use-workbench-session.ts
if (parsed.type === LIFECYCLE.mediaReady) {
const frame = parseMediaReadyFrame(parsed.data);
if (frame) applyMediaReadyFrame(frame);
}
Listening to Specific Events
For isolated components that only care about particular signals, attach a targeted listener:
const source = new EventSource(url);
source.addEventListener('user_question', (e: MessageEvent) => {
const payload = JSON.parse(e.data); // { question: string, options?: … }
// Show a modal, log analytics, etc.
});
TypeScript Type Safety for Event Types
Derive a strict union type from the constant array to ensure exhaustive switch statements:
import { WORKBENCH_EVENT_TYPES } from '@/lib/workbench/use-workbench-session';
type WorkbenchEventType = typeof WORKBENCH_EVENT_TYPES[number];
// WorkbenchEventType is now a union of all 25 string literals
Summary
- 25 distinct event types comprise the complete OpenMAIC streaming interface, divided into host lifecycle (13), legacy (2), and Pi-AI runtime (10) categories.
WORKBENCH_EVENT_TYPESinlib/workbench/use-workbench-session.tsaggregates all valid event names; omissions cause the EventSource API to silently drop frames.- Host lifecycle events originate in
lib/agent-runtime/lifecycle.tsand track session-level state changes likesession_startandmedia_ready. - Legacy names ensure backward compatibility for replaying archived logs after constant renames.
- Pi-AI events provide granular visibility into the AI agent's message generation and tool execution cycles.
Frequently Asked Questions
What happens if an event type is not included in WORKBENCH_EVENT_TYPES?
The EventSource API dispatches SSE frames only to registered listeners. If a type is missing from the WORKBENCH_EVENT_TYPES array, the browser receives the frame but drops it silently, causing "invisible" events that never reach your handlers. This mechanism caused an early bug where user_question events were lost (documented at lines 66-71 of use-workbench-session.ts).
Why does OpenMAIC maintain legacy event types?
The course_link and active_stage_changed legacy names ensure historic session logs remain replayable after lifecycle constants were renamed in subsequent versions, preventing data loss across version migrations of the THU-MAIC/OpenMAIC codebase.
How do Pi-AI runtime events differ from host lifecycle events?
Pi-AI runtime events (message_start, tool_execution_end, etc.) represent low-level assistant message streams and tool execution granularities emitted directly by the AI agent, while host lifecycle events (session_start, media_ready, etc.) track high-level session state and user interactions managed by the OpenMAIC workbench runtime.
Can I register a listener for only one specific event type?
Yes. While the workbench registers all types automatically to ensure completeness, you can create a standalone EventSource connection and call source.addEventListener('user_question', handler) to isolate specific signals without processing the full event stream or loading the entire WORKBENCH_EVENT_TYPES registry.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →