Skip to content

Latest commit

 

History

History
441 lines (277 loc) · 44.4 KB

File metadata and controls

441 lines (277 loc) · 44.4 KB

@cloudflare/codemode

0.5.1

Patch Changes

  • #1557 447013d Thanks @mattzcarey! - Add MCP SDK v2 client and server support. MCPClientConnection now uses the exact-pinned @modelcontextprotocol/client@2.0.0-beta.5. It probes for stateless MCP with server/discover, then falls back to the legacy initialize handshake on the same connection when needed. The SDK auto-fulfills stateless elicitation input_required results through the existing form and URL elicitation handlers while callTool, getPrompt, and readResource remain pending. OAuth reauthorization discards redirect-scoped discovery after token issuance and preserves discovery-triggered authentication, allowing a changed authorization server to be rediscovered and registered without reusing the prior issuer's credentials. Legacy pushed elicitation, Streamable HTTP, SSE, RPC, OAuth, and hibernation recovery remain supported. Codemode's MCP connector now uses an SDK-neutral structural boundary compatible with both MCP client generations.

    Add MCP SDK v2 support to createMcpHandler. Pass a factory returning McpServer or Server from the exact-pinned @modelcontextprotocol/server@2.0.0-beta.5 peer dependency to serve stateless MCP with legacy compatibility by default. The new agents/mcp/server entry exports the stateless Agents handler without retaining McpAgent, WorkerTransport, MCP client transports, PartyServer, or SDK v1 modules. The returned handler remains callable for Worker dispatch and exposes the lower-level SDK fetch(request, options?) method plus typed notify methods; upstream close and event-bus internals are not part of the Agents surface. The retained v1 server APIs use the exact-pinned @modelcontextprotocol/sdk@1.29.0 peer dependency.

    The legacy compatibility fallback now uses SDK v2's web-standard transport, including fail-fast handling for unsupported server-to-client requests, active-request teardown, and the same 25-second Cloudflare SSE keepalive previously supplied by WorkerTransport. It returns 405 for session-only GET and DELETE requests without constructing an application server. createLegacyMcpHandler remains an explicit public API for SDK v1 servers and complete WorkerTransport options.

    The MCP client storage codec now preserves stateless discovery data with resumed HTTP sessions and preserves the binding name and props required to restore RPC servers. Stored HTTP session IDs from older Agents versions have no associated protocol version. The upgraded client discards those IDs and reconnects instead of sending an unsafe resumed request, so in-flight work tied to an old remote session does not resume.

    The v2 callable handler maps verified provider-issued metadata from compatible @cloudflare/workers-oauth-provider releases to standard MCP AuthInfo while preserving getMcpAuthContext().props.

    The Workers handler rejects malformed, opaque, and non-HTTP browser Origins. Its default allowlist includes localhost-class Origins, the endpoint's workers.dev hostname, and a concrete corsOptions.origin hostname. It applies matching Host checks to localhost and workers.dev endpoints. Custom-domain deployments with wildcard CORS can set allowedHostnames and allowedOriginHostnames explicitly, or set allowedOriginHostnames: "*" when trusted upstream middleware already enforces the required Origin policy. Requests without Origin remain valid for non-browser MCP clients. Default CORS preflights allow the stateless Mcp-Method and Mcp-Name request headers.

    @cloudflare/codemode is now an optional peer. Applications that import agents/skills or agents/browser install Codemode explicitly; MCP-only applications no longer install it transitively.

    Deprecations in this release:

    • McpAgent is deprecated and feature-frozen as a stateful SDK v1 path. New servers should use an SDK v2 factory with createMcpHandler from agents/mcp/server.
    • Passing an SDK v1 server to the overloaded createMcpHandler is deprecated for removal in the next major release. Move the server to an SDK v2 factory. Use createLegacyMcpHandler only to temporarily retain sessionful SDK v1 behavior while migrating.
    • The explicit result-schema overloads MCPClientManager.callTool(params, resultSchema, options) and withX402Client(...).callTool(confirm, params, resultSchema, options) are deprecated. Use callTool(params, options) or callTool(confirm, params, options) instead.

    experimental_createMcpHandler was already deprecated and remains scheduled for removal in the next major release. Its warning now directs users to an SDK v2 factory first and names createLegacyMcpHandler only as a temporary bridge for sessionful SDK v1 behavior.

0.5.0

Minor Changes

  • #1922 cb4c1c7 Thanks @cjol! - Support both AI SDK v6 and v7.

    The ai peer range is ai@^6 || ^7 (and @ai-sdk/react is @^3 || ^4) across agents, @cloudflare/ai-chat, @cloudflare/codemode, and @cloudflare/think. Consumers can adopt AI SDK v7 or stay on v6 — no forced AI SDK upgrade when bumping these packages.

    Only the current implementations are covered. New optimisations and APIs made available by AI SDK v7 (broader result-shape audits, stream helper migrations, etc.) are intentionally out of scope.

    How dual-version support works — @cloudflare/think calls the AI SDK through the option names present in both majors (v7 keeps the v6 names as aliases), and normalizes the genuine divergences at the boundary:

    • Uses stepCountIs, system, experimental_telemetry, onStepFinish, and experimental_onToolCallFinish (in v7 this alias resolves to onToolExecutionEnd and fires once).
    • The tool-execution-finished event is normalized across majors: v6's { success, output, error, durationMs, stepNumber } and v7's { toolOutput, toolExecutionMs } collapse to one ToolCallResultContext. stepNumber is undefined under v7 (the v7 event no longer provides it).
    • The UI message stream is built via the result's toUIMessageStream() method (present in both majors); the standalone toUIMessageStream({ stream }) helper and result.stream are v7-only.
    • The workspace read tool emits { type: "file-data", data, mediaType, filename } model output, accepted by both majors (v7's newer { type: "file", data: { type: "data", data } } shape does not exist in v6).

    Public API notes:

    • @cloudflare/think keeps system, onStepFinish, and experimental_telemetry where callers already use them, and also accepts TurnConfig.telemetry (forwarded ahead of experimental_telemetry when present).
    • @cloudflare/ai-chat updates the AIChatAgent.onChatMessage callback type from StreamTextOnFinishCallback to GenerateTextOnFinishCallback.

    Verified against both ai@6 and ai@7: @cloudflare/think type-checks with zero errors and its full workers test suite passes under each major.

    Known limitations:

    • workers-ai-provider (Think's default model provider) is fixed at v4 for AI SDK v7. Consumers on ai@6 who rely on Think's built-in default model may hit a provider-version mismatch; passing their own LanguageModel avoids this.
    • chat@4.31.0 currently declares an ai@^6 peer and does not yet advertise v7 support; tracked separately.
    • CI should exercise both an ai@6 and an ai@7 resolution to guard the matrix.

0.4.4

Patch Changes

  • #1969 80ad8de Thanks @mattzcarey! - Add framework-neutral execute, search, and describe methods to the durable Code Mode runtime handle so MCP servers and other non-AI-SDK hosts can invoke execution and discovery directly. Search and describe results now identify methods that require approval.

0.4.3

Patch Changes

  • #1904 88f7f69 Thanks @mattzcarey! - Echo the durable tool-call log on the proxy tool output. ProxyToolOutput now carries an optional calls field (the execution's ToolLogEntry[]) on completed, paused and error outcomes, so UIs can render an audit trail of every connector call and step — name, args, result, approval requirement and state — without a separate executions() round trip.

0.4.2

Patch Changes

  • #1807 7eea2fb Thanks @mattzcarey! - Cleanup connector imports so connector modules are imported normally and the Vite plugin only auto-exports the CodemodeRuntime facet class. Codemode now fails loudly when the runtime facet class is not exported from the Worker entry.

  • #1814 a79144d Thanks @threepointone! - Dispose the dynamically-loaded Worker and its RPC entrypoint stub after each DynamicWorkerExecutor.execute() run.

    Each execution spins up a child Worker via loader.load() and obtains an RPC Fetcher stub via getEntrypoint(). These own native handles, and the code previously left them for the garbage collector. When such a handle is finalized late — for example during isolate shutdown under @cloudflare/vitest-pool-workers — workerd raises a fatal assertion ("tried to defer destruction during isolate shutdown") that kills the worker, surfacing as a flaky "Worker exited unexpectedly" with no failing assertion. The milder manifestation is workerd's "An RPC result was not disposed properly" warning.

    The executor now disposes the entrypoint stub and the loaded worker in finally blocks (best-effort, via Symbol.dispose), releasing the handles while the isolate is still alive. No behavior or API change for callers.

  • #1793 247ebeb Thanks @mattzcarey! - Pass the outer MCP tool-call context to openApiMcpServer request callbacks so server-to-client requests and notifications can be associated with the originating response stream.

  • #1791 9c85369 Thanks @mattzcarey! - Remove the root entry's runtime dependency on the optional ai and zod peers. Executor and runtime imports now bundle without either framework package installed.

  • #1772 d4f27fe Thanks @mattzcarey! - Include each package's documentation in its published package.

  • #1806 43f663d Thanks @mattzcarey! - Increase the default DynamicWorkerExecutor timeout from 30 seconds to 60 seconds to better support longer-running codemode executions.

0.4.1

Patch Changes

  • #1760 6769830 Thanks @cjol! - Fix the runtime tool description to say "Execute JavaScript" instead of "Execute TypeScript". The codemode sandbox executes JavaScript only; TypeScript types are generated for LLM context but are not executed.

0.4.0

Minor Changes

  • #1581 b2b6762 Thanks @mattzcarey! - Add the connector model and a durable runtime for codemode.

    Connectors — class-based integrations that bridge external services into the sandbox. A connector is three things: name(), optional instructions(), and tools() — one record, one entry per tool, with each tool carrying its own description, schema, requiresApproval, execute, and optional revert:

    • CodemodeConnector — abstract base; author tools() directly (AI SDK toolsets are shape-compatible and can be returned as-is). Its constructor accepts a DurableObjectState or an ExecutionContext, so you pass this.ctx from inside an Agent/DO with no cast.
    • McpConnector — derives tools() from an MCP connection (createConnection()); decorate derived tools via the tool(name, t) hook
    • Per-execution resources — a tool's execute(args, ctx)/revert(args, result, ctx) now receive the run's executionId (stable across pause/resume), and connectors can override disposeExecution(executionId, status) to tear down a resource scoped to one run (a browser/CDP session, a transaction). It fires on each terminal transition (completed/error/rejected/rolled_back) and never on pause, so a resource survives an approval pause and is released when the run truly ends. Must be idempotent (a completed-then-rolled-back run disposes twice). A stale/no-op reject no longer triggers teardown, so a still-resumable run keeps its resources
    • OpenApiConnector — derives one typed tool per operation from the spec (host-side, zero prompt tokens), so the model calls api.get_repository({ owner, repo }) directly; request() remains as a low-level escape hatch. Derivation resolves local $refs (including allOf/oneOf/anyOf) and is memoized by spec identity, so a static spec is parsed once even though connectors are reconstructed per message; operations whose names collide (or hit the reserved request/spec) are skipped with a warning

    RuntimeCodemodeRuntime, a DurableObject facet that wraps an Executor and makes execution durable via abort-and-replay:

    • Every tool call and codemode.step(name, fn) is recorded in a durable log
    • Reads and steps execute and record their result
    • Approval-required actions pause the run (abort)
    • The facet is stateless across calls — execution id + a host-allocated sequence + the approval requirement are threaded into every call, so runs are safe across hibernation and can run concurrently without clobbering one another
    • Once a run pauses or terminates, the facet refuses further progress: every subsequent call/step gets a pause decision and records nothing, so model code that catches the pause sentinel and keeps going can't drive extra side effects
    • A decided-but-not-yet-recorded call is logged as executing (not applied), so a crash between deciding and recording the result re-executes on replay instead of replaying undefined
    • Replay divergence (a call's connector/method or its arguments differ from the recorded run, e.g. nondeterminism not wrapped in codemode.step) is detected and recorded as a failed execution
    • Execution outcomes are returned, not thrown: the tool yields { status: "completed" | "paused" | "error" } so a sandbox error or divergence is an observable tool result rather than an exception that breaks the agent loop
    • Lifecycle calls target an explicit executionId — there is no implicit "current run" (a single shared pointer would be racy with concurrent runs). Every tool outcome (completed/paused/error) carries executionId, and pending()/executions() surface ids for approval UIs
    • runtime.pending() lists actions awaiting approval, for approval UIs — with no executionId it aggregates across all paused runs (not just the most recent); runtime.executions() lists all runs (the audit trail)
    • runtime.approve({ executionId }) replays the log and runs the approved action; it only resumes a paused run — approving a run that already completed, was rejected, or rolled back (a stale/racing approval UI) is a safe no-op that revives nothing (returning an error outcome) rather than re-offering a rejected action or re-applying rolled-back effects. runtime.reject({ seq, executionId }) ends the execution with a first-class rejected status (it does not auto-undo already-applied actions — call rollback() for that)
    • runtime.rollback({ executionId }) reverts all applied, reversible actions (any tool with a revert, not just approval-gated ones) in reverse order, marking only those actually reverted; it attempts every revert even if one fails (surfacing the failures afterward) and marks the execution rolled_back
    • Retention — terminal executions are auto-pruned to maxExecutions (default 50) as new runs begin; runtime.deleteExecution(id) and runtime.pruneExecutions(keep) are explicit controls. Running/paused executions are never pruned.
    • codemode.step(name, fn) is the explicit side-effect boundary — wrap any nondeterministic or side-effectful work so it runs once and replays thereafter
    • The runtime facet's identity is derived from the connector set — changing connectors yields a fresh runtime, so stored snippets and paused executions are always bound to the connectors that can run them

    Snippets — durable, addressable saved scripts that replace the old static skills. The model writes and runs scripts; the developer promotes the good ones with runtime.saveSnippet(name, { executionId?, description }) and the model re-runs them with codemode.run(name, input). Snippets live on the runtime, surface in codemode.search/describe, and are structurally bound to the connector set (no per-snippet dependency tracking).

    Runtime-facing toolcreateCodemodeRuntime({ ctx, executor, connectors }).tool() returns one { code } tool. Inside the sandbox: codemode.search/describe/step/run plus <connector>.<method>(...) globals — a deliberately minimal surface: discover, learn, do-once, reuse.

    Result shapingcreateCodemodeRuntime accepts an optional transformResult that reshapes the model-facing result of a completed run (initial run and resume), after the raw value is recorded — so the audit trail keeps the full result while the model sees the shaped one. Exported truncateResult/truncateResponse (with { maxChars?, maxTokens? }) are the default building blocks: structured results pass through unchanged until oversized, then serialize to a bounded, marked string.

    ResolvedProvider gains an optional prelude — sandbox-side JS that can define real in-sandbox functions on a namespace (used to implement codemode.step, which wraps a local closure that can't cross the RPC boundary). New exported types ToolExecuteContext and ExecutionEndStatus describe the per-execution resource contract.

    Vite plugin@cloudflare/codemode/vite discovers *.codemode.ts files and auto-exports connector classes for ctx.exports access.

    Executor-style ranked search with normalized tokenization and scoring.

  • #1656 4c2d1a7 Thanks @cjol! - Codemode runtime refinements (pre-release):

    • SQL storage. The CodemodeRuntime facet now stores executions, the tool-call log, and snippets in SQLite tables (one row per log entry) instead of single key-value blobs — appends no longer rewrite the whole execution, and pruning/expiry/listing are indexed. Args/results are serialized with a binary- and bigint-safe codec.
    • Size guards. Any single recorded value (call args, a recorded result, the final result) is capped at 1 MB serialized (MAX_DURABLE_VALUE_BYTES). Oversized args or call results fail the run with a model-actionable error; an oversized final result completes normally with a placeholder in the audit trail.
    • Replay policy. Connector tools can declare replay: "reexecute": the call is logged for sequencing/divergence but its result is never stored — replays re-execute it. For idempotent reads with large results. Incompatible with requiresApproval.
    • onPassEnd hook. Connectors get onPassEnd(executionId, status) at the end of every execution pass — including pauses, where disposeExecution deliberately does not fire — to release per-pass resources (sockets, leases).
    • Explicit runtime identity. The runtime facet is keyed by an explicit name (default "default") instead of a fingerprint of the connector set, so executions and snippets survive connector changes. Each execution/snippet records the connector names it needs; resume and codemode.run verify them and fail with a clear error when one is missing.
    • expirePaused. runtime.expirePaused({ maxAgeMs }) (default 24h) expires stale non-terminal runs and fires disposeExecution, reclaiming their resources — for use from a recurring alarm/scheduled task. Paused (awaiting-approval) runs are marked rejected; runs stuck running after a host crash are marked errored (they could never be resumed or pruned otherwise).
    • Lifecycle hardening. runtime.reject() returns whether it actually terminated the run (false for a stale/duplicate reject — e.g. the action was approved from another tab) so callers never report a run as rejected when its gated action actually executed. deleteExecution on a non-terminal run also disposes its per-execution connector resources. Oversized execution code is rejected up front with a model-actionable error, and snippet schemas are size-checked on save. createCodemodeRuntime rejects duplicate connector names (they would silently shadow each other in the sandbox).
    • Reserved-name hardening. The executor rejects provider/connector names that would shadow harness globals (Promise, setTimeout, Error, console, …).
    • Anti-hallucination tool description. The default execute tool description now states explicitly that the connector namespaces plus codemode are the only sandbox globals (no host, fs, require, process), and tells the model to discover method names via codemode.search instead of guessing. tool({ connectorHints }) renders a one-line usage hint next to each connector in the description. A sandbox ReferenceError (x is not defined) now gets the list of available globals appended, so the model's retry is informed.
  • #1656 4c2d1a7 Thanks @cjol! - Add ToolSetConnector — adapt an AI SDK ToolSet into a codemode connector.

    toolSetConnector(ctx, { tools }) (default name tools) turns existing AI SDK tools into connector tools for the durable runtime, converting their input schemas to JSON Schema for the sandbox type declarations. Tools with needsApproval: true are mapped to requiresApproval: true on the connector tool — calling one pauses the execution durably for human approval instead of the tool being unavailable. Tools without an execute function (client-side / provider-executed) are excluded from both the bindings and the generated types, with a one-time warning — the sandbox can't call them. The runtime tool's description now also instructs the model to stop and wait when an execution returns status: "paused".

0.3.8

Patch Changes

  • #1555 2d45abd Thanks @mattzcarey! - Default openApiMcpServer to the MCP SDK's Workers-safe JSON schema validator so elicitation response validation does not rely on runtime code generation.

0.3.7

Patch Changes

  • #1547 f739ec9 Thanks @mattzcarey! - Dispatch all codemode tool calls positionally and remove provider-level positionalArgs configuration.

0.3.6

Patch Changes

  • #1521 2911bae Thanks @mattzcarey! - Preserve binary values across codemode tool calls so Uint8Array arguments and results survive the sandbox boundary. This fixes state.writeFileBytes() from codemode with byte arrays and keeps readFileBytes() results as Uint8Array values.

  • #1523 5f1376f Thanks @mattzcarey! - Remove the echoed source code field from codemode tool results. Successful sandbox executions now return only the execution result and any captured logs.

0.3.5

Patch Changes

  • #1468 186a2a4 Thanks @mattzcarey! - Add a browser-safe codemode export with an iframe sandbox executor and browser tool helper. Harden iframe message handling with nonce-scoped messages, reject sanitized tool name collisions, and keep tools with needsApproval: false.

  • #1470 1033fa2 Thanks @mattzcarey! - Resolve OpenAPI specs inside the codemode sandbox to avoid Worker Loader RPC size limits for heavily-referenced specs.

  • #1508 13acffe Thanks @threepointone! - fix(codemode): harden OpenAPI sandbox ref handling

0.3.4

Patch Changes

  • #1266 d5dbf45 Thanks @threepointone! - Add optional description to codeMcpServer, matching the existing option on createCodeTool. Supports {{types}} and {{example}} placeholders; falls back to the built-in default when omitted.

  • c5ca556 Thanks @threepointone! - Fix @tanstack/ai peer dependency range from ^0.8.0 to >=0.8.0 <1.0.0. The caret range for pre-1.0 packages only allows >=0.8.0 <0.9.0, which excluded the current 0.10.0 release.

0.3.3

Patch Changes

0.3.2

Patch Changes

  • #1204 39d8d62 Thanks @threepointone! - Unwrap MCP content wrappers in codeMcpServer so sandbox code sees plain values instead of raw { content: [{ type: "text", text }] } objects. Error responses (isError) now throw proper exceptions catchable via try/catch, and structuredContent is returned directly when present.

0.3.1

Patch Changes

  • #1181 e9bace9 Thanks @threepointone! - Fix createCodeTool dropping positionalArgs from providers, causing multi-argument tool calls (e.g. stateTools) to silently lose arguments after the first.

0.3.0

Minor Changes

  • #1138 36e2020 Thanks @threepointone! - Drop Zod v3 from peer dependency range — now requires zod ^4.0.0. Replace dynamic import("ai") with z.fromJSONSchema() from Zod 4 for MCP tool schema conversion, removing the ai runtime dependency from the agents core. Remove ensureJsonSchema().

Patch Changes

  • #1149 47ce125 Thanks @threepointone! - feat: add TanStack AI integration (@cloudflare/codemode/tanstack-ai)

    New entry point for using codemode with TanStack AI's chat() instead of the Vercel AI SDK's streamText().

    import {
      createCodeTool,
      tanstackTools
    } from "@cloudflare/codemode/tanstack-ai";
    import { chat } from "@tanstack/ai";
    
    const codeTool = createCodeTool({
      tools: [tanstackTools(myServerTools)],
      executor
    });
    
    const stream = chat({ adapter, tools: [codeTool], messages });

    Exports:

    • createCodeTool — returns a TanStack AI ServerTool (via toolDefinition().server())
    • tanstackTools — converts a TanStackTool[] into a ToolProvider with pre-generated types
    • generateTypes — generates TypeScript type definitions from TanStack AI tools
    • resolveProvider — re-exported framework-agnostic provider resolver

    Internal cleanup: extracted resolveProvider into a framework-agnostic resolve.ts module so the main entry (@cloudflare/codemode) no longer pulls in the ai package at runtime. Shared constants and helpers moved to shared.ts to avoid duplication between the AI SDK and TanStack AI entry points.

0.2.2

Patch Changes

  • #1122 a16e74d Thanks @threepointone! - Add ToolProvider interface for composing tools from multiple sources into a single codemode sandbox. createCodeTool now accepts a ToolProvider[] alongside raw tool sets. Each provider contributes tools under a named namespace (e.g. state.*, mcp.*) with the default being codemode.*. Providers with positionalArgs: true use natural function signatures (state.readFile("/path")) instead of single-object args. The old executor.execute(code, fns) signature is deprecated but still works with a warning.

0.2.1

Patch Changes

  • #1114 5d88b81 Thanks @mattzcarey! - Add @cloudflare/codemode/mcp barrel export with two functions:

    • codeMcpServer({ server, executor }) — wraps an MCP server with a single code tool where each upstream tool becomes a typed codemode.* method
    • openApiMcpServer({ spec, executor, request }) — creates search + execute MCP tools from an OpenAPI spec with host-side request proxying and automatic $ref resolution
  • #1113 1264372 Thanks @mattzcarey! - Add optional modules option to DynamicWorkerExecutorOptions to allow injecting custom ES modules into the sandbox

  • #1117 9837adc Thanks @mattzcarey! - DynamicWorkerExecutor now normalizes code and sanitizes tool names internally. Users no longer need to call normalizeCode() or sanitizeToolName() before passing code/fns to execute().

0.2.0

Minor Changes

  • #1102 f07ef51 Thanks @mattzcarey! - BREAKING: generateTypes and ToolDescriptor/ToolDescriptors types are no longer exported from the main entry point. Import them from @cloudflare/codemode/ai instead:

    // Before
    import { generateTypes } from "@cloudflare/codemode";
    
    // After
    import { generateTypes } from "@cloudflare/codemode/ai";

    The main entry point (@cloudflare/codemode) no longer requires the ai or zod peer dependencies. It now exports:

    • sanitizeToolName — sanitize tool names into valid JS identifiers
    • normalizeCode — normalize LLM-generated code into async arrow functions
    • generateTypesFromJsonSchema — generate TypeScript type definitions from plain JSON Schema (no AI SDK needed)
    • jsonSchemaToType — convert a JSON Schema to a TypeScript type declaration string
    • DynamicWorkerExecutor, ToolDispatcher — sandboxed code execution
    • JsonSchemaToolDescriptor / JsonSchemaToolDescriptors — types for the JSON Schema API

    The ai and zod peer dependencies are now optional — only required when importing from @cloudflare/codemode/ai.

0.1.3

Patch Changes

  • #1092 c2df742 Thanks @mattzcarey! - Export normalizeCode utility function for use by consumers that need to normalize user-provided code to async arrow function format before sandbox execution.

  • #1074 33b92d5 Thanks @mattzcarey! - Remove zod-to-ts dependency to reduce bundle size. Zod schemas are now converted to TypeScript strings via JSON Schema using the existing jsonSchemaToTypeString() function and AI SDK's asSchema().

0.1.2

Patch Changes

0.1.1

Patch Changes

  • #962 ef46d68 Thanks @tumberger! - Validate tool arguments against Zod schema before execution in codemode sandbox

  • #973 969fbff Thanks @threepointone! - Update dependencies

  • #960 179b8cb Thanks @mattzcarey! - Harden JSON Schema to TypeScript converter for production use

    • Add depth and circular reference guards to prevent stack overflows on recursive or deeply nested schemas
    • Add $ref resolution for internal JSON Pointers (#/definitions/..., #/$defs/..., #)
    • Add tuple support (prefixItems for JSON Schema 2020-12, array items for draft-07)
    • Add OpenAPI 3.0 nullable: true support across all schema branches
    • Fix string escaping in enum/const values, property names (control chars, U+2028/U+2029), and JSDoc comments (*/)
    • Add per-tool error isolation in generateTypes() so one malformed schema cannot crash the pipeline
    • Guard missing inputSchema in getAITools() with a fallback to { type: "object" }
    • Add per-tool error isolation in getAITools() so one bad MCP tool does not break the entire tool set
  • #961 f6aa79f Thanks @mattzcarey! - Updated default tool prompt to explicitly request JavaScript code from LLMs, preventing TypeScript syntax errors in the Dynamic Worker executor.

0.1.0

Minor Changes

  • #879 90e54da Thanks @mattzcarey! - Remove experimental_codemode() and CodeModeProxy. Replace with createCodeTool() from @cloudflare/codemode/ai which returns a standard AI SDK Tool. The package no longer owns an LLM call or model choice. Users call streamText/generateText with their own model and pass the codemode tool.

    The AI-dependent export (createCodeTool) is now at @cloudflare/codemode/ai. The root export (@cloudflare/codemode) contains the executor, type generation, and utilities which do not require the ai peer dependency.

    ToolDispatcher (extends RpcTarget) replaces CodeModeProxy (extends WorkerEntrypoint) for dispatching tool calls from the sandbox back to the host. It is passed as a parameter to the dynamic worker's evaluate() method instead of being injected as an env binding, removing the need for CodeModeProxy and globalOutbound service bindings. Only a WorkerLoader binding is required now. globalOutbound on DynamicWorkerExecutor defaults to null which blocks fetch/connect at the runtime level. New Executor interface (execute(code, fns) => ExecuteResult) allows custom sandbox implementations. DynamicWorkerExecutor is the Cloudflare Workers implementation. Console output captured in ExecuteResult.logs. Configurable execution timeout.

    AST-based code normalization via acorn replaces regex. sanitizeToolName() exported for converting MCP-style tool names to valid JS identifiers.

Patch Changes

0.0.8

Patch Changes

  • #916 24e16e0 Thanks @threepointone! - Widen peer dependency ranges across packages to prevent cascading major bumps during 0.x minor releases. Mark @cloudflare/ai-chat and @cloudflare/codemode as optional peer dependencies of agents to fix unmet peer dependency warnings during installation.

0.0.7

Patch Changes

0.0.6

Patch Changes

0.0.5

Patch Changes

0.0.4

Patch Changes

0.0.3

Patch Changes

0.0.2

Patch Changes

  • #756 0c4275f Thanks @threepointone! - feat: split ai-chat and codemode into separate packages

    Extract @cloudflare/ai-chat and @cloudflare/codemode into their own packages with comprehensive READMEs. Update agents README to remove chat-specific content and point to new packages. Fix documentation imports to reflect new package structure.

    Maintains backward compatibility, no breaking changes.

  • Updated dependencies [0c4275f, f12553f]:

    • agents@0.3.2