Skip to content

Threads

Updated View as Markdown

Threads persist conversation state across requests. You never create one explicitly — pass a thread_id on a chat request and Truememory creates or resumes it. This page covers managing them afterwards: list, rename, delete, and history. All endpoints require a Bearer token from Truememory Auth.

Creating Threads

Pass a thread_id in your /v1/chat/completions request to maintain conversation state. Truememory uses it to persist message history so the LLM has context from previous turns.

  • If omitted, Truememory auto-generates a UUID for the thread. Each request starts a new conversation.
  • If provided, Truememory resumes the conversation from where it left off. Use any string (e.g. a UUID you generate client-side).

Retrying a Failed Turn

A chat request that fails partway through can still have stored its messages on the thread. Sending the same request again would store them twice. To avoid that, anchor each request on the last message you received.

  • message_id — the ID of the last message the turn stored. A non-streaming response returns it as a top-level field. A streaming response adds it as a top-level key on the chunk that carries the finish_reason (stop or tool_calls). It is not sent when finish_reason is error, and it is only returned for requests with a thread_id.
  • parent_message_id — send the last message_id you received. messages holds the messages after it. It may also start with replayed history that ends at the parent; that history is dropped exactly as it is without parent_message_id.
{
  "model": "anthropic/claude-sonnet-4-5",
  "thread_id": "my-thread",
  "parent_message_id": "<message_id from the previous response>",
  "messages": [{ "role": "user", "content": "What about tomorrow?" }]
}

If the request fails, send it again unchanged, with the same parent_message_id and messages. You never need to trim it. Truememory drops the replayed history the same way the first attempt did, compares the rest with what is already stored after the parent, and only appends what is missing. When the whole request is already stored and the turn did not finish, the model runs again on the stored thread. A server tool that already returned a result is not run again.

A turn that finished is never run again. That includes a turn that ended in tool calls for your client tools: you already received those calls. You get a 409 THREAD_PARENT_STALE instead. Read the thread history and use the last message’s run_id as the new parent_message_id.

In a client tool loop, use the message_id from the tool_calls finish as the parent of the request that sends the tool result.

parent_message_id is ignored when thread_id is not set. Without it, requests behave as before.

Code Status When
THREAD_PARENT_NOT_FOUND 409 parent_message_id is not a message on this thread
THREAD_PARENT_STALE 409 The turn after the parent already completed, including one that ended in client tool calls (read it from history), or the thread holds different or later messages after the parent
SERVICE_UNAVAILABLE 503 The thread could not be read to check the parent. Send the same request again later

Per-App Thread Isolation

Threads can be scoped to a specific application using the X-App-Id header. This allows multiple apps to share the same Truememory backend while keeping their conversation threads separate.

  • X-App-Id provided — the thread is scoped to that app. Only requests with the same X-App-Id can see, rename, or delete it.
  • X-App-Id omitted — the thread is unscoped (shared). It is visible when listing threads without X-App-Id, but hidden from app-scoped lists.
# Create a thread scoped to "vibrantly"
curl -X POST https://your-tie-host/v1/chat/completions \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-App-Id: vibrantly" \
  -H "X-Agent-Id: chatbot" \
  -d '{"model": "anthropic/claude-sonnet-4-5", "messages": [{"role": "user", "content": "Hello"}], "thread_id": "my-thread"}'

Thread Metadata

Each thread can carry an arbitrary JSON metadata object. Use it to store application-specific context that doesn’t belong in the conversation itself — for example, where the thread originated, which page it’s associated with, or whether it’s pinned in a UI.

{
  "source": "whatsapp",
  "pageType": "whatsapp-dm",
  "pageId": "550e8400-e29b-41d4-a716-446655440000",
  "isPinned": false
}

Metadata is set and updated via the Update Thread endpoint. It is returned in every thread summary (list and update responses). Truememory stores metadata as-is and does not interpret it — your application defines the schema.

List Threads

Returns threads for the authenticated user. Supports cursor-based pagination, sorting, and date filtering.

GET https://your-tie-host/threads
Authorization: Bearer $TOKEN

Headers:

Header Type Default Description
X-App-Id string null Filter threads by app. When set, only threads matching that exact app ID are returned (unscoped threads are excluded). When omitted, all threads are returned (both scoped and unscoped).

Query parameters:

Parameter Type Default Description
agent_id string null Filter threads by agent
cursor string null Pagination token from a previous response (treat as opaque; do not parse or construct it)
limit integer 20 Results per page (1-100)
order_by string created_at Sort field: created_at or updated_at
asc boolean false Sort direction: true for ascending (oldest first), false for descending (newest first)
created_after ISO 8601 datetime null Only return threads created on or after this timestamp
created_before ISO 8601 datetime null Only return threads created on or before this timestamp

Response:

{
  "threads": [
    {
      "thread_id": "847c6285-8fc9-4560-a83f-4e6285809254",
      "agent_id": "chatbot",
      "app_id": "vibrantly",
      "title": "What is the weather in Tokyo?",
      "metadata": {
        "source": "whatsapp",
        "isPinned": false
      },
      "created_at": "2026-03-25T10:00:00+00:00",
      "updated_at": "2026-03-25T10:05:00+00:00"
    }
  ],
  "next_cursor": "MjAyNi0wMy0yNVQxMDowMDowMCswMDowMHw4NDdjNjI4NS04ZmM5LTQ1NjAtYTgzZi00ZTYyODU4MDkyNTQ="
}

Pass next_cursor as the cursor query parameter to fetch the next page. When next_cursor is null, there are no more results.

The app_id field is null for unscoped threads. The metadata field is null when no metadata has been set.

Get Thread History

Retrieve the full message history for a thread:

POST https://your-tie-host/history
Authorization: Bearer $TOKEN
Content-Type: application/json

{ "thread_id": "<your-thread-id>" }

Response:

{
  "messages": [
    {
      "type": "human",
      "content": "What is the weather in Tokyo?",
      "metadata": {
        "session_id": "8b94776f-31ae-49ac-9f06-3be137d69186",
        "platform": "ios",
        "app_version": "2.4.1"
      }
    },
    {
      "type": "ai",
      "content": "The current weather in Tokyo is...",
      "metadata": null
    }
  ]
}

The metadata field on user messages contains the key-value pairs sent with the original request. AI messages have metadata: null since metadata is attached at request time, not per-response.

Update Thread

Update a thread’s title and/or metadata. The title is automatically set from the first user message, but you can override it. Metadata can be set at any time.

At least one of title or metadata must be provided in the request body.

PATCH https://your-tie-host/threads/<thread-id>
Authorization: Bearer $TOKEN
Content-Type: application/json
# Required only if the thread was created with X-App-Id
X-App-Id: vibrantly

{ "title": "My weather conversation", "metadata": { "isPinned": true } }

Request body:

Field Type Required Description
title string No New title for the thread (1-500 characters, cannot be blank)
metadata object | null No Arbitrary metadata dict. Replaces existing metadata entirely. Pass null to clear.

You can send either field alone or both together:

# Rename only
{ "title": "New title" }

# Set metadata only
{ "metadata": { "source": "telegram", "isPinned": false } }

# Clear metadata
{ "metadata": null }

Response:

{
  "thread_id": "847c6285-8fc9-4560-a83f-4e6285809254",
  "agent_id": "chatbot",
  "app_id": "vibrantly",
  "title": "My weather conversation",
  "metadata": { "isPinned": true },
  "created_at": "2026-03-25T10:00:00+00:00",
  "updated_at": "2026-03-25T10:10:00+00:00"
}

Delete Thread

Permanently delete a thread and all its data (title, metadata, timestamps, agent/app association):

DELETE https://your-tie-host/threads/<thread-id>
Authorization: Bearer $TOKEN
# Required only if the thread was created with X-App-Id
X-App-Id: vibrantly

Response:

{ "status": "deleted", "thread_id": "847c6285-8fc9-4560-a83f-4e6285809254" }

Error Codes

Code Status When
AUTH_TOKEN_MISSING 401 No Bearer token provided
THREAD_NOT_FOUND 404 Thread does not exist or is not owned by the user
VALIDATION_ERROR 422 Invalid cursor, empty title, title exceeds 500 characters, or empty update body
THREADS_FETCH_FAILED 500 Unexpected server error while listing threads
THREAD_UPDATE_FAILED 500 Unexpected server error while updating a thread
THREAD_DELETE_FAILED 500 Unexpected server error while deleting a thread
SERVICE_UNAVAILABLE 501 Thread management requires the PostgreSQL memory backend
Navigation

Type to search…

↑↓ navigate↵ selectEsc close