Skip to content

fix(ai-sandbox): pass deterministic id into provider.create - #889

Merged
AlemTuzlak merged 4 commits into
mainfrom
fix/sandbox-deterministic-create-id
Jul 3, 2026
Merged

fix(ai-sandbox): pass deterministic id into provider.create#889
AlemTuzlak merged 4 commits into
mainfrom
fix/sandbox-deterministic-create-id

Conversation

@AlemTuzlak

@AlemTuzlakAlemTuzlak commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Problem

@tanstack/ai-sandbox computes a stable compound sandbox key, but SandboxCreateInput carried no deterministic id into provider.create(). Providers then minted a random id (Cloudflare crypto.randomUUID(), Sprites tanstack-ai-<random>), so the provider-assigned id was recoverable only from the sandbox store.

Out-of-band consumers that reconnect without reading the store — e.g. Forge attaching a preview iframe — had no way to reconstruct that random id. The result: the agent (Codex) edited one sandbox while the iframe watched another.

Fix

  • SandboxCreateInput gains an optional id.
  • ensure() passes the computed compound key (not raw defineSandbox({ id })) into provider.create({ id, ... }). The computed key already folds in threadId / runId (for reuse: 'none') / provider / workspace / tenant, so it can't collide across threads or runs.
  • Providers that are name-addressable and expose a preview URL keyed by that id honor it (input.id ?? <random>): Cloudflare (DO id) and Sprites (sprite name). Consumers can now recompute definition.key(ctx) and address the exact sandbox the agent edits.

Which providers honor it — and why the rest don't

ProviderBackend idPreview reconnectHonors id?
CloudflaregetSandbox(binding, name) — caller-namedDO/tunnel URL keyed by id✅ yes
SpritescreateSprite(name) — caller-namedsprite URL keyed by name✅ yes
DockercreateContainer (could name)localhost host-port only — no cross-process addressno (store-resume suffices)
local-processdir path (could name)none (runs on host)no
Daytonadaytona.create() mints opaque idcan't (no caller id)
VercelSandbox.create() server-assigns namecan't (no caller id)

So the two providers with the exact "caller-named + URL-addressable preview" shape are fixed; Docker/local-process could honor it but have no out-of-band reconnect problem (their store record already covers resume); Daytona/Vercel physically can't, since the backend owns the id.

Tests

  • ai-sandbox/tests/ensure.test.ts: asserts the provider id equals def.key(ctx).
  • ai-sandbox-cloudflare/tests/provider.test.ts (new): getSandbox called with input.id, random fallback otherwise.
  • ai-sandbox-sprites/tests/provider.test.ts: create uses input.id as the sprite name when provided.

Unit tests, typecheck, and lint pass for all three packages. (One pre-existing, unrelated Windows path-separator failure in harness-cwd.test.ts is untouched by this change.)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Sandbox creation now supports deterministic IDs, making it easier to reconnect to the same sandbox later.
    • Some sandbox providers now preserve a requested ID when creating a new sandbox, improving consistency across preview and reconnect flows.
  • Bug Fixes

    • Fixed mismatches where a sandbox could be created with one identifier but referenced with another.
    • Updated test coverage to verify deterministic sandbox IDs are returned and stored correctly.

SandboxCreateInput gains an optional `id`, and ensure() passes the computed
compound sandbox key into provider.create(). Cloudflare honors it
(`input.id ?? crypto.randomUUID()`) so its DO id is reconstructable from run
context. Previously create() minted a random id recoverable only from the
sandbox store, so out-of-band consumers (e.g. a preview iframe) could address
a different sandbox than the one the agent edits.
@github-actions

github-actionsBot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

🚀 Changeset Version Preview

6 package(s) bumped directly, 20 bumped as dependents.

🟨 Minor bumps

PackageVersionReason
@tanstack/ai-anthropic0.15.13 → 0.16.0Changeset

🟩 Patch bumps

PackageVersionReason
@tanstack/ai0.39.0 → 0.39.1Changeset
@tanstack/ai-ollama0.8.12 → 0.8.13Changeset
@tanstack/ai-sandbox0.2.0 → 0.2.1Changeset
@tanstack/ai-sandbox-cloudflare0.2.0 → 0.2.1Changeset
@tanstack/ai-sandbox-sprites0.2.0 → 0.2.1Changeset
@tanstack/ai-angular0.2.1 → 0.2.2Dependent
@tanstack/ai-bedrock0.1.0 → 0.1.1Dependent
@tanstack/ai-client0.19.1 → 0.19.2Dependent
@tanstack/ai-code-mode0.3.4 → 0.3.5Dependent
@tanstack/ai-code-mode-skills0.3.7 → 0.3.8Dependent
@tanstack/ai-devtools-core0.4.20 → 0.4.21Dependent
@tanstack/ai-fal0.9.8 → 0.9.9Dependent
@tanstack/ai-isolate-cloudflare0.2.34 → 0.2.35Dependent
@tanstack/ai-isolate-node0.1.43 → 0.1.44Dependent
@tanstack/ai-isolate-quickjs0.1.43 → 0.1.44Dependent
@tanstack/ai-mcp0.2.1 → 0.2.2Dependent
@tanstack/ai-preact0.10.1 → 0.10.2Dependent
@tanstack/ai-react0.16.2 → 0.16.3Dependent
@tanstack/ai-solid0.14.1 → 0.14.2Dependent
@tanstack/ai-svelte0.14.1 → 0.14.2Dependent
@tanstack/ai-vue0.14.1 → 0.14.2Dependent
@tanstack/ai-vue-ui0.2.29 → 0.2.30Dependent
@tanstack/preact-ai-devtools0.1.63 → 0.1.64Dependent
@tanstack/react-ai-devtools0.2.63 → 0.2.64Dependent
@tanstack/solid-ai-devtools0.2.63 → 0.2.64Dependent

@coderabbitai

coderabbitaiBot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Introduces an optional id field on SandboxCreateInput and updates ensure() to pass the computed sandbox key as a deterministic id to provider.create(). Cloudflare, Sprites, and fake providers honor the supplied id when present, falling back to previous random-generation behavior otherwise. Tests and a changeset document the change.

Changes

Deterministic sandbox id support

Layer / File(s)Summary
Contract and ensure() wiring
packages/ai-sandbox/src/contracts.ts, packages/ai-sandbox/src/sandbox.ts
SandboxCreateInput gains an optional id field, and ensure() passes the computed sandbox key as id when calling provider.create().
Provider implementations honoring deterministic id
packages/ai-sandbox-cloudflare/src/provider.ts, packages/ai-sandbox-sprites/src/provider.ts, packages/ai-sandbox/tests/fakes.ts
CloudflareProvider.create uses input.id for the Durable Object id, SpritesProvider.create uses it for the sprite name, and the fake provider uses it for the handle id, all falling back to random/counter-based generation when absent.
Tests and changeset
packages/ai-sandbox/tests/ensure.test.ts, packages/ai-sandbox-cloudflare/tests/provider.test.ts, packages/ai-sandbox-sprites/tests/provider.test.ts, .changeset/sandbox-deterministic-create-id.md
New tests verify deterministic and fallback id behavior across ensure(), Cloudflare, and Sprites providers, and a changeset documents the patch across the three packages.

Estimated code review effort: 2 (Simple) | ~12 minutes

Sequence Diagram(s)

sequenceDiagram
participant Caller
participant ensure
participant Provider
Caller->>ensure: ensure(ctx)
ensure->>ensure: compute deterministic key from ctx
ensure->>Provider: create({ id: key })
alt provider supports named addressing
Provider-->>ensure: handle with id = key
else provider ignores input id
Provider-->>ensure: handle with self-generated id
end
ensure-->>Caller: sandbox handle
Loading

Possibly related PRs

  • TanStack/ai#868: Introduced the Sprites provider's create() implementation, which this PR modifies to honor a deterministic id for the sprite name.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Description check⚠️ WarningThe description is detailed, but it does not follow the required template sections or include the checklist and release impact entries.Rewrite it to use the required headings: 🎯 Changes, ✅ Checklist, and 🚀 Release Impact, and fill in the checklist items.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
Title check✅ PassedThe PR title is concise and accurately summarizes the main change.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/sandbox-deterministic-create-id

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@nx-cloud

nx-cloudBot commented Jul 3, 2026

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit f7e2c1b

CommandStatusDurationResult
nx affected --targets=test:sherif,test:knip,tes...✅ Succeeded1m 22sView ↗
nx run-many --targets=build --exclude=examples/...✅ Succeeded2sView ↗

☁️ Nx Cloud last updated this comment at 2026-07-03 09:55:37 UTC

@pkg-pr-new

pkg-pr-newBot commented Jul 3, 2026

Copy link
Copy Markdown

Open in StackBlitz

@tanstack/ai

npm i https://pkg.pr.new/@tanstack/ai@889

@tanstack/ai-acp

npm i https://pkg.pr.new/@tanstack/ai-acp@889

@tanstack/ai-angular

npm i https://pkg.pr.new/@tanstack/ai-angular@889

@tanstack/ai-anthropic

npm i https://pkg.pr.new/@tanstack/ai-anthropic@889

@tanstack/ai-bedrock

npm i https://pkg.pr.new/@tanstack/ai-bedrock@889

@tanstack/ai-claude-code

npm i https://pkg.pr.new/@tanstack/ai-claude-code@889

@tanstack/ai-client

npm i https://pkg.pr.new/@tanstack/ai-client@889

@tanstack/ai-code-mode

npm i https://pkg.pr.new/@tanstack/ai-code-mode@889

@tanstack/ai-code-mode-skills

npm i https://pkg.pr.new/@tanstack/ai-code-mode-skills@889

@tanstack/ai-codex

npm i https://pkg.pr.new/@tanstack/ai-codex@889

@tanstack/ai-devtools-core

npm i https://pkg.pr.new/@tanstack/ai-devtools-core@889

@tanstack/ai-elevenlabs

npm i https://pkg.pr.new/@tanstack/ai-elevenlabs@889

@tanstack/ai-event-client

npm i https://pkg.pr.new/@tanstack/ai-event-client@889

@tanstack/ai-fal

npm i https://pkg.pr.new/@tanstack/ai-fal@889

@tanstack/ai-gemini

npm i https://pkg.pr.new/@tanstack/ai-gemini@889

@tanstack/ai-grok

npm i https://pkg.pr.new/@tanstack/ai-grok@889

@tanstack/ai-grok-build

npm i https://pkg.pr.new/@tanstack/ai-grok-build@889

@tanstack/ai-groq

npm i https://pkg.pr.new/@tanstack/ai-groq@889

@tanstack/ai-isolate-cloudflare

npm i https://pkg.pr.new/@tanstack/ai-isolate-cloudflare@889

@tanstack/ai-isolate-node

npm i https://pkg.pr.new/@tanstack/ai-isolate-node@889

@tanstack/ai-isolate-quickjs

npm i https://pkg.pr.new/@tanstack/ai-isolate-quickjs@889

@tanstack/ai-mcp

npm i https://pkg.pr.new/@tanstack/ai-mcp@889

@tanstack/ai-mistral

npm i https://pkg.pr.new/@tanstack/ai-mistral@889

@tanstack/ai-ollama

npm i https://pkg.pr.new/@tanstack/ai-ollama@889

@tanstack/ai-openai

npm i https://pkg.pr.new/@tanstack/ai-openai@889

@tanstack/ai-opencode

npm i https://pkg.pr.new/@tanstack/ai-opencode@889

@tanstack/ai-openrouter

npm i https://pkg.pr.new/@tanstack/ai-openrouter@889

@tanstack/ai-preact

npm i https://pkg.pr.new/@tanstack/ai-preact@889

@tanstack/ai-react

npm i https://pkg.pr.new/@tanstack/ai-react@889

@tanstack/ai-react-ui

npm i https://pkg.pr.new/@tanstack/ai-react-ui@889

@tanstack/ai-sandbox

npm i https://pkg.pr.new/@tanstack/ai-sandbox@889

@tanstack/ai-sandbox-cloudflare

npm i https://pkg.pr.new/@tanstack/ai-sandbox-cloudflare@889

@tanstack/ai-sandbox-daytona

npm i https://pkg.pr.new/@tanstack/ai-sandbox-daytona@889

@tanstack/ai-sandbox-docker

npm i https://pkg.pr.new/@tanstack/ai-sandbox-docker@889

@tanstack/ai-sandbox-local-process

npm i https://pkg.pr.new/@tanstack/ai-sandbox-local-process@889

@tanstack/ai-sandbox-sprites

npm i https://pkg.pr.new/@tanstack/ai-sandbox-sprites@889

@tanstack/ai-sandbox-vercel

npm i https://pkg.pr.new/@tanstack/ai-sandbox-vercel@889

@tanstack/ai-solid

npm i https://pkg.pr.new/@tanstack/ai-solid@889

@tanstack/ai-solid-ui

npm i https://pkg.pr.new/@tanstack/ai-solid-ui@889

@tanstack/ai-svelte

npm i https://pkg.pr.new/@tanstack/ai-svelte@889

@tanstack/ai-utils

npm i https://pkg.pr.new/@tanstack/ai-utils@889

@tanstack/ai-vue

npm i https://pkg.pr.new/@tanstack/ai-vue@889

@tanstack/ai-vue-ui

npm i https://pkg.pr.new/@tanstack/ai-vue-ui@889

@tanstack/openai-base

npm i https://pkg.pr.new/@tanstack/openai-base@889

@tanstack/preact-ai-devtools

npm i https://pkg.pr.new/@tanstack/preact-ai-devtools@889

@tanstack/react-ai-devtools

npm i https://pkg.pr.new/@tanstack/react-ai-devtools@889

@tanstack/solid-ai-devtools

npm i https://pkg.pr.new/@tanstack/solid-ai-devtools@889

commit: 81a7b2a

AlemTuzlakand others added 2 commits July 3, 2026 11:51
Sprites is the same class as Cloudflare — the sprite's preview URL is keyed by
its name, so a random name stranded out-of-band reconnects. Honor
`input.id ?? <random>` so preview consumers can reconstruct the sprite address.
@AlemTuzlak
AlemTuzlak merged commit 9b58c08 into mainJul 3, 2026
10 checks passed
@AlemTuzlak
AlemTuzlak deleted the fix/sandbox-deterministic-create-id branch July 3, 2026 10:04
@github-actionsgithub-actionsBot mentioned this pull request Jul 2, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@AlemTuzlak