Conversations

List, open, rename and delete threads, and generate titles and follow-up suggestions.

A thread is one conversation. Everything a chat sidebar needs takes a handful of calls, each automatically limited to the user the client acts for.

TaskCall
Start a conversationthreads.create()
List the user's conversationsthreads.search(...)
Load a transcriptthreads.get_state(id) / getState(id)
Renamethreads.update(id, metadata=...)
Deletethreads.delete(id)
Title and follow-ups after a turnsuggestions.create_for_thread(id) / createForThread(id)
Home-screen starter promptssuggestions.starters()

List conversations

threads = client.threads.search(limit=30, sort_by="updated_at", sort_order="desc")
for t in threads:
    print(t["metadata"].get("thread_name") or "New conversation", t["thread_id"])
  • Titles come back with the list, so a sidebar costs one request.
  • Sort by updated_at on purpose. The default is created_at, which buries the conversation the user just replied in.
  • There's no cursor and no total. Page with limit and offset: ask for one more row than you show, and if it comes back there's another page.

Load a transcript

state = client.threads.get_state(thread_id)
for m in state["values"]["messages"]:
    print(m["type"], m["content"])  # "human", "ai" or "tool"
typeRender as
humanthe user's message
aithe assistant's text; or, with empty content and a populated tool_calls, a tool call
toola tool's result, paired with the call by tool_call_id. Usually best collapsed

Use get_state, not get_history. get_history returns one checkpoint per internal step, so a two-message exchange comes back as about ten entries. It exists for debugging.

Titles and follow-ups

After each turn finishes, make one call. It generates the thread's title and three follow-up suggestions in a single model call:

result = client.suggestions.create_for_thread(thread_id)
# {"thread_name": "Capital of Kenya",
#  "suggestions": [{"title": "Population?", "prompt": "What is the population of Nairobi?"}],
#  "generated": True}
  • It's the only trigger. No background job does this. The service can't tell a finished turn from a dropped connection, so your code has to say so.
  • Call it once, after the stream ends normally. Not per chunk, and not when the stream failed.
  • title and prompt are different. Show title on the chip and send prompt when it's tapped.
  • generated: false isn't an error. The model produced nothing usable and the stored title and suggestions were left alone.
  • Treat failure as cosmetic. The reply already rendered, so don't show an error toast for a missing title.
StatusMeaning
404the thread doesn't exist, or isn't this user's
409the thread has no turns yet. Call it after a turn, not on creation
503suggestions are switched off for this deployment

Stop the title changing every turn

Each call rewrites the title unless the user renamed it. To keep refreshing suggestions while leaving the title alone, send retitle=false. The SDK method doesn't take query parameters, so make that call directly:

curl -X POST "$AICE_AGENT_URL/threads/$THREAD_ID/postturn?retitle=false" \
  -H "Authorization: Bearer $AICE_API_KEY" -H "X-User-Id: $USER_ID" \
  -H "Content-Type: application/json" -d '{}'

Home-screen starters

Starter prompts come from the user's ten most recent thread titles, and are regenerated only when the saved set is more than six hours old:

starters = client.suggestions.starters()

The response is {items: [{title, prompt}], generated_at, source, generated}. An empty items is normal for a new user. Show the empty state without chips.

Rename

There's no rename endpoint. A rename is a metadata update, and it must write titled_by: "user" in the same call:

client.threads.update(
    thread_id,
    metadata={"thread_name": "Quarterly review", "titled_by": "user"},
)

Leave out titled_by and it looks right in testing, then the next turn's title generation overwrites the user's name. The marker is what tells it to leave the title alone.

Delete

client.threads.delete(thread_id)

Deletion is permanent and takes the thread's runs and history with it. There's no trash. Ask the user to confirm first.

On this page