Sessions

A session holds conversation history, so multi-turn calls remember prior turns.

chat = session()

ai "My name is Ada." with chat
who = ai "What is my name?" with chat     # sees the earlier turn

What with does

It sends the session's prior turns as a native role-separated message array - not a flattened transcript pasted into one prompt - and records the new prompt and reply back into the session.

That distinction matters. A flattened transcript is one long user message, and the model cannot reliably tell your instructions from earlier content. Real roles are what every provider's API expects and what keeps a long conversation coherent.

A session is a cell

cell_get(chat)     # [{ role: "user", content: "..." }, { role: "assistant", ... }]

It is a cell of { role, content } maps, so you can read it, log it, persist it, or trim it:

# keep only the last 20 turns
cell_update(chat, fn(msgs) if len(msgs) > 20 { msgs[-20..] } else { msgs })

Being a cell also means it shares on assignment, which is what lets a session be captured into a handler or a task and still accumulate.

Growth is your problem

Every turn adds to what is sent on the next call, so tokens and cost grow with conversation length. Nothing trims automatically, because only you know what matters. The two usual strategies:

  • Window - keep the last N turns, as above.
  • Summarize - periodically replace old turns with a summary, which is itself

an ai call.

Check the size before spending with tokens:

if tokens(json_encode(cell_get(chat))) > 50000 { chat = compact(chat) }

Restrictions

Conversational turns bypass the cache - a cached reply would break the conversation. Cannot combine with using tools, voting, or -> stream.