# Sessions
URL: /docs/agent/concepts/sessions

Inspect token usage and history, branch or duplicate a conversation, name it, and export it — all without sending a prompt.



An agent's conversation is a Pi **session**, stored as a file in the container. The methods here read and reshape
it without streaming a new prompt — for dashboards, cost tracking, and trying an alternative from an earlier point.
None of them touch the filesystem: a session is a conversation, not a sandbox.

## Token usage and cost [#token-usage-and-cost]

`agent.getSessionStats()` returns a snapshot of the current session's resource consumption:

```ts
const stats = await agent.getSessionStats();

console.log(`Session:       ${stats.sessionId}`);
console.log(`Messages:      ${stats.userMessages} user / ${stats.assistantMessages} assistant`);
console.log(`Tool calls:    ${stats.toolCalls}`);
console.log(`Tokens:        ${stats.tokens.input} in / ${stats.tokens.output} out`);
console.log(`Cache:         ${stats.tokens.cacheRead} read / ${stats.tokens.cacheWrite} write`);
console.log(`Cost:          $${stats.cost.toFixed(6)}`);

if (stats.contextUsage) {
  const { tokens, contextWindow, percent } = stats.contextUsage;
  console.log(`Context:       ${percent.toFixed(1)}% (${tokens} / ${contextWindow})`);
}
```

This is a synchronous read from Pi — it doesn't start a new prompt. Call it after any `prompt()` completes to track cumulative usage across a long session.

### Context window pressure [#context-window-pressure]

`contextUsage.percent` tells you how full Pi's context window is. Pi will auto-compact when it approaches the limit (see [Streaming — Compaction events](/docs/agent/concepts/streaming#compaction-events)), but you can also monitor it proactively:

```ts
const stats = await agent.getSessionStats();
if ((stats.contextUsage?.percent ?? 0) > 80) {
  await agent.compact(); // manual compaction before it becomes automatic
}
```

## Retrieving the last response [#retrieving-the-last-response]

`agent.getLastAssistantText()` returns the text of Pi's most recent assistant message without opening a new stream:

```ts
const text = await agent.getLastAssistantText();
if (text) {
  console.log(`Last response: ${text.slice(0, 200)}`);
}
```

Returns `null` if Pi has not yet responded in the current session. Useful for building "copy last response" buttons or logging the final assistant message after a long autonomous run.

## Branching a conversation [#branching-a-conversation]

`agent.getBranchPoints()` lists the points in the current session a conversation can be branched from:

```ts
const points = await agent.getBranchPoints();

for (const { entryId, text } of points) {
  console.log(`${entryId}  "${text.slice(0, 60)}"`);
}

// Branch from a specific point
if (points.length > 0) {
  const { text, cancelled } = await agent.branchSession(points[0].entryId);
  console.log(`Branched at: "${text.slice(0, 60)}" (cancelled: ${cancelled})`);
}
```

Each entry corresponds to a user turn in the harness's session history. Branching creates a new session branch at that point — useful for trying alternative responses or replaying from a known state. It is a conversation branch, not a sandbox copy: `agent.sandbox.fork()` is what does the latter.

Three more methods start a different conversation in the same container:

| Method                      | Result                                                               |
| --------------------------- | -------------------------------------------------------------------- |
| `agent.newSession()`        | A fresh, empty session. The filesystem is unchanged.                 |
| `agent.duplicateSession()`  | A copy of the current session, to continue in a different direction. |
| `agent.switchSession(path)` | Another session already on disk, by its session file path.           |

Signatures are on [Pi RPC passthroughs](/docs/agent/api-reference/pi-rpc#session-management).

## Available commands [#available-commands]

`agent.getCommands()` lists all slash commands Pi can understand in the current environment — including commands contributed by installed extensions, prompt templates, and skills:

```ts
const commands = await agent.getCommands();

for (const cmd of commands) {
  const source = cmd.source; // "extension" | "prompt" | "skill"
  const desc = cmd.description ?? "(no description)";
  console.log(`/${cmd.name} [${source}]  ${desc}`);
}
```

This is primarily useful when building a command palette or auto-complete UI on top of the agent.

## Naming sessions [#naming-sessions]

`agent.setSessionName()` sets a display name for the current Pi session. The name is stored as metadata in the session file — it doesn't affect the session ID or behaviour:

```ts
await agent.setSessionName(`audit-${new Date().toISOString().slice(0, 10)}`);
```

## Exporting an HTML transcript [#exporting-an-html-transcript]

`agent.exportHtml()` generates a static HTML file containing the full session transcript and writes it to the sandbox filesystem:

```ts
const { path } = await agent.exportHtml();
// path is a container-relative path, e.g. /root/pi-session-2024-01-15_abc123.html

// Read the file from the sandbox back to the host
const html = await agent.sandbox.readFile(path);

// Write it somewhere local
await Bun.write("./session-transcript.html", html);
```

You can optionally specify where the file should be written inside the container:

```ts
const { path } = await agent.exportHtml("/workspace/exports/session.html");
```
