@cloudflare/think@0.4.2

cloudflare/agents@cloudflare/think@0.4.2Apr 28, 2026by github-actions[bot]

AI Summary

This patch release adds AbortSignal support for programmatic turn cancellation in Think, allowing external cancellation of `saveMessages` and `continueLastTurn` calls with proper cleanup and partial chunk persistence. It also tightens internal peer dependency floors to reflect currently tested versions.

Key Highlights

  • Added `options.signal` parameter to `Think.saveMessages` and `Think.continueLastTurn` for external cancellation
  • Added protected `abortRequest(id, reason?)` and `abortAllRequests()` methods as clean alternatives to internal `_aborts` registry access
  • `SaveMessagesResult.status` now includes `"aborted"` status alongside `"completed"` and `"skipped"`
  • Tightened peer dependency floors: `agents` (>=0.11.7), `@cloudflare/codemode` (>=0.3.4), `@cloudflare/shell` (>=0.3.4)
  • Aborted signals properly clean up listeners to prevent leaks when reusing long-lived AbortSignals across multiple turns

New Features

  • AbortSignal support in `Think.saveMessages` and `Think.continueLastTurn` for cancelling programmatic turns
  • Protected `abortRequest(id, reason?)` method for DO subclasses to cancel specific turns
  • Protected `abortAllRequests()` method to cancel all active turns
  • New `"aborted"` status in `SaveMessagesResult` when inference loop is terminated mid-stream
  • Partial chunks are persisted to resumable stream when signal aborts during streaming
  • Pre-aborted signals short-circuit before any model work runs for efficiency

Full Release Notes

### Patch Changes

-   [`ca510d4`](https://github.com/cloudflare/agents/commit/ca510d4fecbecb07d0d3cdad7d78c32cc226275e) Thanks [@threepointone](https://github.com/threepointone)! - Tighten internal peer dependency floors to reflect the current monorepo set we actually test against: `agents` (`>=0.8.7` → `>=0.11.7`), `@cloudflare/codemode` (`>=0.0.7` → `>=0.3.4`), and `@cloudflare/shell` (`>=0.2.0` → `>=0.3.4`). Upper bounds (`<1.0.0`) are unchanged.

    No runtime change in `@cloudflare/think` itself. The visible effect for consumers: pairing the latest `@cloudflare/think` with a stale `agents` (`<0.11.7`), `@cloudflare/codemode` (`<0.3.4`), or `@cloudflare/shell` (`<0.3.4`) now produces a peer warning where it previously did not. That's the intended signal — those older combinations are no longer tested in the monorepo.

-   [#1411](https://github.com/cloudflare/agents/pull/1411) [`2fa68be`](https://github.com/cloudflare/agents/commit/2fa68bea891e1bd8f30839586c2519627f364b0c) Thanks [@threepointone](https://github.com/threepointone)! - Add `options.signal` to `Think.saveMessages` and `Think.continueLastTurn` for external cancellation of programmatic turns, plus protected `abortRequest(id)` / `abortAllRequests()` methods to replace bracket access into the private `_aborts` registry ([#1406](https://github.com/cloudflare/agents/issues/1406)).

    `saveMessages` and `continueLastTurn` accept a second `SaveMessagesOptions` argument:

    ```typescript
    const result = await this.saveMessages(messages, {
      signal: controller.signal,
    });
    if (result.status === "aborted") {
      // Inference loop terminated mid-stream; partial chunks persisted.
    }
    ```

    The signal is linked to Think's per-turn `AbortController` for the duration of the call. When it aborts:

    -   the inference loop's signal aborts (the same path `chat-request-cancel` takes);
    -   partial chunks already streamed are persisted to the resumable stream;
    -   `saveMessages` resolves with `{ status: "aborted" }`;
    -   `onChatResponse` fires with `status: "aborted"`.

    Pre-aborted signals short-circuit before any model work runs. Listeners are detached cleanly when the turn finishes, so passing the same long-lived `AbortSignal` to many turns (e.g. a parent chat-turn signal driving multiple sub-agent calls) is safe and leak-free.

    `abortRequest(id, reason?)` and `abortAllRequests()` are protected entry points for DO subclasses (e.g. RPC-driven helpers) that want to cancel turns without tracking ids — they replace the historical `(this as unknown as { _aborts: ... })._aborts.destroyAll()` workaround used by helper-as-sub-agent implementations.

    `SaveMessagesResult.status` now includes `"aborted"` alongside `"completed"` and `"skipped"`. Existing callers that only switch on `"completed"` are unaffected.

    **Limitations.**

    -   `AbortSignal` cannot cross Durable Object RPC. Construct the controller inside the DO that calls `saveMessages`. To bridge a parent's intent into a child DO, return a `ReadableStream` from the child whose `cancel` callback aborts a per-turn controller — `examples/agents-as-tools` shows the canonical pattern.
    -   The signal lives in memory only. If the DO hibernates mid-turn and `chatRecovery` is enabled, the recovered turn calls `continueLastTurn()` internally without the original signal — an abort fired after restart has no effect on the recovered turn.

    See [`cloudflare/agents#1406`](https://github.com/cloudflare/agents/issues/1406) for the motivating use case.