[KongchangAI]
Tutorials· 2 min read· 1,125 words

The Foundation of Agent Platforms: Practical Guide to Session Event Abstraction, Transport, and Storage

The Foundation of Agent Platforms: Practical Guide to Session Event Abstraction, Transport, and Storage

Practical design of Session Event abstraction, transport, and storage for production Agent platforms

This article systematically examines three major engineering challenges of Session Events when building production-grade Agent platforms, based on real-world experience. First, facing fragmented event formats across different LLM APIs and Agent runtimes from OpenAI, Anthropic, and others, a Universal Event abstraction layer is needed for seamless runtime switching. Second, evolving from local single-hop SSE to a Client-Control Plane-Agent three-party streaming transport architecture requires solving multi-link fault tolerance, breakpoint resumption, and data consistency in many-to-many relationships. Third, the storage approach evolves from an initial PostgreSQL one-message-per-row design, driven by performance bottlenecks like write amplification from frequent JSONB incremental updates.

When building a production-grade Agent platform, the event data generated from each interaction with an LLM API may seem simple, but it actually conceals a wealth of engineering challenges. Based on real-world lessons learned, this article systematically examines the design philosophy and technical details of Session Events across three dimensions: abstraction, transport, and storage — helping developers avoid common pitfalls.

Why You Need Unified Event Abstraction

The Fragmented Landscape of Industry APIs

LLM APIs are gradually converging, but mainstream API specifications still exhibit significant divergence. OpenAI has two sets of APIs — the traditional Chat Completions and the newly introduced Responses API — while Anthropic's API has become another mainstream choice due to the widespread adoption of Claude Code.

In the Agent domain, data format differences are further amplified. Take the Claude SDK as an example: it provides message-level event granularity, largely consistent with the LLM API's message structure — user message, assistant message, tool call, and tool result. Codex, on the other hand, employs a finer-grained event design with delta-level incremental events for both tool calls and text output.

Event format differences across different runtimes in an Agent platform

If you also need to support the Python runtime used by OpenAI, other Agent runtimes like Goose, or even custom-built runtimes in the future, these differences will only grow. Although standards like ACP (Agent Communication Protocol), driven by the code editor ecosystem, exist, not every provider supports them by default.

Background: ACP and the Agent Interoperability Protocol Ecosystem The Agent Communication Protocol (ACP) is an Agent interoperability standard driven by the code editor ecosystem (represented by Cursor, VS Code, etc.), designed to define standardized communication interfaces between Agents and between Agents and their host environments. Similarly, there's MCP (Model Context Protocol) led by Anthropic, which focuses on standardized connections between models and tools/data sources. The emergence of these protocols reflects the trend of the Agent ecosystem moving from "going it alone" toward interoperability. However, due to diverging commercial interests and differing technical approaches, no truly unified industry standard has yet emerged. For platform developers, maintaining your own Universal Event abstraction at the platform layer is the more pragmatic engineering choice until protocol standards converge.

Universal Event: A Platform-Level Unified Abstraction

To address multi-runtime compatibility, the platform layer needs an abstraction called Universal Event. The core objective is to prevent event differences between different Agents from leaking into downstream systems — whether it's the UI rendering layer, the database persistence layer, or the data analytics engine, they all work with a unified event format.

The direct benefit of this abstraction is seamless runtime switching. When using Agents locally, switching from Claude Code to Codex without a platform abstraction would cause migration costs to skyrocket as usage deepens — MCP configurations, Skills configurations, thinking level settings, sub-agent definitions, and more would all need to be re-adapted. With Universal Event abstraction, historical Session data is fully preserved after switching runtimes.

Streaming Event Transport Architecture Design

From Single-Hop to Three-Party Architecture

LLM inference takes considerable time, so since ChatGPT, streaming APIs (typically based on SSE, or Server-Sent Events) have been the standard.

Background: SSE Protocol and LLM Streaming Output Server-Sent Events (SSE) is a unidirectional real-time communication protocol based on HTTP, standardized by the W3C. Unlike WebSocket's bidirectional communication, SSE is designed specifically for servers to push data to clients, with native support for automatic reconnection and event ID-based resume. In LLM scenarios, SSE's advantage lies in its use of plain HTTP, which can traverse most proxies and firewalls, and browsers natively support the EventSource API. After OpenAI introduced it for ChatGPT in 2020, SSE became the de facto industry standard for LLM streaming output. Its text/event-stream format is simple — each message contains a data field separated by double newlines — making it ideal for token-level incremental output scenarios.

In local Agent scenarios, the architecture is straightforward: Client connects directly to the Agent via a single-hop SSE connection. But in an Agent platform, the architecture becomes a three-party structure: Client → Control Plane → Agent. This introduces a core design question: should streaming events use single-hop SSE (proxied and forwarded by the Control Plane), or a decoupled approach?

Three-party architecture design for streaming event transport

Fault Tolerance in Three-Party Architecture

In a single-hop architecture, when the Client loses connection with the Agent, you just need both parties to be failure-tolerant — the Client reconnects and reattaches to the Agent. But in a three-party architecture, any link in the chain can break, and each segment needs independent exception handling.

The key design principle is: when the three parties are inconsistent, who is the source of truth? This requires a clear priority strategy:

  • The Agent, as the event producer, is typically the source of truth
  • The Control Plane, as the middle layer, is responsible for event persistence and distribution
  • The Client, as the consumer, needs the ability to resume from breakpoints

The Complexity of Many-to-Many Relationships

Local Agents have a simple one-to-one relationship, but once platformized, it becomes a complex many-to-many:

  • Multiple Clients → One Control Plane: Multiple browser tabs and API Clients may simultaneously access the same Session
  • One Control Plane → Multiple Agents: The platform manages multiple Agent instances

The same Session may be accessed by multiple Clients simultaneously — something that virtually never occurs with local Agents. The platform needs to redesign event isolation and sharing strategies to ensure data consistency during multi-client collaboration.

Storage Solution Evolution and Lessons Learned

Initial Approach: One Message Per Row in PostgreSQL

The most intuitive storage approach is having each row in PostgreSQL correspond to one message, with tool call details stored in JSONB format, maintained through incremental updates.

Storage architecture evolution for Session Events

This approach looks elegant, but it ran into severe performance bottlenecks in practice. The reason: the size of Agent tool call results is highly unpredictable. When an Agent matches a large directory via a command-line tool, the returned result can reach tens of KB or even exceed the entire Context size. Frequent incremental updates to JSONB fields cause lock contention and write amplification under high concurrency.

Background: PostgreSQL MVCC and JSONB Write Amplification PostgreSQL's JSONB type stores JSON data in binary format, supports GIN indexing and efficient key-value queries, and is a common choice for storing semi-structured data. However, PostgreSQL uses an MVCC (Multi-Version Concurrency Control) mechanism where each UPDATE operation actually writes a new row version, with old versions asynchronously cleaned up by the VACUUM process. When performing frequent incremental updates on rows containing large JSONB fields, each update copies the entire row's data, even if only a small field was modified. This "write amplification"

#Agent platform#Session Event#Universal Event#LLM streaming#SSE#PostgreSQL JSONB#event abstraction#control plane architecture#write amplification#Agent runtime
Share:

Related articles