github cloudflare/agents @cloudflare/think@0.3.0

7 hours ago

Minor Changes

  • #1340 3cbe776 Thanks @threepointone! - Align Think lifecycle hooks with the AI SDK and fix latent bugs around tool-call hooks and extension dispatch.

    Lifecycle hook context types are now derived from the AI SDK (resolves #1339). StepContext, ChunkContext, ToolCallContext, and ToolCallResultContext are derived from StepResult, TextStreamPart, and TypedToolCall so users get full typed access to reasoning, sources, files, providerMetadata (where Anthropic cache tokens live), request/response, etc., instead of unknown. The relevant AI SDK types are re-exported from @cloudflare/think.

    beforeToolCall / afterToolCall now fire with correct timing. beforeToolCall runs before the tool's execute (Think wraps every tool's execute), and afterToolCall runs after with durationMs and a discriminated success/output/error outcome (backed by experimental_onToolCallFinish).

    ToolCallDecision is now functional. Returning { action: "block", reason }, { action: "substitute", output }, or { action: "allow", input } from beforeToolCall actually intercepts execution.

    Extension hook dispatch. ExtensionManifest.hooks claimed support for beforeToolCall/afterToolCall/onStepFinish/onChunk but Think only ever dispatched beforeTurn. All five hooks now dispatch to subscribed extensions with JSON-safe snapshots. Extension hook handlers also receive (snapshot, host) (symmetric with tool execute); previously only tool executes got the host bridge.

    Breaking renames (per AI SDK conventions): ToolCallContext.argsinput, ToolCallResultContext.argsinput, ToolCallResultContext.resultoutput. afterToolCall is now a discriminated union — read output only when ctx.success === true, and error when ctx.success === false. Equivalent renames on ToolCallDecision.

    See docs/think/lifecycle-hooks.md for the full hook reference.

Patch Changes

  • #1340 3cbe776 Thanks @threepointone! - Fix _wrapToolsWithDecision to await originalExecute(...) before checking for Symbol.asyncIterator. The previous code missed Promise<AsyncIterable> returns from plain async functions (async function execute(...) { return makeIter(); }) — Symbol.asyncIterator in promise is always false, the collapse logic was skipped, and the AI SDK ended up treating the iterator instance itself as the final output value (which the wrapper's own comment warned about). Both sync-returned-iterable and async-returned-iterable cases are now covered, with regression tests for each.

Don't miss a new agents release

NewReleases is sending notifications on new releases.