sandbox-agent/docs/multiplayer.mdx
2026-02-11 06:43:52 -08:00

115 lines
3 KiB
Text

---
title: "Multiplayer"
description: "Use Rivet Actors to coordinate shared sessions."
icon: "users"
---
For multiplayer orchestration, use [Rivet Actors](https://rivet.dev/docs/actors).
Recommended model:
- One actor per collaborative workspace/thread.
- The actor owns Sandbox Agent session lifecycle and persistence.
- Clients connect to the actor and receive realtime broadcasts.
Use [actor keys](https://rivet.dev/docs/actors/keys) to map each workspace to one actor, [events](https://rivet.dev/docs/actors/events) for realtime updates, and [lifecycle hooks](https://rivet.dev/docs/actors/lifecycle) for cleanup.
## Example
<CodeGroup>
```ts Actor (server)
import { actor, setup } from "rivetkit";
import { SandboxAgent } from "sandbox-agent";
import { RivetSessionPersistDriver, type RivetPersistState } from "@sandbox-agent/persist-rivet";
type WorkspaceState = RivetPersistState & {
sandboxId: string;
baseUrl: string;
};
export const workspace = actor({
createState: async () => {
return {
sandboxId: "sbx_123",
baseUrl: "http://127.0.0.1:2468",
} satisfies Partial<WorkspaceState>;
},
createVars: async (c) => {
const persist = new RivetSessionPersistDriver(c);
const sdk = await SandboxAgent.connect({
baseUrl: c.state.baseUrl,
persist,
});
const session = await sdk.resumeOrCreateSession({ id: "default", agent: "codex" });
const unsubscribe = session.onEvent((event) => {
c.broadcast("session.event", event);
});
return { sdk, session, unsubscribe };
},
actions: {
getSessionInfo: (c) => ({
workspaceId: c.key[0],
sandboxId: c.state.sandboxId,
}),
prompt: async (c, input: { userId: string; text: string }) => {
c.broadcast("chat.user", {
userId: input.userId,
text: input.text,
createdAt: Date.now(),
});
await c.vars.session.prompt([{ type: "text", text: input.text }]);
},
},
onSleep: async (c) => {
c.vars.unsubscribe?.();
await c.vars.sdk.dispose();
},
});
export const registry = setup({
use: { workspace },
});
```
```ts Client (browser)
import { createClient } from "rivetkit/client";
import type { registry } from "./actors";
const client = createClient<typeof registry>({
endpoint: process.env.NEXT_PUBLIC_RIVET_ENDPOINT!,
});
const workspaceId = "workspace-42";
const room = client.workspace.getOrCreate([workspaceId]);
const conn = room.connect();
conn.on("chat.user", (event) => {
console.log("user message", event);
});
conn.on("session.event", (event) => {
console.log("sandbox event", event);
});
await conn.prompt({
userId: "user-123",
text: "Propose a refactor plan for auth middleware.",
});
```
</CodeGroup>
## Notes
- Keep sandbox calls actor-only. Browser clients should not call Sandbox Agent directly.
- Use `@sandbox-agent/persist-rivet` so session history persists in actor state.
- For client connection patterns, see [Rivet JavaScript client](https://rivet.dev/docs/clients/javascript).