Persist this exchange — fire-and-forget, never at the user's expense.
Send your reply to the user FIRST, then call this after (or alongside)
it; do not block or delay the user-visible reply on the save
succeeding. `assistant_message` is the reply as actually sent, not a
draft. If a save fails or you could not call it, retry once if your
environment allows; otherwise catch up on the NEXT turn by also
saving the missed prior turn. Re-sends are safe: retried or duplicate
saves are deduplicated server-side (the response carries
`deduped: true` and the original chat_id instead of double-saving).
chat_id: omit or null to start a new conversation; otherwise reuse the id returned by a prior save_turn.
source (required): the product or surface you run in — self-identify with a short label.
Examples: Claude, Claude Code, Claude Cowork, Cursor, ChatGPT, Codex, Kiro, Gemini,
a phone chatbot app, or an IDE agent. Use the same source for both messages in this turn.
`attachment_context` (optional, default "") — if the user's message
for this turn had an attachment (file, image, code paste, screenshot
OCR), pass a short plain-text summary of it here. Persisted next to
`user_message` so later retrieval can match on the attachment topic.
Pass the SAME summary you passed to `get_context` this turn. Empty =
no attachment.
`turn_id` (optional) — a client-generated id for this turn (any short
unique string). A retried save with the same turn_id never
double-saves, even if the content was edited between attempts.
Without it, identical re-sends are still deduplicated by content
within a short window.
`assistant_message_sha256` (optional) — sha256 hex digest of the
assistant message as actually RENDERED to the user. If supplied, the
server checks it against the stored message and returns `drift: true`
when they differ (you saved a different message than the user saw).
The save always proceeds; this is an integrity signal only.
ConnectorOAuth