Skip to Content
Welcome to RitoSwap's documentation!

Streaming Context (Real-Time State)

In a streaming AI application, “context” is not just the static history; it’s the live, flowing state of the conversation. RitoSwap uses a custom Server-Sent Events (SSE) protocol to keep the Client and Server in perfect sync.

The SSE Protocol

Standard text streaming is insufficient for our needs because we need to stream structured events (Tool Inputs, Tool Outputs, Errors) alongside the text generation.

Our sse-stream.ts utility defines a custom protocol:

Event TypePayloadPurpose
start{ messageId }Signals the beginning of a response.
text-delta{ delta }A chunk of generated text.
tool-input-start{ toolCallId, toolName }The agent has decided to call a tool.
tool-input-delta{ delta }Streaming the arguments for the tool (e.g., JSON).
tool-output-available{ output }The Full JSON result of the tool (for the UI).
finish{}The stream is complete.

This protocol ensures that the Client’s ToolActivityStore always has the exact same context as the Server’s execution log.

Message Conversion: Normalization

The UI sends messages in a format optimized for React rendering (with parts, uiState, etc.). The LLM expects messages in a strict format (System, Human, AI).

The message-converter.ts acts as the translator between these two worlds.

The UiMessage Format

The client sends:

{ "role": "user", "parts": [ { "type": "text", "text": "Draw a cat" }, { "type": "image", "data": "..." } ] }

The BaseMessage Format

The converter flattens each message into a LangChain HumanMessage/AIMessage. Today we collapse everything to plain text via contentToText, so non-text parts (images, UI hints) drop out before the LLM receives the history:

// dapp/app/lib/llm/message-converter.ts const content = contentToText(msg.content ?? msg.parts ?? msg.text ?? ''); switch (msg.role) { case 'user': messages.push(new HumanMessage(content)); break; case 'assistant': messages.push(new AIMessage(content)); break; }

This keeps the provider-facing transcript linear and predictable. If we later route to a vision-capable model, this is the seam where we would preserve image parts instead of stripping them.

Error Context

If a tool fails or the stream is interrupted, the context must be preserved.

  • Tool Errors: If a tool throws an error, we catch it on the server, format it as a “Tool Output” (e.g., Error: API unavailable), and feed it back to the LLM. This allows the agent to apologize or retry rather than crashing.
  • Stream Interruption: If the user closes the tab, the server detects the closed stream (isClosed()) and aborts execution to save resources, preventing “zombie context” from continuing to run in the background.

RitoSwap Docs does not store, collect or access any of your conversations. All saved prompts are stored locally in your browser only.