diff --git a/.changeset/acp-compatible.md b/.changeset/acp-compatible.md deleted file mode 100644 index eb64a2319..000000000 --- a/.changeset/acp-compatible.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@tanstack/ai-acp': minor ---- - -Add `acpCompatible` / `acpCompatibleText` — the harness equivalent of `openaiCompatible`. Build a `chat()` text adapter for any ACP-compliant agent CLI and plug it into a sandbox without a dedicated adapter package: configure `command` (stdio) or `openTransport` (WebSocket/custom) once, then select a model per call. Handles sandbox resolution, tool→MCP bridging, session resume, permission modes (`headless` / `interactive`), abort, and AG-UI translation. Also exports the shared `buildAcpPrompt` helper. - -Typed configuration (parity with `openaiCompatible`): declare `models` for a type-safe model union, and a `modelOptions` brand (`{} as { … }`) for the per-call options accepted via `chat({ modelOptions })`. Declared options are merged with the base ACP options and exposed on `ctx.modelOptions` in `command` / `openTransport` so they can become CLI flags. - -ACP client compliance: the `initialize` handshake now sends `clientInfo` and validates the negotiated protocol version. The stream translator surfaces non-text agent content (image/audio/resource blocks) as a `CUSTOM` event (via the new optional `contentEvent` translate label; `acpCompatible` enables it as `.message-content`) instead of dropping it, and preserves non-text tool content (diffs, terminal, images) in the tool-call result payload. - -Workspace skill projection: `acpCompatible` now projects `withSandbox` workspace skills — MCP skills are passed to the agent over ACP's native `mcpServers` (secrets/bearer headers resolved), and `gitSkill`s are linked into a harness-declared `skillsDir` (e.g. `.pi/skills`). `fileSkill`/`instructions`/`secrets` are handled by the provider-agnostic bootstrap. Exposes `workspaceMcpServers` / `projectAcpWorkspace` for adapters built on `openTransport`. diff --git a/.changeset/add-ai-mistral.md b/.changeset/add-ai-mistral.md deleted file mode 100644 index 4e1199e98..000000000 --- a/.changeset/add-ai-mistral.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@tanstack/ai-mistral': minor ---- - -Add new `@tanstack/ai-mistral` adapter package for Mistral models using the `@mistralai/mistralai` SDK. Supports streaming chat, tool calling, vision input (Pixtral / Mistral Medium / Small), structured output via JSON Schema, and reasoning streams (Magistral) — emitted as AG-UI `REASONING_*` events. Includes model metadata for Mistral Large, Medium, Small, Ministral 3B/8B, Codestral, Pixtral, Magistral, and Open Mistral Nemo. diff --git a/.changeset/ai-acp-extract.md b/.changeset/ai-acp-extract.md deleted file mode 100644 index 41c9ec486..000000000 --- a/.changeset/ai-acp-extract.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@tanstack/ai-acp': minor -'@tanstack/ai-grok-build': minor ---- - -Extract shared ACP transport, session, and AG-UI translation into `@tanstack/ai-acp`. Add WebSocket framing for in-sandbox harness servers (`grok agent serve` via `sandbox.ports.connect`). Grok Build defaults to ACP with auto stdio/WebSocket transport selection; `protocol: 'streaming-json'` keeps the legacy NDJSON path. diff --git a/.changeset/ai-bedrock-adapter.md b/.changeset/ai-bedrock-adapter.md deleted file mode 100644 index 197ba8acd..000000000 --- a/.changeset/ai-bedrock-adapter.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@tanstack/ai-bedrock': minor ---- - -Add `@tanstack/ai-bedrock`: an Amazon Bedrock adapter. The default `bedrockText` path uses Bedrock's **Converse** API (`@aws-sdk/client-bedrock-runtime`), reaching the broad chat catalog including Anthropic Claude, Amazon Nova, and Meta Llama, with streaming, tools, reasoning, and structured output. Opt into Bedrock's OpenAI-compatible endpoints with `api: 'chat'` (Chat Completions) or `api: 'responses'` (gpt-oss Responses). Authentication supports Bedrock API keys or SigV4 via the AWS credential chain. diff --git a/.changeset/ai-claude-code-initial.md b/.changeset/ai-claude-code-initial.md deleted file mode 100644 index 35a41dfe4..000000000 --- a/.changeset/ai-claude-code-initial.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@tanstack/ai-claude-code': minor ---- - -New `@tanstack/ai-claude-code` package: a Claude Code **harness adapter that runs inside a sandbox**. It declares `requires: [SandboxCapability]` and spawns the `claude` CLI (`claude -p --output-format stream-json`) inside the sandbox provided by `withSandbox(...)`, streaming its events back as AG-UI chunks. Claude Code owns the agent loop and executes its own native tools (bash, file edits, search) against the sandbox workspace; their activity streams back as resolved tool-call events. `chat()`-provided server tools are bridged to the in-sandbox agent over a host-side MCP tool-proxy (calls are proxied back to the host where `execute()` runs). Sessions are resumable via `modelOptions.sessionId` (surfaced through a `claude-code.session-id` custom event), and the working-tree diff is emitted as a `file.changed` custom event after each run. A `defineSandboxPolicy` (allow/ask/deny command globs + file-write/network capability rules) is enforced via Claude Code's `--permission-prompt-tool`: each native tool use is checked against the policy and the client's approval decisions, and an `ask` action with no decision yet surfaces an `approval-requested` event (the client approves and re-runs to continue). Requires the `claude` executable and `ANTHROPIC_API_KEY` to be available in the sandbox (e.g. via `workspace.secrets`). diff --git a/.changeset/ai-codex-initial.md b/.changeset/ai-codex-initial.md deleted file mode 100644 index c6a4d711c..000000000 --- a/.changeset/ai-codex-initial.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@tanstack/ai-codex': minor ---- - -New `@tanstack/ai-codex` package: a Codex **harness adapter that runs inside a sandbox**. It declares `requires: [SandboxCapability]` and spawns `codex exec --experimental-json` inside the sandbox provided by `withSandbox(...)` (mirroring `@openai/codex-sdk`'s own CLI invocation), feeding the prompt via stdin and streaming its JSONL thread events back as AG-UI chunks. Codex owns the agent loop and executes its built-in tools (shell, file changes, web search, todo lists) against the sandbox workspace. Threads are resumable via `modelOptions.sessionId` (surfaced through a `codex.session-id` custom event); sandbox mode / approval policy / reasoning effort map to codex CLI flags. Requires the `codex` executable and `CODEX_API_KEY` (or a `codex login`) in the sandbox. chat()-provided server tools are bridged into the agent via the host MCP tool-proxy. A `defineSandboxPolicy` is mapped onto Codex's coarse permission knobs (sandbox mode, `approval_policy`, `network_access`); because `codex exec` runs non-interactively with no per-action host callback, the fine-grained resume-based interactive-approval flow is not available for Codex (it refuses, rather than prompts for, actions needing approval). diff --git a/.changeset/ai-opencode-initial.md b/.changeset/ai-opencode-initial.md deleted file mode 100644 index a160e9f22..000000000 --- a/.changeset/ai-opencode-initial.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@tanstack/ai-opencode': minor ---- - -New `@tanstack/ai-opencode` package: an OpenCode **harness adapter that runs inside a sandbox**. It declares `requires: [SandboxCapability]`, spawns `opencode serve` inside the sandbox provided by `withSandbox(...)`, exposes its port, and connects the `@opencode-ai/sdk` HTTP client to it via `baseUrl`. OpenCode owns the agent loop and executes its built-in tools (shell, file edits, search) against the sandbox workspace; assistant text/thinking stream as token-level deltas and tool activity as resolved tool-call events. Sessions are resumable, and OpenCode permission requests are answered by a configurable `permissionMode` (`default` / `acceptEdits` / `bypassPermissions` or a custom handler), and a request the policy would reject with no client decision yet surfaces an `approval-requested` event so the client can approve and re-run to grant it (interactive approvals). Requires the `opencode` CLI in the sandbox (Docker: publish the server port via `publishPorts`). chat()-provided server tools are bridged into the agent via the host MCP tool-proxy. diff --git a/.changeset/ai-sandbox-cloudflare.md b/.changeset/ai-sandbox-cloudflare.md deleted file mode 100644 index 2be9ac1b8..000000000 --- a/.changeset/ai-sandbox-cloudflare.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@tanstack/ai-sandbox-cloudflare': minor ---- - -New `@tanstack/ai-sandbox-cloudflare` package: a Cloudflare Containers sandbox provider (`cloudflareSandbox`) built on `@cloudflare/sandbox`, for running harness adapters at the edge inside a Worker. Implements the uniform `SandboxHandle` (exec, base64-backed fs, git, `exposePort` preview URLs, env) over the Cloudflare Sandbox Durable Object. The container disk is ephemeral and snapshots are not yet GA, so `withSandbox` re-bootstraps under the same identity across cold starts (`durableFilesystem`/`snapshots` are reported false). Background processes don't expose stdin on Cloudflare, so stdin-fed harnesses (e.g. Claude Code) need a stdin-capable provider; `exec` works fully. diff --git a/.changeset/codex-mcp-bridge-http-headers.md b/.changeset/codex-mcp-bridge-http-headers.md deleted file mode 100644 index 5ad02b750..000000000 --- a/.changeset/codex-mcp-bridge-http-headers.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@tanstack/ai-codex': patch ---- - -Fix codex failing to start whenever `chat()`-provided tools are bridged to it. The adapter configured the MCP tool-bridge with an inline `mcp_servers..bearer_token`, but current codex rejects that for the streamable-HTTP transport — the run died immediately with `Error loading config.toml: bearer_token is not supported for streamable_http`. The per-run bearer is now passed as an `Authorization` header (`http_headers = { "Authorization" = "Bearer " }`), matching what the workspace-MCP projection already emits and what the host tool-bridge authenticates against. Codex with bridged tools (e.g. the Cloudflare sandbox example) now runs end to end. diff --git a/.changeset/sandbox-bootstrap-no-stdin.md b/.changeset/sandbox-bootstrap-no-stdin.md deleted file mode 100644 index 0d6011b3e..000000000 --- a/.changeset/sandbox-bootstrap-no-stdin.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@tanstack/ai-sandbox': patch ---- - -Fix workspace bootstrap on sandbox providers without a writable stdin -(`capabilities.writableStdin === false`, e.g. Daytona / Vercel / Cloudflare): - -- The bootstrap shell previously **always** drove setup commands over a spawned - process's stdin (a sentinel-echo protocol), which those providers reject — so - any `defineWorkspace({ setup })` step threw `stdin is not writable`. The - bootstrap shell now falls back to an **exec-backed** implementation that - threads `cwd`/exported env across discrete `process.exec` calls, reproducing - the persistent-shell semantics without stdin. -- `defineSandbox().ensure()` now **destroys the freshly-created sandbox if - bootstrap fails** (before it has been recorded), instead of leaking an - orphaned — and, for hosted providers, billed — sandbox on a failed/retried run. diff --git a/.changeset/sandbox-claude-edge-streaming.md b/.changeset/sandbox-claude-edge-streaming.md deleted file mode 100644 index 1f4002659..000000000 --- a/.changeset/sandbox-claude-edge-streaming.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@tanstack/ai-sandbox-cloudflare': patch -'@tanstack/ai-claude-code': patch ---- - -Fix the Claude Code harness never starting its turn in a Cloudflare sandbox (runs sat at `status:running` forever, streaming nothing). Two root causes: - -- **`@tanstack/ai-claude-code`**: the adapter defaults `--permission-mode bypassPermissions`, which Claude Code maps to `--dangerously-skip-permissions` and refuses to run as root. Sandbox containers (Docker/Cloudflare) run as root, so `claude` died instantly. The adapter now sets `IS_SANDBOX=1` in the CLI's environment (Claude Code's documented escape hatch for running skip-permissions in an isolated environment), merged over any caller-provided env. -- **`@tanstack/ai-sandbox-cloudflare`**: `spawn()` used `@cloudflare/sandbox`'s background-process API (`startProcess` + `streamProcessLogs`), whose `onOutput`/`onExit` callbacks never fire, so a stdout-NDJSON harness hung forever. `spawn()` now streams over `exec({ stream: true, onOutput })` — the same proven command path as one-shot `exec` — and resolves the exit code from its result. The caller's `AbortSignal` is no longer forwarded across the Durable Object RPC boundary (Workers RPC cannot serialize an `AbortSignal`, which previously threw before the command ran); mid-run cancellation is unavailable on this provider and a stuck run is bounded by the coordinator watchdog instead. A failed command now rejects `wait()` so the adapter surfaces a `RUN_ERROR` rather than a silent zero-output run. diff --git a/.changeset/sandbox-cloudflare-harness-agnostic-env.md b/.changeset/sandbox-cloudflare-harness-agnostic-env.md deleted file mode 100644 index 6a6c43d63..000000000 --- a/.changeset/sandbox-cloudflare-harness-agnostic-env.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -'@tanstack/ai-sandbox-cloudflare': minor ---- - -Make the Cloudflare sandbox factory **harness-agnostic about auth**. `SandboxAgentEnv` / `ContainerCoordinatorEnv` no longer bind a hardcoded `ANTHROPIC_API_KEY` field, and neither the do-drives default sandbox nor the colocated container runner injects an Anthropic key anymore. Instead the run's workspace **declares** the secret names it needs (via `createSecrets`), and the coordinator copies each declared name out of the Worker `env` into the sandbox/container env — so a Claude Code app declares `ANTHROPIC_API_KEY`, a Codex app declares `CODEX_API_KEY`, and the package binds no key of its own. - -**Breaking:** apps that relied on the implicit `ANTHROPIC_API_KEY` field must now add it to their own env type and supply it via a `sandbox`/`workspace` resolver, e.g.: - -```ts -interface AppEnv extends SandboxAgentEnv { - ANTHROPIC_API_KEY: string -} -createCloudflareSandboxAgent({ - adapter: () => claudeCodeText('sonnet'), - sandbox: (input, env) => - defineSandbox({ - // … - workspace: defineWorkspace({ - source: { type: 'none' }, - secrets: createSecrets({ ANTHROPIC_API_KEY: env.ANTHROPIC_API_KEY }), - }), - }), -}) -``` diff --git a/.changeset/sandbox-daytona-vercel.md b/.changeset/sandbox-daytona-vercel.md deleted file mode 100644 index 94efee897..000000000 --- a/.changeset/sandbox-daytona-vercel.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@tanstack/ai-sandbox-daytona': minor -'@tanstack/ai-sandbox-vercel': minor ---- - -Two new sandbox provider packages so harness adapters can run **inside** managed cloud sandboxes through the uniform `SandboxHandle`: - -- **`@tanstack/ai-sandbox-daytona`** — `daytonaSandbox()`: runs the agent inside an isolated [Daytona](https://www.daytona.io/) cloud sandbox (`@daytona/sdk`), with `fs`/`exec`/`git`, background processes via Daytona sessions, port preview links (`ports.connect`), and resume-by-id. Requires a Daytona API key (`config.apiKey` or `DAYTONA_API_KEY`). -- **`@tanstack/ai-sandbox-vercel`** — `vercelSandbox()`: runs the agent inside an isolated [Vercel Sandbox](https://vercel.com/docs/sandbox) microVM (`@vercel/sandbox`), with `fs`/`exec`/`git`, detached background processes, exposed-port domains (`ports.connect`), and resume-by-id. Requires a Vercel access token (`config.token` or `VERCEL_TOKEN` / `VERCEL_OIDC_TOKEN`) plus team/project scope. - -Both providers advertise `writableStdin: false` (background-process stdin is delivered via a file + shell redirect, not a live stream) and reuse the shared `createExecBackedGit` helper for a uniform `sandbox.git` surface. diff --git a/.changeset/sandbox-hooks-redesign.md b/.changeset/sandbox-hooks-redesign.md deleted file mode 100644 index b32c1d5df..000000000 --- a/.changeset/sandbox-hooks-redesign.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -'@tanstack/ai': minor -'@tanstack/ai-sandbox': minor -'@tanstack/ai-sandbox-local-process': minor ---- - -Declarative sandbox file-event hooks: observe file create / change / delete -inside a sandbox and have them fire automatically during a chat run. - -- `@tanstack/ai`: chat middleware gains an optional `sandbox` hook group - (`onFile`/`onFileCreate`/`onFileChange`/`onFileDelete`), a `SandboxFileEvent` - type, and a `sandbox` debug-logging category. The engine auto-emits a - `CUSTOM` `sandbox.file` event per change (client reads it from `parts`). -- `@tanstack/ai-sandbox`: `defineSandbox({ hooks, fileEvents })` declares - file + lifecycle hooks (`onFile*`/`onReady`/`onError`/`onDestroy`) that fire - automatically while the sandbox runs in a chat — `withSandbox` owns the - watcher. The watcher is provider-agnostic: a native `fs.watch` fast-path when - the provider advertises it, otherwise a portable `find -printf` mtime - snapshot-diff poll (no extra deps; `.git`/`node_modules` ignored by default). - `watchWorkspace()` / `diffSnapshots` remain as low-level building blocks. -- `@tanstack/ai-sandbox-local-process`: implements the optional `fs.watch` seam - via Node's recursive `fs.watch` (Windows/macOS); Linux falls back to the core - exec-poll automatically. diff --git a/.changeset/sandbox-layer.md b/.changeset/sandbox-layer.md deleted file mode 100644 index 6f2d57dd3..000000000 --- a/.changeset/sandbox-layer.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@tanstack/ai-sandbox': minor -'@tanstack/ai-sandbox-local-process': minor -'@tanstack/ai-sandbox-docker': minor -'@tanstack/ai': minor ---- - -New provider-agnostic sandbox layer so harness adapters can run **inside** isolated sandboxes. - -- **`@tanstack/ai-sandbox`** — `defineSandbox()` (lazy controller + resume→restoreSnapshot→create+bootstrap ensure algorithm), `withSandbox()` middleware, `defineWorkspace()` (git/local source, package-manager detection, setup, skills, secrets), `defineSandboxPolicy()`, the `SandboxProvider`/`SandboxHandle`/`SandboxCapabilities` contracts, capability tokens (`SandboxCapability` plus the optional `SandboxStore`/`Locks` persistence seams with in-memory defaults), `bootstrapWorkspace`, `createExecBackedGit`, `spawnNdjson` (run an agent CLI in a sandbox and stream its NDJSON stdout), the host MCP tool-proxy bridge (`startHostToolBridge` — exposes `chat()` server tools to the in-sandbox agent, with an optional permission-prompt tool), and the shared interactive-approval primitives (`resolveApproval`, `approvalId`, `buildApprovalRequestedEvent`) harness adapters use to enforce a policy and surface `approval-requested` events for client-in-the-loop approvals. -- **`@tanstack/ai-sandbox-local-process`** — `localProcessSandbox()`: runs the agent on the host through the uniform `SandboxHandle` (no isolation; the fast dev loop). -- **`@tanstack/ai-sandbox-docker`** — `dockerSandbox()`: runs the agent inside an isolated Docker container (dockerode), with commit-based snapshots, fork, and resume-by-id. -- **`@tanstack/ai`** — `TextOptions.capabilities` exposes the middleware capability context to adapters so harness adapters that declare `requires: [...]` can read provided capabilities from `chatStream`; `TextOptions.approvals` threads client approval decisions through to adapters for the interactive-approval (deny + `approval-requested` + re-run) flow; `DefinedChatMiddleware` and `AnyChatMiddleware` are now exported for portable middleware authoring. diff --git a/.changeset/sandbox-provisioning-fast-init.md b/.changeset/sandbox-provisioning-fast-init.md deleted file mode 100644 index bdc4c62b5..000000000 --- a/.changeset/sandbox-provisioning-fast-init.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -'@tanstack/ai-sandbox': minor -'@tanstack/ai-claude-code': minor -'@tanstack/ai-codex': minor -'@tanstack/ai-opencode': minor -'@tanstack/ai-sandbox-docker': patch ---- - -Declarative sandbox provisioning + faster headless init. - -- **`createSecrets`**: type-safe secret references; underlying values are stored - in a non-enumerable symbol-keyed registry and never written to snapshots, the - sandbox store, or the event log. Use `secret: secrets.GH` in `gitSkill` for - private-repo auth and `bearer(secrets.GH)` in MCP header values. -- **Declarative `skills` / `plugins` / `instructions`**: `agentSkill`, - `gitSkill` (private-repo clone with `secret`), `mcpSkill` (MCP server with - resolved header values), and `fileSkill` are projected per harness into each - CLI's native format (Claude Code `.mcp.json`, Codex `.codex/config.toml`, - OpenCode `opencode.json`). `instructions` is written - as a canonical `AGENTS.md` at the workspace root; `CLAUDE.md` and `GEMINI.md` - are symlinked (copy fallback). Concepts a CLI lacks emit a warning and are - skipped rather than throwing. -- **Shallow clone by default**: `githubRepo`/`gitSource` default to - `--depth 1 --single-branch`. Pass `depth: number` for a specific history - depth or `depth: 'full'` to disable the flag. -- **Serial/parallel `setup` callback**: `setup` accepts a plain `Array` - (all serial) or a `({ serial, parallel }) => void` callback that records - groups run over a persistent shell — the shell's cwd and env carry over - between serial steps; `parallel([...])` launches commands concurrently - using the shell's forked state. -- **Default snapshot-after-setup**: when the provider supports snapshots, - bootstrap takes one automatically after `setup` completes. Add - `lifecycle.snapshotMaxAge` (e.g. `'24h'`) to re-create the sandbox when the - snapshot is older than the TTL. -- **`@tanstack/ai-sandbox-docker` fix**: a spawned process's demuxed - stdout/stderr now end on the exec stream's `close`/`error` (not only `end`), - so disposing a long-lived process (e.g. the bootstrap shell) no longer hangs - after `kill()`. diff --git a/.changeset/sandbox-serverless-runtime.md b/.changeset/sandbox-serverless-runtime.md deleted file mode 100644 index 25893f247..000000000 --- a/.changeset/sandbox-serverless-runtime.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -'@tanstack/ai-sandbox': minor -'@tanstack/ai-sandbox-cloudflare': minor -'@tanstack/ai-claude-code': minor -'@tanstack/ai-codex': minor -'@tanstack/ai-opencode': minor -'@tanstack/ai-sandbox-docker': patch -'@tanstack/ai-sandbox-local-process': patch ---- - -Serverless/edge run model for the sandbox layer — a trigger can start an agent run and return immediately while a durable orchestrator drives it and clients tail the stream from a resumable cursor. - -- **Resumable run event-log** (`RunEventLog`, `InMemoryRunEventLog`, `RunEvent`, `RunRecord`, `isTerminalRunStatus`) — an append-only, `seq`-indexed log of a run's `StreamChunk`s with replay-then-tail reads. A dropped connection, a new tab, or an orchestrator that hibernated between chunks all reconnect by passing their last-seen `seq`. The run never depends on a single open connection. -- **Run driver** (`pipeToRunLog`, `RunController`) — pumps a `chat()` stream into a `RunEventLog` (status transitions, RUN_ERROR capture, abort handling), and a controller that starts a run without blocking, exposes a resumable `attach(runId, { fromSeq })`, and `drain()`s in-flight runs for `waitUntil`-style flushing. -- **Transport-agnostic tool-bridge** — the MCP tool-proxy is split into a portable core (`createToolBridgeCore`, `handleBridgeJsonRpc`) and a transport. `startHostToolBridge` remains the `node:http` host transport (now loopback-bound unless a Docker container must reach it, with a constant-time bearer check); a serverless/edge orchestrator serves the same core from its own `fetch` handler — no raw TCP listener. A new `ToolBridgeProvisioner` capability (`getToolBridgeProvisioner` / `provideToolBridgeProvisioner`, default `nodeHttpBridgeProvisioner`) lets the orchestrator inject the transport. -- **Harness adapters inverted** — `claude-code`, `codex`, and `opencode` now resolve their tool-bridge from the `ToolBridgeProvisioner` capability (defaulting to the host transport) instead of hardcoding `node:http`, so they run unchanged on the host and on the edge. -- **Claude Code runs on the Cloudflare sandbox** — a new required `SandboxCapabilities.writableStdin` flag lets a provider advertise whether spawned processes have a writable host→process stdin — `true` for the host/Docker/local-process providers, `false` for Cloudflare. The Claude Code adapter detects `false` and delivers the prompt via a file + in-shell stdin-redirection (`claude -p … < file`) instead of a host stdin write, keeping it out of argv. Host/Docker behaviour is unchanged (stdin path). -- **Tool-bridge token hardening** — the per-run bearer token is no longer passed inline in argv. The Claude Code adapter writes the bridge MCP config to a file and passes claude the path (`--mcp-config `), so the token can't be read from `ps` / `/proc//cmdline` by other processes in the sandbox. -- **Co-located ("combined") run model** — new `@tanstack/ai-sandbox` exports (`remoteToolStubs`, `toolDescriptors`, `httpRemoteToolExecutor`, `executeHostTool`, plus the `RemoteToolExecutor` interface) let the harness loop AND its MCP tool-bridge run INSIDE the container (the in-container sandbox is just `local-process`, with native stdin + a localhost `node:http` bridge). The orchestrator serializes its tools with `toolDescriptors`; the container rebuilds them as delegating stubs with `remoteToolStubs(descriptors, httpRemoteToolExecutor(url, token))`; the orchestrator answers that one call with `executeHostTool(tools, name, args)`. Only host-tool **execution** crosses the container→orchestrator boundary — the MCP transport itself never leaves the container, shrinking the public surface from the whole MCP protocol to a single authenticated tool-exec call. -- **Request-derived callback hosts, split into bridge vs preview (`resolveBridgeOrigin` / `resolvePreviewHost`)** — the off-isolate sandbox container reaches the Worker over two distinct surfaces, now resolved separately (both exported from `@tanstack/ai-sandbox-cloudflare/agent`; the Worker captures the trigger host as `StartRunInput.publicHost`): - - **Bridge / tool-exec** (container → Worker): `PUBLIC_HOSTNAME` is **optional** — unset → derived from the `POST /runs` request, which is safe on Cloudflare (the edge only routes hostnames you own to your Worker, so the request host is never an attacker's `Host` and the per-run bearer token can't be steered off-domain). A `*.workers.dev` deploy needs no config; **local dev uses `host.docker.internal`** (the Docker host gateway), so agent runs work locally with **no tunnel**. - - **Preview** (browser → Worker → container, `exposePort`): a separate `PREVIEW_HOSTNAME`, because preview URLs require **wildcard DNS**. **Local** uses `*.localhost` (browser-resolved to loopback — previews work locally with no tunnel); **deployed** requires a **custom domain** with a `*.` route. `*.workers.dev` has no wildcard subdomains (the SDK's `exposePort` rejects it), so `resolvePreviewHost` throws a clear error pointing at `PREVIEW_HOSTNAME` rather than returning a dead URL. -- **Preview wiring is package-provided, not example glue** — `@tanstack/ai-sandbox-cloudflare/agent` now exports `exposePreviewTool(input, env)` (a ready-made `exposePreview` `chat()` server tool) and `PREVIEW_GUIDANCE` (an app-agnostic system prompt), and `createCloudflareSandboxAgent` gains a `systemPrompts` option (do-drives) to wire the guidance in. The tool mints previews via a **Cloudflare quick tunnel** (`sandbox.tunnels.get(port)` → `*.trycloudflare.com`), served by `cloudflared` inside the sandbox — deliberately NOT `exposePort` + `proxyToSandbox`, which routes the preview through the Worker origin (in local dev, your Vite dev server, whose middleware then serves the preview's `/@vite/client` / `/src/*` / `/@fs/*` from the host instead of the container and breaks the page). A tunnel bypasses the Vite port, needs no custom domain on a deploy, and forwards WebSockets (HMR works). `PREVIEW_GUIDANCE` just tells the agent to bind wide and allow all hosts so the tunnel hostname is accepted (Vite `server: { host: true, allowedHosts: true }`). Because `sandbox.tunnels` exists only on the SDK's **RPC** transport (it throws `requires the RPC transport` on the default `http`), `cloudflareSandbox` now defaults to `transport: 'rpc'` (new `transport` config option to override) and applies it to create/resume/destroy; `exposePreviewTool` obtains its stub with `transport: 'rpc'` too. `exposePort` + `resolvePreviewHost` remain available for Worker-fronted previews on a custom domain. Adds `zod` as a peer dependency. -- **`@tanstack/ai-sandbox-cloudflare` ships the runtime, not just the example** — the Worker router, the coordinator Durable Object, the durable run-log, and the `POST /run` wire contract are now package code, exported from two entries: `@tanstack/ai-sandbox-cloudflare/agent` (Workers-only — `createCloudflareSandboxAgent`, the coordinator base classes, `DurableObjectRunEventLog`, plus the shared `ContainerRunRequest` + `parseContainerRunRequest`), and `@tanstack/ai-sandbox-cloudflare/runner` (Node — `runInContainerHarness`, the in-container `chat()` server that validates the request, builds `chat()` over `localProcessSandbox()`, and streams NDJSON back). An app supplies only its config + an adapter resolver: the co-located example's whole worker + container program collapse to ~14 lines. Adds `@tanstack/ai-sandbox-local-process` as a peer dependency (used by the `/runner` entry). - -See `examples/sandbox-cloudflare` for the Worker → Durable Object → Container reference — a TanStack Start app that ships the UI, the agent, the coordinator DO, and the container in one Worker (trigger returns immediately; the DO coordinates, persists to a DO-backed `RunEventLog`, serves the bridge from its `fetch` handler, and streams to clients over a hibernatable WebSocket). The co-located variant (harness + bridge in the container; only `executeHostTool` crosses back) is a supported package mode — `createCloudflareSandboxAgent({ mode: 'colocated' })` plus a one-`runInContainerHarness`-call container program — documented in `docs/sandbox/overview.md`. diff --git a/.changeset/vercel-sandbox-mkdir-idempotent.md b/.changeset/vercel-sandbox-mkdir-idempotent.md deleted file mode 100644 index eb7ac8654..000000000 --- a/.changeset/vercel-sandbox-mkdir-idempotent.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@tanstack/ai-sandbox-vercel': patch ---- - -Fix `create()` failing with HTTP 400 `"cannot create directory '/vercel/sandbox': File exists"` when the workspace directory already exists. The Vercel SDK's native `mkDir` is not idempotent and the default workdir ships in the runtime image, so a fresh sandbox already has it. An "already exists" failure is now treated as success while other filesystem errors still surface. diff --git a/packages/ai-acp/CHANGELOG.md b/packages/ai-acp/CHANGELOG.md new file mode 100644 index 000000000..7900c8e65 --- /dev/null +++ b/packages/ai-acp/CHANGELOG.md @@ -0,0 +1,21 @@ +# @tanstack/ai-acp + +## 0.2.0 + +### Minor Changes + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - Add `acpCompatible` / `acpCompatibleText` — the harness equivalent of `openaiCompatible`. Build a `chat()` text adapter for any ACP-compliant agent CLI and plug it into a sandbox without a dedicated adapter package: configure `command` (stdio) or `openTransport` (WebSocket/custom) once, then select a model per call. Handles sandbox resolution, tool→MCP bridging, session resume, permission modes (`headless` / `interactive`), abort, and AG-UI translation. Also exports the shared `buildAcpPrompt` helper. + + Typed configuration (parity with `openaiCompatible`): declare `models` for a type-safe model union, and a `modelOptions` brand (`{} as { … }`) for the per-call options accepted via `chat({ modelOptions })`. Declared options are merged with the base ACP options and exposed on `ctx.modelOptions` in `command` / `openTransport` so they can become CLI flags. + + ACP client compliance: the `initialize` handshake now sends `clientInfo` and validates the negotiated protocol version. The stream translator surfaces non-text agent content (image/audio/resource blocks) as a `CUSTOM` event (via the new optional `contentEvent` translate label; `acpCompatible` enables it as `.message-content`) instead of dropping it, and preserves non-text tool content (diffs, terminal, images) in the tool-call result payload. + + Workspace skill projection: `acpCompatible` now projects `withSandbox` workspace skills — MCP skills are passed to the agent over ACP's native `mcpServers` (secrets/bearer headers resolved), and `gitSkill`s are linked into a harness-declared `skillsDir` (e.g. `.pi/skills`). `fileSkill`/`instructions`/`secrets` are handled by the provider-agnostic bootstrap. Exposes `workspaceMcpServers` / `projectAcpWorkspace` for adapters built on `openTransport`. + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - Extract shared ACP transport, session, and AG-UI translation into `@tanstack/ai-acp`. Add WebSocket framing for in-sandbox harness servers (`grok agent serve` via `sandbox.ports.connect`). Grok Build defaults to ACP with auto stdio/WebSocket transport selection; `protocol: 'streaming-json'` keeps the legacy NDJSON path. + +### Patch Changes + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai-sandbox@0.2.0 + - @tanstack/ai@0.39.0 diff --git a/packages/ai-acp/package.json b/packages/ai-acp/package.json index fa4d1cdbd..e7935418a 100644 --- a/packages/ai-acp/package.json +++ b/packages/ai-acp/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-acp", - "version": "0.1.0", + "version": "0.2.0", "description": "Shared Agent Client Protocol (ACP) transport, session, and AG-UI translation for TanStack AI harness adapters.", "author": "", "license": "MIT", diff --git a/packages/ai-angular/CHANGELOG.md b/packages/ai-angular/CHANGELOG.md index 0c5e1041f..2749b369f 100644 --- a/packages/ai-angular/CHANGELOG.md +++ b/packages/ai-angular/CHANGELOG.md @@ -1,5 +1,13 @@ # @tanstack/ai-angular +## 0.2.1 + +### Patch Changes + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai@0.39.0 + - @tanstack/ai-client@0.19.1 + ## 0.2.0 ### Minor Changes diff --git a/packages/ai-angular/package.json b/packages/ai-angular/package.json index 0e40e657f..ed05dfd51 100644 --- a/packages/ai-angular/package.json +++ b/packages/ai-angular/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-angular", - "version": "0.2.0", + "version": "0.2.1", "description": "Angular signals integration for TanStack AI streaming chat, structured outputs, and media generation.", "author": "", "license": "MIT", diff --git a/packages/ai-anthropic/CHANGELOG.md b/packages/ai-anthropic/CHANGELOG.md index 15a4c84b3..200b95043 100644 --- a/packages/ai-anthropic/CHANGELOG.md +++ b/packages/ai-anthropic/CHANGELOG.md @@ -1,5 +1,12 @@ # @tanstack/ai-anthropic +## 0.15.12 + +### Patch Changes + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai@0.39.0 + ## 0.15.11 ### Patch Changes diff --git a/packages/ai-anthropic/package.json b/packages/ai-anthropic/package.json index 3747640dd..e8e4efa32 100644 --- a/packages/ai-anthropic/package.json +++ b/packages/ai-anthropic/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-anthropic", - "version": "0.15.11", + "version": "0.15.12", "description": "Anthropic Claude adapter for TanStack AI chat, tool calling, thinking, and structured outputs.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/ai-bedrock/CHANGELOG.md b/packages/ai-bedrock/CHANGELOG.md new file mode 100644 index 000000000..085efd76f --- /dev/null +++ b/packages/ai-bedrock/CHANGELOG.md @@ -0,0 +1,13 @@ +# @tanstack/ai-bedrock + +## 0.1.0 + +### Minor Changes + +- [#665](https://github.com/TanStack/ai/pull/665) [`27ba4c7`](https://github.com/TanStack/ai/commit/27ba4c72eb959786635046dc9e7d58cad3d6c4cd) - Add `@tanstack/ai-bedrock`: an Amazon Bedrock adapter. The default `bedrockText` path uses Bedrock's **Converse** API (`@aws-sdk/client-bedrock-runtime`), reaching the broad chat catalog including Anthropic Claude, Amazon Nova, and Meta Llama, with streaming, tools, reasoning, and structured output. Opt into Bedrock's OpenAI-compatible endpoints with `api: 'chat'` (Chat Completions) or `api: 'responses'` (gpt-oss Responses). Authentication supports Bedrock API keys or SigV4 via the AWS credential chain. + +### Patch Changes + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai@0.39.0 + - @tanstack/openai-base@0.9.6 diff --git a/packages/ai-bedrock/package.json b/packages/ai-bedrock/package.json index 7d4672de4..46cc3e56f 100644 --- a/packages/ai-bedrock/package.json +++ b/packages/ai-bedrock/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-bedrock", - "version": "0.0.1", + "version": "0.1.0", "type": "module", "description": "Amazon Bedrock adapter for TanStack AI — OpenAI-compatible chat, responses, tools, and reasoning.", "author": "", diff --git a/packages/ai-claude-code/CHANGELOG.md b/packages/ai-claude-code/CHANGELOG.md new file mode 100644 index 000000000..7fbed1350 --- /dev/null +++ b/packages/ai-claude-code/CHANGELOG.md @@ -0,0 +1,63 @@ +# @tanstack/ai-claude-code + +## 0.2.0 + +### Minor Changes + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - New `@tanstack/ai-claude-code` package: a Claude Code **harness adapter that runs inside a sandbox**. It declares `requires: [SandboxCapability]` and spawns the `claude` CLI (`claude -p --output-format stream-json`) inside the sandbox provided by `withSandbox(...)`, streaming its events back as AG-UI chunks. Claude Code owns the agent loop and executes its own native tools (bash, file edits, search) against the sandbox workspace; their activity streams back as resolved tool-call events. `chat()`-provided server tools are bridged to the in-sandbox agent over a host-side MCP tool-proxy (calls are proxied back to the host where `execute()` runs). Sessions are resumable via `modelOptions.sessionId` (surfaced through a `claude-code.session-id` custom event), and the working-tree diff is emitted as a `file.changed` custom event after each run. A `defineSandboxPolicy` (allow/ask/deny command globs + file-write/network capability rules) is enforced via Claude Code's `--permission-prompt-tool`: each native tool use is checked against the policy and the client's approval decisions, and an `ask` action with no decision yet surfaces an `approval-requested` event (the client approves and re-runs to continue). Requires the `claude` executable and `ANTHROPIC_API_KEY` to be available in the sandbox (e.g. via `workspace.secrets`). + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - Declarative sandbox provisioning + faster headless init. + - **`createSecrets`**: type-safe secret references; underlying values are stored + in a non-enumerable symbol-keyed registry and never written to snapshots, the + sandbox store, or the event log. Use `secret: secrets.GH` in `gitSkill` for + private-repo auth and `bearer(secrets.GH)` in MCP header values. + - **Declarative `skills` / `plugins` / `instructions`**: `agentSkill`, + `gitSkill` (private-repo clone with `secret`), `mcpSkill` (MCP server with + resolved header values), and `fileSkill` are projected per harness into each + CLI's native format (Claude Code `.mcp.json`, Codex `.codex/config.toml`, + OpenCode `opencode.json`). `instructions` is written + as a canonical `AGENTS.md` at the workspace root; `CLAUDE.md` and `GEMINI.md` + are symlinked (copy fallback). Concepts a CLI lacks emit a warning and are + skipped rather than throwing. + - **Shallow clone by default**: `githubRepo`/`gitSource` default to + `--depth 1 --single-branch`. Pass `depth: number` for a specific history + depth or `depth: 'full'` to disable the flag. + - **Serial/parallel `setup` callback**: `setup` accepts a plain `Array` + (all serial) or a `({ serial, parallel }) => void` callback that records + groups run over a persistent shell — the shell's cwd and env carry over + between serial steps; `parallel([...])` launches commands concurrently + using the shell's forked state. + - **Default snapshot-after-setup**: when the provider supports snapshots, + bootstrap takes one automatically after `setup` completes. Add + `lifecycle.snapshotMaxAge` (e.g. `'24h'`) to re-create the sandbox when the + snapshot is older than the TTL. + - **`@tanstack/ai-sandbox-docker` fix**: a spawned process's demuxed + stdout/stderr now end on the exec stream's `close`/`error` (not only `end`), + so disposing a long-lived process (e.g. the bootstrap shell) no longer hangs + after `kill()`. + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - Serverless/edge run model for the sandbox layer — a trigger can start an agent run and return immediately while a durable orchestrator drives it and clients tail the stream from a resumable cursor. + - **Resumable run event-log** (`RunEventLog`, `InMemoryRunEventLog`, `RunEvent`, `RunRecord`, `isTerminalRunStatus`) — an append-only, `seq`-indexed log of a run's `StreamChunk`s with replay-then-tail reads. A dropped connection, a new tab, or an orchestrator that hibernated between chunks all reconnect by passing their last-seen `seq`. The run never depends on a single open connection. + - **Run driver** (`pipeToRunLog`, `RunController`) — pumps a `chat()` stream into a `RunEventLog` (status transitions, RUN_ERROR capture, abort handling), and a controller that starts a run without blocking, exposes a resumable `attach(runId, { fromSeq })`, and `drain()`s in-flight runs for `waitUntil`-style flushing. + - **Transport-agnostic tool-bridge** — the MCP tool-proxy is split into a portable core (`createToolBridgeCore`, `handleBridgeJsonRpc`) and a transport. `startHostToolBridge` remains the `node:http` host transport (now loopback-bound unless a Docker container must reach it, with a constant-time bearer check); a serverless/edge orchestrator serves the same core from its own `fetch` handler — no raw TCP listener. A new `ToolBridgeProvisioner` capability (`getToolBridgeProvisioner` / `provideToolBridgeProvisioner`, default `nodeHttpBridgeProvisioner`) lets the orchestrator inject the transport. + - **Harness adapters inverted** — `claude-code`, `codex`, and `opencode` now resolve their tool-bridge from the `ToolBridgeProvisioner` capability (defaulting to the host transport) instead of hardcoding `node:http`, so they run unchanged on the host and on the edge. + - **Claude Code runs on the Cloudflare sandbox** — a new required `SandboxCapabilities.writableStdin` flag lets a provider advertise whether spawned processes have a writable host→process stdin — `true` for the host/Docker/local-process providers, `false` for Cloudflare. The Claude Code adapter detects `false` and delivers the prompt via a file + in-shell stdin-redirection (`claude -p … < file`) instead of a host stdin write, keeping it out of argv. Host/Docker behaviour is unchanged (stdin path). + - **Tool-bridge token hardening** — the per-run bearer token is no longer passed inline in argv. The Claude Code adapter writes the bridge MCP config to a file and passes claude the path (`--mcp-config `), so the token can't be read from `ps` / `/proc//cmdline` by other processes in the sandbox. + - **Co-located ("combined") run model** — new `@tanstack/ai-sandbox` exports (`remoteToolStubs`, `toolDescriptors`, `httpRemoteToolExecutor`, `executeHostTool`, plus the `RemoteToolExecutor` interface) let the harness loop AND its MCP tool-bridge run INSIDE the container (the in-container sandbox is just `local-process`, with native stdin + a localhost `node:http` bridge). The orchestrator serializes its tools with `toolDescriptors`; the container rebuilds them as delegating stubs with `remoteToolStubs(descriptors, httpRemoteToolExecutor(url, token))`; the orchestrator answers that one call with `executeHostTool(tools, name, args)`. Only host-tool **execution** crosses the container→orchestrator boundary — the MCP transport itself never leaves the container, shrinking the public surface from the whole MCP protocol to a single authenticated tool-exec call. + - **Request-derived callback hosts, split into bridge vs preview (`resolveBridgeOrigin` / `resolvePreviewHost`)** — the off-isolate sandbox container reaches the Worker over two distinct surfaces, now resolved separately (both exported from `@tanstack/ai-sandbox-cloudflare/agent`; the Worker captures the trigger host as `StartRunInput.publicHost`): + - **Bridge / tool-exec** (container → Worker): `PUBLIC_HOSTNAME` is **optional** — unset → derived from the `POST /runs` request, which is safe on Cloudflare (the edge only routes hostnames you own to your Worker, so the request host is never an attacker's `Host` and the per-run bearer token can't be steered off-domain). A `*.workers.dev` deploy needs no config; **local dev uses `host.docker.internal`** (the Docker host gateway), so agent runs work locally with **no tunnel**. + - **Preview** (browser → Worker → container, `exposePort`): a separate `PREVIEW_HOSTNAME`, because preview URLs require **wildcard DNS**. **Local** uses `*.localhost` (browser-resolved to loopback — previews work locally with no tunnel); **deployed** requires a **custom domain** with a `*.` route. `*.workers.dev` has no wildcard subdomains (the SDK's `exposePort` rejects it), so `resolvePreviewHost` throws a clear error pointing at `PREVIEW_HOSTNAME` rather than returning a dead URL. + - **Preview wiring is package-provided, not example glue** — `@tanstack/ai-sandbox-cloudflare/agent` now exports `exposePreviewTool(input, env)` (a ready-made `exposePreview` `chat()` server tool) and `PREVIEW_GUIDANCE` (an app-agnostic system prompt), and `createCloudflareSandboxAgent` gains a `systemPrompts` option (do-drives) to wire the guidance in. The tool mints previews via a **Cloudflare quick tunnel** (`sandbox.tunnels.get(port)` → `*.trycloudflare.com`), served by `cloudflared` inside the sandbox — deliberately NOT `exposePort` + `proxyToSandbox`, which routes the preview through the Worker origin (in local dev, your Vite dev server, whose middleware then serves the preview's `/@vite/client` / `/src/*` / `/@fs/*` from the host instead of the container and breaks the page). A tunnel bypasses the Vite port, needs no custom domain on a deploy, and forwards WebSockets (HMR works). `PREVIEW_GUIDANCE` just tells the agent to bind wide and allow all hosts so the tunnel hostname is accepted (Vite `server: { host: true, allowedHosts: true }`). Because `sandbox.tunnels` exists only on the SDK's **RPC** transport (it throws `requires the RPC transport` on the default `http`), `cloudflareSandbox` now defaults to `transport: 'rpc'` (new `transport` config option to override) and applies it to create/resume/destroy; `exposePreviewTool` obtains its stub with `transport: 'rpc'` too. `exposePort` + `resolvePreviewHost` remain available for Worker-fronted previews on a custom domain. Adds `zod` as a peer dependency. + - **`@tanstack/ai-sandbox-cloudflare` ships the runtime, not just the example** — the Worker router, the coordinator Durable Object, the durable run-log, and the `POST /run` wire contract are now package code, exported from two entries: `@tanstack/ai-sandbox-cloudflare/agent` (Workers-only — `createCloudflareSandboxAgent`, the coordinator base classes, `DurableObjectRunEventLog`, plus the shared `ContainerRunRequest` + `parseContainerRunRequest`), and `@tanstack/ai-sandbox-cloudflare/runner` (Node — `runInContainerHarness`, the in-container `chat()` server that validates the request, builds `chat()` over `localProcessSandbox()`, and streams NDJSON back). An app supplies only its config + an adapter resolver: the co-located example's whole worker + container program collapse to ~14 lines. Adds `@tanstack/ai-sandbox-local-process` as a peer dependency (used by the `/runner` entry). + + See `examples/sandbox-cloudflare` for the Worker → Durable Object → Container reference — a TanStack Start app that ships the UI, the agent, the coordinator DO, and the container in one Worker (trigger returns immediately; the DO coordinates, persists to a DO-backed `RunEventLog`, serves the bridge from its `fetch` handler, and streams to clients over a hibernatable WebSocket). The co-located variant (harness + bridge in the container; only `executeHostTool` crosses back) is a supported package mode — `createCloudflareSandboxAgent({ mode: 'colocated' })` plus a one-`runInContainerHarness`-call container program — documented in `docs/sandbox/overview.md`. + +### Patch Changes + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - Fix the Claude Code harness never starting its turn in a Cloudflare sandbox (runs sat at `status:running` forever, streaming nothing). Two root causes: + - **`@tanstack/ai-claude-code`**: the adapter defaults `--permission-mode bypassPermissions`, which Claude Code maps to `--dangerously-skip-permissions` and refuses to run as root. Sandbox containers (Docker/Cloudflare) run as root, so `claude` died instantly. The adapter now sets `IS_SANDBOX=1` in the CLI's environment (Claude Code's documented escape hatch for running skip-permissions in an isolated environment), merged over any caller-provided env. + - **`@tanstack/ai-sandbox-cloudflare`**: `spawn()` used `@cloudflare/sandbox`'s background-process API (`startProcess` + `streamProcessLogs`), whose `onOutput`/`onExit` callbacks never fire, so a stdout-NDJSON harness hung forever. `spawn()` now streams over `exec({ stream: true, onOutput })` — the same proven command path as one-shot `exec` — and resolves the exit code from its result. The caller's `AbortSignal` is no longer forwarded across the Durable Object RPC boundary (Workers RPC cannot serialize an `AbortSignal`, which previously threw before the command ran); mid-run cancellation is unavailable on this provider and a stuck run is bounded by the coordinator watchdog instead. A failed command now rejects `wait()` so the adapter surfaces a `RUN_ERROR` rather than a silent zero-output run. + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai-sandbox@0.2.0 + - @tanstack/ai@0.39.0 diff --git a/packages/ai-claude-code/package.json b/packages/ai-claude-code/package.json index 3fb3ed30b..f41ac9333 100644 --- a/packages/ai-claude-code/package.json +++ b/packages/ai-claude-code/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-claude-code", - "version": "0.1.0", + "version": "0.2.0", "description": "Claude Code harness adapter for TanStack AI — run Claude Code as a chat backend with local tool execution and stateful sessions.", "author": "", "license": "MIT", diff --git a/packages/ai-client/CHANGELOG.md b/packages/ai-client/CHANGELOG.md index a10043f9a..60988914e 100644 --- a/packages/ai-client/CHANGELOG.md +++ b/packages/ai-client/CHANGELOG.md @@ -1,5 +1,12 @@ # @tanstack/ai-client +## 0.19.1 + +### Patch Changes + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai@0.39.0 + ## 0.19.0 ### Minor Changes diff --git a/packages/ai-client/package.json b/packages/ai-client/package.json index 28cf40b6d..46e656b3c 100644 --- a/packages/ai-client/package.json +++ b/packages/ai-client/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-client", - "version": "0.19.0", + "version": "0.19.1", "description": "Framework-agnostic headless client for TanStack AI chat, realtime sessions, streaming transports, and media generations.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/ai-code-mode-skills/CHANGELOG.md b/packages/ai-code-mode-skills/CHANGELOG.md index dac55d193..e2acb8378 100644 --- a/packages/ai-code-mode-skills/CHANGELOG.md +++ b/packages/ai-code-mode-skills/CHANGELOG.md @@ -1,5 +1,13 @@ # @tanstack/ai-code-mode-skills +## 0.3.6 + +### Patch Changes + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai@0.39.0 + - @tanstack/ai-code-mode@0.3.3 + ## 0.3.5 ### Patch Changes diff --git a/packages/ai-code-mode-skills/package.json b/packages/ai-code-mode-skills/package.json index 3743e5a2c..4d1e25826 100644 --- a/packages/ai-code-mode-skills/package.json +++ b/packages/ai-code-mode-skills/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-code-mode-skills", - "version": "0.3.5", + "version": "0.3.6", "description": "Persistent runtime skill library for TanStack AI Code Mode agents and sandboxed tool orchestration.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/ai-code-mode/CHANGELOG.md b/packages/ai-code-mode/CHANGELOG.md index ea1957ba5..b90e66ac0 100644 --- a/packages/ai-code-mode/CHANGELOG.md +++ b/packages/ai-code-mode/CHANGELOG.md @@ -1,5 +1,12 @@ # @tanstack/ai-code-mode +## 0.3.3 + +### Patch Changes + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai@0.39.0 + ## 0.3.2 ### Patch Changes diff --git a/packages/ai-code-mode/package.json b/packages/ai-code-mode/package.json index 258011724..177491d19 100644 --- a/packages/ai-code-mode/package.json +++ b/packages/ai-code-mode/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-code-mode", - "version": "0.3.2", + "version": "0.3.3", "description": "Secure TypeScript Code Mode for TanStack AI agents to execute sandboxed tool orchestration programs.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/ai-codex/CHANGELOG.md b/packages/ai-codex/CHANGELOG.md new file mode 100644 index 000000000..7e38d204a --- /dev/null +++ b/packages/ai-codex/CHANGELOG.md @@ -0,0 +1,61 @@ +# @tanstack/ai-codex + +## 0.2.0 + +### Minor Changes + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - New `@tanstack/ai-codex` package: a Codex **harness adapter that runs inside a sandbox**. It declares `requires: [SandboxCapability]` and spawns `codex exec --experimental-json` inside the sandbox provided by `withSandbox(...)` (mirroring `@openai/codex-sdk`'s own CLI invocation), feeding the prompt via stdin and streaming its JSONL thread events back as AG-UI chunks. Codex owns the agent loop and executes its built-in tools (shell, file changes, web search, todo lists) against the sandbox workspace. Threads are resumable via `modelOptions.sessionId` (surfaced through a `codex.session-id` custom event); sandbox mode / approval policy / reasoning effort map to codex CLI flags. Requires the `codex` executable and `CODEX_API_KEY` (or a `codex login`) in the sandbox. chat()-provided server tools are bridged into the agent via the host MCP tool-proxy. A `defineSandboxPolicy` is mapped onto Codex's coarse permission knobs (sandbox mode, `approval_policy`, `network_access`); because `codex exec` runs non-interactively with no per-action host callback, the fine-grained resume-based interactive-approval flow is not available for Codex (it refuses, rather than prompts for, actions needing approval). + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - Declarative sandbox provisioning + faster headless init. + - **`createSecrets`**: type-safe secret references; underlying values are stored + in a non-enumerable symbol-keyed registry and never written to snapshots, the + sandbox store, or the event log. Use `secret: secrets.GH` in `gitSkill` for + private-repo auth and `bearer(secrets.GH)` in MCP header values. + - **Declarative `skills` / `plugins` / `instructions`**: `agentSkill`, + `gitSkill` (private-repo clone with `secret`), `mcpSkill` (MCP server with + resolved header values), and `fileSkill` are projected per harness into each + CLI's native format (Claude Code `.mcp.json`, Codex `.codex/config.toml`, + OpenCode `opencode.json`). `instructions` is written + as a canonical `AGENTS.md` at the workspace root; `CLAUDE.md` and `GEMINI.md` + are symlinked (copy fallback). Concepts a CLI lacks emit a warning and are + skipped rather than throwing. + - **Shallow clone by default**: `githubRepo`/`gitSource` default to + `--depth 1 --single-branch`. Pass `depth: number` for a specific history + depth or `depth: 'full'` to disable the flag. + - **Serial/parallel `setup` callback**: `setup` accepts a plain `Array` + (all serial) or a `({ serial, parallel }) => void` callback that records + groups run over a persistent shell — the shell's cwd and env carry over + between serial steps; `parallel([...])` launches commands concurrently + using the shell's forked state. + - **Default snapshot-after-setup**: when the provider supports snapshots, + bootstrap takes one automatically after `setup` completes. Add + `lifecycle.snapshotMaxAge` (e.g. `'24h'`) to re-create the sandbox when the + snapshot is older than the TTL. + - **`@tanstack/ai-sandbox-docker` fix**: a spawned process's demuxed + stdout/stderr now end on the exec stream's `close`/`error` (not only `end`), + so disposing a long-lived process (e.g. the bootstrap shell) no longer hangs + after `kill()`. + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - Serverless/edge run model for the sandbox layer — a trigger can start an agent run and return immediately while a durable orchestrator drives it and clients tail the stream from a resumable cursor. + - **Resumable run event-log** (`RunEventLog`, `InMemoryRunEventLog`, `RunEvent`, `RunRecord`, `isTerminalRunStatus`) — an append-only, `seq`-indexed log of a run's `StreamChunk`s with replay-then-tail reads. A dropped connection, a new tab, or an orchestrator that hibernated between chunks all reconnect by passing their last-seen `seq`. The run never depends on a single open connection. + - **Run driver** (`pipeToRunLog`, `RunController`) — pumps a `chat()` stream into a `RunEventLog` (status transitions, RUN_ERROR capture, abort handling), and a controller that starts a run without blocking, exposes a resumable `attach(runId, { fromSeq })`, and `drain()`s in-flight runs for `waitUntil`-style flushing. + - **Transport-agnostic tool-bridge** — the MCP tool-proxy is split into a portable core (`createToolBridgeCore`, `handleBridgeJsonRpc`) and a transport. `startHostToolBridge` remains the `node:http` host transport (now loopback-bound unless a Docker container must reach it, with a constant-time bearer check); a serverless/edge orchestrator serves the same core from its own `fetch` handler — no raw TCP listener. A new `ToolBridgeProvisioner` capability (`getToolBridgeProvisioner` / `provideToolBridgeProvisioner`, default `nodeHttpBridgeProvisioner`) lets the orchestrator inject the transport. + - **Harness adapters inverted** — `claude-code`, `codex`, and `opencode` now resolve their tool-bridge from the `ToolBridgeProvisioner` capability (defaulting to the host transport) instead of hardcoding `node:http`, so they run unchanged on the host and on the edge. + - **Claude Code runs on the Cloudflare sandbox** — a new required `SandboxCapabilities.writableStdin` flag lets a provider advertise whether spawned processes have a writable host→process stdin — `true` for the host/Docker/local-process providers, `false` for Cloudflare. The Claude Code adapter detects `false` and delivers the prompt via a file + in-shell stdin-redirection (`claude -p … < file`) instead of a host stdin write, keeping it out of argv. Host/Docker behaviour is unchanged (stdin path). + - **Tool-bridge token hardening** — the per-run bearer token is no longer passed inline in argv. The Claude Code adapter writes the bridge MCP config to a file and passes claude the path (`--mcp-config `), so the token can't be read from `ps` / `/proc//cmdline` by other processes in the sandbox. + - **Co-located ("combined") run model** — new `@tanstack/ai-sandbox` exports (`remoteToolStubs`, `toolDescriptors`, `httpRemoteToolExecutor`, `executeHostTool`, plus the `RemoteToolExecutor` interface) let the harness loop AND its MCP tool-bridge run INSIDE the container (the in-container sandbox is just `local-process`, with native stdin + a localhost `node:http` bridge). The orchestrator serializes its tools with `toolDescriptors`; the container rebuilds them as delegating stubs with `remoteToolStubs(descriptors, httpRemoteToolExecutor(url, token))`; the orchestrator answers that one call with `executeHostTool(tools, name, args)`. Only host-tool **execution** crosses the container→orchestrator boundary — the MCP transport itself never leaves the container, shrinking the public surface from the whole MCP protocol to a single authenticated tool-exec call. + - **Request-derived callback hosts, split into bridge vs preview (`resolveBridgeOrigin` / `resolvePreviewHost`)** — the off-isolate sandbox container reaches the Worker over two distinct surfaces, now resolved separately (both exported from `@tanstack/ai-sandbox-cloudflare/agent`; the Worker captures the trigger host as `StartRunInput.publicHost`): + - **Bridge / tool-exec** (container → Worker): `PUBLIC_HOSTNAME` is **optional** — unset → derived from the `POST /runs` request, which is safe on Cloudflare (the edge only routes hostnames you own to your Worker, so the request host is never an attacker's `Host` and the per-run bearer token can't be steered off-domain). A `*.workers.dev` deploy needs no config; **local dev uses `host.docker.internal`** (the Docker host gateway), so agent runs work locally with **no tunnel**. + - **Preview** (browser → Worker → container, `exposePort`): a separate `PREVIEW_HOSTNAME`, because preview URLs require **wildcard DNS**. **Local** uses `*.localhost` (browser-resolved to loopback — previews work locally with no tunnel); **deployed** requires a **custom domain** with a `*.` route. `*.workers.dev` has no wildcard subdomains (the SDK's `exposePort` rejects it), so `resolvePreviewHost` throws a clear error pointing at `PREVIEW_HOSTNAME` rather than returning a dead URL. + - **Preview wiring is package-provided, not example glue** — `@tanstack/ai-sandbox-cloudflare/agent` now exports `exposePreviewTool(input, env)` (a ready-made `exposePreview` `chat()` server tool) and `PREVIEW_GUIDANCE` (an app-agnostic system prompt), and `createCloudflareSandboxAgent` gains a `systemPrompts` option (do-drives) to wire the guidance in. The tool mints previews via a **Cloudflare quick tunnel** (`sandbox.tunnels.get(port)` → `*.trycloudflare.com`), served by `cloudflared` inside the sandbox — deliberately NOT `exposePort` + `proxyToSandbox`, which routes the preview through the Worker origin (in local dev, your Vite dev server, whose middleware then serves the preview's `/@vite/client` / `/src/*` / `/@fs/*` from the host instead of the container and breaks the page). A tunnel bypasses the Vite port, needs no custom domain on a deploy, and forwards WebSockets (HMR works). `PREVIEW_GUIDANCE` just tells the agent to bind wide and allow all hosts so the tunnel hostname is accepted (Vite `server: { host: true, allowedHosts: true }`). Because `sandbox.tunnels` exists only on the SDK's **RPC** transport (it throws `requires the RPC transport` on the default `http`), `cloudflareSandbox` now defaults to `transport: 'rpc'` (new `transport` config option to override) and applies it to create/resume/destroy; `exposePreviewTool` obtains its stub with `transport: 'rpc'` too. `exposePort` + `resolvePreviewHost` remain available for Worker-fronted previews on a custom domain. Adds `zod` as a peer dependency. + - **`@tanstack/ai-sandbox-cloudflare` ships the runtime, not just the example** — the Worker router, the coordinator Durable Object, the durable run-log, and the `POST /run` wire contract are now package code, exported from two entries: `@tanstack/ai-sandbox-cloudflare/agent` (Workers-only — `createCloudflareSandboxAgent`, the coordinator base classes, `DurableObjectRunEventLog`, plus the shared `ContainerRunRequest` + `parseContainerRunRequest`), and `@tanstack/ai-sandbox-cloudflare/runner` (Node — `runInContainerHarness`, the in-container `chat()` server that validates the request, builds `chat()` over `localProcessSandbox()`, and streams NDJSON back). An app supplies only its config + an adapter resolver: the co-located example's whole worker + container program collapse to ~14 lines. Adds `@tanstack/ai-sandbox-local-process` as a peer dependency (used by the `/runner` entry). + + See `examples/sandbox-cloudflare` for the Worker → Durable Object → Container reference — a TanStack Start app that ships the UI, the agent, the coordinator DO, and the container in one Worker (trigger returns immediately; the DO coordinates, persists to a DO-backed `RunEventLog`, serves the bridge from its `fetch` handler, and streams to clients over a hibernatable WebSocket). The co-located variant (harness + bridge in the container; only `executeHostTool` crosses back) is a supported package mode — `createCloudflareSandboxAgent({ mode: 'colocated' })` plus a one-`runInContainerHarness`-call container program — documented in `docs/sandbox/overview.md`. + +### Patch Changes + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - Fix codex failing to start whenever `chat()`-provided tools are bridged to it. The adapter configured the MCP tool-bridge with an inline `mcp_servers..bearer_token`, but current codex rejects that for the streamable-HTTP transport — the run died immediately with `Error loading config.toml: bearer_token is not supported for streamable_http`. The per-run bearer is now passed as an `Authorization` header (`http_headers = { "Authorization" = "Bearer " }`), matching what the workspace-MCP projection already emits and what the host tool-bridge authenticates against. Codex with bridged tools (e.g. the Cloudflare sandbox example) now runs end to end. + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai-sandbox@0.2.0 + - @tanstack/ai@0.39.0 diff --git a/packages/ai-codex/package.json b/packages/ai-codex/package.json index cf0149965..8f9d004c3 100644 --- a/packages/ai-codex/package.json +++ b/packages/ai-codex/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-codex", - "version": "0.1.0", + "version": "0.2.0", "description": "Codex harness adapter for TanStack AI — run OpenAI Codex as a chat backend with local tool execution and stateful sessions.", "author": "", "license": "MIT", diff --git a/packages/ai-devtools/CHANGELOG.md b/packages/ai-devtools/CHANGELOG.md index 20624e94a..7e99a5e59 100644 --- a/packages/ai-devtools/CHANGELOG.md +++ b/packages/ai-devtools/CHANGELOG.md @@ -1,5 +1,12 @@ # @tanstack/ai-devtools-core +## 0.4.20 + +### Patch Changes + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai@0.39.0 + ## 0.4.19 ### Patch Changes diff --git a/packages/ai-devtools/package.json b/packages/ai-devtools/package.json index 8de070bfe..379534763 100644 --- a/packages/ai-devtools/package.json +++ b/packages/ai-devtools/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-devtools-core", - "version": "0.4.19", + "version": "0.4.20", "description": "Core TanStack AI Devtools plugin for inspecting chat messages, tool calls, streams, and errors.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/ai-elevenlabs/CHANGELOG.md b/packages/ai-elevenlabs/CHANGELOG.md index f930069b1..dc077878c 100644 --- a/packages/ai-elevenlabs/CHANGELOG.md +++ b/packages/ai-elevenlabs/CHANGELOG.md @@ -1,5 +1,12 @@ # @tanstack/ai-elevenlabs +## 0.2.31 + +### Patch Changes + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai@0.39.0 + ## 0.2.30 ### Patch Changes diff --git a/packages/ai-elevenlabs/package.json b/packages/ai-elevenlabs/package.json index 09449ae88..c44961eeb 100644 --- a/packages/ai-elevenlabs/package.json +++ b/packages/ai-elevenlabs/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-elevenlabs", - "version": "0.2.30", + "version": "0.2.31", "description": "ElevenLabs adapter for TanStack AI realtime voice, text-to-speech, transcription, music, and sound effects.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/ai-fal/CHANGELOG.md b/packages/ai-fal/CHANGELOG.md index 10d180a60..4e5141eb9 100644 --- a/packages/ai-fal/CHANGELOG.md +++ b/packages/ai-fal/CHANGELOG.md @@ -1,5 +1,12 @@ # @tanstack/ai-fal +## 0.9.8 + +### Patch Changes + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai@0.39.0 + ## 0.9.7 ### Patch Changes diff --git a/packages/ai-fal/package.json b/packages/ai-fal/package.json index 73b9a3947..54ca82705 100644 --- a/packages/ai-fal/package.json +++ b/packages/ai-fal/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-fal", - "version": "0.9.7", + "version": "0.9.8", "description": "fal.ai adapter for TanStack AI image, video, audio, speech, and transcription generation.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/ai-gemini/CHANGELOG.md b/packages/ai-gemini/CHANGELOG.md index 21637ebd5..16090e4fe 100644 --- a/packages/ai-gemini/CHANGELOG.md +++ b/packages/ai-gemini/CHANGELOG.md @@ -1,5 +1,12 @@ # @tanstack/ai-gemini +## 0.18.4 + +### Patch Changes + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai@0.39.0 + ## 0.18.3 ### Patch Changes diff --git a/packages/ai-gemini/package.json b/packages/ai-gemini/package.json index e2b5fdb38..2b29fd21f 100644 --- a/packages/ai-gemini/package.json +++ b/packages/ai-gemini/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-gemini", - "version": "0.18.3", + "version": "0.18.4", "description": "Google Gemini adapter for TanStack AI chat, images, speech, audio generation, and structured outputs.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/ai-grok-build/CHANGELOG.md b/packages/ai-grok-build/CHANGELOG.md new file mode 100644 index 000000000..b5aea8ac1 --- /dev/null +++ b/packages/ai-grok-build/CHANGELOG.md @@ -0,0 +1,14 @@ +# @tanstack/ai-grok-build + +## 0.2.0 + +### Minor Changes + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - Extract shared ACP transport, session, and AG-UI translation into `@tanstack/ai-acp`. Add WebSocket framing for in-sandbox harness servers (`grok agent serve` via `sandbox.ports.connect`). Grok Build defaults to ACP with auto stdio/WebSocket transport selection; `protocol: 'streaming-json'` keeps the legacy NDJSON path. + +### Patch Changes + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai-acp@0.2.0 + - @tanstack/ai-sandbox@0.2.0 + - @tanstack/ai@0.39.0 diff --git a/packages/ai-grok-build/package.json b/packages/ai-grok-build/package.json index 0d1d7cdc9..d714236dc 100644 --- a/packages/ai-grok-build/package.json +++ b/packages/ai-grok-build/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-grok-build", - "version": "0.1.0", + "version": "0.2.0", "description": "Grok Build harness adapter for TanStack AI — run Grok Build as a chat backend with local tool execution and stateful sessions.", "author": "", "license": "MIT", diff --git a/packages/ai-grok/CHANGELOG.md b/packages/ai-grok/CHANGELOG.md index 85d26bea7..266ba4035 100644 --- a/packages/ai-grok/CHANGELOG.md +++ b/packages/ai-grok/CHANGELOG.md @@ -1,5 +1,13 @@ # @tanstack/ai-grok +## 0.14.6 + +### Patch Changes + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai@0.39.0 + - @tanstack/openai-base@0.9.6 + ## 0.14.5 ### Patch Changes diff --git a/packages/ai-grok/package.json b/packages/ai-grok/package.json index 8d15b16e8..a1463db0e 100644 --- a/packages/ai-grok/package.json +++ b/packages/ai-grok/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-grok", - "version": "0.14.5", + "version": "0.14.6", "description": "xAI Grok adapter for TanStack AI chat, image generation, realtime, and structured outputs.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/ai-groq/CHANGELOG.md b/packages/ai-groq/CHANGELOG.md index b4264e84c..d1115617f 100644 --- a/packages/ai-groq/CHANGELOG.md +++ b/packages/ai-groq/CHANGELOG.md @@ -1,5 +1,13 @@ # @tanstack/ai-groq +## 0.4.16 + +### Patch Changes + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai@0.39.0 + - @tanstack/openai-base@0.9.6 + ## 0.4.15 ### Patch Changes diff --git a/packages/ai-groq/package.json b/packages/ai-groq/package.json index bc2eaee23..555f36832 100644 --- a/packages/ai-groq/package.json +++ b/packages/ai-groq/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-groq", - "version": "0.4.15", + "version": "0.4.16", "description": "Groq adapter for TanStack AI low-latency chat, tool calling, and structured outputs.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/ai-isolate-cloudflare/CHANGELOG.md b/packages/ai-isolate-cloudflare/CHANGELOG.md index 38beeec59..f4cd550e9 100644 --- a/packages/ai-isolate-cloudflare/CHANGELOG.md +++ b/packages/ai-isolate-cloudflare/CHANGELOG.md @@ -1,5 +1,12 @@ # @tanstack/ai-isolate-cloudflare +## 0.2.33 + +### Patch Changes + +- Updated dependencies []: + - @tanstack/ai-code-mode@0.3.3 + ## 0.2.32 ### Patch Changes diff --git a/packages/ai-isolate-cloudflare/package.json b/packages/ai-isolate-cloudflare/package.json index 859aa056b..875982623 100644 --- a/packages/ai-isolate-cloudflare/package.json +++ b/packages/ai-isolate-cloudflare/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-isolate-cloudflare", - "version": "0.2.32", + "version": "0.2.33", "description": "Cloudflare Workers sandbox driver for TanStack AI Code Mode TypeScript execution at the edge.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/ai-isolate-node/CHANGELOG.md b/packages/ai-isolate-node/CHANGELOG.md index ccde69c8a..be62a3297 100644 --- a/packages/ai-isolate-node/CHANGELOG.md +++ b/packages/ai-isolate-node/CHANGELOG.md @@ -1,5 +1,12 @@ # @tanstack/ai-isolate-node +## 0.1.42 + +### Patch Changes + +- Updated dependencies []: + - @tanstack/ai-code-mode@0.3.3 + ## 0.1.41 ### Patch Changes diff --git a/packages/ai-isolate-node/package.json b/packages/ai-isolate-node/package.json index 719ac78a5..67f91b581 100644 --- a/packages/ai-isolate-node/package.json +++ b/packages/ai-isolate-node/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-isolate-node", - "version": "0.1.41", + "version": "0.1.42", "description": "Node.js isolated-vm sandbox driver for TanStack AI Code Mode TypeScript execution.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/ai-isolate-quickjs/CHANGELOG.md b/packages/ai-isolate-quickjs/CHANGELOG.md index cb8002087..d817f5b21 100644 --- a/packages/ai-isolate-quickjs/CHANGELOG.md +++ b/packages/ai-isolate-quickjs/CHANGELOG.md @@ -1,5 +1,12 @@ # @tanstack/ai-isolate-quickjs +## 0.1.42 + +### Patch Changes + +- Updated dependencies []: + - @tanstack/ai-code-mode@0.3.3 + ## 0.1.41 ### Patch Changes diff --git a/packages/ai-isolate-quickjs/package.json b/packages/ai-isolate-quickjs/package.json index 09a1e5729..bd1b51881 100644 --- a/packages/ai-isolate-quickjs/package.json +++ b/packages/ai-isolate-quickjs/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-isolate-quickjs", - "version": "0.1.41", + "version": "0.1.42", "description": "QuickJS WASM sandbox driver for TanStack AI Code Mode TypeScript execution across runtimes.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/ai-mcp/CHANGELOG.md b/packages/ai-mcp/CHANGELOG.md index 937d2ca53..c0730f919 100644 --- a/packages/ai-mcp/CHANGELOG.md +++ b/packages/ai-mcp/CHANGELOG.md @@ -1,5 +1,12 @@ # @tanstack/ai-mcp +## 0.2.1 + +### Patch Changes + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai@0.39.0 + ## 0.2.0 ### Minor Changes diff --git a/packages/ai-mcp/package.json b/packages/ai-mcp/package.json index 360ac7ea2..6e573de53 100644 --- a/packages/ai-mcp/package.json +++ b/packages/ai-mcp/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-mcp", - "version": "0.2.0", + "version": "0.2.1", "description": "Host-side Model Context Protocol client for TanStack AI: discover and run MCP server tools, resources, and prompts in any adapter's chat() loop, with generated end-to-end types.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/ai-mistral/CHANGELOG.md b/packages/ai-mistral/CHANGELOG.md new file mode 100644 index 000000000..0e42f809a --- /dev/null +++ b/packages/ai-mistral/CHANGELOG.md @@ -0,0 +1,12 @@ +# @tanstack/ai-mistral + +## 0.2.0 + +### Minor Changes + +- [#462](https://github.com/TanStack/ai/pull/462) [`e5f2f4b`](https://github.com/TanStack/ai/commit/e5f2f4b7ed3efb389377e614e9f0c177b42a555a) - Add new `@tanstack/ai-mistral` adapter package for Mistral models using the `@mistralai/mistralai` SDK. Supports streaming chat, tool calling, vision input (Pixtral / Mistral Medium / Small), structured output via JSON Schema, and reasoning streams (Magistral) — emitted as AG-UI `REASONING_*` events. Includes model metadata for Mistral Large, Medium, Small, Ministral 3B/8B, Codestral, Pixtral, Magistral, and Open Mistral Nemo. + +### Patch Changes + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai@0.39.0 diff --git a/packages/ai-mistral/package.json b/packages/ai-mistral/package.json index 958cec7b8..94d854669 100644 --- a/packages/ai-mistral/package.json +++ b/packages/ai-mistral/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-mistral", - "version": "0.1.0", + "version": "0.2.0", "type": "module", "description": "Mistral adapter for TanStack AI", "author": "", diff --git a/packages/ai-ollama/CHANGELOG.md b/packages/ai-ollama/CHANGELOG.md index ec89f893e..dabd3a274 100644 --- a/packages/ai-ollama/CHANGELOG.md +++ b/packages/ai-ollama/CHANGELOG.md @@ -1,5 +1,12 @@ # @tanstack/ai-ollama +## 0.8.12 + +### Patch Changes + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai@0.39.0 + ## 0.8.11 ### Patch Changes diff --git a/packages/ai-ollama/package.json b/packages/ai-ollama/package.json index 0a5f1957d..8f2d4d11c 100644 --- a/packages/ai-ollama/package.json +++ b/packages/ai-ollama/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-ollama", - "version": "0.8.11", + "version": "0.8.12", "description": "Ollama adapter for TanStack AI local LLM chat, tool calling, and structured outputs.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/ai-openai/CHANGELOG.md b/packages/ai-openai/CHANGELOG.md index 5be762ee8..05f9cd03d 100644 --- a/packages/ai-openai/CHANGELOG.md +++ b/packages/ai-openai/CHANGELOG.md @@ -1,5 +1,13 @@ # @tanstack/ai-openai +## 0.15.10 + +### Patch Changes + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai@0.39.0 + - @tanstack/openai-base@0.9.6 + ## 0.15.9 ### Patch Changes diff --git a/packages/ai-openai/package.json b/packages/ai-openai/package.json index 6df43c6ce..c4747729f 100644 --- a/packages/ai-openai/package.json +++ b/packages/ai-openai/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-openai", - "version": "0.15.9", + "version": "0.15.10", "description": "OpenAI adapter for TanStack AI chat, tools, images, video, speech, transcription, realtime, and structured outputs.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/ai-opencode/CHANGELOG.md b/packages/ai-opencode/CHANGELOG.md new file mode 100644 index 000000000..394a18795 --- /dev/null +++ b/packages/ai-opencode/CHANGELOG.md @@ -0,0 +1,59 @@ +# @tanstack/ai-opencode + +## 0.2.0 + +### Minor Changes + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - New `@tanstack/ai-opencode` package: an OpenCode **harness adapter that runs inside a sandbox**. It declares `requires: [SandboxCapability]`, spawns `opencode serve` inside the sandbox provided by `withSandbox(...)`, exposes its port, and connects the `@opencode-ai/sdk` HTTP client to it via `baseUrl`. OpenCode owns the agent loop and executes its built-in tools (shell, file edits, search) against the sandbox workspace; assistant text/thinking stream as token-level deltas and tool activity as resolved tool-call events. Sessions are resumable, and OpenCode permission requests are answered by a configurable `permissionMode` (`default` / `acceptEdits` / `bypassPermissions` or a custom handler), and a request the policy would reject with no client decision yet surfaces an `approval-requested` event so the client can approve and re-run to grant it (interactive approvals). Requires the `opencode` CLI in the sandbox (Docker: publish the server port via `publishPorts`). chat()-provided server tools are bridged into the agent via the host MCP tool-proxy. + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - Declarative sandbox provisioning + faster headless init. + - **`createSecrets`**: type-safe secret references; underlying values are stored + in a non-enumerable symbol-keyed registry and never written to snapshots, the + sandbox store, or the event log. Use `secret: secrets.GH` in `gitSkill` for + private-repo auth and `bearer(secrets.GH)` in MCP header values. + - **Declarative `skills` / `plugins` / `instructions`**: `agentSkill`, + `gitSkill` (private-repo clone with `secret`), `mcpSkill` (MCP server with + resolved header values), and `fileSkill` are projected per harness into each + CLI's native format (Claude Code `.mcp.json`, Codex `.codex/config.toml`, + OpenCode `opencode.json`). `instructions` is written + as a canonical `AGENTS.md` at the workspace root; `CLAUDE.md` and `GEMINI.md` + are symlinked (copy fallback). Concepts a CLI lacks emit a warning and are + skipped rather than throwing. + - **Shallow clone by default**: `githubRepo`/`gitSource` default to + `--depth 1 --single-branch`. Pass `depth: number` for a specific history + depth or `depth: 'full'` to disable the flag. + - **Serial/parallel `setup` callback**: `setup` accepts a plain `Array` + (all serial) or a `({ serial, parallel }) => void` callback that records + groups run over a persistent shell — the shell's cwd and env carry over + between serial steps; `parallel([...])` launches commands concurrently + using the shell's forked state. + - **Default snapshot-after-setup**: when the provider supports snapshots, + bootstrap takes one automatically after `setup` completes. Add + `lifecycle.snapshotMaxAge` (e.g. `'24h'`) to re-create the sandbox when the + snapshot is older than the TTL. + - **`@tanstack/ai-sandbox-docker` fix**: a spawned process's demuxed + stdout/stderr now end on the exec stream's `close`/`error` (not only `end`), + so disposing a long-lived process (e.g. the bootstrap shell) no longer hangs + after `kill()`. + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - Serverless/edge run model for the sandbox layer — a trigger can start an agent run and return immediately while a durable orchestrator drives it and clients tail the stream from a resumable cursor. + - **Resumable run event-log** (`RunEventLog`, `InMemoryRunEventLog`, `RunEvent`, `RunRecord`, `isTerminalRunStatus`) — an append-only, `seq`-indexed log of a run's `StreamChunk`s with replay-then-tail reads. A dropped connection, a new tab, or an orchestrator that hibernated between chunks all reconnect by passing their last-seen `seq`. The run never depends on a single open connection. + - **Run driver** (`pipeToRunLog`, `RunController`) — pumps a `chat()` stream into a `RunEventLog` (status transitions, RUN_ERROR capture, abort handling), and a controller that starts a run without blocking, exposes a resumable `attach(runId, { fromSeq })`, and `drain()`s in-flight runs for `waitUntil`-style flushing. + - **Transport-agnostic tool-bridge** — the MCP tool-proxy is split into a portable core (`createToolBridgeCore`, `handleBridgeJsonRpc`) and a transport. `startHostToolBridge` remains the `node:http` host transport (now loopback-bound unless a Docker container must reach it, with a constant-time bearer check); a serverless/edge orchestrator serves the same core from its own `fetch` handler — no raw TCP listener. A new `ToolBridgeProvisioner` capability (`getToolBridgeProvisioner` / `provideToolBridgeProvisioner`, default `nodeHttpBridgeProvisioner`) lets the orchestrator inject the transport. + - **Harness adapters inverted** — `claude-code`, `codex`, and `opencode` now resolve their tool-bridge from the `ToolBridgeProvisioner` capability (defaulting to the host transport) instead of hardcoding `node:http`, so they run unchanged on the host and on the edge. + - **Claude Code runs on the Cloudflare sandbox** — a new required `SandboxCapabilities.writableStdin` flag lets a provider advertise whether spawned processes have a writable host→process stdin — `true` for the host/Docker/local-process providers, `false` for Cloudflare. The Claude Code adapter detects `false` and delivers the prompt via a file + in-shell stdin-redirection (`claude -p … < file`) instead of a host stdin write, keeping it out of argv. Host/Docker behaviour is unchanged (stdin path). + - **Tool-bridge token hardening** — the per-run bearer token is no longer passed inline in argv. The Claude Code adapter writes the bridge MCP config to a file and passes claude the path (`--mcp-config `), so the token can't be read from `ps` / `/proc//cmdline` by other processes in the sandbox. + - **Co-located ("combined") run model** — new `@tanstack/ai-sandbox` exports (`remoteToolStubs`, `toolDescriptors`, `httpRemoteToolExecutor`, `executeHostTool`, plus the `RemoteToolExecutor` interface) let the harness loop AND its MCP tool-bridge run INSIDE the container (the in-container sandbox is just `local-process`, with native stdin + a localhost `node:http` bridge). The orchestrator serializes its tools with `toolDescriptors`; the container rebuilds them as delegating stubs with `remoteToolStubs(descriptors, httpRemoteToolExecutor(url, token))`; the orchestrator answers that one call with `executeHostTool(tools, name, args)`. Only host-tool **execution** crosses the container→orchestrator boundary — the MCP transport itself never leaves the container, shrinking the public surface from the whole MCP protocol to a single authenticated tool-exec call. + - **Request-derived callback hosts, split into bridge vs preview (`resolveBridgeOrigin` / `resolvePreviewHost`)** — the off-isolate sandbox container reaches the Worker over two distinct surfaces, now resolved separately (both exported from `@tanstack/ai-sandbox-cloudflare/agent`; the Worker captures the trigger host as `StartRunInput.publicHost`): + - **Bridge / tool-exec** (container → Worker): `PUBLIC_HOSTNAME` is **optional** — unset → derived from the `POST /runs` request, which is safe on Cloudflare (the edge only routes hostnames you own to your Worker, so the request host is never an attacker's `Host` and the per-run bearer token can't be steered off-domain). A `*.workers.dev` deploy needs no config; **local dev uses `host.docker.internal`** (the Docker host gateway), so agent runs work locally with **no tunnel**. + - **Preview** (browser → Worker → container, `exposePort`): a separate `PREVIEW_HOSTNAME`, because preview URLs require **wildcard DNS**. **Local** uses `*.localhost` (browser-resolved to loopback — previews work locally with no tunnel); **deployed** requires a **custom domain** with a `*.` route. `*.workers.dev` has no wildcard subdomains (the SDK's `exposePort` rejects it), so `resolvePreviewHost` throws a clear error pointing at `PREVIEW_HOSTNAME` rather than returning a dead URL. + - **Preview wiring is package-provided, not example glue** — `@tanstack/ai-sandbox-cloudflare/agent` now exports `exposePreviewTool(input, env)` (a ready-made `exposePreview` `chat()` server tool) and `PREVIEW_GUIDANCE` (an app-agnostic system prompt), and `createCloudflareSandboxAgent` gains a `systemPrompts` option (do-drives) to wire the guidance in. The tool mints previews via a **Cloudflare quick tunnel** (`sandbox.tunnels.get(port)` → `*.trycloudflare.com`), served by `cloudflared` inside the sandbox — deliberately NOT `exposePort` + `proxyToSandbox`, which routes the preview through the Worker origin (in local dev, your Vite dev server, whose middleware then serves the preview's `/@vite/client` / `/src/*` / `/@fs/*` from the host instead of the container and breaks the page). A tunnel bypasses the Vite port, needs no custom domain on a deploy, and forwards WebSockets (HMR works). `PREVIEW_GUIDANCE` just tells the agent to bind wide and allow all hosts so the tunnel hostname is accepted (Vite `server: { host: true, allowedHosts: true }`). Because `sandbox.tunnels` exists only on the SDK's **RPC** transport (it throws `requires the RPC transport` on the default `http`), `cloudflareSandbox` now defaults to `transport: 'rpc'` (new `transport` config option to override) and applies it to create/resume/destroy; `exposePreviewTool` obtains its stub with `transport: 'rpc'` too. `exposePort` + `resolvePreviewHost` remain available for Worker-fronted previews on a custom domain. Adds `zod` as a peer dependency. + - **`@tanstack/ai-sandbox-cloudflare` ships the runtime, not just the example** — the Worker router, the coordinator Durable Object, the durable run-log, and the `POST /run` wire contract are now package code, exported from two entries: `@tanstack/ai-sandbox-cloudflare/agent` (Workers-only — `createCloudflareSandboxAgent`, the coordinator base classes, `DurableObjectRunEventLog`, plus the shared `ContainerRunRequest` + `parseContainerRunRequest`), and `@tanstack/ai-sandbox-cloudflare/runner` (Node — `runInContainerHarness`, the in-container `chat()` server that validates the request, builds `chat()` over `localProcessSandbox()`, and streams NDJSON back). An app supplies only its config + an adapter resolver: the co-located example's whole worker + container program collapse to ~14 lines. Adds `@tanstack/ai-sandbox-local-process` as a peer dependency (used by the `/runner` entry). + + See `examples/sandbox-cloudflare` for the Worker → Durable Object → Container reference — a TanStack Start app that ships the UI, the agent, the coordinator DO, and the container in one Worker (trigger returns immediately; the DO coordinates, persists to a DO-backed `RunEventLog`, serves the bridge from its `fetch` handler, and streams to clients over a hibernatable WebSocket). The co-located variant (harness + bridge in the container; only `executeHostTool` crosses back) is a supported package mode — `createCloudflareSandboxAgent({ mode: 'colocated' })` plus a one-`runInContainerHarness`-call container program — documented in `docs/sandbox/overview.md`. + +### Patch Changes + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai-sandbox@0.2.0 + - @tanstack/ai@0.39.0 diff --git a/packages/ai-opencode/package.json b/packages/ai-opencode/package.json index 093f72795..42f0fe611 100644 --- a/packages/ai-opencode/package.json +++ b/packages/ai-opencode/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-opencode", - "version": "0.1.0", + "version": "0.2.0", "description": "OpenCode harness adapter for TanStack AI — run OpenCode as a chat backend with local tool execution and stateful sessions.", "author": "", "license": "MIT", diff --git a/packages/ai-openrouter/CHANGELOG.md b/packages/ai-openrouter/CHANGELOG.md index e95bbb4ac..9fe45a4e5 100644 --- a/packages/ai-openrouter/CHANGELOG.md +++ b/packages/ai-openrouter/CHANGELOG.md @@ -1,5 +1,12 @@ # @tanstack/ai-openrouter +## 0.15.6 + +### Patch Changes + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai@0.39.0 + ## 0.15.5 ### Patch Changes diff --git a/packages/ai-openrouter/package.json b/packages/ai-openrouter/package.json index 807260e4a..ace72e814 100644 --- a/packages/ai-openrouter/package.json +++ b/packages/ai-openrouter/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-openrouter", - "version": "0.15.5", + "version": "0.15.6", "description": "TanStack AI adapter for OpenRouter chat, provider tools, structured outputs, and access to hundreds of LLMs.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/ai-preact/CHANGELOG.md b/packages/ai-preact/CHANGELOG.md index be0121c60..88f9409b4 100644 --- a/packages/ai-preact/CHANGELOG.md +++ b/packages/ai-preact/CHANGELOG.md @@ -1,5 +1,13 @@ # @tanstack/ai-preact +## 0.10.1 + +### Patch Changes + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai@0.39.0 + - @tanstack/ai-client@0.19.1 + ## 0.10.0 ### Minor Changes diff --git a/packages/ai-preact/package.json b/packages/ai-preact/package.json index 9936851ba..901f0b402 100644 --- a/packages/ai-preact/package.json +++ b/packages/ai-preact/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-preact", - "version": "0.10.0", + "version": "0.10.1", "description": "Preact hooks for TanStack AI streaming chat and typed messages.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/ai-react/CHANGELOG.md b/packages/ai-react/CHANGELOG.md index 271741cce..8e5a0cf09 100644 --- a/packages/ai-react/CHANGELOG.md +++ b/packages/ai-react/CHANGELOG.md @@ -1,5 +1,13 @@ # @tanstack/ai-react +## 0.16.1 + +### Patch Changes + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai@0.39.0 + - @tanstack/ai-client@0.19.1 + ## 0.16.0 ### Minor Changes diff --git a/packages/ai-react/package.json b/packages/ai-react/package.json index 20beb9269..99da66a84 100644 --- a/packages/ai-react/package.json +++ b/packages/ai-react/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-react", - "version": "0.16.0", + "version": "0.16.1", "description": "React hooks for TanStack AI streaming chat, realtime voice, structured outputs, and media generation.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/ai-sandbox-cloudflare/CHANGELOG.md b/packages/ai-sandbox-cloudflare/CHANGELOG.md new file mode 100644 index 000000000..a801f74f0 --- /dev/null +++ b/packages/ai-sandbox-cloudflare/CHANGELOG.md @@ -0,0 +1,55 @@ +# @tanstack/ai-sandbox-cloudflare + +## 0.2.0 + +### Minor Changes + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - New `@tanstack/ai-sandbox-cloudflare` package: a Cloudflare Containers sandbox provider (`cloudflareSandbox`) built on `@cloudflare/sandbox`, for running harness adapters at the edge inside a Worker. Implements the uniform `SandboxHandle` (exec, base64-backed fs, git, `exposePort` preview URLs, env) over the Cloudflare Sandbox Durable Object. The container disk is ephemeral and snapshots are not yet GA, so `withSandbox` re-bootstraps under the same identity across cold starts (`durableFilesystem`/`snapshots` are reported false). Background processes don't expose stdin on Cloudflare, so stdin-fed harnesses (e.g. Claude Code) need a stdin-capable provider; `exec` works fully. + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - Make the Cloudflare sandbox factory **harness-agnostic about auth**. `SandboxAgentEnv` / `ContainerCoordinatorEnv` no longer bind a hardcoded `ANTHROPIC_API_KEY` field, and neither the do-drives default sandbox nor the colocated container runner injects an Anthropic key anymore. Instead the run's workspace **declares** the secret names it needs (via `createSecrets`), and the coordinator copies each declared name out of the Worker `env` into the sandbox/container env — so a Claude Code app declares `ANTHROPIC_API_KEY`, a Codex app declares `CODEX_API_KEY`, and the package binds no key of its own. + + **Breaking:** apps that relied on the implicit `ANTHROPIC_API_KEY` field must now add it to their own env type and supply it via a `sandbox`/`workspace` resolver, e.g.: + + ```ts + interface AppEnv extends SandboxAgentEnv { + ANTHROPIC_API_KEY: string + } + createCloudflareSandboxAgent({ + adapter: () => claudeCodeText('sonnet'), + sandbox: (input, env) => + defineSandbox({ + // … + workspace: defineWorkspace({ + source: { type: 'none' }, + secrets: createSecrets({ ANTHROPIC_API_KEY: env.ANTHROPIC_API_KEY }), + }), + }), + }) + ``` + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - Serverless/edge run model for the sandbox layer — a trigger can start an agent run and return immediately while a durable orchestrator drives it and clients tail the stream from a resumable cursor. + - **Resumable run event-log** (`RunEventLog`, `InMemoryRunEventLog`, `RunEvent`, `RunRecord`, `isTerminalRunStatus`) — an append-only, `seq`-indexed log of a run's `StreamChunk`s with replay-then-tail reads. A dropped connection, a new tab, or an orchestrator that hibernated between chunks all reconnect by passing their last-seen `seq`. The run never depends on a single open connection. + - **Run driver** (`pipeToRunLog`, `RunController`) — pumps a `chat()` stream into a `RunEventLog` (status transitions, RUN_ERROR capture, abort handling), and a controller that starts a run without blocking, exposes a resumable `attach(runId, { fromSeq })`, and `drain()`s in-flight runs for `waitUntil`-style flushing. + - **Transport-agnostic tool-bridge** — the MCP tool-proxy is split into a portable core (`createToolBridgeCore`, `handleBridgeJsonRpc`) and a transport. `startHostToolBridge` remains the `node:http` host transport (now loopback-bound unless a Docker container must reach it, with a constant-time bearer check); a serverless/edge orchestrator serves the same core from its own `fetch` handler — no raw TCP listener. A new `ToolBridgeProvisioner` capability (`getToolBridgeProvisioner` / `provideToolBridgeProvisioner`, default `nodeHttpBridgeProvisioner`) lets the orchestrator inject the transport. + - **Harness adapters inverted** — `claude-code`, `codex`, and `opencode` now resolve their tool-bridge from the `ToolBridgeProvisioner` capability (defaulting to the host transport) instead of hardcoding `node:http`, so they run unchanged on the host and on the edge. + - **Claude Code runs on the Cloudflare sandbox** — a new required `SandboxCapabilities.writableStdin` flag lets a provider advertise whether spawned processes have a writable host→process stdin — `true` for the host/Docker/local-process providers, `false` for Cloudflare. The Claude Code adapter detects `false` and delivers the prompt via a file + in-shell stdin-redirection (`claude -p … < file`) instead of a host stdin write, keeping it out of argv. Host/Docker behaviour is unchanged (stdin path). + - **Tool-bridge token hardening** — the per-run bearer token is no longer passed inline in argv. The Claude Code adapter writes the bridge MCP config to a file and passes claude the path (`--mcp-config `), so the token can't be read from `ps` / `/proc//cmdline` by other processes in the sandbox. + - **Co-located ("combined") run model** — new `@tanstack/ai-sandbox` exports (`remoteToolStubs`, `toolDescriptors`, `httpRemoteToolExecutor`, `executeHostTool`, plus the `RemoteToolExecutor` interface) let the harness loop AND its MCP tool-bridge run INSIDE the container (the in-container sandbox is just `local-process`, with native stdin + a localhost `node:http` bridge). The orchestrator serializes its tools with `toolDescriptors`; the container rebuilds them as delegating stubs with `remoteToolStubs(descriptors, httpRemoteToolExecutor(url, token))`; the orchestrator answers that one call with `executeHostTool(tools, name, args)`. Only host-tool **execution** crosses the container→orchestrator boundary — the MCP transport itself never leaves the container, shrinking the public surface from the whole MCP protocol to a single authenticated tool-exec call. + - **Request-derived callback hosts, split into bridge vs preview (`resolveBridgeOrigin` / `resolvePreviewHost`)** — the off-isolate sandbox container reaches the Worker over two distinct surfaces, now resolved separately (both exported from `@tanstack/ai-sandbox-cloudflare/agent`; the Worker captures the trigger host as `StartRunInput.publicHost`): + - **Bridge / tool-exec** (container → Worker): `PUBLIC_HOSTNAME` is **optional** — unset → derived from the `POST /runs` request, which is safe on Cloudflare (the edge only routes hostnames you own to your Worker, so the request host is never an attacker's `Host` and the per-run bearer token can't be steered off-domain). A `*.workers.dev` deploy needs no config; **local dev uses `host.docker.internal`** (the Docker host gateway), so agent runs work locally with **no tunnel**. + - **Preview** (browser → Worker → container, `exposePort`): a separate `PREVIEW_HOSTNAME`, because preview URLs require **wildcard DNS**. **Local** uses `*.localhost` (browser-resolved to loopback — previews work locally with no tunnel); **deployed** requires a **custom domain** with a `*.` route. `*.workers.dev` has no wildcard subdomains (the SDK's `exposePort` rejects it), so `resolvePreviewHost` throws a clear error pointing at `PREVIEW_HOSTNAME` rather than returning a dead URL. + - **Preview wiring is package-provided, not example glue** — `@tanstack/ai-sandbox-cloudflare/agent` now exports `exposePreviewTool(input, env)` (a ready-made `exposePreview` `chat()` server tool) and `PREVIEW_GUIDANCE` (an app-agnostic system prompt), and `createCloudflareSandboxAgent` gains a `systemPrompts` option (do-drives) to wire the guidance in. The tool mints previews via a **Cloudflare quick tunnel** (`sandbox.tunnels.get(port)` → `*.trycloudflare.com`), served by `cloudflared` inside the sandbox — deliberately NOT `exposePort` + `proxyToSandbox`, which routes the preview through the Worker origin (in local dev, your Vite dev server, whose middleware then serves the preview's `/@vite/client` / `/src/*` / `/@fs/*` from the host instead of the container and breaks the page). A tunnel bypasses the Vite port, needs no custom domain on a deploy, and forwards WebSockets (HMR works). `PREVIEW_GUIDANCE` just tells the agent to bind wide and allow all hosts so the tunnel hostname is accepted (Vite `server: { host: true, allowedHosts: true }`). Because `sandbox.tunnels` exists only on the SDK's **RPC** transport (it throws `requires the RPC transport` on the default `http`), `cloudflareSandbox` now defaults to `transport: 'rpc'` (new `transport` config option to override) and applies it to create/resume/destroy; `exposePreviewTool` obtains its stub with `transport: 'rpc'` too. `exposePort` + `resolvePreviewHost` remain available for Worker-fronted previews on a custom domain. Adds `zod` as a peer dependency. + - **`@tanstack/ai-sandbox-cloudflare` ships the runtime, not just the example** — the Worker router, the coordinator Durable Object, the durable run-log, and the `POST /run` wire contract are now package code, exported from two entries: `@tanstack/ai-sandbox-cloudflare/agent` (Workers-only — `createCloudflareSandboxAgent`, the coordinator base classes, `DurableObjectRunEventLog`, plus the shared `ContainerRunRequest` + `parseContainerRunRequest`), and `@tanstack/ai-sandbox-cloudflare/runner` (Node — `runInContainerHarness`, the in-container `chat()` server that validates the request, builds `chat()` over `localProcessSandbox()`, and streams NDJSON back). An app supplies only its config + an adapter resolver: the co-located example's whole worker + container program collapse to ~14 lines. Adds `@tanstack/ai-sandbox-local-process` as a peer dependency (used by the `/runner` entry). + + See `examples/sandbox-cloudflare` for the Worker → Durable Object → Container reference — a TanStack Start app that ships the UI, the agent, the coordinator DO, and the container in one Worker (trigger returns immediately; the DO coordinates, persists to a DO-backed `RunEventLog`, serves the bridge from its `fetch` handler, and streams to clients over a hibernatable WebSocket). The co-located variant (harness + bridge in the container; only `executeHostTool` crosses back) is a supported package mode — `createCloudflareSandboxAgent({ mode: 'colocated' })` plus a one-`runInContainerHarness`-call container program — documented in `docs/sandbox/overview.md`. + +### Patch Changes + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - Fix the Claude Code harness never starting its turn in a Cloudflare sandbox (runs sat at `status:running` forever, streaming nothing). Two root causes: + - **`@tanstack/ai-claude-code`**: the adapter defaults `--permission-mode bypassPermissions`, which Claude Code maps to `--dangerously-skip-permissions` and refuses to run as root. Sandbox containers (Docker/Cloudflare) run as root, so `claude` died instantly. The adapter now sets `IS_SANDBOX=1` in the CLI's environment (Claude Code's documented escape hatch for running skip-permissions in an isolated environment), merged over any caller-provided env. + - **`@tanstack/ai-sandbox-cloudflare`**: `spawn()` used `@cloudflare/sandbox`'s background-process API (`startProcess` + `streamProcessLogs`), whose `onOutput`/`onExit` callbacks never fire, so a stdout-NDJSON harness hung forever. `spawn()` now streams over `exec({ stream: true, onOutput })` — the same proven command path as one-shot `exec` — and resolves the exit code from its result. The caller's `AbortSignal` is no longer forwarded across the Durable Object RPC boundary (Workers RPC cannot serialize an `AbortSignal`, which previously threw before the command ran); mid-run cancellation is unavailable on this provider and a stuck run is bounded by the coordinator watchdog instead. A failed command now rejects `wait()` so the adapter surfaces a `RUN_ERROR` rather than a silent zero-output run. + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai-sandbox@0.2.0 + - @tanstack/ai@0.39.0 + - @tanstack/ai-sandbox-local-process@0.2.0 diff --git a/packages/ai-sandbox-cloudflare/package.json b/packages/ai-sandbox-cloudflare/package.json index 94440be07..f5ffbf3af 100644 --- a/packages/ai-sandbox-cloudflare/package.json +++ b/packages/ai-sandbox-cloudflare/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-sandbox-cloudflare", - "version": "0.1.0", + "version": "0.2.0", "description": "Cloudflare sandbox provider for TanStack AI — run harness adapters inside Cloudflare Containers (edge) through the uniform SandboxHandle.", "author": "", "license": "MIT", diff --git a/packages/ai-sandbox-daytona/CHANGELOG.md b/packages/ai-sandbox-daytona/CHANGELOG.md new file mode 100644 index 000000000..e6a434ee1 --- /dev/null +++ b/packages/ai-sandbox-daytona/CHANGELOG.md @@ -0,0 +1,16 @@ +# @tanstack/ai-sandbox-daytona + +## 0.2.0 + +### Minor Changes + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - Two new sandbox provider packages so harness adapters can run **inside** managed cloud sandboxes through the uniform `SandboxHandle`: + - **`@tanstack/ai-sandbox-daytona`** — `daytonaSandbox()`: runs the agent inside an isolated [Daytona](https://www.daytona.io/) cloud sandbox (`@daytona/sdk`), with `fs`/`exec`/`git`, background processes via Daytona sessions, port preview links (`ports.connect`), and resume-by-id. Requires a Daytona API key (`config.apiKey` or `DAYTONA_API_KEY`). + - **`@tanstack/ai-sandbox-vercel`** — `vercelSandbox()`: runs the agent inside an isolated [Vercel Sandbox](https://vercel.com/docs/sandbox) microVM (`@vercel/sandbox`), with `fs`/`exec`/`git`, detached background processes, exposed-port domains (`ports.connect`), and resume-by-id. Requires a Vercel access token (`config.token` or `VERCEL_TOKEN` / `VERCEL_OIDC_TOKEN`) plus team/project scope. + + Both providers advertise `writableStdin: false` (background-process stdin is delivered via a file + shell redirect, not a live stream) and reuse the shared `createExecBackedGit` helper for a uniform `sandbox.git` surface. + +### Patch Changes + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai-sandbox@0.2.0 diff --git a/packages/ai-sandbox-daytona/package.json b/packages/ai-sandbox-daytona/package.json index e00122d18..1419bf311 100644 --- a/packages/ai-sandbox-daytona/package.json +++ b/packages/ai-sandbox-daytona/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-sandbox-daytona", - "version": "0.1.0", + "version": "0.2.0", "description": "Daytona sandbox provider for TanStack AI — run harness adapters inside isolated Daytona cloud sandboxes through the uniform SandboxHandle.", "author": "", "license": "MIT", diff --git a/packages/ai-sandbox-docker/CHANGELOG.md b/packages/ai-sandbox-docker/CHANGELOG.md new file mode 100644 index 000000000..ef558b9a2 --- /dev/null +++ b/packages/ai-sandbox-docker/CHANGELOG.md @@ -0,0 +1,62 @@ +# @tanstack/ai-sandbox-docker + +## 0.2.0 + +### Minor Changes + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - New provider-agnostic sandbox layer so harness adapters can run **inside** isolated sandboxes. + - **`@tanstack/ai-sandbox`** — `defineSandbox()` (lazy controller + resume→restoreSnapshot→create+bootstrap ensure algorithm), `withSandbox()` middleware, `defineWorkspace()` (git/local source, package-manager detection, setup, skills, secrets), `defineSandboxPolicy()`, the `SandboxProvider`/`SandboxHandle`/`SandboxCapabilities` contracts, capability tokens (`SandboxCapability` plus the optional `SandboxStore`/`Locks` persistence seams with in-memory defaults), `bootstrapWorkspace`, `createExecBackedGit`, `spawnNdjson` (run an agent CLI in a sandbox and stream its NDJSON stdout), the host MCP tool-proxy bridge (`startHostToolBridge` — exposes `chat()` server tools to the in-sandbox agent, with an optional permission-prompt tool), and the shared interactive-approval primitives (`resolveApproval`, `approvalId`, `buildApprovalRequestedEvent`) harness adapters use to enforce a policy and surface `approval-requested` events for client-in-the-loop approvals. + - **`@tanstack/ai-sandbox-local-process`** — `localProcessSandbox()`: runs the agent on the host through the uniform `SandboxHandle` (no isolation; the fast dev loop). + - **`@tanstack/ai-sandbox-docker`** — `dockerSandbox()`: runs the agent inside an isolated Docker container (dockerode), with commit-based snapshots, fork, and resume-by-id. + - **`@tanstack/ai`** — `TextOptions.capabilities` exposes the middleware capability context to adapters so harness adapters that declare `requires: [...]` can read provided capabilities from `chatStream`; `TextOptions.approvals` threads client approval decisions through to adapters for the interactive-approval (deny + `approval-requested` + re-run) flow; `DefinedChatMiddleware` and `AnyChatMiddleware` are now exported for portable middleware authoring. + +### Patch Changes + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - Declarative sandbox provisioning + faster headless init. + - **`createSecrets`**: type-safe secret references; underlying values are stored + in a non-enumerable symbol-keyed registry and never written to snapshots, the + sandbox store, or the event log. Use `secret: secrets.GH` in `gitSkill` for + private-repo auth and `bearer(secrets.GH)` in MCP header values. + - **Declarative `skills` / `plugins` / `instructions`**: `agentSkill`, + `gitSkill` (private-repo clone with `secret`), `mcpSkill` (MCP server with + resolved header values), and `fileSkill` are projected per harness into each + CLI's native format (Claude Code `.mcp.json`, Codex `.codex/config.toml`, + OpenCode `opencode.json`). `instructions` is written + as a canonical `AGENTS.md` at the workspace root; `CLAUDE.md` and `GEMINI.md` + are symlinked (copy fallback). Concepts a CLI lacks emit a warning and are + skipped rather than throwing. + - **Shallow clone by default**: `githubRepo`/`gitSource` default to + `--depth 1 --single-branch`. Pass `depth: number` for a specific history + depth or `depth: 'full'` to disable the flag. + - **Serial/parallel `setup` callback**: `setup` accepts a plain `Array` + (all serial) or a `({ serial, parallel }) => void` callback that records + groups run over a persistent shell — the shell's cwd and env carry over + between serial steps; `parallel([...])` launches commands concurrently + using the shell's forked state. + - **Default snapshot-after-setup**: when the provider supports snapshots, + bootstrap takes one automatically after `setup` completes. Add + `lifecycle.snapshotMaxAge` (e.g. `'24h'`) to re-create the sandbox when the + snapshot is older than the TTL. + - **`@tanstack/ai-sandbox-docker` fix**: a spawned process's demuxed + stdout/stderr now end on the exec stream's `close`/`error` (not only `end`), + so disposing a long-lived process (e.g. the bootstrap shell) no longer hangs + after `kill()`. + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - Serverless/edge run model for the sandbox layer — a trigger can start an agent run and return immediately while a durable orchestrator drives it and clients tail the stream from a resumable cursor. + - **Resumable run event-log** (`RunEventLog`, `InMemoryRunEventLog`, `RunEvent`, `RunRecord`, `isTerminalRunStatus`) — an append-only, `seq`-indexed log of a run's `StreamChunk`s with replay-then-tail reads. A dropped connection, a new tab, or an orchestrator that hibernated between chunks all reconnect by passing their last-seen `seq`. The run never depends on a single open connection. + - **Run driver** (`pipeToRunLog`, `RunController`) — pumps a `chat()` stream into a `RunEventLog` (status transitions, RUN_ERROR capture, abort handling), and a controller that starts a run without blocking, exposes a resumable `attach(runId, { fromSeq })`, and `drain()`s in-flight runs for `waitUntil`-style flushing. + - **Transport-agnostic tool-bridge** — the MCP tool-proxy is split into a portable core (`createToolBridgeCore`, `handleBridgeJsonRpc`) and a transport. `startHostToolBridge` remains the `node:http` host transport (now loopback-bound unless a Docker container must reach it, with a constant-time bearer check); a serverless/edge orchestrator serves the same core from its own `fetch` handler — no raw TCP listener. A new `ToolBridgeProvisioner` capability (`getToolBridgeProvisioner` / `provideToolBridgeProvisioner`, default `nodeHttpBridgeProvisioner`) lets the orchestrator inject the transport. + - **Harness adapters inverted** — `claude-code`, `codex`, and `opencode` now resolve their tool-bridge from the `ToolBridgeProvisioner` capability (defaulting to the host transport) instead of hardcoding `node:http`, so they run unchanged on the host and on the edge. + - **Claude Code runs on the Cloudflare sandbox** — a new required `SandboxCapabilities.writableStdin` flag lets a provider advertise whether spawned processes have a writable host→process stdin — `true` for the host/Docker/local-process providers, `false` for Cloudflare. The Claude Code adapter detects `false` and delivers the prompt via a file + in-shell stdin-redirection (`claude -p … < file`) instead of a host stdin write, keeping it out of argv. Host/Docker behaviour is unchanged (stdin path). + - **Tool-bridge token hardening** — the per-run bearer token is no longer passed inline in argv. The Claude Code adapter writes the bridge MCP config to a file and passes claude the path (`--mcp-config `), so the token can't be read from `ps` / `/proc//cmdline` by other processes in the sandbox. + - **Co-located ("combined") run model** — new `@tanstack/ai-sandbox` exports (`remoteToolStubs`, `toolDescriptors`, `httpRemoteToolExecutor`, `executeHostTool`, plus the `RemoteToolExecutor` interface) let the harness loop AND its MCP tool-bridge run INSIDE the container (the in-container sandbox is just `local-process`, with native stdin + a localhost `node:http` bridge). The orchestrator serializes its tools with `toolDescriptors`; the container rebuilds them as delegating stubs with `remoteToolStubs(descriptors, httpRemoteToolExecutor(url, token))`; the orchestrator answers that one call with `executeHostTool(tools, name, args)`. Only host-tool **execution** crosses the container→orchestrator boundary — the MCP transport itself never leaves the container, shrinking the public surface from the whole MCP protocol to a single authenticated tool-exec call. + - **Request-derived callback hosts, split into bridge vs preview (`resolveBridgeOrigin` / `resolvePreviewHost`)** — the off-isolate sandbox container reaches the Worker over two distinct surfaces, now resolved separately (both exported from `@tanstack/ai-sandbox-cloudflare/agent`; the Worker captures the trigger host as `StartRunInput.publicHost`): + - **Bridge / tool-exec** (container → Worker): `PUBLIC_HOSTNAME` is **optional** — unset → derived from the `POST /runs` request, which is safe on Cloudflare (the edge only routes hostnames you own to your Worker, so the request host is never an attacker's `Host` and the per-run bearer token can't be steered off-domain). A `*.workers.dev` deploy needs no config; **local dev uses `host.docker.internal`** (the Docker host gateway), so agent runs work locally with **no tunnel**. + - **Preview** (browser → Worker → container, `exposePort`): a separate `PREVIEW_HOSTNAME`, because preview URLs require **wildcard DNS**. **Local** uses `*.localhost` (browser-resolved to loopback — previews work locally with no tunnel); **deployed** requires a **custom domain** with a `*.` route. `*.workers.dev` has no wildcard subdomains (the SDK's `exposePort` rejects it), so `resolvePreviewHost` throws a clear error pointing at `PREVIEW_HOSTNAME` rather than returning a dead URL. + - **Preview wiring is package-provided, not example glue** — `@tanstack/ai-sandbox-cloudflare/agent` now exports `exposePreviewTool(input, env)` (a ready-made `exposePreview` `chat()` server tool) and `PREVIEW_GUIDANCE` (an app-agnostic system prompt), and `createCloudflareSandboxAgent` gains a `systemPrompts` option (do-drives) to wire the guidance in. The tool mints previews via a **Cloudflare quick tunnel** (`sandbox.tunnels.get(port)` → `*.trycloudflare.com`), served by `cloudflared` inside the sandbox — deliberately NOT `exposePort` + `proxyToSandbox`, which routes the preview through the Worker origin (in local dev, your Vite dev server, whose middleware then serves the preview's `/@vite/client` / `/src/*` / `/@fs/*` from the host instead of the container and breaks the page). A tunnel bypasses the Vite port, needs no custom domain on a deploy, and forwards WebSockets (HMR works). `PREVIEW_GUIDANCE` just tells the agent to bind wide and allow all hosts so the tunnel hostname is accepted (Vite `server: { host: true, allowedHosts: true }`). Because `sandbox.tunnels` exists only on the SDK's **RPC** transport (it throws `requires the RPC transport` on the default `http`), `cloudflareSandbox` now defaults to `transport: 'rpc'` (new `transport` config option to override) and applies it to create/resume/destroy; `exposePreviewTool` obtains its stub with `transport: 'rpc'` too. `exposePort` + `resolvePreviewHost` remain available for Worker-fronted previews on a custom domain. Adds `zod` as a peer dependency. + - **`@tanstack/ai-sandbox-cloudflare` ships the runtime, not just the example** — the Worker router, the coordinator Durable Object, the durable run-log, and the `POST /run` wire contract are now package code, exported from two entries: `@tanstack/ai-sandbox-cloudflare/agent` (Workers-only — `createCloudflareSandboxAgent`, the coordinator base classes, `DurableObjectRunEventLog`, plus the shared `ContainerRunRequest` + `parseContainerRunRequest`), and `@tanstack/ai-sandbox-cloudflare/runner` (Node — `runInContainerHarness`, the in-container `chat()` server that validates the request, builds `chat()` over `localProcessSandbox()`, and streams NDJSON back). An app supplies only its config + an adapter resolver: the co-located example's whole worker + container program collapse to ~14 lines. Adds `@tanstack/ai-sandbox-local-process` as a peer dependency (used by the `/runner` entry). + + See `examples/sandbox-cloudflare` for the Worker → Durable Object → Container reference — a TanStack Start app that ships the UI, the agent, the coordinator DO, and the container in one Worker (trigger returns immediately; the DO coordinates, persists to a DO-backed `RunEventLog`, serves the bridge from its `fetch` handler, and streams to clients over a hibernatable WebSocket). The co-located variant (harness + bridge in the container; only `executeHostTool` crosses back) is a supported package mode — `createCloudflareSandboxAgent({ mode: 'colocated' })` plus a one-`runInContainerHarness`-call container program — documented in `docs/sandbox/overview.md`. + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai-sandbox@0.2.0 diff --git a/packages/ai-sandbox-docker/package.json b/packages/ai-sandbox-docker/package.json index 327b01ea6..3c3cadd09 100644 --- a/packages/ai-sandbox-docker/package.json +++ b/packages/ai-sandbox-docker/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-sandbox-docker", - "version": "0.1.0", + "version": "0.2.0", "description": "Docker sandbox provider for TanStack AI — run harness adapters inside isolated Docker containers through the uniform SandboxHandle.", "author": "", "license": "MIT", diff --git a/packages/ai-sandbox-local-process/CHANGELOG.md b/packages/ai-sandbox-local-process/CHANGELOG.md new file mode 100644 index 000000000..10197a8f0 --- /dev/null +++ b/packages/ai-sandbox-local-process/CHANGELOG.md @@ -0,0 +1,49 @@ +# @tanstack/ai-sandbox-local-process + +## 0.2.0 + +### Minor Changes + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - Declarative sandbox file-event hooks: observe file create / change / delete + inside a sandbox and have them fire automatically during a chat run. + - `@tanstack/ai`: chat middleware gains an optional `sandbox` hook group + (`onFile`/`onFileCreate`/`onFileChange`/`onFileDelete`), a `SandboxFileEvent` + type, and a `sandbox` debug-logging category. The engine auto-emits a + `CUSTOM` `sandbox.file` event per change (client reads it from `parts`). + - `@tanstack/ai-sandbox`: `defineSandbox({ hooks, fileEvents })` declares + file + lifecycle hooks (`onFile*`/`onReady`/`onError`/`onDestroy`) that fire + automatically while the sandbox runs in a chat — `withSandbox` owns the + watcher. The watcher is provider-agnostic: a native `fs.watch` fast-path when + the provider advertises it, otherwise a portable `find -printf` mtime + snapshot-diff poll (no extra deps; `.git`/`node_modules` ignored by default). + `watchWorkspace()` / `diffSnapshots` remain as low-level building blocks. + - `@tanstack/ai-sandbox-local-process`: implements the optional `fs.watch` seam + via Node's recursive `fs.watch` (Windows/macOS); Linux falls back to the core + exec-poll automatically. + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - New provider-agnostic sandbox layer so harness adapters can run **inside** isolated sandboxes. + - **`@tanstack/ai-sandbox`** — `defineSandbox()` (lazy controller + resume→restoreSnapshot→create+bootstrap ensure algorithm), `withSandbox()` middleware, `defineWorkspace()` (git/local source, package-manager detection, setup, skills, secrets), `defineSandboxPolicy()`, the `SandboxProvider`/`SandboxHandle`/`SandboxCapabilities` contracts, capability tokens (`SandboxCapability` plus the optional `SandboxStore`/`Locks` persistence seams with in-memory defaults), `bootstrapWorkspace`, `createExecBackedGit`, `spawnNdjson` (run an agent CLI in a sandbox and stream its NDJSON stdout), the host MCP tool-proxy bridge (`startHostToolBridge` — exposes `chat()` server tools to the in-sandbox agent, with an optional permission-prompt tool), and the shared interactive-approval primitives (`resolveApproval`, `approvalId`, `buildApprovalRequestedEvent`) harness adapters use to enforce a policy and surface `approval-requested` events for client-in-the-loop approvals. + - **`@tanstack/ai-sandbox-local-process`** — `localProcessSandbox()`: runs the agent on the host through the uniform `SandboxHandle` (no isolation; the fast dev loop). + - **`@tanstack/ai-sandbox-docker`** — `dockerSandbox()`: runs the agent inside an isolated Docker container (dockerode), with commit-based snapshots, fork, and resume-by-id. + - **`@tanstack/ai`** — `TextOptions.capabilities` exposes the middleware capability context to adapters so harness adapters that declare `requires: [...]` can read provided capabilities from `chatStream`; `TextOptions.approvals` threads client approval decisions through to adapters for the interactive-approval (deny + `approval-requested` + re-run) flow; `DefinedChatMiddleware` and `AnyChatMiddleware` are now exported for portable middleware authoring. + +### Patch Changes + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - Serverless/edge run model for the sandbox layer — a trigger can start an agent run and return immediately while a durable orchestrator drives it and clients tail the stream from a resumable cursor. + - **Resumable run event-log** (`RunEventLog`, `InMemoryRunEventLog`, `RunEvent`, `RunRecord`, `isTerminalRunStatus`) — an append-only, `seq`-indexed log of a run's `StreamChunk`s with replay-then-tail reads. A dropped connection, a new tab, or an orchestrator that hibernated between chunks all reconnect by passing their last-seen `seq`. The run never depends on a single open connection. + - **Run driver** (`pipeToRunLog`, `RunController`) — pumps a `chat()` stream into a `RunEventLog` (status transitions, RUN_ERROR capture, abort handling), and a controller that starts a run without blocking, exposes a resumable `attach(runId, { fromSeq })`, and `drain()`s in-flight runs for `waitUntil`-style flushing. + - **Transport-agnostic tool-bridge** — the MCP tool-proxy is split into a portable core (`createToolBridgeCore`, `handleBridgeJsonRpc`) and a transport. `startHostToolBridge` remains the `node:http` host transport (now loopback-bound unless a Docker container must reach it, with a constant-time bearer check); a serverless/edge orchestrator serves the same core from its own `fetch` handler — no raw TCP listener. A new `ToolBridgeProvisioner` capability (`getToolBridgeProvisioner` / `provideToolBridgeProvisioner`, default `nodeHttpBridgeProvisioner`) lets the orchestrator inject the transport. + - **Harness adapters inverted** — `claude-code`, `codex`, and `opencode` now resolve their tool-bridge from the `ToolBridgeProvisioner` capability (defaulting to the host transport) instead of hardcoding `node:http`, so they run unchanged on the host and on the edge. + - **Claude Code runs on the Cloudflare sandbox** — a new required `SandboxCapabilities.writableStdin` flag lets a provider advertise whether spawned processes have a writable host→process stdin — `true` for the host/Docker/local-process providers, `false` for Cloudflare. The Claude Code adapter detects `false` and delivers the prompt via a file + in-shell stdin-redirection (`claude -p … < file`) instead of a host stdin write, keeping it out of argv. Host/Docker behaviour is unchanged (stdin path). + - **Tool-bridge token hardening** — the per-run bearer token is no longer passed inline in argv. The Claude Code adapter writes the bridge MCP config to a file and passes claude the path (`--mcp-config `), so the token can't be read from `ps` / `/proc//cmdline` by other processes in the sandbox. + - **Co-located ("combined") run model** — new `@tanstack/ai-sandbox` exports (`remoteToolStubs`, `toolDescriptors`, `httpRemoteToolExecutor`, `executeHostTool`, plus the `RemoteToolExecutor` interface) let the harness loop AND its MCP tool-bridge run INSIDE the container (the in-container sandbox is just `local-process`, with native stdin + a localhost `node:http` bridge). The orchestrator serializes its tools with `toolDescriptors`; the container rebuilds them as delegating stubs with `remoteToolStubs(descriptors, httpRemoteToolExecutor(url, token))`; the orchestrator answers that one call with `executeHostTool(tools, name, args)`. Only host-tool **execution** crosses the container→orchestrator boundary — the MCP transport itself never leaves the container, shrinking the public surface from the whole MCP protocol to a single authenticated tool-exec call. + - **Request-derived callback hosts, split into bridge vs preview (`resolveBridgeOrigin` / `resolvePreviewHost`)** — the off-isolate sandbox container reaches the Worker over two distinct surfaces, now resolved separately (both exported from `@tanstack/ai-sandbox-cloudflare/agent`; the Worker captures the trigger host as `StartRunInput.publicHost`): + - **Bridge / tool-exec** (container → Worker): `PUBLIC_HOSTNAME` is **optional** — unset → derived from the `POST /runs` request, which is safe on Cloudflare (the edge only routes hostnames you own to your Worker, so the request host is never an attacker's `Host` and the per-run bearer token can't be steered off-domain). A `*.workers.dev` deploy needs no config; **local dev uses `host.docker.internal`** (the Docker host gateway), so agent runs work locally with **no tunnel**. + - **Preview** (browser → Worker → container, `exposePort`): a separate `PREVIEW_HOSTNAME`, because preview URLs require **wildcard DNS**. **Local** uses `*.localhost` (browser-resolved to loopback — previews work locally with no tunnel); **deployed** requires a **custom domain** with a `*.` route. `*.workers.dev` has no wildcard subdomains (the SDK's `exposePort` rejects it), so `resolvePreviewHost` throws a clear error pointing at `PREVIEW_HOSTNAME` rather than returning a dead URL. + - **Preview wiring is package-provided, not example glue** — `@tanstack/ai-sandbox-cloudflare/agent` now exports `exposePreviewTool(input, env)` (a ready-made `exposePreview` `chat()` server tool) and `PREVIEW_GUIDANCE` (an app-agnostic system prompt), and `createCloudflareSandboxAgent` gains a `systemPrompts` option (do-drives) to wire the guidance in. The tool mints previews via a **Cloudflare quick tunnel** (`sandbox.tunnels.get(port)` → `*.trycloudflare.com`), served by `cloudflared` inside the sandbox — deliberately NOT `exposePort` + `proxyToSandbox`, which routes the preview through the Worker origin (in local dev, your Vite dev server, whose middleware then serves the preview's `/@vite/client` / `/src/*` / `/@fs/*` from the host instead of the container and breaks the page). A tunnel bypasses the Vite port, needs no custom domain on a deploy, and forwards WebSockets (HMR works). `PREVIEW_GUIDANCE` just tells the agent to bind wide and allow all hosts so the tunnel hostname is accepted (Vite `server: { host: true, allowedHosts: true }`). Because `sandbox.tunnels` exists only on the SDK's **RPC** transport (it throws `requires the RPC transport` on the default `http`), `cloudflareSandbox` now defaults to `transport: 'rpc'` (new `transport` config option to override) and applies it to create/resume/destroy; `exposePreviewTool` obtains its stub with `transport: 'rpc'` too. `exposePort` + `resolvePreviewHost` remain available for Worker-fronted previews on a custom domain. Adds `zod` as a peer dependency. + - **`@tanstack/ai-sandbox-cloudflare` ships the runtime, not just the example** — the Worker router, the coordinator Durable Object, the durable run-log, and the `POST /run` wire contract are now package code, exported from two entries: `@tanstack/ai-sandbox-cloudflare/agent` (Workers-only — `createCloudflareSandboxAgent`, the coordinator base classes, `DurableObjectRunEventLog`, plus the shared `ContainerRunRequest` + `parseContainerRunRequest`), and `@tanstack/ai-sandbox-cloudflare/runner` (Node — `runInContainerHarness`, the in-container `chat()` server that validates the request, builds `chat()` over `localProcessSandbox()`, and streams NDJSON back). An app supplies only its config + an adapter resolver: the co-located example's whole worker + container program collapse to ~14 lines. Adds `@tanstack/ai-sandbox-local-process` as a peer dependency (used by the `/runner` entry). + + See `examples/sandbox-cloudflare` for the Worker → Durable Object → Container reference — a TanStack Start app that ships the UI, the agent, the coordinator DO, and the container in one Worker (trigger returns immediately; the DO coordinates, persists to a DO-backed `RunEventLog`, serves the bridge from its `fetch` handler, and streams to clients over a hibernatable WebSocket). The co-located variant (harness + bridge in the container; only `executeHostTool` crosses back) is a supported package mode — `createCloudflareSandboxAgent({ mode: 'colocated' })` plus a one-`runInContainerHarness`-call container program — documented in `docs/sandbox/overview.md`. + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai-sandbox@0.2.0 diff --git a/packages/ai-sandbox-local-process/package.json b/packages/ai-sandbox-local-process/package.json index 46f9f7983..a8eed5b05 100644 --- a/packages/ai-sandbox-local-process/package.json +++ b/packages/ai-sandbox-local-process/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-sandbox-local-process", - "version": "0.1.0", + "version": "0.2.0", "description": "Local-process sandbox provider for TanStack AI — runs the agent directly on the host through the uniform SandboxHandle (no isolation; trusted/dev use).", "author": "", "license": "MIT", diff --git a/packages/ai-sandbox-vercel/CHANGELOG.md b/packages/ai-sandbox-vercel/CHANGELOG.md new file mode 100644 index 000000000..0ca6cfc5a --- /dev/null +++ b/packages/ai-sandbox-vercel/CHANGELOG.md @@ -0,0 +1,18 @@ +# @tanstack/ai-sandbox-vercel + +## 0.2.0 + +### Minor Changes + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - Two new sandbox provider packages so harness adapters can run **inside** managed cloud sandboxes through the uniform `SandboxHandle`: + - **`@tanstack/ai-sandbox-daytona`** — `daytonaSandbox()`: runs the agent inside an isolated [Daytona](https://www.daytona.io/) cloud sandbox (`@daytona/sdk`), with `fs`/`exec`/`git`, background processes via Daytona sessions, port preview links (`ports.connect`), and resume-by-id. Requires a Daytona API key (`config.apiKey` or `DAYTONA_API_KEY`). + - **`@tanstack/ai-sandbox-vercel`** — `vercelSandbox()`: runs the agent inside an isolated [Vercel Sandbox](https://vercel.com/docs/sandbox) microVM (`@vercel/sandbox`), with `fs`/`exec`/`git`, detached background processes, exposed-port domains (`ports.connect`), and resume-by-id. Requires a Vercel access token (`config.token` or `VERCEL_TOKEN` / `VERCEL_OIDC_TOKEN`) plus team/project scope. + + Both providers advertise `writableStdin: false` (background-process stdin is delivered via a file + shell redirect, not a live stream) and reuse the shared `createExecBackedGit` helper for a uniform `sandbox.git` surface. + +### Patch Changes + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - Fix `create()` failing with HTTP 400 `"cannot create directory '/vercel/sandbox': File exists"` when the workspace directory already exists. The Vercel SDK's native `mkDir` is not idempotent and the default workdir ships in the runtime image, so a fresh sandbox already has it. An "already exists" failure is now treated as success while other filesystem errors still surface. + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai-sandbox@0.2.0 diff --git a/packages/ai-sandbox-vercel/package.json b/packages/ai-sandbox-vercel/package.json index bcbe2eb43..e3c7ddf91 100644 --- a/packages/ai-sandbox-vercel/package.json +++ b/packages/ai-sandbox-vercel/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-sandbox-vercel", - "version": "0.1.0", + "version": "0.2.0", "description": "Vercel Sandbox provider for TanStack AI — run harness adapters inside isolated Vercel microVM sandboxes through the uniform SandboxHandle.", "author": "", "license": "MIT", diff --git a/packages/ai-sandbox/CHANGELOG.md b/packages/ai-sandbox/CHANGELOG.md new file mode 100644 index 000000000..06de4e93c --- /dev/null +++ b/packages/ai-sandbox/CHANGELOG.md @@ -0,0 +1,91 @@ +# @tanstack/ai-sandbox + +## 0.2.0 + +### Minor Changes + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - Declarative sandbox file-event hooks: observe file create / change / delete + inside a sandbox and have them fire automatically during a chat run. + - `@tanstack/ai`: chat middleware gains an optional `sandbox` hook group + (`onFile`/`onFileCreate`/`onFileChange`/`onFileDelete`), a `SandboxFileEvent` + type, and a `sandbox` debug-logging category. The engine auto-emits a + `CUSTOM` `sandbox.file` event per change (client reads it from `parts`). + - `@tanstack/ai-sandbox`: `defineSandbox({ hooks, fileEvents })` declares + file + lifecycle hooks (`onFile*`/`onReady`/`onError`/`onDestroy`) that fire + automatically while the sandbox runs in a chat — `withSandbox` owns the + watcher. The watcher is provider-agnostic: a native `fs.watch` fast-path when + the provider advertises it, otherwise a portable `find -printf` mtime + snapshot-diff poll (no extra deps; `.git`/`node_modules` ignored by default). + `watchWorkspace()` / `diffSnapshots` remain as low-level building blocks. + - `@tanstack/ai-sandbox-local-process`: implements the optional `fs.watch` seam + via Node's recursive `fs.watch` (Windows/macOS); Linux falls back to the core + exec-poll automatically. + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - New provider-agnostic sandbox layer so harness adapters can run **inside** isolated sandboxes. + - **`@tanstack/ai-sandbox`** — `defineSandbox()` (lazy controller + resume→restoreSnapshot→create+bootstrap ensure algorithm), `withSandbox()` middleware, `defineWorkspace()` (git/local source, package-manager detection, setup, skills, secrets), `defineSandboxPolicy()`, the `SandboxProvider`/`SandboxHandle`/`SandboxCapabilities` contracts, capability tokens (`SandboxCapability` plus the optional `SandboxStore`/`Locks` persistence seams with in-memory defaults), `bootstrapWorkspace`, `createExecBackedGit`, `spawnNdjson` (run an agent CLI in a sandbox and stream its NDJSON stdout), the host MCP tool-proxy bridge (`startHostToolBridge` — exposes `chat()` server tools to the in-sandbox agent, with an optional permission-prompt tool), and the shared interactive-approval primitives (`resolveApproval`, `approvalId`, `buildApprovalRequestedEvent`) harness adapters use to enforce a policy and surface `approval-requested` events for client-in-the-loop approvals. + - **`@tanstack/ai-sandbox-local-process`** — `localProcessSandbox()`: runs the agent on the host through the uniform `SandboxHandle` (no isolation; the fast dev loop). + - **`@tanstack/ai-sandbox-docker`** — `dockerSandbox()`: runs the agent inside an isolated Docker container (dockerode), with commit-based snapshots, fork, and resume-by-id. + - **`@tanstack/ai`** — `TextOptions.capabilities` exposes the middleware capability context to adapters so harness adapters that declare `requires: [...]` can read provided capabilities from `chatStream`; `TextOptions.approvals` threads client approval decisions through to adapters for the interactive-approval (deny + `approval-requested` + re-run) flow; `DefinedChatMiddleware` and `AnyChatMiddleware` are now exported for portable middleware authoring. + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - Declarative sandbox provisioning + faster headless init. + - **`createSecrets`**: type-safe secret references; underlying values are stored + in a non-enumerable symbol-keyed registry and never written to snapshots, the + sandbox store, or the event log. Use `secret: secrets.GH` in `gitSkill` for + private-repo auth and `bearer(secrets.GH)` in MCP header values. + - **Declarative `skills` / `plugins` / `instructions`**: `agentSkill`, + `gitSkill` (private-repo clone with `secret`), `mcpSkill` (MCP server with + resolved header values), and `fileSkill` are projected per harness into each + CLI's native format (Claude Code `.mcp.json`, Codex `.codex/config.toml`, + OpenCode `opencode.json`). `instructions` is written + as a canonical `AGENTS.md` at the workspace root; `CLAUDE.md` and `GEMINI.md` + are symlinked (copy fallback). Concepts a CLI lacks emit a warning and are + skipped rather than throwing. + - **Shallow clone by default**: `githubRepo`/`gitSource` default to + `--depth 1 --single-branch`. Pass `depth: number` for a specific history + depth or `depth: 'full'` to disable the flag. + - **Serial/parallel `setup` callback**: `setup` accepts a plain `Array` + (all serial) or a `({ serial, parallel }) => void` callback that records + groups run over a persistent shell — the shell's cwd and env carry over + between serial steps; `parallel([...])` launches commands concurrently + using the shell's forked state. + - **Default snapshot-after-setup**: when the provider supports snapshots, + bootstrap takes one automatically after `setup` completes. Add + `lifecycle.snapshotMaxAge` (e.g. `'24h'`) to re-create the sandbox when the + snapshot is older than the TTL. + - **`@tanstack/ai-sandbox-docker` fix**: a spawned process's demuxed + stdout/stderr now end on the exec stream's `close`/`error` (not only `end`), + so disposing a long-lived process (e.g. the bootstrap shell) no longer hangs + after `kill()`. + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - Serverless/edge run model for the sandbox layer — a trigger can start an agent run and return immediately while a durable orchestrator drives it and clients tail the stream from a resumable cursor. + - **Resumable run event-log** (`RunEventLog`, `InMemoryRunEventLog`, `RunEvent`, `RunRecord`, `isTerminalRunStatus`) — an append-only, `seq`-indexed log of a run's `StreamChunk`s with replay-then-tail reads. A dropped connection, a new tab, or an orchestrator that hibernated between chunks all reconnect by passing their last-seen `seq`. The run never depends on a single open connection. + - **Run driver** (`pipeToRunLog`, `RunController`) — pumps a `chat()` stream into a `RunEventLog` (status transitions, RUN_ERROR capture, abort handling), and a controller that starts a run without blocking, exposes a resumable `attach(runId, { fromSeq })`, and `drain()`s in-flight runs for `waitUntil`-style flushing. + - **Transport-agnostic tool-bridge** — the MCP tool-proxy is split into a portable core (`createToolBridgeCore`, `handleBridgeJsonRpc`) and a transport. `startHostToolBridge` remains the `node:http` host transport (now loopback-bound unless a Docker container must reach it, with a constant-time bearer check); a serverless/edge orchestrator serves the same core from its own `fetch` handler — no raw TCP listener. A new `ToolBridgeProvisioner` capability (`getToolBridgeProvisioner` / `provideToolBridgeProvisioner`, default `nodeHttpBridgeProvisioner`) lets the orchestrator inject the transport. + - **Harness adapters inverted** — `claude-code`, `codex`, and `opencode` now resolve their tool-bridge from the `ToolBridgeProvisioner` capability (defaulting to the host transport) instead of hardcoding `node:http`, so they run unchanged on the host and on the edge. + - **Claude Code runs on the Cloudflare sandbox** — a new required `SandboxCapabilities.writableStdin` flag lets a provider advertise whether spawned processes have a writable host→process stdin — `true` for the host/Docker/local-process providers, `false` for Cloudflare. The Claude Code adapter detects `false` and delivers the prompt via a file + in-shell stdin-redirection (`claude -p … < file`) instead of a host stdin write, keeping it out of argv. Host/Docker behaviour is unchanged (stdin path). + - **Tool-bridge token hardening** — the per-run bearer token is no longer passed inline in argv. The Claude Code adapter writes the bridge MCP config to a file and passes claude the path (`--mcp-config `), so the token can't be read from `ps` / `/proc//cmdline` by other processes in the sandbox. + - **Co-located ("combined") run model** — new `@tanstack/ai-sandbox` exports (`remoteToolStubs`, `toolDescriptors`, `httpRemoteToolExecutor`, `executeHostTool`, plus the `RemoteToolExecutor` interface) let the harness loop AND its MCP tool-bridge run INSIDE the container (the in-container sandbox is just `local-process`, with native stdin + a localhost `node:http` bridge). The orchestrator serializes its tools with `toolDescriptors`; the container rebuilds them as delegating stubs with `remoteToolStubs(descriptors, httpRemoteToolExecutor(url, token))`; the orchestrator answers that one call with `executeHostTool(tools, name, args)`. Only host-tool **execution** crosses the container→orchestrator boundary — the MCP transport itself never leaves the container, shrinking the public surface from the whole MCP protocol to a single authenticated tool-exec call. + - **Request-derived callback hosts, split into bridge vs preview (`resolveBridgeOrigin` / `resolvePreviewHost`)** — the off-isolate sandbox container reaches the Worker over two distinct surfaces, now resolved separately (both exported from `@tanstack/ai-sandbox-cloudflare/agent`; the Worker captures the trigger host as `StartRunInput.publicHost`): + - **Bridge / tool-exec** (container → Worker): `PUBLIC_HOSTNAME` is **optional** — unset → derived from the `POST /runs` request, which is safe on Cloudflare (the edge only routes hostnames you own to your Worker, so the request host is never an attacker's `Host` and the per-run bearer token can't be steered off-domain). A `*.workers.dev` deploy needs no config; **local dev uses `host.docker.internal`** (the Docker host gateway), so agent runs work locally with **no tunnel**. + - **Preview** (browser → Worker → container, `exposePort`): a separate `PREVIEW_HOSTNAME`, because preview URLs require **wildcard DNS**. **Local** uses `*.localhost` (browser-resolved to loopback — previews work locally with no tunnel); **deployed** requires a **custom domain** with a `*.` route. `*.workers.dev` has no wildcard subdomains (the SDK's `exposePort` rejects it), so `resolvePreviewHost` throws a clear error pointing at `PREVIEW_HOSTNAME` rather than returning a dead URL. + - **Preview wiring is package-provided, not example glue** — `@tanstack/ai-sandbox-cloudflare/agent` now exports `exposePreviewTool(input, env)` (a ready-made `exposePreview` `chat()` server tool) and `PREVIEW_GUIDANCE` (an app-agnostic system prompt), and `createCloudflareSandboxAgent` gains a `systemPrompts` option (do-drives) to wire the guidance in. The tool mints previews via a **Cloudflare quick tunnel** (`sandbox.tunnels.get(port)` → `*.trycloudflare.com`), served by `cloudflared` inside the sandbox — deliberately NOT `exposePort` + `proxyToSandbox`, which routes the preview through the Worker origin (in local dev, your Vite dev server, whose middleware then serves the preview's `/@vite/client` / `/src/*` / `/@fs/*` from the host instead of the container and breaks the page). A tunnel bypasses the Vite port, needs no custom domain on a deploy, and forwards WebSockets (HMR works). `PREVIEW_GUIDANCE` just tells the agent to bind wide and allow all hosts so the tunnel hostname is accepted (Vite `server: { host: true, allowedHosts: true }`). Because `sandbox.tunnels` exists only on the SDK's **RPC** transport (it throws `requires the RPC transport` on the default `http`), `cloudflareSandbox` now defaults to `transport: 'rpc'` (new `transport` config option to override) and applies it to create/resume/destroy; `exposePreviewTool` obtains its stub with `transport: 'rpc'` too. `exposePort` + `resolvePreviewHost` remain available for Worker-fronted previews on a custom domain. Adds `zod` as a peer dependency. + - **`@tanstack/ai-sandbox-cloudflare` ships the runtime, not just the example** — the Worker router, the coordinator Durable Object, the durable run-log, and the `POST /run` wire contract are now package code, exported from two entries: `@tanstack/ai-sandbox-cloudflare/agent` (Workers-only — `createCloudflareSandboxAgent`, the coordinator base classes, `DurableObjectRunEventLog`, plus the shared `ContainerRunRequest` + `parseContainerRunRequest`), and `@tanstack/ai-sandbox-cloudflare/runner` (Node — `runInContainerHarness`, the in-container `chat()` server that validates the request, builds `chat()` over `localProcessSandbox()`, and streams NDJSON back). An app supplies only its config + an adapter resolver: the co-located example's whole worker + container program collapse to ~14 lines. Adds `@tanstack/ai-sandbox-local-process` as a peer dependency (used by the `/runner` entry). + + See `examples/sandbox-cloudflare` for the Worker → Durable Object → Container reference — a TanStack Start app that ships the UI, the agent, the coordinator DO, and the container in one Worker (trigger returns immediately; the DO coordinates, persists to a DO-backed `RunEventLog`, serves the bridge from its `fetch` handler, and streams to clients over a hibernatable WebSocket). The co-located variant (harness + bridge in the container; only `executeHostTool` crosses back) is a supported package mode — `createCloudflareSandboxAgent({ mode: 'colocated' })` plus a one-`runInContainerHarness`-call container program — documented in `docs/sandbox/overview.md`. + +### Patch Changes + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - Fix workspace bootstrap on sandbox providers without a writable stdin + (`capabilities.writableStdin === false`, e.g. Daytona / Vercel / Cloudflare): + - The bootstrap shell previously **always** drove setup commands over a spawned + process's stdin (a sentinel-echo protocol), which those providers reject — so + any `defineWorkspace({ setup })` step threw `stdin is not writable`. The + bootstrap shell now falls back to an **exec-backed** implementation that + threads `cwd`/exported env across discrete `process.exec` calls, reproducing + the persistent-shell semantics without stdin. + - `defineSandbox().ensure()` now **destroys the freshly-created sandbox if + bootstrap fails** (before it has been recorded), instead of leaking an + orphaned — and, for hosted providers, billed — sandbox on a failed/retried run. + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai@0.39.0 diff --git a/packages/ai-sandbox/package.json b/packages/ai-sandbox/package.json index b8a94e442..8d24f9f10 100644 --- a/packages/ai-sandbox/package.json +++ b/packages/ai-sandbox/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-sandbox", - "version": "0.1.0", + "version": "0.2.0", "description": "Provider-agnostic sandbox layer for TanStack AI — run harness adapters inside isolated sandboxes (defineSandbox, defineWorkspace, withSandbox) with a uniform SandboxHandle, workspace bootstrap, policy, and resumable lifecycle.", "author": "", "license": "MIT", diff --git a/packages/ai-solid/CHANGELOG.md b/packages/ai-solid/CHANGELOG.md index 8588a9a96..1de01c5be 100644 --- a/packages/ai-solid/CHANGELOG.md +++ b/packages/ai-solid/CHANGELOG.md @@ -1,5 +1,13 @@ # @tanstack/ai-solid +## 0.14.1 + +### Patch Changes + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai@0.39.0 + - @tanstack/ai-client@0.19.1 + ## 0.14.0 ### Minor Changes diff --git a/packages/ai-solid/package.json b/packages/ai-solid/package.json index 8cfc2be34..fab4447d8 100644 --- a/packages/ai-solid/package.json +++ b/packages/ai-solid/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-solid", - "version": "0.14.0", + "version": "0.14.1", "description": "Solid hooks for TanStack AI streaming chat, structured outputs, and media generation.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/ai-svelte/CHANGELOG.md b/packages/ai-svelte/CHANGELOG.md index f8b15cc01..0d8cb6220 100644 --- a/packages/ai-svelte/CHANGELOG.md +++ b/packages/ai-svelte/CHANGELOG.md @@ -1,5 +1,13 @@ # @tanstack/ai-svelte +## 0.14.1 + +### Patch Changes + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai@0.39.0 + - @tanstack/ai-client@0.19.1 + ## 0.14.0 ### Minor Changes diff --git a/packages/ai-svelte/package.json b/packages/ai-svelte/package.json index ff0329690..82d9828ab 100644 --- a/packages/ai-svelte/package.json +++ b/packages/ai-svelte/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-svelte", - "version": "0.14.0", + "version": "0.14.1", "description": "Svelte 5 bindings for TanStack AI streaming chat, structured outputs, and media generation.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/ai-vue-ui/CHANGELOG.md b/packages/ai-vue-ui/CHANGELOG.md index 42113bdfc..986154de4 100644 --- a/packages/ai-vue-ui/CHANGELOG.md +++ b/packages/ai-vue-ui/CHANGELOG.md @@ -1,5 +1,12 @@ # @tanstack/ai-vue-ui +## 0.2.29 + +### Patch Changes + +- Updated dependencies []: + - @tanstack/ai-vue@0.14.1 + ## 0.2.28 ### Patch Changes diff --git a/packages/ai-vue-ui/package.json b/packages/ai-vue-ui/package.json index 9762fce2a..054e47f54 100644 --- a/packages/ai-vue-ui/package.json +++ b/packages/ai-vue-ui/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-vue-ui", - "version": "0.2.28", + "version": "0.2.29", "description": "Headless Vue components for building TanStack AI chat interfaces with streamed message parts.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/ai-vue/CHANGELOG.md b/packages/ai-vue/CHANGELOG.md index 9d9a0f2cc..01685bb5a 100644 --- a/packages/ai-vue/CHANGELOG.md +++ b/packages/ai-vue/CHANGELOG.md @@ -1,5 +1,13 @@ # @tanstack/ai-vue +## 0.14.1 + +### Patch Changes + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai@0.39.0 + - @tanstack/ai-client@0.19.1 + ## 0.14.0 ### Minor Changes diff --git a/packages/ai-vue/package.json b/packages/ai-vue/package.json index f5f9f6224..f75ae9f9c 100644 --- a/packages/ai-vue/package.json +++ b/packages/ai-vue/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai-vue", - "version": "0.14.0", + "version": "0.14.1", "description": "Vue composables for TanStack AI streaming chat, structured outputs, and media generation.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/ai/CHANGELOG.md b/packages/ai/CHANGELOG.md index 105f802c8..e522381fa 100644 --- a/packages/ai/CHANGELOG.md +++ b/packages/ai/CHANGELOG.md @@ -1,5 +1,32 @@ # @tanstack/ai +## 0.39.0 + +### Minor Changes + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - Declarative sandbox file-event hooks: observe file create / change / delete + inside a sandbox and have them fire automatically during a chat run. + - `@tanstack/ai`: chat middleware gains an optional `sandbox` hook group + (`onFile`/`onFileCreate`/`onFileChange`/`onFileDelete`), a `SandboxFileEvent` + type, and a `sandbox` debug-logging category. The engine auto-emits a + `CUSTOM` `sandbox.file` event per change (client reads it from `parts`). + - `@tanstack/ai-sandbox`: `defineSandbox({ hooks, fileEvents })` declares + file + lifecycle hooks (`onFile*`/`onReady`/`onError`/`onDestroy`) that fire + automatically while the sandbox runs in a chat — `withSandbox` owns the + watcher. The watcher is provider-agnostic: a native `fs.watch` fast-path when + the provider advertises it, otherwise a portable `find -printf` mtime + snapshot-diff poll (no extra deps; `.git`/`node_modules` ignored by default). + `watchWorkspace()` / `diffSnapshots` remain as low-level building blocks. + - `@tanstack/ai-sandbox-local-process`: implements the optional `fs.watch` seam + via Node's recursive `fs.watch` (Windows/macOS); Linux falls back to the core + exec-poll automatically. + +- [#774](https://github.com/TanStack/ai/pull/774) [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4) - New provider-agnostic sandbox layer so harness adapters can run **inside** isolated sandboxes. + - **`@tanstack/ai-sandbox`** — `defineSandbox()` (lazy controller + resume→restoreSnapshot→create+bootstrap ensure algorithm), `withSandbox()` middleware, `defineWorkspace()` (git/local source, package-manager detection, setup, skills, secrets), `defineSandboxPolicy()`, the `SandboxProvider`/`SandboxHandle`/`SandboxCapabilities` contracts, capability tokens (`SandboxCapability` plus the optional `SandboxStore`/`Locks` persistence seams with in-memory defaults), `bootstrapWorkspace`, `createExecBackedGit`, `spawnNdjson` (run an agent CLI in a sandbox and stream its NDJSON stdout), the host MCP tool-proxy bridge (`startHostToolBridge` — exposes `chat()` server tools to the in-sandbox agent, with an optional permission-prompt tool), and the shared interactive-approval primitives (`resolveApproval`, `approvalId`, `buildApprovalRequestedEvent`) harness adapters use to enforce a policy and surface `approval-requested` events for client-in-the-loop approvals. + - **`@tanstack/ai-sandbox-local-process`** — `localProcessSandbox()`: runs the agent on the host through the uniform `SandboxHandle` (no isolation; the fast dev loop). + - **`@tanstack/ai-sandbox-docker`** — `dockerSandbox()`: runs the agent inside an isolated Docker container (dockerode), with commit-based snapshots, fork, and resume-by-id. + - **`@tanstack/ai`** — `TextOptions.capabilities` exposes the middleware capability context to adapters so harness adapters that declare `requires: [...]` can read provided capabilities from `chatStream`; `TextOptions.approvals` threads client approval decisions through to adapters for the interactive-approval (deny + `approval-requested` + re-run) flow; `DefinedChatMiddleware` and `AnyChatMiddleware` are now exported for portable middleware authoring. + ## 0.38.0 ### Minor Changes diff --git a/packages/ai/package.json b/packages/ai/package.json index b9fc37dcd..9c807f15a 100644 --- a/packages/ai/package.json +++ b/packages/ai/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/ai", - "version": "0.38.0", + "version": "0.39.0", "description": "Type-safe TypeScript AI SDK for streaming chat, tool calling, agents, structured outputs, and multimodal generation.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/openai-base/CHANGELOG.md b/packages/openai-base/CHANGELOG.md index d3ee9d102..a14287ebd 100644 --- a/packages/openai-base/CHANGELOG.md +++ b/packages/openai-base/CHANGELOG.md @@ -1,5 +1,12 @@ # @tanstack/openai-base +## 0.9.6 + +### Patch Changes + +- Updated dependencies [[`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4), [`b628a4d`](https://github.com/TanStack/ai/commit/b628a4da5fd21184922c6944059768d1ed6071d4)]: + - @tanstack/ai@0.39.0 + ## 0.9.5 ### Patch Changes diff --git a/packages/openai-base/package.json b/packages/openai-base/package.json index ecfcd44ab..c53506455 100644 --- a/packages/openai-base/package.json +++ b/packages/openai-base/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/openai-base", - "version": "0.9.5", + "version": "0.9.6", "description": "Shared OpenAI SDK base adapters for TanStack AI providers using Chat Completions and Responses APIs.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/preact-ai-devtools/CHANGELOG.md b/packages/preact-ai-devtools/CHANGELOG.md index 8e4eac550..a91b0577a 100644 --- a/packages/preact-ai-devtools/CHANGELOG.md +++ b/packages/preact-ai-devtools/CHANGELOG.md @@ -1,5 +1,12 @@ # @tanstack/preact-ai-devtools +## 0.1.63 + +### Patch Changes + +- Updated dependencies []: + - @tanstack/ai-devtools-core@0.4.20 + ## 0.1.62 ### Patch Changes diff --git a/packages/preact-ai-devtools/package.json b/packages/preact-ai-devtools/package.json index 397162821..28ecb4651 100644 --- a/packages/preact-ai-devtools/package.json +++ b/packages/preact-ai-devtools/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/preact-ai-devtools", - "version": "0.1.62", + "version": "0.1.63", "description": "Preact Devtools plugin for inspecting TanStack AI chat messages, tool calls, streams, and errors.", "author": "tannerlinsley", "license": "MIT", diff --git a/packages/react-ai-devtools/CHANGELOG.md b/packages/react-ai-devtools/CHANGELOG.md index d728c8019..71c96b76a 100644 --- a/packages/react-ai-devtools/CHANGELOG.md +++ b/packages/react-ai-devtools/CHANGELOG.md @@ -1,5 +1,12 @@ # @tanstack/react-ai-devtools +## 0.2.63 + +### Patch Changes + +- Updated dependencies []: + - @tanstack/ai-devtools-core@0.4.20 + ## 0.2.62 ### Patch Changes diff --git a/packages/react-ai-devtools/package.json b/packages/react-ai-devtools/package.json index fa10fb966..4a55f7bfa 100644 --- a/packages/react-ai-devtools/package.json +++ b/packages/react-ai-devtools/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/react-ai-devtools", - "version": "0.2.62", + "version": "0.2.63", "description": "React Devtools plugin for inspecting TanStack AI chat messages, tool calls, streams, and errors.", "author": "tannerlinsley", "license": "MIT", diff --git a/packages/solid-ai-devtools/CHANGELOG.md b/packages/solid-ai-devtools/CHANGELOG.md index d599e6a06..1401a58de 100644 --- a/packages/solid-ai-devtools/CHANGELOG.md +++ b/packages/solid-ai-devtools/CHANGELOG.md @@ -1,5 +1,12 @@ # @tanstack/solid-ai-devtools +## 0.2.63 + +### Patch Changes + +- Updated dependencies []: + - @tanstack/ai-devtools-core@0.4.20 + ## 0.2.62 ### Patch Changes diff --git a/packages/solid-ai-devtools/package.json b/packages/solid-ai-devtools/package.json index 2c5629af1..32d6f212b 100644 --- a/packages/solid-ai-devtools/package.json +++ b/packages/solid-ai-devtools/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/solid-ai-devtools", - "version": "0.2.62", + "version": "0.2.63", "description": "Solid Devtools plugin for inspecting TanStack AI chat messages, tool calls, streams, and errors.", "author": "Tanner Linsley", "license": "MIT",