From d008283c179957636cc102dfde8cd4e31149db7b Mon Sep 17 00:00:00 2001 From: Nathan Flurry Date: Sun, 15 Mar 2026 15:52:31 -0700 Subject: [PATCH] Sync upstream changes: multiplayer docs, logos, openapi spec, foundry config Co-Authored-By: Claude Opus 4.6 --- docs/multiplayer.mdx | 41 +++++++++++++++++-- examples/e2b/src/index.ts | 7 +--- foundry/compose.dev.yaml | 2 - foundry/docker/backend.Dockerfile | 1 - foundry/packages/backend/package.json | 1 - .../website/public/logos/cloudflare.svg | 3 ++ .../website/public/logos/computesdk.svg | 3 ++ .../packages/website/public/logos/docker.svg | 3 ++ .../packages/website/public/logos/modal.svg | 3 ++ 9 files changed, 52 insertions(+), 12 deletions(-) create mode 100644 frontend/packages/website/public/logos/cloudflare.svg create mode 100644 frontend/packages/website/public/logos/computesdk.svg create mode 100644 frontend/packages/website/public/logos/docker.svg create mode 100644 frontend/packages/website/public/logos/modal.svg diff --git a/docs/multiplayer.mdx b/docs/multiplayer.mdx index 4f405ea..c09ca23 100644 --- a/docs/multiplayer.mdx +++ b/docs/multiplayer.mdx @@ -20,8 +20,43 @@ Use [actor keys](https://rivet.dev/docs/actors/keys) to map each workspace to on ```ts Actor (server) import { actor, setup } from "rivetkit"; -import { SandboxAgent } from "sandbox-agent"; -import { RivetSessionPersistDriver, type RivetPersistState } from "@sandbox-agent/persist-rivet"; +import { SandboxAgent, type SessionPersistDriver, type SessionRecord, type SessionEvent, type ListPageRequest, type ListPage, type ListEventsRequest } from "sandbox-agent"; + +// Inline Rivet persist driver — copy into your project. +// See https://github.com/nichochar/sandbox-agent/tree/main/examples/persist-rivet +interface ActorContextLike { state: Record; } +interface RivetPersistData { sessions: Record; events: Record; } +type RivetPersistState = { _sandboxAgentPersist: RivetPersistData }; + +class RivetSessionPersistDriver implements SessionPersistDriver { + private readonly stateKey: string; + private readonly ctx: ActorContextLike; + constructor(ctx: ActorContextLike, options: { stateKey?: string } = {}) { + this.ctx = ctx; + this.stateKey = options.stateKey ?? "_sandboxAgentPersist"; + if (!this.ctx.state[this.stateKey]) { + this.ctx.state[this.stateKey] = { sessions: {}, events: {} }; + } + } + private get data(): RivetPersistData { return this.ctx.state[this.stateKey] as RivetPersistData; } + async getSession(id: string) { const s = this.data.sessions[id]; return s ? { ...s } : undefined; } + async listSessions(request: ListPageRequest = {}): Promise> { + const sorted = Object.values(this.data.sessions).sort((a, b) => a.createdAt - b.createdAt || a.id.localeCompare(b.id)); + const offset = Number(request.cursor ?? 0); + const limit = request.limit ?? 100; + const slice = sorted.slice(offset, offset + limit); + return { items: slice, nextCursor: offset + slice.length < sorted.length ? String(offset + slice.length) : undefined }; + } + async updateSession(session: SessionRecord) { this.data.sessions[session.id] = { ...session }; if (!this.data.events[session.id]) this.data.events[session.id] = []; } + async listEvents(request: ListEventsRequest): Promise> { + const all = [...(this.data.events[request.sessionId] ?? [])].sort((a, b) => a.eventIndex - b.eventIndex || a.id.localeCompare(b.id)); + const offset = Number(request.cursor ?? 0); + const limit = request.limit ?? 100; + const slice = all.slice(offset, offset + limit); + return { items: slice, nextCursor: offset + slice.length < all.length ? String(offset + slice.length) : undefined }; + } + async insertEvent(sessionId: string, event: SessionEvent) { const events = this.data.events[sessionId] ?? []; events.push({ ...event, payload: JSON.parse(JSON.stringify(event.payload)) }); this.data.events[sessionId] = events; } +} type WorkspaceState = RivetPersistState & { sandboxId: string; @@ -111,5 +146,5 @@ await conn.prompt({ ## 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. +- Inline the Rivet persist driver (shown above) so session history persists in actor state. - For client connection patterns, see [Rivet JavaScript client](https://rivet.dev/docs/clients/javascript). diff --git a/examples/e2b/src/index.ts b/examples/e2b/src/index.ts index 996b99f..c20ebaa 100644 --- a/examples/e2b/src/index.ts +++ b/examples/e2b/src/index.ts @@ -7,13 +7,10 @@ if (process.env.ANTHROPIC_API_KEY) envs.ANTHROPIC_API_KEY = process.env.ANTHROPI if (process.env.OPENAI_API_KEY) envs.OPENAI_API_KEY = process.env.OPENAI_API_KEY; const client = await SandboxAgent.start({ - sandbox: e2b({ - create: { envs }, - }), + // ✨ NEW ✨ + sandbox: e2b({ create: { envs } }), }); -console.log(`UI: ${client.inspectorUrl}`); - const session = await client.createSession({ agent: detectAgent(), cwd: "/home/user", diff --git a/foundry/compose.dev.yaml b/foundry/compose.dev.yaml index b96805e..c57d971 100644 --- a/foundry/compose.dev.yaml +++ b/foundry/compose.dev.yaml @@ -65,7 +65,6 @@ services: - "foundry_backend_root_node_modules:/app/node_modules" - "foundry_backend_backend_node_modules:/app/foundry/packages/backend/node_modules" - "foundry_backend_shared_node_modules:/app/foundry/packages/shared/node_modules" - - "foundry_backend_persist_rivet_node_modules:/app/sdks/persist-rivet/node_modules" - "foundry_backend_typescript_node_modules:/app/sdks/typescript/node_modules" - "foundry_backend_pnpm_store:/root/.local/share/pnpm/store" # Persist RivetKit local storage across container restarts. @@ -120,7 +119,6 @@ volumes: foundry_backend_root_node_modules: {} foundry_backend_backend_node_modules: {} foundry_backend_shared_node_modules: {} - foundry_backend_persist_rivet_node_modules: {} foundry_backend_typescript_node_modules: {} foundry_backend_pnpm_store: {} foundry_rivetkit_storage: {} diff --git a/foundry/docker/backend.Dockerfile b/foundry/docker/backend.Dockerfile index c41fd1f..3dc1c7d 100644 --- a/foundry/docker/backend.Dockerfile +++ b/foundry/docker/backend.Dockerfile @@ -13,7 +13,6 @@ RUN pnpm --filter @sandbox-agent/foundry-shared build RUN pnpm --filter acp-http-client build RUN pnpm --filter @sandbox-agent/cli-shared build RUN SKIP_OPENAPI_GEN=1 pnpm --filter sandbox-agent build -RUN pnpm --filter @sandbox-agent/persist-rivet build RUN pnpm --filter @sandbox-agent/foundry-backend build RUN pnpm --filter @sandbox-agent/foundry-backend deploy --prod /out diff --git a/foundry/packages/backend/package.json b/foundry/packages/backend/package.json index e11cd62..562bab7 100644 --- a/foundry/packages/backend/package.json +++ b/foundry/packages/backend/package.json @@ -18,7 +18,6 @@ "@hono/node-ws": "^1.3.0", "@iarna/toml": "^2.2.5", "@sandbox-agent/foundry-shared": "workspace:*", - "@sandbox-agent/persist-rivet": "workspace:*", "better-auth": "^1.5.5", "dockerode": "^4.0.9", "drizzle-kit": "^0.31.8", diff --git a/frontend/packages/website/public/logos/cloudflare.svg b/frontend/packages/website/public/logos/cloudflare.svg new file mode 100644 index 0000000..76a2e80 --- /dev/null +++ b/frontend/packages/website/public/logos/cloudflare.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/packages/website/public/logos/computesdk.svg b/frontend/packages/website/public/logos/computesdk.svg new file mode 100644 index 0000000..45c6271 --- /dev/null +++ b/frontend/packages/website/public/logos/computesdk.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/packages/website/public/logos/docker.svg b/frontend/packages/website/public/logos/docker.svg new file mode 100644 index 0000000..33582ef --- /dev/null +++ b/frontend/packages/website/public/logos/docker.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/packages/website/public/logos/modal.svg b/frontend/packages/website/public/logos/modal.svg new file mode 100644 index 0000000..990b5bd --- /dev/null +++ b/frontend/packages/website/public/logos/modal.svg @@ -0,0 +1,3 @@ + + +