Skip to content
GitHub Get Started
Agent

Sessions

Sessions launch an agent inside the VM, stream its responses in real time over sessionEvent, and persist a replayable ACP transcript that survives sleep/wake.

Use createSession to launch an agent inside the VM. Returns session metadata including capabilities and agent info. The agent starts in /workspace by default; override it with the cwd option below.

client.ts
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");
const session = await agent.createSession("pi", {
env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },
});
console.log(session.sessionId);
console.log(session.capabilities);
console.log(session.agentInfo);

See Full Example

The second argument to createSession accepts:

  • env: environment variables for the agent process (e.g. API keys). Not inherited from the host.
  • cwd: working directory inside the VM. Defaults to /workspace.
  • mcpServers: MCP servers (local child processes or remote URLs) exposing extra tools.
  • additionalInstructions: text appended to the agent’s system prompt.
  • skipOsInstructions: skip the base OS instructions injection. Tool documentation is still included.

Use sendPrompt to send a message to an active session. The response contains the agent’s reply.

client.ts
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");
const session = await agent.createSession("pi", {
env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },
});
const response = await agent.sendPrompt(
session.sessionId,
"Create a TypeScript function that checks if a number is prime",
);
console.log(response.text);

See Full Example

Subscribe to sessionEvent to receive real-time streaming output from the agent.

client.ts
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");
const conn = agent.connect();
// Subscribe to session events before sending the prompt
conn.on("sessionEvent", (data) => {
console.log(`[${data.sessionId}]`, data.event.method, data.event.params);
});
const session = await agent.createSession("pi", {
env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },
});
await agent.sendPrompt(session.sessionId, "Explain how async/await works");

See Full Example

Use cancelPrompt to stop an in-progress prompt.

client.ts
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");
const session = await agent.createSession("pi", {
env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },
});
// Start a long-running prompt
const promptPromise = agent.sendPrompt(
session.sessionId,
"Refactor the entire codebase to use TypeScript strict mode",
);
// Cancel after 10 seconds
setTimeout(async () => {
await agent.cancelPrompt(session.sessionId);
}, 10_000);
const response = await promptPromise;
console.log(response.text);

See Full Example

  • closeSession gracefully closes a session without removing persisted data
  • destroySession removes the session and all persisted data
  • To reconnect to a previously created session and replay its history, see Replay events and Resuming a suspended session
client.ts
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");
const session = await agent.createSession("pi", {
env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },
});
// Close without destroying persisted data
await agent.closeSession(session.sessionId);
// Destroy session and all persisted events
await agent.destroySession(session.sessionId);

See Full Example

Use getSessionEvents to replay a session’s persisted events, including for VMs that are not currently running. Pair it with listPersistedSessions to find earlier sessions.

client.ts
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");
const session = await agent.createSession("pi", {
env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },
});
await agent.sendPrompt(session.sessionId, "Hello");
// Replay persisted events
const events = await agent.getSessionEvents(session.sessionId);
console.log(events);

See Full Example

Query session history from SQLite. Works even when the VM is not running.

client.ts
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");
// List all persisted sessions
const sessions = await agent.listPersistedSessions();
for (const s of sessions) {
console.log(s.sessionId, s.agentType, s.createdAt);
}
// Get full event history for a session
const events = await agent.getSessionEvents(sessions[0].sessionId);
for (const e of events) {
console.log(e.method, e.params);
}

See Full Example

Enumerate the agents registered on a VM and check which are installed before creating a session. listAgents() returns an AgentRegistryEntry[]:

const agents = agent.listAgents();
for (const a of agents) {
// a.id -- agent id you pass to createSession, e.g. "pi", "pi-cli",
// "opencode", "claude", "codex", plus any package-provided ids
// a.acpAdapter -- ACP adapter npm package
// a.agentPackage-- underlying agent npm package
// a.installed -- whether the adapter package is resolvable in the VM
console.log(a.id, a.installed);
}

The ids combine the built-in agents with any package-provided agents you’ve added via software. installed: false simply means the adapter package isn’t mounted in the VM’s /root/node_modules (or a mounted software root) yet — it is not an error, just an indication that createSession for that id needs the package added first.

A single VM can run multiple sessions simultaneously. Each session has its own agent process but shares the same filesystem. Use different session IDs to manage them independently.

client.ts
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");
// Create two sessions in the same VM
const coder = await agent.createSession("pi", {
env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },
});
const reviewer = await agent.createSession("pi", {
env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },
});
// Coder writes code
await agent.sendPrompt(coder.sessionId, "Write a REST API at /home/agentos/api.ts");
// Reviewer reads and reviews the same file
await agent.sendPrompt(reviewer.sessionId, "Review /home/agentos/api.ts for issues");
// Close each session independently
await agent.closeSession(coder.sessionId);
await agent.closeSession(reviewer.sessionId);

See Full Example

The agent (ACP adapter) runs as a process inside the VM. It uses stdout for ACP protocol traffic, so its stderr is the channel for logs, warnings, and crash diagnostics. Pass onAgentStderr to the VM to capture it, and route it to your own logger to see exactly what the agent is doing (or why it exited).

server.ts
import { agentOS, setup } from "@rivet-dev/agentos";
import pi from "@agentos-software/pi";
const vm = agentOS({
software: [pi],
onAgentStderr(event) {
// event: { sessionId, agentType, processId, pid, chunk: Uint8Array }
const line = new TextDecoder().decode(event.chunk);
logger.info(`[agent:${event.agentType} session:${event.sessionId}] ${line}`);
},
});
export const registry = setup({ use: { vm } });
registry.start();