Skip to content

AG-UI Protocol Drift: arkavo-agui implements custom event system instead of spec-compliant AG-UI protocol #562

@superninja-app

Description

@superninja-app

AG-UI Protocol Drift Analysis: arkavo-agui vs Official Specification

Executive Summary

The arkavo-agui crate has severe structural drift from the official AG-UI protocol specification. Rather than implementing the standardized event-driven streaming protocol defined by AG-UI, the crate implements a custom, proprietary event system that shares only superficial naming similarities with the spec. The drift is fundamental — affecting event types, message types, data structures, serialization format, transport semantics, and API surface.

Drift Severity: CRITICAL

  • ~32 spec-defined event types → only 3 partially implemented (StateSnapshot, MessagesSnapshot, StateDelta)
  • 7 spec-defined message roles → 3 implemented (missing developer, tool, activity, reasoning)
  • Spec's streaming Start→Content→End pattern → replaced with custom MessageDelta pattern
  • Spec's SCREAMING_SNAKE_CASE event type discriminator → replaced with camelCase
  • Spec's RunAgentInput contract → not implemented
  • ~60+ custom event types added that are not in the spec

Detailed Findings

1. EVENT SYSTEM — Fundamental Structural Divergence

1.1 Missing Event Types (Spec → Not in Crate)

The AG-UI spec defines 32 event types (including deprecated). The crate is missing 29 of them:

Lifecycle Events (0/5 implemented correctly):

Spec Event Status Notes
RUN_STARTED ❌ Missing Replaced by custom LifecycleStart with sessionId instead of threadId/runId
RUN_FINISHED ❌ Missing Replaced by custom LifecycleEnd with reason instead of threadId/runId/result
RUN_ERROR ❌ Missing Replaced by custom LifecycleError with code+message but wrong field structure
STEP_STARTED ❌ Missing No equivalent
STEP_FINISHED ❌ Missing No equivalent

Text Message Events (0/4 implemented):

Spec Event Status Notes
TEXT_MESSAGE_START ❌ Missing Replaced by custom MessageDelta with incompatible structure
TEXT_MESSAGE_CONTENT ❌ Missing Replaced by custom MessageDelta with delta.text
TEXT_MESSAGE_END ❌ Missing No equivalent — no message completion signal
TEXT_MESSAGE_CHUNK ❌ Missing No equivalent

Tool Call Events (0/5 implemented correctly):

Spec Event Status Notes
TOOL_CALL_START ❌ Missing Custom ToolCall event is non-streaming, sends all args at once
TOOL_CALL_ARGS ❌ Missing No streaming tool arguments
TOOL_CALL_END ❌ Missing No tool call completion signal
TOOL_CALL_RESULT ❌ Missing Custom ToolResult has different structure
TOOL_CALL_CHUNK ❌ Missing No equivalent

Reasoning Events (0/7 implemented):

Spec Event Status Notes
REASONING_START ❌ Missing No reasoning support
REASONING_MESSAGE_START ❌ Missing
REASONING_MESSAGE_CONTENT ❌ Missing
REASONING_MESSAGE_END ❌ Missing
REASONING_MESSAGE_CHUNK ❌ Missing
REASONING_END ❌ Missing
REASONING_ENCRYPTED_VALUE ❌ Missing

Activity Events (0/2 implemented):

Spec Event Status Notes
ACTIVITY_SNAPSHOT ❌ Missing No activity support
ACTIVITY_DELTA ❌ Missing

Special Events (0/2 implemented):

Spec Event Status Notes
RAW ❌ Missing No passthrough event support
CUSTOM ❌ Missing No custom event support

Deprecated Thinking Events (0/5):

Spec Event Status Notes
THINKING_START ❌ Missing
THINKING_END ❌ Missing
THINKING_TEXT_MESSAGE_START ❌ Missing
THINKING_TEXT_MESSAGE_CONTENT ❌ Missing
THINKING_TEXT_MESSAGE_END ❌ Missing

Partially Implemented Events (3/32):

Spec Event Status Notes
STATE_SNAPSHOT ⚠️ Partial Has extra eventId field not in spec; missing timestamp/rawEvent base fields
MESSAGES_SNAPSHOT ⚠️ Partial Has extra eventId field; messages use wrong structure
STATE_DELTA ⚠️ Partial Uses patch field instead of spec's delta field; has extra eventId

1.2 Event Serialization Format Mismatch

Spec requires:

{
  "type": "TEXT_MESSAGE_START",
  "timestamp": 1234567890,
  "messageId": "msg-1",
  "role": "assistant"
}

Crate produces:

{
  "type": "messageDelta",
  "messageId": "msg-1",
  "delta": { "type": "text", "text": "Hello" }
}

Key differences:

  • Spec uses SCREAMING_SNAKE_CASE for event type discriminator values; crate uses camelCase
  • Spec uses type field with enum values like TEXT_MESSAGE_START; crate uses different type values like messageDelta, lifecycle.start
  • Spec uses serde tag rename_all = "SCREAMING_SNAKE_CASE"; crate uses rename_all = "camelCase"
  • Spec base event has timestamp and rawEvent; crate has no base event fields

2. MESSAGE TYPES — Incomplete and Incompatible

2.1 Missing Message Roles

Spec Role Status Notes
user ✅ Present
assistant ✅ Present
system ✅ Present
developer ❌ Missing
tool ❌ Missing Crate has no ToolMessage type
activity ❌ Missing
reasoning ❌ Missing

2.2 Message Structure Differences

Spec Message (discriminated union on role):

// Each role has specific fields
AssistantMessage: { id, role, content?, toolCalls?, name?, encryptedValue? }
UserMessage: { id, role, content: string | InputContent[], name? }
ToolMessage: { id, role, content, toolCallId, error?, encryptedValue? }
ActivityMessage: { id, role, activityType, content: Record<string, any> }
ReasoningMessage: { id, role, content, encryptedValue? }

Crate Message:

pub struct Message {
    pub id: String,
    pub role: MessageRole,  // Only User/Assistant/System
    pub content: String,    // Always String, never multimodal
    pub tool_calls: Option<Vec<ToolCall>>,
    pub metadata: Option<HashMap<String, Value>>,  // Not in spec
}

Differences:

  • Missing name field on messages
  • Missing encryptedValue field on messages
  • content is always String — spec allows string | InputContent[] for UserMessage (multimodal)
  • Extra metadata field not in spec
  • No discriminated union — flat struct with enum role

2.3 ToolCall Structure Mismatch

Spec ToolCall:

{
  id: string,
  type: "function",
  function: { name: string, arguments: string }  // arguments is JSON string
}

Crate ToolCall:

pub struct ToolCall {
    pub id: String,
    pub name: String,        // Flat, not nested under function
    pub arguments: Value,    // JSON Value, not String
}

Differences:

  • Missing type: "function" field
  • Missing nested function object — name and arguments are flat
  • arguments is serde_json::Value instead of String (JSON-encoded string)

3. TRANSPORT LAYER — Wrong Protocol Pattern

3.1 HTTP/SSE Endpoint

Spec requires: POST endpoint accepting RunAgentInput, returning SSE stream of BaseEvent

Crate implements: WebSocket-only with custom bidirectional message protocol — no HTTP/SSE support

3.2 RunAgentInput — Not Implemented

Spec defines:

interface RunAgentInput {
  threadId: string
  runId: string
  parentRunId?: string
  state: any
  messages: Message[]
  tools: Tool[]
  context: Context[]
  forwardedProps: any
}

Crate: No RunAgentInput type exists. The crate uses custom events like Connect, UserMessage, SubmitTask, etc.

3.3 Tool Definition — Not Implemented

Spec defines:

interface Tool {
  name: string
  description: string
  parameters: any  // JSON Schema
}

Crate: No Tool definition type. Tools are handled ad-hoc through custom events.

3.4 Context — Not Implemented

Spec defines:

interface Context {
  description: string
  value: string
}

Crate: No Context type exists.

4. CAPABILITY DISCOVERY — Not Implemented

The spec defines AgentCapabilities with categories:

  • identity — agent metadata
  • transport — SSE, WebSocket, binary protocol support
  • tools — tool calling configuration
  • output — structured output, MIME types
  • state — snapshots, deltas, memory
  • multiAgent — delegation, handoffs
  • reasoning — chain-of-thought, encrypted thinking
  • multimodal — image, audio, video, PDF, file input/output
  • execution — code execution, sandboxing, limits
  • humanInTheLoop — approvals, interventions, feedback

Crate: No capability discovery mechanism exists.

5. ADDITIONAL FEATURES NOT IN SPEC (~60+ custom events)

The crate defines numerous custom events that have no equivalent in the AG-UI spec:

UI Generation (9 events): SubmitPrompt, Plan, PartStream, ApplyPart, AppliedPart, CancelGeneration, Undo, Redo, UndoAvailable

Configuration Management (8 events): GetAgentConfig, AgentConfigSnapshot, UpdateAgentConfig, ConfigUpdateResult, ValidateAgentConfig, ConfigValidationResult, RestoreAgentConfig, ConfigRestoreResult

Budget/Cost (10 events): BudgetStatusUpdate, BudgetAlert, SpendingRecorded, BudgetConfigUpdate, ModelSelected, GetBudgetStatus, SetAgentBudget, ResetBudgetWindow, GetCostMetrics, CostMetricsUpdate, GetROIDashboard, ROIDashboardUpdate, GetCostPrediction, CostPredictionUpdate

Mesh/Discovery (5 events): RequestMeshStatus, MeshStatus, AgentDiscovered, AgentLost, A2AMessage

Task Management (5 events): RequestTaskList, TaskList, SubmitTask, TaskSubmitted, TaskStatusChanged

Security (5 events): GetSecurityStatus, SecurityStatusUpdate, TdfAuditEvent, PolicyApplied, GetDataPlaneStatus, DataPlaneStatusUpdate, DataPlaneTransfer

Learning/Telemetry (6 events): RequestLearningStatus, LearningStatusUpdate, RoutingEvaluation, RoutingOutcome, LessonExtracted, TelemetryEvent

System (6 events): RequestStatus, StatusUpdate, SystemNotification, ComputeBudgetUpdate, AgentSystemMetrics, AgentTaskCounts

Chat (4 events): Connect, UserMessage, ChatOpen, ChatClose, UserEdit, SaveSession

Custom Protocol (3 events): TypingStart, TypingStop, UiAction

6. VERSION COMPATIBILITY

Aspect Spec Crate
Protocol version Events define SCREAMING_SNAKE_CASE enum No version tracking
Rust SDK reference ag-ui-core community crate exists Not used as dependency
Serialization format JSON with type tag, protobuf binary JSON with type tag (different values)
Backward compat Deprecated THINKING_* events maintained N/A — never implemented

Impact Assessment

Critical Impact

  1. Zero interoperability: Any AG-UI compliant client (CopilotKit, ag-ui-client, etc.) cannot connect to this crate's WebSocket endpoint — the event format is completely incompatible.
  2. No standard streaming: The spec's Start→Content→End streaming pattern for text messages and tool calls is not implemented, preventing incremental rendering.
  3. No run lifecycle: Without RUN_STARTED/RUN_FINISHED/RUN_ERROR, clients cannot track agent execution state.

High Impact

  1. Missing tool call streaming: Tool arguments are sent as a single blob instead of being streamed incrementally.
  2. No reasoning support: The entire reasoning/thinking event family is absent.
  3. No capability discovery: Clients cannot query what the agent supports.
  4. No multimodal messages: UserMessage.content is always a string, not supporting InputContent[].

Medium Impact

  1. Missing message roles: developer, tool, activity, reasoning roles not supported.
  2. No activity events: No structured UI progress/status events.
  3. No event compaction/serialization: No support for persisting and restoring event streams.

Low Impact

  1. Extra eventId fields: Present on snapshot/delta events but not in spec (may be useful for reconnection but non-standard).
  2. metadata field on messages: Not in spec but relatively harmless.

Remediation Plan

Phase 1: Core Protocol Alignment (Priority: CRITICAL)

P1.1 — Adopt the official Rust SDK types

  • Add ag-ui-core as a dependency (from sdks/community/rust/)
  • Or re-implement the canonical types matching the TypeScript SDK exactly
  • Implement all 7 message roles with correct field structures
  • Implement ToolCall with nested function object and string arguments

P1.2 — Implement all 32 spec event types

  • Implement EventType enum with SCREAMING_SNAKE_CASE serialization
  • Implement BaseEvent with type, timestamp, rawEvent
  • Implement all lifecycle events: RUN_STARTED, RUN_FINISHED, RUN_ERROR, STEP_STARTED, STEP_FINISHED
  • Implement text message streaming: TEXT_MESSAGE_START, TEXT_MESSAGE_CONTENT, TEXT_MESSAGE_END, TEXT_MESSAGE_CHUNK
  • Implement tool call streaming: TOOL_CALL_START, TOOL_CALL_ARGS, TOOL_CALL_END, TOOL_CALL_RESULT, TOOL_CALL_CHUNK
  • Implement state events: STATE_SNAPSHOT, STATE_DELTA, MESSAGES_SNAPSHOT (fix field names)
  • Implement activity events: ACTIVITY_SNAPSHOT, ACTIVITY_DELTA
  • Implement reasoning events: REASONING_START, REASONING_MESSAGE_START, REASONING_MESSAGE_CONTENT, REASONING_MESSAGE_END, REASONING_MESSAGE_CHUNK, REASONING_END, REASONING_ENCRYPTED_VALUE
  • Implement special events: RAW, CUSTOM

P1.3 — Implement RunAgentInput

  • Define RunAgentInput with threadId, runId, state, messages, tools, context, forwardedProps
  • Implement Tool and Context types
  • Wire up HTTP POST endpoint accepting RunAgentInput

Phase 2: Transport Layer (Priority: HIGH)

P2.1 — Add HTTP/SSE transport

  • Implement POST endpoint at standard path (e.g., /api/agent)
  • Accept RunAgentInput as request body
  • Return SSE stream of BaseEvent objects
  • Maintain WebSocket as optional additional transport

P2.2 — Add capability discovery

  • Implement getCapabilities() endpoint
  • Return AgentCapabilities with appropriate flags

Phase 3: Streaming Patterns (Priority: HIGH)

P3.1 — Implement Start→Content→End streaming for text

  • Replace MessageDelta with proper TEXT_MESSAGE_STARTTEXT_MESSAGE_CONTENTTEXT_MESSAGE_END sequence
  • Ensure messageId links all events in a message stream

P3.2 — Implement streaming tool calls

  • Replace monolithic ToolCall event with TOOL_CALL_STARTTOOL_CALL_ARGSTOOL_CALL_END sequence
  • Stream JSON arguments incrementally

Phase 4: Custom Extension Strategy (Priority: MEDIUM)

P4.1 — Migrate custom events to CUSTOM event type

  • Wrap all Arkavo-specific events (budget, mesh, security, learning, etc.) inside CUSTOM events
  • Use name field to discriminate: e.g., { type: "CUSTOM", name: "arkavo.budget_status", value: {...} }
  • This preserves all existing functionality while becoming spec-compliant

P4.2 — Map existing features to spec patterns

  • Map TypingStart/TypingStop to activity events
  • Map task management to step events where appropriate
  • Map configuration events to state management events where appropriate

Phase 5: Quality & Testing (Priority: MEDIUM)

P5.1 — Add protocol conformance tests

  • Test event serialization matches spec format exactly
  • Test against official AG-UI SDK test fixtures if available
  • Verify interoperability with ag-ui-client TypeScript package

P5.2 — Update frontend TypeScript types

  • Update static/agui/events.ts to match official AG-UI event types
  • Update static/agui/ws.ts to handle spec-compliant events
  • Consider importing from @ag-ui/core package

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions