Skip to main content

Sessions

A session is one conversation with an agent. This page explains how the platform stores history, why an agent "remembers" your last message, and how to browse and delete transcripts.

What a session is

Every invoke belongs to a session, identified by a session_id. The platform saves the full history of that session: every user message, every agent reply, and every tool call. On each new turn it replays that history to the model.

That replay is the whole mechanism. The model is stateless — it remembers nothing between calls, so every request must carry whatever it needs to know. The continuity you see comes from the platform feeding the history back in, not from the model.

A concrete thread we'll use through this page. Turn 2 states no facts of its own, so the only way it can be answered is from stored history:

# Turn 1 — a new session is minted and returned
platformctl invoke research-buddy "My boat is a Mastercraft Maristar 245."

You should see:

Nice — a Mastercraft Maristar 245. Noted!
(session: 3f2c8a1e-9d41-4c1b-a2f7-0b1c2d3e4f5a)
# Turn 2 — same session id, so the agent has the history
platformctl invoke research-buddy "What boat do I have?" --session 3f2c8a1e-9d41-4c1b-a2f7-0b1c2d3e4f5a

You should see:

You have a Mastercraft Maristar 245.
(session: 3f2c8a1e-9d41-4c1b-a2f7-0b1c2d3e4f5a)

Session history lives in the platform's managed store and survives the agent scaling to zero. It is per-session working memory: a fresh session starts blank. To carry facts across sessions, use the memory bank.

Optional expiry

By default sessions are kept indefinitely. Your administrator can configure an expiry (SESSION_TTL_SECONDS) so idle sessions age out.

Session ids

  • Omit session_id on invoke and the platform mints a UUID and returns it. This is the recommended path.
  • Ids must match ^[A-Za-z0-9_.-]{1,128}$. A bad id in a URL path returns 400 invalid session id.
  • An anonymous caller who chooses their own id must make it at least 24 characters, or invoke fails with 400: session_id chosen by an unauthenticated caller must be at least 24 characters of unguessable randomness (or omit it and the platform will generate one). A short, guessable id would let anyone else read this conversation. Signed-in callers are exempt.

User ids

Every session belongs to a user, identified by a user_id (must match ^[A-Za-z0-9_.:@-]{1,128}$). You almost never need to set it:

  • Omit user_id and the platform works one out from the session id, using a rule that always gives the same answer for the same input (a UUIDv5). Every invoke on that session therefore resolves to the same user. That is what makes multi-turn conversations work with no bookkeeping on your side.
  • Set it explicitly when your application has real end users and you want to group each person's sessions under their own id (for example user_id: "alice@example.com").
  • An invalid value returns 400: invalid user_id: must match ^[A-Za-z0-9_.:@-]{1,128}$ (omit it and the platform will derive one from the session).
The classic continuity bug

If turn 2 doesn't remember turn 1, you changed the session_id between calls — or supplied two different user_id values yourself. Reuse both. If you omit user_id entirely, the platform keeps it stable for you.

Browse users and sessions

The platform exposes a read surface for an agent's conversations. These are management routes: they require signing in, and only the agent's owner (or a project admin) can use them.

MethodPathReturns
GET/v1/agents/{name}/usersWho has talked to this agent
GET/v1/agents/{name}/sessions?user_id=<id>One user's sessions
GET/v1/agents/{name}/sessions/{id}A full transcript
DELETE/v1/agents/{name}/sessions/{id}Deletes one session

Long lists come back one page at a time. Set page_size to choose how many items a page holds — the default is 50 and the maximum is 200. Each response includes a next_page_token; send it back as page_token to fetch the following page. The token is opaque, so treat it as a bookmark rather than something to read or build yourself. An empty next_page_token means there are no more pages. The CLI follows the tokens for you and prints the complete list; the console pages with a Load more button.

List users

Start here. Sessions are indexed per user, so the list below is where the ids for every other command on this page come from.

platformctl agents users list research-buddy

You should see:

USER_ID LAST_SEEN SESSIONS
7c9e6679-7425-40de-944b-e07fc1f90ae7 2026-08-11T14:03:00Z 2

first_seen is in the response but not in the table — add -o json for every field.

The count is how many of that user's conversations the platform still holds. Transcripts can be deleted or aged out, so a user who talked to the agent long ago may be listed with none left.

List one user's sessions

platformctl agents sessions list research-buddy \
--user 7c9e6679-7425-40de-944b-e07fc1f90ae7

You should see:

SESSION_ID LAST_UPDATE EVENTS PREVIEW
3f2c8a1e-9d41-4c1b-a2f7-0b1c2d3e4f5a 2026-08-10T09:14:21Z 6 My boat is a Mastercraft Maristar 245.

--user is required, for the same reason the query parameter is.

Read a transcript

platformctl agents sessions get research-buddy \
3f2c8a1e-9d41-4c1b-a2f7-0b1c2d3e4f5a -o json

The transcript's events are a nested array, which a table cannot render — so reach for -o json (or -o yaml) whenever the turns themselves are what you're after.

The response carries these fields:

FieldWhat it holds
session_id, user_idWho this conversation belongs to
created, last_updateTimestamps in RFC3339 UTC — the 2026-08-10T09:12:00Z format, always in UTC
stateNotes the agent wrote for itself during the conversation, such as anything an ADK tool saved through tool_context.state
eventsThe turns of the conversation, oldest first

Each event in events carries an author — either "user" or the agent's own name — plus a timestamp, an invocation_id grouping everything from one turn, and content.parts. A part is one piece of a turn, and there are three kinds:

  • a text part, the words themselves;
  • a function_call part, the agent calling a tool;
  • a function_response part, that tool's result.

A part carrying the agent's private reasoning is flagged thought: true.

Watch the two timestamp formats. Event timestamp values are epoch seconds — a decimal count of seconds since 1 January 1970 — and come back exactly as stored. Only the session-level created and last_update fields, here and in the list-sessions response above, are converted to RFC3339 strings.

{
"session_id": "3f2c8a1e-9d41-4c1b-a2f7-0b1c2d3e4f5a",
"user_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"created": "2026-08-10T09:12:00Z",
"last_update": "2026-08-10T09:14:21Z",
"state": {},
"events": [
{
"author": "user",
"timestamp": 1786353120.0,
"invocation_id": "inv-001",
"content": {"parts": [{"text": "My boat is a Mastercraft Maristar 245."}]}
},
{
"author": "research-buddy",
"timestamp": 1786353122.0,
"invocation_id": "inv-001",
"content": {"parts": [{"text": "Nice - a Mastercraft Maristar 245. Noted!"}]}
}
]
}

A missing session returns 404 session <id> not found.

Delete a session

This is the erasure path for a "delete my data" request. The owning user is resolved from the session itself, so you never have to name it.

platformctl agents sessions delete research-buddy \
3f2c8a1e-9d41-4c1b-a2f7-0b1c2d3e4f5a

You should see:

deleted session 3f2c8a1e-9d41-4c1b-a2f7-0b1c2d3e4f5a from agent research-buddy

There is no Console tab here: the browser can read a transcript but not delete one. Deletion is the CLI or the API.

Deleting a session removes its history; it does not remove anything already committed to the memory bank. There is also no bulk delete — the walk is always users, then that user's sessions, then one delete per session.

If session browsing answers 503

These routes proxy to the agent's internal read surface using a platform credential. If the platform is not configured with one, every route above answers 503: session browsing is not configured: the control plane has no CAI_INTERNAL_TOKEN, so it cannot authenticate to the agent's read surface. Ask your administrator.

A transcript is customer data

A transcript contains whatever the end user typed and whatever arguments the agent's tools were called with. Handle that output the way you would handle any other customer data.

Debug a conversation without changing it

A session id is enough to append to that conversation. That is the problem this section solves: the obvious way to reproduce a bad answer — invoke the session the customer reported — writes your message into the history they are still using. Their next turn is then answered with a stranger's message in context, and nothing tells them it happened.

So the platform gives you a copy instead.

Clone a session

A clone is a full copy of the history under a debug identity. It does not appear in the original user's session list, and nothing you do to it can reach the original.

platformctl agents sessions clone research-buddy \
3f2c8a1e-9d41-4c1b-a2f7-0b1c2d3e4f5a -o json

You should see:

{
"session_id": "dbg-26efd45f590bdb6b815ed2b7",
"cloned_from": "3f2c8a1e-9d41-4c1b-a2f7-0b1c2d3e4f5a",
"user_id": "debug:alice@example.com",
"events": 4,
"note": "A copy of that conversation, owned by a debug identity. Writing to it cannot affect the original or appear in the original user's session list."
}

The clone records where it came from, so this survives a reload and a different browser:

Field on the cloneMeaning
_cloned_fromThe session id it was copied from
_cloned_from_userThe user id that owns the original
_cloned_atWhen the copy was taken

Rewind a clone

Rewind cuts a conversation back to a chosen turn and hands you back the prompt it dropped. Two things you can do from there, and the platform does not care which:

  • Edit the prompt and send it — how does the agent react to a different question?
  • Send it unchanged — does a new model, a re-indexed corpus, or a changed tool give a different answer than it did last week?
platformctl agents sessions rewind research-buddy \
dbg-26efd45f590bdb6b815ed2b7 --keep-turns 1 -o json

You should see:

{
"session_id": "dbg-26efd45f590bdb6b815ed2b7",
"turns": 2,
"kept_turns": 1,
"dropped_events": 2,
"next_prompt": "Now say the single word: pong"
}

--keep-turns 0 empties the conversation but keeps the session.

Rewind only works on a clone

Rewind deletes recorded turns and there is no undo. Asking to rewind anything that is not a clone is refused with 403:

rewind only works on a cloned session: it deletes recorded history with no undo,
and doing that to a live conversation destroys it for the person having it.
Clone this session first.

What a clone costs

A clone is a full copy of the events, so it uses storage like any other session. Delete it when you are done — platformctl agents sessions delete <agent> <clone-id> — the same as any other session. Clones are not garbage-collected for you.

Summary

QuestionAnswer
Where is history stored?In the platform's managed store, replayed to the model each turn
Does history survive scale-to-zero?Yes
Who mints session ids?The platform, unless you supply one (24+ chars if anonymous)
Who mints user ids?Derived from the session id unless you set one
Can I read transcripts?Yes — owner or project admin, via API, console, or platformctl agents sessions get
Does a new session remember old ones?No — use the memory bank for that
Can I reproduce a customer's conversation safely?Yes — clone it; the copy is isolated from the original
Can I change a past prompt and re-run it?Yes — rewind the clone, then edit or resend the returned next_prompt

Next steps