---
title: "Stream Chat Post"
method: POST
path: "/api/chat/sessions/{session_id}/stream"
tags: ["v2", "chat", "chat"]
---

# Stream Chat Post

`POST /api/chat/sessions/{session_id}/stream`

Start a new turn and return an AI SDK UI message stream.

Returns an SSE stream (``text/event-stream``) with Vercel AI SDK chunks
(text fragments, tool-call UI, tool results). The generation runs in a
background task that survives client disconnects; reconnect via
``GET /sessions/{session_id}/stream`` to resume.

Follow-up messages typed while a turn is already running should use
``POST /sessions/{session_id}/messages/pending``. If an older client still
posts that follow-up here, we queue it defensively but still return a valid
empty UI-message stream so AI SDK transports never receive a JSON body from
the stream endpoint.

Args:
    session_id: The chat session identifier.
    request: Request body with message, is_user_message, and optional context.
    user_id: Authenticated user ID.

## Path parameters

- `session_id` string, required

## Request body

- StreamChatRequest — Request model for streaming chat with optional context.
  - `message` string, required
  - `is_user_message` boolean
  - `context` object, nullable
  - `file_ids` string[], nullable
  - `mode` 'fast' | 'extended_thinking', nullable — Autopilot mode: 'fast' for baseline LLM, 'extended_thinking' for Claude Agent SDK. If None, uses the server default (extended_thinking).
  - `model` 'standard' | 'advanced', nullable — Model tier: 'standard' for the default model, 'advanced' for the highest-capability model. If None, the server applies per-user LD targeting then falls back to config.
  - `message_id` string, nullable — Optional per-click UUID generated by the frontend. Becomes the persisted ``ChatMessage.id`` (PK). Frontend / network / RMQ-redelivery retransmits of the same logical send reuse the id, so the Postgres unique-constraint on the PK is the atomic dedup primitive: a duplicate INSERT returns a subscribe-only response without creating a parallel turn. Distinct user clicks (even with identical text) MUST send different ids — the frontend's per-click ``crypto.randomUUID()`` guarantees that.

## Response `200`

Successful Response

- unknown

## Other responses

- `401` — Authentication required
- `402` — Subscription required (NO_TIER user, paywall on)
- `404` — Session not found or access denied
- `422` — Validation Error
- `429` — Cost rate-limit, call-frequency cap, or per-user concurrent-turn limit exceeded
- `503` — Chat service degraded (Redis unavailable for rate limit or stream registry); client should honour the Retry-After header before retrying.

---

[API](https://skmtc.net/significant-gravitas/apis/autogpt-agent-server.md) · [All operations](https://skmtc.net/significant-gravitas/apis/autogpt-agent-server/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/significant-gravitas/autogpt-agent-server/versions/382041c7ecb2/schema)
