Append a user message + enqueue a chat turn
Persists the user message and enqueues a ChatTurnWorkflow. Returns 202 Accepted with the persisted message id + the Temporal workflow id. The agent’s streamed response is consumed via GET /chat/sessions/<id>/events. Pass client_message_id for idempotent retries — a duplicate returns 409 with the original message id and no new turn is enqueued.
The response also includes since_cursor: the SSE stream id snapshotted right before this turn was enqueued. Pass it as ?since=<since_cursor> on the very next call to /chat/sessions/<id>/events so the tail skips envelopes from prior turns on this session — skipping the cursor on a 2nd+ turn against the same session causes the tail to return the previous turn’s final state.
To include images, first upload each via POST /chat/sessions/<id>/attachments/upload-url, then pass the returned blob_path values in attachments. message may be empty when at least one attachment is provided. Images are surfaced on later GET .../messages replays.
Authorizations
Authorization: Bearer <token> where <token> is either a neo_sk_<env>_<secret> API key (service account) or a Microsoft Entra ID access token (dashboard user).
Path Parameters
Body
Images to include with this turn. Each must first be uploaded via POST /chat/sessions/<id>/attachments/upload-url. At most 6 per turn.
Speed/quality tier for this turn (ENG-5851): FAST keeps the agent's configured model; SMART escalates a single turn to a stronger model. May be flipped per turn to switch mid-conversation. Defaults to FAST.
FAST, SMART Response
Success.
202 Accepted body — the turn is enqueued, the agent's response streams via SSE.
since_cursor is the Redis-stream event id snapshotted right before this turn
was enqueued. Callers tailing /chat/sessions/<id>/events should pass it as
?since=<since_cursor> (or Last-Event-Id: <since_cursor>) so the SSE tail
starts strictly after the previous turn's terminal envelopes. Skipping this on a
2nd+ turn against the same session causes the tail to return the previous turn's
final state. May be None on the first turn of a fresh session or under Redis
failure; consumers treat None as "tail from beginning."
