> ## Documentation Index
> Fetch the complete documentation index at: https://docs.autosage.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Chat & streaming

> Consume the streaming chat endpoint over Server-Sent Events, or use the non-streaming alternative.

AutoSage can stream live progress, sources, charts, and final answer content so your users can follow a run as it happens. This guide covers the event stream, how to read it, and the non-streaming alternative.

## The streaming endpoint

`POST /chats/:id/messages/stream` sends a message to an existing chat and returns the response as **Server-Sent Events (SSE)**. The connection stays open, emitting events until the response is complete.

```bash theme={null}
export AUTOSAGE_KEY="sk_live_your_key_here"
export AUTOSAGE_URL="https://api.autosage.ai/api/v1"

curl -N -X POST "$AUTOSAGE_URL/chats/CHAT_ID/messages/stream" \
  -H "Authorization: Bearer $AUTOSAGE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "What is our refund window, and how has it changed?",
    "model": "MODEL_ID"
  }'
```

The `-N` flag disables curl's output buffering so you see events as they stream.

## Event types

Each SSE message carries an event with a JSON payload. Handle these types:

| Event                               | What it carries                         | How to handle it                                                                                                   |
| ----------------------------------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| `ping`                              | Keep-alive heartbeat                    | Ignore it. It only keeps the connection open.                                                                      |
| `user_message`                      | Confirmation of the message you sent    | Optional — useful to render the user's turn.                                                                       |
| `agent_thought`                     | A progress update from a multi-step run | Show as optional progress UI.                                                                                      |
| `data_preview`                      | A preview of available grounded data    | Use for optional context or progress UI.                                                                           |
| `todo_update`                       | Updated task state from the agent       | Refresh task or progress UI.                                                                                       |
| `mcp_tool_call` / `mcp_tool_result` | Tool activity from an MCP server        | Show only when your product exposes tool progress.                                                                 |
| `final_response`                    | The assistant's answer in `content`     | Treat `isComplete: true` as the canonical complete answer. Also support partial events for protocol compatibility. |
| `sources`                           | Cited source passages                   | Render as citations when they arrive.                                                                              |
| `chart`                             | A structured chart the answer produced  | Render the chart.                                                                                                  |
| `tokens`                            | Usage information for the turn          | Record for accounting if needed.                                                                                   |
| `done`                              | The stream has finished successfully    | Close the connection.                                                                                              |
| `error`                             | An error occurred during generation     | Surface the message and close the connection.                                                                      |

<Note>
  The main runtime normally emits one `final_response` with `isComplete: true` and the complete answer in `content`. Clients should also support partial `final_response` events: append partial `content`, then replace the accumulated text with the canonical `content` when `isComplete` is `true`.
</Note>

## Read the stream in JavaScript

This example reads the SSE body with `fetch`, parses each event, and accumulates the answer.

```js theme={null}
const res = await fetch(
  `${AUTOSAGE_URL}/chats/${chatId}/messages/stream`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${AUTOSAGE_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      content: "What is our refund window?",
      model: "MODEL_ID",
    }),
  }
);

const reader = res.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
let answer = "";

stream: while (true) {
  const { value, done } = await reader.read();
  if (done) break;

  buffer += decoder.decode(value, { stream: true });
  const messages = buffer.split("\n\n");
  buffer = messages.pop() ?? ""; // keep the incomplete trailing chunk

  for (const message of messages) {
    const eventLine = message.match(/^event:\s*(.+)$/m)?.[1];
    const dataLine = message.match(/^data: (.+)$/m)?.[1];
    if (!dataLine) continue;

    const payload = JSON.parse(dataLine);

    const eventType = payload.type ?? eventLine;

    switch (eventType) {
      case "ping":
        break; // keep-alive, ignore
      case "final_response":
        answer = payload.isComplete
          ? payload.content // canonical complete answer
          : answer + payload.content; // compatible with partial events
        renderAnswer(answer);
        break;
      case "sources":
        renderSources(payload.sources);
        break;
      case "chart":
        renderChart(payload.chart);
        break;
      case "done":
        break stream; // stream complete
      case "error":
        showError(payload.message);
        break stream;
    }
  }
}
```

<Tip>
  For the best experience, show progress events while the run is active, render `final_response` content when it arrives, and show `sources` as soon as they are emitted. Always handle `done` and `error` to close the stream cleanly, and treat `ping` as a no-op.
</Tip>

## One active stream per chat

A chat has **one active stream at a time**. If the connection drops mid-response, the partial answer generated so far is saved to the chat. Reopen the chat to see what was produced and continue the conversation from there — you don't lose progress.

To stop a stream in progress, call:

```bash theme={null}
curl -X POST "$AUTOSAGE_URL/chats/CHAT_ID/stop" \
  -H "Authorization: Bearer $AUTOSAGE_KEY"
```

## Non-streaming alternative

If you don't need a live experience, `POST /chats/:id/messages` returns the complete response in a single JSON body once generation finishes.

```bash theme={null}
curl -X POST "$AUTOSAGE_URL/chats/CHAT_ID/messages" \
  -H "Authorization: Bearer $AUTOSAGE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "What is our refund window?",
    "model": "MODEL_ID"
  }'
```

The response contains the full answer text, its sources, and usage information — the same content the stream produces, delivered all at once.

## Next steps

<CardGroup cols={2}>
  <Card title="Chat lifecycle" icon="comments" href="/developers/lifecycles/chat-lifecycle">
    How a chat turn is created, streamed, saved, and resumed.
  </Card>

  <Card title="Streaming reference" icon="bolt" href="/chat/streaming">
    The event protocol in full detail.
  </Card>

  <Card title="Chats API" icon="code" href="/developers/api/chats">
    Endpoints for creating chats and sending messages.
  </Card>

  <Card title="Rate limits & credits" icon="gauge" href="/developers/rate-limits">
    Handle backoff and credit balance in your client.
  </Card>
</CardGroup>
