Skip to main content
Agent

Sessions

Open durable ACP sessions, prompt them, read history, and restore adapters.

AgentOS sessions are durable records backed by the VM’s SQLite database.

  • The public session ID is stable across VM sleep and adapter restarts.
  • The adapter’s private ACP session ID stays internal.

Open a session

openSession creates or restores a session, completes ACP negotiation, and resolves without a value.

  • Choose and retain the sessionId before calling; omitted → main.
  • getSession — call separately for durable metadata.
  • Idempotent to repeat; changing immutable creation options for an existing ID returns session_conflict.

Input fields: agent, cwd, additionalDirectories, env, mcpServers, permissionPolicy, skipOsInstructions, additionalInstructions.

  • Omitted cwd/home/agentos.
  • Actor deployments inject their SQLite database automatically; standalone core clients must configure a VM SQLite file or descriptor.

MCP servers

  • MCP config belongs to the session — its tools are part of the agent’s runtime context.
  • Configure local child-process or remote servers before opening the session.
  • Config path and transports come from the selected agent adapter (e.g. Pi reads .mcp.json from its AgentOS home).
  • Install local MCP server packages before opening the session so first-run package-manager output can’t corrupt a stdio handshake.
  • See the agent guide for adapter specifics.
const mcpConfig = JSON.stringify({
	mcpServers: {
		filesystem: {
			command: "npx",
			args: [
				"-y",
				"@modelcontextprotocol/server-filesystem",
				"/home/agentos",
			],
		},
		remote: {
			url: "https://mcp.example.com/sse",
			headers: { Authorization: "Bearer my-token" },
		},
	},
});

await agent.filesystem.mkdir("/home/agentos/.pi/agent");
await agent.filesystem.writeFile("/home/agentos/.pi/agent/.mcp.json", mcpConfig);

await agent.sessions.open({
	agent: "pi",
	env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },
});

Prompt

  • prompt accepts native ACP ContentBlock[] — not a special text format.
  • Never creates a missing session.
  • The complete user message is committed before dispatch; a prompt whose delivery may have reached the adapter is never auto-replayed.
  • Bounded by limits.acp.maxPromptBytes and limits.acp.maxPromptBlocks; limit errors name the field to raise.
  • An oversized durable update batch is rejected before it changes history.
  • idempotencyKey — use when the caller may retry. Reusing a key with different content fails; retrying while the first call is active waits and returns its committed result.

Events and history

sessionEvent is a flat discriminated union.

  • Top-level type = native ACP SessionUpdate.sessionUpdate value; ACP payload fields (content, toolCallId, entries) sit beside the durability envelope. No nested update wrapper.
  • durability: "ephemeral" — live agent-message/thought delta; not sequenced or stored.
  • durability: "durable" — has a session sequence, emitted only after its SQLite commit. Completed/coalesced message chunks are durable.
  • Permission request/response variants use the same flat shape with top-level options, toolCall, or outcome.
  • readHistory({ sessionId, before, after, limit }) — SQLite-only, never starts an adapter. before/after are exclusive and mutually exclusive. Dedup live durable delivery by (sessionId, sequence).
  • Also SQLite-only reads: getSession, listSessions, getSessionConfig, getSessionCapabilities, getSessionAgentInfo. Listing uses an opaque keyset cursor — not a frozen snapshot.

Restoration

After VM sleep, the next prompt transparently starts the adapter. AgentOS tries, in order:

  1. Native ACP session/resume.
  2. Stable session/load.
  3. A fresh private ACP session with bounded continuation context from AgentOS history.
  • Adapter replay during load is suppressed — SQLite is the sole history source of truth.
  • Fallback transcript bounded by limits.acp.maxFallbackContinuationBytes.
  • AgentOS stores its own exact ACP updates because ACP has no portable history-reading API and adapters restore inconsistently.

Permissions

permissionPolicy is reject_all, ask, or allow_all (default allow_all).

  • Controls how AgentOS answers native ACP permission requests — not VM permissions or adapter tool access.
  • Set ask when opening the session; subscribing alone doesn’t change the immutable policy.
  • ask — durably records the request as a permission_request event.
  • allow_all — resolves automatically, emits no permission event.
  • Reply with the exact adapter-supplied optionId and explicit session ID:
await agent.sessions.respondPermission({
  sessionId: request.sessionId,
  requestId: request.requestId,
  optionId: request.options[0].optionId,
});
  • First valid response wins atomically.
  • Requests don’t expire; cancellation, adapter exit, deletion, or VM shutdown records a terminal reason.
  • Accepted responses are sequenced in durable history.

Cancel, unload, and delete

  • cancelPrompt — cooperative ACP cancellation; returns cancelled or no_active_prompt.
  • unloadSession — releases the live adapter, keeps SQLite metadata/history; a later prompt restores it.
  • deleteSession — permanently removes the session and history. Omitted ID → main; repeated deletion is idempotent.

Runtime configuration

  • getSessionConfig — returns the negotiated native ACP config collection + a revision.
  • setSessionConfigOption — may restore the adapter, lets ACP validate the value, then replaces the cached collection.
import { createClient } from "@rivet-dev/agentos/client";
import type { registry } from "./server";

const client = createClient<typeof registry>({
	endpoint: "http://localhost:6420",
});
const agent = client.vm.getOrCreate("my-agent");

await agent.sessions.open({
	agent: "pi",
	env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },
});

const config = await agent.sessions.getConfig();
console.log(config.options);

await agent.sessions.setConfigOption({
	configId: "model",
	value: "anthropic/claude-sonnet-4",
});