CopilotKit

Events

The AG-UI Protocol SDK uses a streaming event-based architecture. Events are the fundamental units of communication between agents and the frontend. This section documents the event types and their properties in the Go SDK.

EventType Constants

The EventType constants define all possible event types in the system:

type EventType string

const (
    EventTypeTextMessageStart   EventType = "TEXT_MESSAGE_START"
    EventTypeTextMessageContent EventType = "TEXT_MESSAGE_CONTENT"
    EventTypeTextMessageEnd     EventType = "TEXT_MESSAGE_END"
    EventTypeTextMessageChunk   EventType = "TEXT_MESSAGE_CHUNK"
    EventTypeToolCallStart      EventType = "TOOL_CALL_START"
    EventTypeToolCallArgs       EventType = "TOOL_CALL_ARGS"
    EventTypeToolCallEnd        EventType = "TOOL_CALL_END"
    EventTypeToolCallChunk      EventType = "TOOL_CALL_CHUNK"
    EventTypeToolCallResult     EventType = "TOOL_CALL_RESULT"
    EventTypeStateSnapshot      EventType = "STATE_SNAPSHOT"
    EventTypeStateDelta         EventType = "STATE_DELTA"
    EventTypeMessagesSnapshot   EventType = "MESSAGES_SNAPSHOT"
    EventTypeRaw                EventType = "RAW"
    EventTypeCustom             EventType = "CUSTOM"
    EventTypeRunStarted         EventType = "RUN_STARTED"
    EventTypeRunFinished        EventType = "RUN_FINISHED"
    EventTypeRunError           EventType = "RUN_ERROR"
    EventTypeStepStarted        EventType = "STEP_STARTED"
    EventTypeStepFinished       EventType = "STEP_FINISHED"

    // Thinking events for reasoning phase support
    EventTypeThinkingStart              EventType = "THINKING_START"
    EventTypeThinkingEnd                EventType = "THINKING_END"
    EventTypeThinkingTextMessageStart   EventType = "THINKING_TEXT_MESSAGE_START"
    EventTypeThinkingTextMessageContent EventType = "THINKING_TEXT_MESSAGE_CONTENT"
    EventTypeThinkingTextMessageEnd     EventType = "THINKING_TEXT_MESSAGE_END"
)

Event Interface

All events implement the Event interface, which provides a common contract for event handling:

type Event interface {
    // Type returns the event type
    Type() EventType

    // Timestamp returns the event timestamp (Unix milliseconds)
    Timestamp() *int64

    // SetTimestamp sets the event timestamp
    SetTimestamp(timestamp int64)

    // ThreadID returns the thread ID associated with this event
    ThreadID() string

    // RunID returns the run ID associated with this event
    RunID() string

    // Validate validates the event structure and content
    Validate() error

    // ToJSON serializes the event to JSON for cross-SDK compatibility
    ToJSON() ([]byte, error)

    // GetBaseEvent returns the underlying base event
    GetBaseEvent() *BaseEvent
}

BaseEvent

All events embed the BaseEvent struct, which provides common fields and functionality:

type BaseEvent struct {
    EventType   EventType `json:"type"`
    TimestampMs *int64    `json:"timestamp,omitempty"`
    RawEvent    any       `json:"rawEvent,omitempty"`
}
FieldTypeDescription
EventTypeEventTypeThe type of event (discriminator field)
TimestampMs*int64Timestamp when the event was created (Unix milliseconds)
RawEventanyOriginal event data if this event was transformed

Creating a Base Event


// Create a new base event with automatic timestamp
baseEvent := events.NewBaseEvent(events.EventTypeCustom)

Text Message Events

These events handle streaming text message content from agents.

TextMessageStartEvent

Signals the start of a streaming text message.

type TextMessageStartEvent struct {
    *BaseEvent
    MessageID string  `json:"messageId"`
    Role      *string `json:"role,omitempty"`
}
FieldTypeDescription
MessageIDstringUnique identifier for the message
Role*stringRole of the message sender (e.g., "assistant", "user")

Usage Example:

// Create a text message start event
event := events.NewTextMessageStartEvent("msg-123", events.WithRole("assistant"))

// Handle the event
switch e := event.(type) {
case *events.TextMessageStartEvent:
    fmt.Printf("Message started: %s with role: %s\n", e.MessageID, *e.Role)
}

TextMessageContentEvent

Contains a piece of streaming text message content.

type TextMessageContentEvent struct {
    *BaseEvent
    MessageID string `json:"messageId"`
    Delta     string `json:"delta"`
}
FieldTypeDescription
MessageIDstringID of the message this content belongs to
DeltastringThe text content chunk

Usage Example:

// Create a content event
event := events.NewTextMessageContentEvent("msg-123", "Hello, world!")

// Handle streaming content
switch e := event.(type) {
case *events.TextMessageContentEvent:
    fmt.Print(e.Delta) // Stream the content to output
}

TextMessageEndEvent

Signals the end of a streaming text message.

type TextMessageEndEvent struct {
    *BaseEvent
    MessageID string `json:"messageId"`
}
FieldTypeDescription
MessageIDstringID of the message that has ended

Usage Example:

// Create an end event
event := events.NewTextMessageEndEvent("msg-123")

// Handle message completion
switch e := event.(type) {
case *events.TextMessageEndEvent:
    fmt.Printf("\nMessage %s completed\n", e.MessageID)
}

Tool Call Events

These events handle tool/function calls made by the agent.

ToolCallStartEvent

Signals the start of a tool call.

type ToolCallStartEvent struct {
    *BaseEvent
    ToolCallID      string  `json:"toolCallId"`
    ToolCallName    string  `json:"toolCallName"`
    ParentMessageID *string `json:"parentMessageId,omitempty"`
}
FieldTypeDescription
ToolCallIDstringUnique identifier for the tool call
ToolCallNamestringName of the tool being called
ParentMessageID*stringID of the parent message (if applicable)

Usage Example:

// Create a tool call start event
event := events.NewToolCallStartEvent(
    "tool-456",
    "calculate",
    events.WithParentMessageID("msg-123"),
)

// Handle tool call initiation
switch e := event.(type) {
case *events.ToolCallStartEvent:
    fmt.Printf("Tool %s started: %s\n", e.ToolCallName, e.ToolCallID)
}

ToolCallArgsEvent

Contains streaming tool call arguments.

type ToolCallArgsEvent struct {
    *BaseEvent
    ToolCallID string `json:"toolCallId"`
    Delta      string `json:"delta"`
}
FieldTypeDescription
ToolCallIDstringID of the tool call
DeltastringJSON string chunk of the arguments

Usage Example:

// Create a tool call args event
event := events.NewToolCallArgsEvent("tool-456", `{"x": 10, "y": 20}`)

// Accumulate streaming arguments
var argsBuffer strings.Builder
switch e := event.(type) {
case *events.ToolCallArgsEvent:
    argsBuffer.WriteString(e.Delta)
}

ToolCallEndEvent

Signals the end of a tool call.

type ToolCallEndEvent struct {
    *BaseEvent
    ToolCallID string `json:"toolCallId"`
}
FieldTypeDescription
ToolCallIDstringID of the tool call that has ended

ToolCallResultEvent

Contains the result of a tool call execution.

type ToolCallResultEvent struct {
    *BaseEvent
    MessageID  string  `json:"messageId"`
    ToolCallID string  `json:"toolCallId"`
    Content    string  `json:"content"`
    Role       *string `json:"role,omitempty"`
}
FieldTypeDescription
MessageIDstringID of the result message
ToolCallIDstringID of the tool call
ContentstringResult content from the tool
Role*stringRole (typically "tool")

Run Lifecycle Events

These events track the lifecycle of agent runs.

RunStartedEvent

Signals the start of an agent run.

type RunStartedEvent struct {
    *BaseEvent
    ThreadIDValue string `json:"threadId"`
    RunIDValue    string `json:"runId"`
}
FieldTypeDescription
ThreadIDValuestringID of the conversation thread
RunIDValuestringID of the agent run

Usage Example:

// Create a run started event
event := events.NewRunStartedEvent("thread-789", "run-012")

// Handle run initiation
switch e := event.(type) {
case *events.RunStartedEvent:
    fmt.Printf("Run %s started in thread %s\n", e.RunID(), e.ThreadID())
}

RunFinishedEvent

Signals the successful completion of an agent run.

type RunFinishedEvent struct {
    *BaseEvent
    ThreadIDValue string      `json:"threadId"`
    RunIDValue    string      `json:"runId"`
    Result        interface{} `json:"result,omitempty"`
}
FieldTypeDescription
ThreadIDValuestringID of the conversation thread
RunIDValuestringID of the agent run
Resultinterface{}Result data from the agent run

RunErrorEvent

Signals an error during an agent run.

type RunErrorEvent struct {
    *BaseEvent
    Code       *string `json:"code,omitempty"`
    Message    string  `json:"message"`
    RunIDValue string  `json:"runId,omitempty"`
}
FieldTypeDescription
Code*stringError code
MessagestringError message
RunIDValuestringID of the run that encountered the error

Usage Example:

// Create an error event
event := events.NewRunErrorEvent(
    "Tool execution failed",
    events.WithErrorCode("TOOL_ERROR"),
    events.WithRunID("run-012"),
)

State Management Events

These events handle state synchronization between agent and client.

StateSnapshotEvent

Contains a complete snapshot of the state.

type StateSnapshotEvent struct {
    *BaseEvent
    Snapshot any `json:"snapshot"`
}
FieldTypeDescription
SnapshotanyComplete state snapshot

Usage Example:

// Create a state snapshot
state := map[string]interface{}{
    "currentStep": "processing",
    "progress": 75,
}
event := events.NewStateSnapshotEvent(state)

StateDeltaEvent

Contains incremental state changes using JSON Patch operations (RFC 6902).

type StateDeltaEvent struct {
    *BaseEvent
    Delta []JSONPatchOperation `json:"delta"`
}

type JSONPatchOperation struct {
    Op    string `json:"op"`              // "add", "remove", "replace", "move", "copy", "test"
    Path  string `json:"path"`            // JSON Pointer path
    Value any    `json:"value,omitempty"` // Value for add, replace, test operations
    From  string `json:"from,omitempty"`  // Source path for move, copy operations
}
FieldTypeDescription
Delta[]JSONPatchOperationArray of JSON Patch operations

Usage Example:

// Create state delta with JSON Patch operations
delta := []events.JSONPatchOperation{
    {
        Op:    "replace",
        Path:  "/progress",
        Value: 100,
    },
    {
        Op:   "add",
        Path: "/completedAt",
        Value: time.Now().Unix(),
    },
}
event := events.NewStateDeltaEvent(delta)

Thinking Events

These events support reasoning/thinking phases where the agent shows its thought process.

ThinkingStartEvent

Signals the start of a thinking phase.

type ThinkingStartEvent struct {
    *BaseEvent
    Title *string `json:"title,omitempty"`
}
FieldTypeDescription
Title*stringOptional title for the thinking phase

ThinkingTextMessageContentEvent

Contains streaming thinking content.

type ThinkingTextMessageContentEvent struct {
    *BaseEvent
    Delta string `json:"delta"`
}
FieldTypeDescription
DeltastringThinking content chunk

Event Decoding

The SDK provides an EventDecoder for parsing SSE events into typed Go structs:

    "github.com/ag-ui-protocol/ag-ui/sdks/community/go/pkg/core/events"
    "github.com/sirupsen/logrus"
)

// Create a decoder
logger := logrus.New()
decoder := events.NewEventDecoder(logger)

// Decode an SSE event
event, err := decoder.DecodeEvent("TEXT_MESSAGE_START", sseData)
if err != nil {
    log.Printf("Failed to decode event: %v", err)
    return
}

// Type-safe event handling
switch e := event.(type) {
case *events.TextMessageStartEvent:
    fmt.Printf("Message started: %s\n", e.MessageID)
case *events.TextMessageContentEvent:
    fmt.Printf("Content: %s\n", e.Delta)
case *events.ToolCallStartEvent:
    fmt.Printf("Tool call: %s\n", e.ToolCallName)
}

Event Validation

All events support validation to ensure they conform to the protocol specification:

Individual Event Validation

event := events.NewTextMessageStartEvent("")

// Validate the event
if err := event.Validate(); err != nil {
    // Handle validation error
    fmt.Printf("Invalid event: %v\n", err)
}

Sequence Validation

The SDK can validate entire event sequences to ensure they follow the protocol rules:

// Validate a sequence of events
events := []events.Event{
    events.NewRunStartedEvent("thread-1", "run-1"),
    events.NewTextMessageStartEvent("msg-1"),
    events.NewTextMessageContentEvent("msg-1", "Hello"),
    events.NewTextMessageEndEvent("msg-1"),
    events.NewRunFinishedEvent("thread-1", "run-1"),
}

if err := events.ValidateSequence(events); err != nil {
    // Handle sequence validation error
    fmt.Printf("Invalid event sequence: %v\n", err)
}

Sequence validation ensures:

  • Runs are started before they can be finished or errored
  • Messages are started before content can be added or ended
  • Tool calls follow the proper start → args → end lifecycle
  • Events maintain referential integrity

ID Generation

The SDK provides utilities for generating unique IDs:

// Generate various ID types
threadID := events.GenerateThreadID()  // "thread-{uuid}"
runID := events.GenerateRunID()        // "run-{uuid}"
messageID := events.GenerateMessageID() // "msg-{uuid}"
toolCallID := events.GenerateToolCallID() // "tool-{uuid}"
stepID := events.GenerateStepID()      // "step-{uuid}"

// Use with event creation
event := events.NewRunStartedEvent(
    events.GenerateThreadID(),
    events.GenerateRunID(),
)

Custom and Raw Events

CustomEvent

For application-specific events:

type CustomEvent struct {
    *BaseEvent
    Name  string `json:"name"`
    Value any    `json:"value,omitempty"`
}

Usage Example:

// Create a custom event
event := events.NewCustomEvent(
    "user.preference.changed",
    events.WithValue(map[string]string{
        "theme": "dark",
    }),
)

RawEvent

For passing through external event data:

type RawEvent struct {
    *BaseEvent
    Event  any     `json:"event"`
    Source *string `json:"source,omitempty"`
}

Usage Example:

// Create a raw event
event := events.NewRawEvent(
    externalEventData,
    events.WithSource("external-system"),
)