Skip to content

event_system

github-actions[bot] edited this page Sep 20, 2026 · 1 revision

Event System Architecture

This document provides a comprehensive overview of the event system in the Multi-Agent Builder, covering type safety, filtering layers, frontend delivery mechanisms, and hierarchical grouping.


1. Event Type Discriminated Unions

📋 Overview

The event type system uses a TypeScript Discriminated Union pattern to enforce strict type safety, eliminate unsafe casting, and improve developer experience.

Key Benefits:

  • Type Safety: The compiler guarantees that event.data.data matches event.type.
  • Zero Casting: Removes the need for manual as Type casts or helper functions.
  • Better IDE Support: Autocomplete works correctly based on the checked type.

📊 Wire Format (Actual Structure)

PollingEvent (Backend: event_store.go)
├── id: string
├── type: "tool_call_start"          ← Event type discriminator
├── timestamp: ISO string
├── session_id?: string
├── error?: string
└── data: AgentEvent                 ← Unified payload for Orchestrator & MCP
    ├── type: "tool_call_start"      ← Same as parent
    ├── timestamp: ISO string
    ├── event_index: number
    ├── trace_id?: string
    ├── hierarchy_level: number
    ├── correlation_id?: string      ← Used for delegation grouping
    ├── parent_id?: string           ← Used for direct parenting
    └── data: ToolCallStartEvent     ← Actual typed event data
        ├── tool_name: string
        ├── tool_params: object
        └── server_name: string

Key Insight: Event data is located at event.data.data, not event.data.


2. Event Filtering & Storage Flow

The system uses multiple layers of filtering to manage performance, bandwidth, and storage space.

Layer 1: Emission Filtering (SKIP_EVENTS)

File: agent_go/cmd/server/event_bridge/base_bridge.go
Events in this map are discarded immediately and never reach the memory store or database.

  • Types: tool_execution, tool_output, tool_response, tool_call_progress, and all cache_* events.

Layer 2: Database Storage Filtering (DB_SKIP_EVENTS)

File: agent_go/cmd/server/event_bridge/base_bridge.go
Events in this map are kept in memory (for real-time SSE and polling) but never saved to the database. This saves massive amounts of space and enables "Micro Mode" by default.

  • Types: step_progress_updated, llm_generation_start, conversation_turn, streaming_chunk.
  • CRITICAL EXCEPTION: llm_generation_end and agent_end are NOT skipped. They are required to clear the "Generating..." state when a session is restored.

Layer 3: Polling Layer Filtering (NEVER_SHOW_EVENTS)

File: agent_go/internal/events/event_store.go
Acts as a safety net at the polling layer. It filters out events that might have been stored in the database before SKIP_EVENTS was implemented.

  • Types: Mirrors SKIP_EVENTS + ephemeral streaming_start/chunk events.

Layer 4: UI Visibility Filtering (HIDDEN_EVENTS & Runtime Logic)

File: agent_go/internal/events/event_store.go & EventHierarchy.tsx
These events reach the frontend and are available in the state (e.g., for token usage calculations) but are hidden from the main event list.

  • Types: llm_generation_start, agent_start, conversation_start.
  • Runtime Filtering: token_usage events with context: 'conversation_total' are stripped from the main view to reduce UI noise.

3. Delivery Lifecycle: SSE, Resiliency, and Fallback

Real-Time Delivery (SSEConnection)

The frontend establishes a Server-Sent Events (SSE) connection to receive real-time updates.

  • Store: Events are deduplicated and stored by session in useChatStore (tabEvents).
  • Streaming Chunks: streaming_chunk events bypass the database and polling completely. They are delivered exclusively via the SSE buffer for real-time text rendering.

Auto-Catchup Mechanism

The frontend tracks the highest event_index received per session (tabEventIndices).

  • On reconnection, the SSEConnection sends this index via the Last-Event-ID header.
  • The backend uses this to automatically replay any events missed during the network drop before resuming real-time delivery.

Polling Fallback

If the SSE connection fails consecutively (e.g., 5 network failures), the frontend ChatArea.tsx orchestration gracefully degrades to HTTP polling (pollEvents) to ensure the session remains responsive.


4. Sub-Agent Isolation & Workflow Grouping

File: frontend/src/components/events/EventHierarchy.tsx

The UI reconstructs complex multi-agent and workflow executions into an expandable tree using correlation_id and parent_id.

Sub-Agent / Delegation Grouping

When a sub-agent is spawned, it generates many events. To prevent these from cluttering the main orchestrator's timeline:

  1. The frontend scans for events with a correlation_id starting with delegation-.
  2. These child events are extracted from the flat timeline.
  3. They are visually re-parented under the specific delegation_start node (rendered as an expandable Sub-Agent Card).

Parallel Agent Grouping

For concurrent workflows, parallel tool calls are parented under their respective orchestrator_agent_start node via correlation_id. This guarantees parallel agent tool executions don't incorrectly merge.

Tool Call Collapsing

To further reduce noise in the main timeline, consecutive tool-related events (tool_call_start, tool_call_end, token_usage, llm_generation_end) are collapsed into a single + N tool calls inline button.

  • Because sub-agent events are removed from the flat list (as described above), they never interfere with or get swallowed by the main agent's tool call groups.

Clone this wiki locally