Skip to content

Releases: cloudflare/agents

create-think@0.1.1

26 Jun 12:19
062611d

Choose a tag to compare

Patch Changes

  • #1817 7f367d8 Thanks @threepointone! - create-think now prompts for a starter template when --template is omitted (and falls back to basic when stdin is non-interactive). npm create think and think init initialize a git repository — skipping cleanly when the target is already inside one — and scaffold projects with Oxlint/Oxfmt config plus a check script. Removes the unused declarative agent() framework helper and the identity helpers (defineMessengers, defineScheduledTasks, defineChannels) in favor of class-based agents and typed object returns.

agents@0.17.0

26 Jun 12:19
062611d

Choose a tag to compare

Minor Changes

  • #1758 6b46b04 Thanks @threepointone! - Add progress signalling and durable milestones for agent-tool sub-agents
    (#1758, rfc-detached-agent-tools §progress, phases 4a + 4b).

    A sub-agent running as an agent tool (awaited or detached/background) can now
    report mid-run progress:

    // Inside the child sub-agent (e.g. from a tool's execute):
    await this.reportProgress({
      fraction: 0.6,
      phase: "deploying",
      message: "Generating menu page…",
    });

    These signals ride the child's own turn stream as a transient
    data-agent-progress part, so they re-broadcast to the parent's connected
    clients and surface on AgentToolRunState.progress via useAgentToolEvents — a
    background-runs tray can render a live bar / phase / status line without drilling
    in. Highlights:

    • reportProgress({ fraction?, message?, phase?, data? }, { persist? }) on
      chat agents (@cloudflare/think, AIChatAgent); a no-op with a dev warning on
      the base Agent and when called outside an active agent-tool run. The framework
      resolves the run id from the active turn — no threading required. Bursts are
      coalesced (latest-wins; a fraction >= 1 "done" frame always flushes). data
      is live-only unless { persist: true }.
    • onProgress(run, progress) parent hook, fired best-effort from the tail
      for both awaited and detached runs.
    • Latest-snapshot persistence + recovery inspect. The child stores a
      progress_json + last_signal_at on its run row and surfaces it through
      inspectAgentToolRun().progress, so a rehydrated parent reconstructs progress
      after eviction.
    • Resetting no-progress budget for detached runs. Once a detached child has
      reported at least one signal, the backbone gives up if it then goes silent for
      detachedNoProgressBudgetMs (default 1h; per-run override via
      detached: { noProgressBudgetMs }), surfaced as interrupted with the
      no-progress reason. A child that never reports is bounded only by the absolute
      detachedMaxBudgetMs ceiling — we never give up on a run merely for being slow.

    Durable milestones (phase 4b)

    Naming a milestone promotes a signal from the ephemeral tier to a durable
    one — there is still only one emit method:

    // Inside the child sub-agent:
    await this.reportProgress({
      milestone: "sources-gathered",
      data: { sources: 2 },
    });
    • Persisted + replayable. Each milestone is one row on the child
      (cf_agent_tool_milestones / cf_ai_chat_agent_tool_milestones) with a
      monotonic per-run sequence. It rides the stream as a persisted
      data-agent-milestone part (vs. transient progress), so drill-in replay and a
      rehydrated parent both see it. Surfaced via inspectAgentToolRun().milestones
      and AgentToolRunState.milestones (deduped by sequence).

    • onProgress fires for milestones too — the snapshot carries
      progress.milestone, so a consumer can branch on milestone vs. ephemeral.

    • detached: { onMilestones } chat convenience (@cloudflare/think and
      AIChatAgent). When a configured milestone lands, the chat agent surfaces an
      idempotent synthetic chat message (keyed/idempotent per (runId, name))
      before the run finishes. Delivered from both the warm tail and the cold
      backbone reconcile; the deterministic id collapses them to at-most-once. Two
      modes (the string[] shorthand defaults to "narrate"):

      • "narrate" (default) — a synthetic assistant message injected directly
        (no inference): a cheap, honest status line that does not trigger a turn.
      • "react" — a user-role turn so the model responds to the milestone
        (steer, start dependent work). Costs a model turn.
      detached: { onMilestones: ["preview-ready"] } // narrate (default)
      detached: { onMilestones: { names: ["needs-approval"], mode: "react" } }

      Override the wording via formatDetachedMilestone(run, milestone). These
      synthetic messages carry metadata.source so clients can render them as an
      agent event rather than a human turn (the example does this).

    The awaitable join point (awaitAgentToolMilestone, phase 4c) is intentionally
    not included here — it is gated behind a design addendum.

  • #1790 190ea81 Thanks @threepointone! - Add typed action ledger observability events to the diagnostics channel event union.

  • #1790 190ea81 Thanks @threepointone! - Add typed action:pause:* (created/approved/rejected/swept) observability events to the diagnostics channel event union for durable-pause action approvals.

  • #1790 190ea81 Thanks @threepointone! - Add the ReplyAttachment type and an optional attachments field on ChatResponseResult, plus an action:reply-attached diagnostics event, to support the Think actions reply-attachment side-channel.

  • #1799 3c2afc9 Thanks @threepointone! - Stop reconnecting on terminal WebSocket close events and expose terminal connection failures via connectionError / onConnectionError on AgentClient, useAgent, and useAgentChat.

  • #1758 6b46b04 Thanks @threepointone! - Add first-class detached ("background") agent-tool runs with a durable
    completion hook (#1752).

    runAgentTool(cls, { detached }) now dispatches a sub-agent without blocking
    the calling turn
    , returning a { runId, agentType, status: "running" } handle
    immediately:

    // Fire-and-forget — observe via agent-tool-event frames + onAgentToolFinish.
    const { runId } = await this.runAgentTool(ImportAgent, {
      input,
      detached: true
    });
    
    // Or wire a durable, eviction-surviving completion callback (by METHOD NAME,
    // like schedule()):
    await this.runAgentTool(ImportAgent, {
      input,
      detached: { onFinish: "onImportDone", maxBudgetMs: 60 * 60 * 1000 }
    });
    
    async onImportDone(run: AgentToolRunInfo, result: AgentToolLifecycleResult) {
      // Branch on result.status: "completed" | "error" | "aborted" | "interrupted".
      // A budget give-up arrives as interrupted / reason "budget-exceeded".
    }

    Highlights:

    • Durable, exactly-once-on-the-happy-path completion. A warm fast path
      (low-latency while the isolate is alive) plus a self-scheduling reconcile
      backbone (survives eviction / deploys) route through one guarded delivery
      funnel. Two independent ledger slots (finish / give-up) with a claim+lease
      mean a premature give-up can never dedupe a child's real late completion away.
    • No silent abandonment. Detached runs are never sealed interrupted just
      because their dispatching turn ended (the normal state for a background run);
      the backbone owns them and re-arms on restart.
    • Bounded. An absolute maxBudgetMs ceiling (default 24h, configurable via
      the detachedMaxBudgetMs static option) gives up — surfaced as interrupted
      with the new budget-exceeded reason — and tears the child down so an
      abandoned run cannot hold a concurrency slot forever.
    • cancelAgentTool(runId) cancels a detached (or awaited) run by id through
      the same guarded path, so a wired onFinish still fires once with
      status: "aborted", and the terminal agent-tool-event is always broadcast
      to connected clients (a cancelled run's UI settles immediately).
    • Recovery-safe delivery. A chat host (@cloudflare/think / AIChatAgent)
      runs the completion callback serialized on its turn queue, so an onFinish
      that mutates chat state can never interleave with a live LLM turn. Concurrent
      detached dispatches in one turn no longer race to arm multiple reconcile
      backbones (arming is serialized).
    • Observability. New events agent_tool:detached:delivery_failed (a wired
      callback threw; the slot stays open for retry) and
      agent_tool:detached:live_count_warning (edge-triggered when live detached
      runs cross a threshold — a leak smoke alarm, since detached runs hold a
      concurrency slot for their whole life).

    A detached run deliberately does NOT inherit options.signal (it must outlive
    the spawning turn); cancel it explicitly with cancelAgentTool.

  • #1801 c58b401 Thanks @threepointone! - Add the shared agents/chat/react entry with useAgentChat, chat transport helper...

Read more

@cloudflare/voice@0.3.3

26 Jun 12:20
062611d

Choose a tag to compare

Patch Changes

  • #1605 8bfebf0 Thanks @cjol! - Support AI SDK fullStream responses in voice turns and warn when textStream is used.

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

  • #1816 f18ff01 Thanks @cjol! - Fix assistant speech playing back slow on a new turn after an idle gap. VoiceClient routes playback through a MediaStreamAudioDestinationNode -> HTMLAudioElement bridge, and reusing that element for a fresh burst after it had been idle between turns made the new turn resume at the wrong rate (audible as slow-motion that re-converges to normal over the turn). The bridge is now torn down and rebuilt once it has fully drained and been idle past a short threshold, so each turn plays through a freshly created element. Rebuilds never happen mid-turn, since chunks within a turn keep at least one source scheduled on the playback cursor.

@cloudflare/think@0.11.0

26 Jun 12:20
062611d

Choose a tag to compare

Minor Changes

  • #1758 6b46b04 Thanks @threepointone! - Add progress signalling and durable milestones for agent-tool sub-agents
    (#1758, rfc-detached-agent-tools §progress, phases 4a + 4b).

    A sub-agent running as an agent tool (awaited or detached/background) can now
    report mid-run progress:

    // Inside the child sub-agent (e.g. from a tool's execute):
    await this.reportProgress({
      fraction: 0.6,
      phase: "deploying",
      message: "Generating menu page…"
    });

    These signals ride the child's own turn stream as a transient
    data-agent-progress part, so they re-broadcast to the parent's connected
    clients and surface on AgentToolRunState.progress via useAgentToolEvents — a
    background-runs tray can render a live bar / phase / status line without drilling
    in. Highlights:

    • reportProgress({ fraction?, message?, phase?, data? }, { persist? }) on
      chat agents (@cloudflare/think, AIChatAgent); a no-op with a dev warning on
      the base Agent and when called outside an active agent-tool run. The framework
      resolves the run id from the active turn — no threading required. Bursts are
      coalesced (latest-wins; a fraction >= 1 "done" frame always flushes). data
      is live-only unless { persist: true }.
    • onProgress(run, progress) parent hook, fired best-effort from the tail
      for both awaited and detached runs.
    • Latest-snapshot persistence + recovery inspect. The child stores a
      progress_json + last_signal_at on its run row and surfaces it through
      inspectAgentToolRun().progress, so a rehydrated parent reconstructs progress
      after eviction.
    • Resetting no-progress budget for detached runs. Once a detached child has
      reported at least one signal, the backbone gives up if it then goes silent for
      detachedNoProgressBudgetMs (default 1h; per-run override via
      detached: { noProgressBudgetMs }), surfaced as interrupted with the
      no-progress reason. A child that never reports is bounded only by the absolute
      detachedMaxBudgetMs ceiling — we never give up on a run merely for being slow.

    Durable milestones (phase 4b)

    Naming a milestone promotes a signal from the ephemeral tier to a durable
    one — there is still only one emit method:

    // Inside the child sub-agent:
    await this.reportProgress({
      milestone: "sources-gathered",
      data: { sources: 2 }
    });
    • Persisted + replayable. Each milestone is one row on the child
      (cf_agent_tool_milestones / cf_ai_chat_agent_tool_milestones) with a
      monotonic per-run sequence. It rides the stream as a persisted
      data-agent-milestone part (vs. transient progress), so drill-in replay and a
      rehydrated parent both see it. Surfaced via inspectAgentToolRun().milestones
      and AgentToolRunState.milestones (deduped by sequence).

    • onProgress fires for milestones too — the snapshot carries
      progress.milestone, so a consumer can branch on milestone vs. ephemeral.

    • detached: { onMilestones } chat convenience (@cloudflare/think and
      AIChatAgent). When a configured milestone lands, the chat agent surfaces an
      idempotent synthetic chat message (keyed/idempotent per (runId, name))
      before the run finishes. Delivered from both the warm tail and the cold
      backbone reconcile; the deterministic id collapses them to at-most-once. Two
      modes (the string[] shorthand defaults to "narrate"):

      • "narrate" (default) — a synthetic assistant message injected directly
        (no inference): a cheap, honest status line that does not trigger a turn.
      • "react" — a user-role turn so the model responds to the milestone
        (steer, start dependent work). Costs a model turn.
      detached: { onMilestones: ["preview-ready"] } // narrate (default)
      detached: { onMilestones: { names: ["needs-approval"], mode: "react" } }

      Override the wording via formatDetachedMilestone(run, milestone). These
      synthetic messages carry metadata.source so clients can render them as an
      agent event rather than a human turn (the example does this).

    The awaitable join point (awaitAgentToolMilestone, phase 4c) is intentionally
    not included here — it is gated behind a design addendum.

  • #1758 6b46b04 Thanks @threepointone! - Add detached: { notify: true } support for runAgentTool on chat agents
    (@cloudflare/think and AIChatAgent) (#1752).

    When a detached sub-agent run finishes, a chat agent can inject a message back
    into the chat so the model reacts to the result — without you wiring onFinish
    by hand:

    await this.runAgentTool(ResearchAgent, {
      input,
      detached: { notify: { source: "research-background" } }
    });

    The injected turn is idempotent per run + terminal status, so an exactly-once
    finish never duplicates, while a soft give-up followed by a real late completion
    surfaces as two distinct turns. (Think dedupes via a submitMessages
    idempotency key; AIChatAgent, which has no durable-submission layer, persists
    under a deterministic message id and runs the follow-up turn inline within the
    already-serialized delivery slot.) Use notify: true for the default
    metadata.source, pass notify: { source } to match your app's message
    taxonomy, and override formatDetachedCompletion(run, result) to customize (or
    suppress) the injected text.

  • #1817 7f367d8 Thanks @threepointone! - create-think now prompts for a starter template when --template is omitted (and falls back to basic when stdin is non-interactive). npm create think and think init initialize a git repository — skipping cleanly when the target is already inside one — and scaffold projects with Oxlint/Oxfmt config plus a check script. Removes the unused declarative agent() framework helper and the identity helpers (defineMessengers, defineScheduledTasks, defineChannels) in favor of class-based agents and typed object returns.

  • #1790 190ea81 Thanks @threepointone! - Add ctx.attachReply(attachment) for actions: an advisory, recording-only reply-attachment side-channel surfaced on ChatResponseResult.attachments (in onChatResponse) and a public replyAttachments(requestId?) getter. Attachments are JSON-normalized, deep-copied on read, capped per turn, and never alter the model-visible tool output; policy callbacks are no-ops, failed executions discard their attachments, approval-gated approved actions support it, and durable-pause approved actions are a v1 no-op.

  • #1790 190ea81 Thanks @threepointone! - Add a pending-retry lease for the action ledger via the new actionLedgerPendingRetryLeaseMs config (default 5 minutes). A pending ledger row left behind by a crashed executor is now reclaimed and re-run once it is stale, but ONLY for actions that declare an explicit idempotencyKey — the key is the developer's assertion that re-running the keyed side effect is safe. Behavior change: such a stale row previously blocked forever with ActionPendingError; it now reclaims (refreshing updated_at in place, still pending), emits action:ledger:reclaimed, and re-runs execute. Fresh rows, fallback tool:${toolCallId} keys, and a disabled lease (actionLedgerPendingRetryLeaseMs = false) keep the conservative ActionPendingError behavior. Same-isolate coalescing still wins first, so an in-flight run is never reclaimed.

  • #1790 190ea81 Thanks @threepointone! - Add a durable action ledger for action() descriptors so settled server action outputs can be replayed by stable idempotency key without re-running side effects.

  • #1790 190ea81 Thanks @threepointone! - Generalize the messenger runtime into a public channel surface. Add configureChannels() and ChannelDefinition (web, voice, messenger, and custom channels) wrapping getMessengers(), a no-turn deliverNotice() with informModel, additive DeliveryTag (kind + turnEnded) on messenger snapshots, per-channel policy (instructions, tool-narrowing, maxTurns) applied as overridable defaults, turn-scoped channel context threaded through runTurn (persisted for recovery), reply-attachment rendering at delivery, and channel:*/notice:* observability events.

  • #1790 [190ea81](190ea814c4ea61c216509a431b...

Read more

@cloudflare/shell@0.4.1

26 Jun 12:20
062611d

Choose a tag to compare

Patch Changes

@cloudflare/codemode@0.4.2

26 Jun 12:19
062611d

Choose a tag to compare

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.

@cloudflare/ai-chat@0.9.0

26 Jun 12:19
062611d

Choose a tag to compare

Minor Changes

  • #1758 6b46b04 Thanks @threepointone! - Add progress signalling and durable milestones for agent-tool sub-agents
    (#1758, rfc-detached-agent-tools §progress, phases 4a + 4b).

    A sub-agent running as an agent tool (awaited or detached/background) can now
    report mid-run progress:

    // Inside the child sub-agent (e.g. from a tool's execute):
    await this.reportProgress({
      fraction: 0.6,
      phase: "deploying",
      message: "Generating menu page…"
    });

    These signals ride the child's own turn stream as a transient
    data-agent-progress part, so they re-broadcast to the parent's connected
    clients and surface on AgentToolRunState.progress via useAgentToolEvents — a
    background-runs tray can render a live bar / phase / status line without drilling
    in. Highlights:

    • reportProgress({ fraction?, message?, phase?, data? }, { persist? }) on
      chat agents (@cloudflare/think, AIChatAgent); a no-op with a dev warning on
      the base Agent and when called outside an active agent-tool run. The framework
      resolves the run id from the active turn — no threading required. Bursts are
      coalesced (latest-wins; a fraction >= 1 "done" frame always flushes). data
      is live-only unless { persist: true }.
    • onProgress(run, progress) parent hook, fired best-effort from the tail
      for both awaited and detached runs.
    • Latest-snapshot persistence + recovery inspect. The child stores a
      progress_json + last_signal_at on its run row and surfaces it through
      inspectAgentToolRun().progress, so a rehydrated parent reconstructs progress
      after eviction.
    • Resetting no-progress budget for detached runs. Once a detached child has
      reported at least one signal, the backbone gives up if it then goes silent for
      detachedNoProgressBudgetMs (default 1h; per-run override via
      detached: { noProgressBudgetMs }), surfaced as interrupted with the
      no-progress reason. A child that never reports is bounded only by the absolute
      detachedMaxBudgetMs ceiling — we never give up on a run merely for being slow.

    Durable milestones (phase 4b)

    Naming a milestone promotes a signal from the ephemeral tier to a durable
    one — there is still only one emit method:

    // Inside the child sub-agent:
    await this.reportProgress({
      milestone: "sources-gathered",
      data: { sources: 2 }
    });
    • Persisted + replayable. Each milestone is one row on the child
      (cf_agent_tool_milestones / cf_ai_chat_agent_tool_milestones) with a
      monotonic per-run sequence. It rides the stream as a persisted
      data-agent-milestone part (vs. transient progress), so drill-in replay and a
      rehydrated parent both see it. Surfaced via inspectAgentToolRun().milestones
      and AgentToolRunState.milestones (deduped by sequence).

    • onProgress fires for milestones too — the snapshot carries
      progress.milestone, so a consumer can branch on milestone vs. ephemeral.

    • detached: { onMilestones } chat convenience (@cloudflare/think and
      AIChatAgent). When a configured milestone lands, the chat agent surfaces an
      idempotent synthetic chat message (keyed/idempotent per (runId, name))
      before the run finishes. Delivered from both the warm tail and the cold
      backbone reconcile; the deterministic id collapses them to at-most-once. Two
      modes (the string[] shorthand defaults to "narrate"):

      • "narrate" (default) — a synthetic assistant message injected directly
        (no inference): a cheap, honest status line that does not trigger a turn.
      • "react" — a user-role turn so the model responds to the milestone
        (steer, start dependent work). Costs a model turn.
      detached: { onMilestones: ["preview-ready"] } // narrate (default)
      detached: { onMilestones: { names: ["needs-approval"], mode: "react" } }

      Override the wording via formatDetachedMilestone(run, milestone). These
      synthetic messages carry metadata.source so clients can render them as an
      agent event rather than a human turn (the example does this).

    The awaitable join point (awaitAgentToolMilestone, phase 4c) is intentionally
    not included here — it is gated behind a design addendum.

  • #1799 3c2afc9 Thanks @threepointone! - Stop reconnecting on terminal WebSocket close events and expose terminal connection failures via connectionError / onConnectionError on AgentClient, useAgent, and useAgentChat.

  • #1794 b6ad4d5 Thanks @threepointone! - Recover interrupted server-tool calls on resume instead of abandoning them.

    When a turn is interrupted mid tool call (e.g. a server tool whose execute()
    died with an evicted isolate, leaving an input-available orphan that nothing
    will ever resolve), AIChatAgent now repairs the transcript before re-entering
    inference on the recovered turn — the same behavior @cloudflare/think already
    has. The interrupted tool part is flipped to an errored tool-result through the
    shared agents/chat repair primitive, so the next convertToModelMessages no
    longer 400s with AI_MissingToolResultsError and the turn continues.

    Adds an overridable repairInterruptedToolPart(part) hook (default: flip to an
    output-error result) so apps can customize the repaired shape for
    client-resolved tools (e.g. preserve an interrupted question tool as text).
    Repair only ever reshapes assistant tool parts; the corrected transcript is
    persisted and broadcast through the normal write path.

    Repair runs before EVERY inference chokepoint — live submit, tool
    auto-continuation, continueLastTurn, saveMessages/retry, and the chat
    recovery callbacks — mirroring how @cloudflare/think repairs before every
    inference (the app owns convertToModelMessages, so the framework repairs
    this.messages right before handing control to onChatMessage). This closes
    the cases a recovery-only repair missed: a mixed client+server orphan whose
    client replay drives an auto-continuation, and any agent running with
    chatRecovery disabled. Repair is scoped per-part to dead SERVER orphans: a
    part still legitimately awaiting a client (an input-available client tool or an
    approval-requested part the user may still answer) is left verbatim, so a fresh
    dead-server orphan at the leaf is repaired even when an unrelated abandoned client
    orphan sits earlier in history. It is a no-op (no write, no broadcast) for a
    healthy transcript.

    The recovery-path stability wait (waitUntilStable) now gates on the narrower
    client-resolvable predicate so a dead server-tool orphan no longer blocks
    stability — it is repaired and the turn continues. waitUntilStable gains an
    optional pendingInteraction predicate; its default (and the documented
    semantics for app overrides) is unchanged.

  • #1788 3b2af54 Thanks @threepointone! - AIChatAgent now uses an event-driven auto-continuation barrier that parks
    indefinitely on an incomplete parallel tool batch instead of force-continuing
    after a fixed timeout.

    Previously, when a turn ended with several parallel client tool calls and only
    some results had arrived, AIChatAgent ran the completeness barrier inside
    the continuation turn and polled for up to 60s
    (AUTO_CONTINUATION_PENDING_TOOL_TIMEOUT_MS), after which it continued
    inference against whatever results had landed — potentially a half-complete tool
    batch. The barrier is now event-driven and runs before the continuation is
    enqueued (converging onto @cloudflare/think's model): it fires only once every
    result in the batch has arrived, re-arms as each sibling result is applied and
    when a streaming turn finalizes, guards against double-fire, and is gated on no
    active stream. There is no orphan timeout — a batch with a never-arriving
    sibling now parks budget-free until it completes (the same way a turn already
    parks on a pending HITL/client interaction) rather than force-continuing with
    missing results.

    This is a behavior change for the rare stuck-tool case: a result that never
    arrives no longer triggers a continuation after 60s; it parks until the missing
    result lands (or a later user turn / chat recovery repairs the transcript). A
    parked continuation leaves the same on-disk signature as a HITL park, so a
    deploy/crash mid-park recovers by re-arming rather than terminalizing.

  • #1788 3b2af54 Thanks @threepointone! - AIChatAgent now replays the live "recovering…" status on connect (#1620).

    Previously the cf_agent_chat_recovering frame was only broadcast live, ...

Read more

@cloudflare/voice@0.3.2

19 Jun 19:54
1e571a5

Choose a tag to compare

Patch Changes

  • #1747 28653b3 Thanks @cjol! - Fix audible clicks at audio chunk boundaries during agent speech. VoiceClient played each response chunk by starting it at currentTime and waiting for its ended event before scheduling the next, so every chunk seam carried a few milliseconds of silence (event-loop latency plus the next chunk's setup) — audible as a periodic click, roughly one per chunk. Chunks are now scheduled back-to-back on the audio clock via a playback cursor (start(Math.max(currentTime, cursor))), so consecutive chunks butt together sample-tight. Because chunks can now be scheduled ahead of playback, the client tracks every scheduled source and stops them all on interrupt/end-call (previously only the single active source needed stopping), and playback counts as active until the last scheduled chunk finishes so barge-in detection keeps working through the scheduled tail.

create-think@0.1.0

17 Jun 11:55
8019e61

Choose a tag to compare

Minor Changes

  • #1770 718634f Thanks @threepointone! - Add webhook-agent and business-workflow starter templates.

    webhook-agent scaffolds an agent fed by inbound webhooks through durable,
    idempotent submissions (a custom src/server.ts entry + submitMessages).
    business-workflow scaffolds a back-office operations agent with
    human-in-the-loop approval gates (needsApproval + an approval UI) and a
    scheduled digest. Every starter now also ships a start.md you can paste into an
    AI coding agent for guided setup.

agents@0.16.2

17 Jun 11:55
8019e61

Choose a tag to compare

Patch Changes

  • #1767 f03dee6 Thanks @threepointone! - Reduce Think Durable Object SQLite reads during normal wakes and text-only turns.

    Think now avoids automatic media-eviction scans until hydration has been windowed or an oversized appended message has been observed. The shared resumable stream buffer also avoids per-wake metadata-column introspection by creating new tables with the current columns and lazily migrating legacy tables only when a stream write needs it.

  • #1722 9f8e14b Thanks @mattzcarey! - Fix two MCP client OAuth bugs found by the new conformance suite, and add MCP conformance testing.

    • MCPClientConnection now finishes OAuth on the transport that received the 401. A fresh transport loses the resource metadata URL from the WWW-Authenticate header, so token exchange fell back to the default /token path and failed against authorization servers at non-default locations.
    • MCPClientConnection.init() detaches the previous transport before reconnecting. Re-authorizing after a mid-session 401 (scope step-up, token revocation) previously failed permanently with "Already connected to a transport".
    • Added the official @modelcontextprotocol/conformance suite (as used by the MCP TypeScript SDK) running against the MCP client (Agent + MCPClientManager), McpAgent, and createMcpHandler + WorkerTransport — all hosted in workerd via wrangler dev. See packages/agents/conformance/README.md.
  • #1767 f03dee6 Thanks @threepointone! - Cache the active branch tip in AgentSessionProvider so finding the latest leaf no longer scans the whole session on every read and append.

    latestLeafRow() previously ran an anti-join over every message row (O(rows)) to locate the branch tip — on each hydration AND each auto-parent append, so on long transcripts it dominated a wake's read cost. The tip is now maintained in place on append/delete/clear; a cached tip is re-validated on read with an O(1) existence + still-childless check (so it self-heals if another writer deletes the tip or gives it a child), and the full scan only runs when that check fails or the cache is cold. Per-hydration and per-append tip lookups drop from O(rows) to O(1), and the full scan never runs more often than before.