Skip to content

Streaming

The chat client supports real-time streaming via Server-Sent Events (SSE). Use StreamChat to get an incremental token stream from the AI model.

Basic Example

package main

import (
    "context"
    "fmt"
    "log"

    sdk "github.com/emergent-company/emergent.memory/apps/server/pkg/sdk"
    "github.com/emergent-company/emergent.memory/apps/server/pkg/sdk/chat"
)

func streamResponse(client *sdk.Client, conversationID string) {
    ctx := context.Background()

    stream, err := client.Chat.StreamChat(ctx, &chat.StreamRequest{
        ConversationID: conversationID,
        Message:        "What objects are in this project?",
    })
    if err != nil {
        log.Fatal("failed to start stream:", err)
    }
    defer stream.Close()

    fmt.Print("Response: ")
    for event := range stream.Events() {
        switch event.Type {
        case "token":
            fmt.Print(event.Token)
        case "done":
            fmt.Println()
            fmt.Println("[stream complete]")
            return
        case "error":
            log.Printf("stream error: %s", event.Error)
            return
        }
    }

    // Check for stream-level error after channel closes
    if err := stream.Err(); err != nil {
        log.Printf("stream ended with error: %v", err)
    }
}

StreamRequest

type StreamRequest struct {
    ConversationID string // Required: ID of the conversation to stream into
    Message        string // Required: User message to send
}

Stream Type

type Stream struct { /* ... */ }

func (s *Stream) Events() <-chan *StreamEvent  // Receive events as they arrive
func (s *Stream) Close() error                 // Close the stream and release resources
func (s *Stream) Err() error                   // Check for a stream-level error after close

Events() returns a read-only channel. The channel is closed automatically when the stream ends (either with a done event or an error).

StreamEvent Types

Type Meaning Field
"meta" Stream metadata ConversationID contains the conversation ID
"token" Incremental text token Token contains text to append to output
"done" Stream complete Message may contain final message text
"error" Stream-level error Error contains error description

Usage Pattern

Always defer stream.Close() immediately after receiving the *Stream. This ensures the HTTP connection is released even if you exit early.

stream, err := client.Chat.StreamChat(ctx, req)
if err != nil {
    return err
}
defer stream.Close()  // ← always close

for event := range stream.Events() {
    // process events
}

Creating a Conversation First

StreamChat requires an existing conversation ID. Create one first with CreateConversation:

conv, err := client.Chat.CreateConversation(ctx, &chat.CreateConversationRequest{
    Title: "My conversation",
})
if err != nil {
    log.Fatal(err)
}

stream, err := client.Chat.StreamChat(ctx, &chat.StreamRequest{
    ConversationID: conv.ID,
    Message:        "Hello!",
})

See the chat reference for the complete Chat client API.