Skip to content

Version Packages#1140

Merged
threepointone merged 1 commit into
mainfrom
changeset-release/main
Mar 23, 2026
Merged

Version Packages#1140
threepointone merged 1 commit into
mainfrom
changeset-release/main

Conversation

@github-actions
Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot commented Mar 20, 2026

This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.

Releases

agents@0.8.0

Minor Changes

  • #1152 16cc622 Thanks @threepointone! - feat: expose readable state property on useAgent and AgentClient

    Both useAgent (React) and AgentClient (vanilla JS) now expose a state property that tracks the current agent state. Previously, state was write-only via setState() — reading state required manually tracking it through the onStateUpdate callback.

    React (useAgent)

    const agent = useAgent<GameAgent, GameState>({
      agent: "game-agent",
      name: "room-123",
    });
    
    // Read state directly — no need for separate useState + onStateUpdate
    return <div>Score: {agent.state?.score}</div>;
    
    // Spread for partial updates — works correctly now
    agent.setState({ ...agent.state, score: agent.state.score + 10 });

    agent.state is reactive — the component re-renders when state changes from either the server or client-side setState().

    Vanilla JS (AgentClient)

    const client = new AgentClient<GameAgent>({
      agent: "game-agent",
      name: "room-123",
      host: "your-worker.workers.dev",
    });
    
    // State updates synchronously on setState and server broadcasts
    client.setState({ score: 100 });
    console.log(client.state); // { score: 100 }

    Backward compatible

    The onStateUpdate callback continues to work exactly as before. The new state property is additive — it provides a simpler alternative to manual state tracking for the common case.

    Type: State | undefined

    State starts as undefined and is populated when the server sends state on connect (from initialState) or when setState() is called. Use optional chaining (agent.state?.field) for safe access.

  • #1154 74a018a Thanks @threepointone! - feat: idempotent schedule() to prevent row accumulation across DO restarts

    schedule() now supports an idempotent option that deduplicates by (type, callback, payload), preventing duplicate rows from accumulating when called repeatedly (e.g., in onStart()).

    Cron schedules are idempotent by default. Calling schedule("0 * * * *", "tick") multiple times with the same callback, cron expression, and payload returns the existing schedule instead of creating a duplicate. Set { idempotent: false } to override.

    Delayed and scheduled (Date) types support opt-in idempotency:

    async onStart() {
      // Safe across restarts — only one row exists at a time
      await this.schedule(60, "maintenance", undefined, { idempotent: true });
    }

    New warnings for common foot-guns:

    • schedule() called inside onStart() without { idempotent: true } now emits a console.warn with actionable guidance (once per callback, skipped for cron and when idempotent is explicitly set)
    • alarm() processing ≥10 stale one-shot rows for the same callback emits a console.warn and a schedule:duplicate_warning diagnostics channel event
  • #1146 b74e108 Thanks @threepointone! - feat: strongly-typed AgentClient with call inference and stub proxy

    AgentClient now accepts an optional agent type parameter for full type inference on RPC calls, matching the typed experience that useAgent already provides.

    New: typed call and stub

    When an agent type is provided, call() infers method names, argument types, and return types from the agent's methods. A new stub property provides a direct RPC-style proxy — call agent methods as if they were local functions:

    const client = new AgentClient<MyAgent>({
      agent: "my-agent",
      host: window.location.host,
    });
    
    // Typed call — method name autocompletes, args and return type inferred
    const value = await client.call("getValue");
    
    // Typed stub — direct RPC-style proxy
    await client.stub.getValue();
    await client.stub.add(1, 2);

    State is automatically inferred from the agent type, so onStateUpdate is also typed:

    const client = new AgentClient<MyAgent>({
      agent: "my-agent",
      host: window.location.host,
      onStateUpdate: (state) => {
        // state is typed as MyAgent's state type
      },
    });

    Backward compatible

    Existing untyped usage continues to work without changes:

    const client = new AgentClient({ agent: "my-agent", host: "..." });
    client.call("anyMethod", [args]); // still works
    client.call<number>("add", [1, 2]); // explicit return type still works
    client.stub.anyMethod("arg1", 123); // untyped stub also available

    The previous AgentClient<State> pattern is preserved — new AgentClient<{ count: number }>({...}) still correctly types onStateUpdate and leaves call/stub untyped.

    Breaking: call is now an instance property instead of a prototype method

    AgentClient.prototype.call no longer exists. The call function is assigned per-instance in the constructor (via .bind()). This is required for the conditional type system to switch between typed and untyped signatures. Normal usage (client.call(...)) is unaffected, but code that reflects on the prototype or subclasses that override call as a method may need adjustment.

    Shared type utilities

    The RPC type utilities (AgentMethods, AgentStub, RPCMethods, etc.) are now exported from agents/client so they can be shared between AgentClient and useAgent, and are available to consumers who need them for advanced typing scenarios.

  • #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

  • #1147 1f85b06 Thanks @threepointone! - Replace schedule-based keepAlive with lightweight ref-counted alarms

    • keepAlive() no longer creates schedule rows or emits schedule:create/schedule:execute/schedule:cancel observability events — it uses an in-memory ref count and feeds directly into _scheduleNextAlarm()
    • multiple concurrent keepAlive() callers now share a single alarm cycle instead of each creating their own interval schedule row
    • add _onAlarmHousekeeping() hook (called on every alarm cycle) for extensions like the fiber mixin to run housekeeping without coupling to the scheduling system
    • bump internal schema to v2 with a migration that cleans up orphaned _cf_keepAliveHeartbeat schedule rows from the previous implementation
    • remove @experimental from keepAlive() and keepAliveWhile()

@cloudflare/ai-chat@0.2.0

Minor Changes

  • #1150 81a8710 Thanks @threepointone! - feat: add sanitizeMessageForPersistence hook and built-in Anthropic tool payload truncation

    • New protected hook: sanitizeMessageForPersistence(message) — override this method to apply custom transformations to messages before they are persisted to storage. Runs after built-in sanitization. Default is identity (returns message unchanged).
    • Anthropic provider-executed tool truncation: Large string values in input and output of provider-executed tool parts (e.g. Anthropic code_execution, text_editor) are now automatically truncated. These server-side tool payloads can exceed 200KB and are dead weight once the model has consumed the result.

    Closes #1118

  • #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

  • #1151 b0c52a5 Thanks @whoiskatrin! - fix(ai-chat): simplify turn coordination API

    • rename waitForPendingInteractionResolution() to waitUntilStable() and make it wait for a fully stable conversation state, including queued continuation turns
    • add resetTurnState() for scoped clear handlers that need to abort active work and invalidate queued continuations
    • demote isChatTurnActive(), waitForIdle(), and abortActiveTurn() to private — their behavior is subsumed by waitUntilStable() and resetTurnState()
    • harden pending-interaction bookkeeping so rejected tool-result and approval applies do not leak as unhandled rejections
  • #1106 3184282 Thanks @threepointone! - fix: abort/stop no longer creates duplicate split messages (issue #1100)

    When a user clicked stop during an active stream, the assistant message was split into two separate messages. This happened because onAbort in the transport immediately removed the requestId from activeRequestIds, causing onAgentMessage to treat in-flight server chunks as a new broadcast.

    • WebSocketChatTransport: onAbort now keeps the requestId in activeRequestIds so in-flight server chunks are correctly skipped by the dedup guard
    • useAgentChat: onAgentMessage now cleans up the kept ID when receiving done: true, preventing a minor memory leak
  • #1142 5651ece Thanks @whoiskatrin! - fix(ai-chat): serialize chat turns and expose turn control helpers

    • queue onChatMessage() + _reply() work so user requests, tool continuations, and saveMessages() never stream concurrently
    • make saveMessages() wait for the queued turn to finish before resolving, and reuse the request id for reply cleanup
    • skip queued continuations and saveMessages() calls that were enqueued before a chat clear
    • capture saveMessages() context (_lastClientTools, _lastBody) at enqueue time so a later request cannot overwrite it before execution
    • add protected isChatTurnActive(), waitForIdle(), abortActiveTurn(), hasPendingInteraction(), and waitForPendingInteractionResolution() helpers for subclass code that needs to coordinate active turns and pending tool interactions
  • #1096 0d0b7d3 Thanks @threepointone! - fix(ai-chat): prevent duplicate messages after tool calls and orphaned client IDs

    • CF_AGENT_MESSAGE_UPDATED handler no longer appends when message not found in client state, fixing race between transport stream and server broadcast
    • _resolveMessageForToolMerge reconciles IDs by toolCallId regardless of tool state, preventing client nanoid IDs from leaking into persistent storage

@cloudflare/codemode@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.

@cloudflare/think@0.1.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().

@cloudflare/worker-bundler@0.0.4

Patch Changes

  • #1145 94fac05 Thanks @threepointone! - Separate assets from isolate: createApp now returns assets for host-side serving instead of embedding them in the dynamic isolate. Removes DO wrapper code generation and durableObject option — mounting is the caller's concern. Preview proxy replaced with Service Worker-based URL rewriting.

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Open in Devin Review

@github-actions github-actions Bot force-pushed the changeset-release/main branch 14 times, most recently from 0a4ddc9 to 6d0a063 Compare March 23, 2026 11:20
@github-actions github-actions Bot force-pushed the changeset-release/main branch from 6d0a063 to cc83085 Compare March 23, 2026 11:22
@threepointone threepointone merged commit 0b97e62 into main Mar 23, 2026
@threepointone threepointone deleted the changeset-release/main branch March 23, 2026 11:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature request: add public way to extend AIChatAgent._sanitizeMessageForPersistence

1 participant