Skip to main content
The AI advisor uses Server-Sent Events (SSE) for real-time streaming. Every /ai/stream request opens a persistent HTTP connection; the backend pushes events as they happen rather than waiting for a complete response.

Event format

Each event is a JSON object on a single line, prefixed with data: and followed by a double newline:
The Flutter AiService parses each line, strips the data: prefix, and decodes the JSON.

Event types

phase

Indicates which stage the pipeline is in. Flutter updates the loading indicator text.

tool

Fires when a tool call starts. Flutter shows a dismissible badge in the chat bubble.
The Flutter _toolLabels map in chat_provider.dart converts tool names to readable labels:

token

Incremental text from Claude’s streaming output. Flutter appends each token to the current message bubble in real time.

done

Final event. Contains the complete assembled text plus any widgets and follow-up suggestions.

error

Replaces done if the pipeline fails. Flutter shows an error bubble with fallback suggestions.

Widget response schema

When the answer is better expressed as a chart or card, Claude returns a structured widget object in the done event’s widgets array. Flutter’s widget_renderer.dart renders each widget natively.

Chart widget

Summary card

Alert card

Multi-widget


HTTP headers

The /ai/stream endpoint sets three headers critical for SSE to work through nginx:
X-Accel-Buffering: no is essential — without it, nginx buffers the entire response before forwarding, which defeats the purpose of streaming.

Flutter SSE parsing

The provider in chat_provider.dart listens to this stream and updates state for each event type, triggering selective widget rebuilds via Riverpod.

Non-streaming endpoint

POST /ai/ask runs the same pipeline but collects all SSE events internally and returns a single AgentResponse. Use this for programmatic calls where you don’t need real-time streaming:
Response: