Agent Skills; Telegram messengers; durable chat recovery hardened
v0.14.0
The latest release of the Agents SDK adds four new ways to build with @cloudflare/think: on-demand Agent Skills, chat messengers (starting with Telegram), declarative scheduled tasks, and durable reasoning steps inside Workflows. This release also significantly hardens durable chat recovery, so turns reliably ride through deploys, evictions, and stalled model streams in production.
Agent Skills (experimental)
Give an agent a catalog of on-demand instructions, resources, and scripts. A skill source adds a catalog to the system prompt, and the model activates a skill only when a task matches — so a large library of capabilities does not bloat every prompt.
-
JavaScript
<div><div><span>import </span><span>{</span><span><span> </span><span>Think</span></span><span>,</span><span><span> </span><span>skills</span><span> </span></span><span>}</span><span> from </span><span>"@cloudflare/think"</span><span>;</span></div></div><div><div><span><span>import </span><span>bundledSkills</span><span> from </span></span><span>"agents:skills"</span><span>;</span></div></div><div><div> </div></div><div><div><span>export</span><span> </span><span>class</span><span> </span><span>SkillsAgent</span><span> </span><span>extends</span><span> </span><span>Think</span><span> </span><span>{</span></div></div><div><div><span> </span><span>getSkills</span><span>()</span><span> </span><span>{</span></div></div><div><div><span> </span><span>return</span><span> [</span></div></div><div><div><span> </span><span>bundledSkills</span><span>,</span></div></div><div><div><span><span> </span></span><span>skills</span><span>.</span><span>r2</span><span>(</span><span>this</span><span>.</span><span>env</span><span>.</span><span>SKILLS_BUCKET</span><span>,</span><span> </span><span>{</span><span> prefix</span><span>:</span><span> </span><span>"skills/"</span><span> </span><span>}</span><span>)</span><span>,</span></div></div><div><div><span><span> </span></span><span>]</span><span>;</span></div></div><div><div><span> </span><span>}</span></div></div><div><div><span>}</span></div></div> -
TypeScript
<div><div><span>import </span><span>{</span><span><span> </span><span>Think</span></span><span>,</span><span><span> </span><span>skills</span><span> </span></span><span>}</span><span> from </span><span>"@cloudflare/think"</span><span>;</span></div></div><div><div><span><span>import </span><span>bundledSkills</span><span> from </span></span><span>"agents:skills"</span><span>;</span></div></div><div><div> </div></div><div><div><span>export</span><span> </span><span>class</span><span> </span><span>SkillsAgent</span><span> </span><span>extends</span><span> </span><span>Think</span><span><</span><span>Env</span><span>></span><span> </span><span>{</span></div></div><div><div><span> </span><span>getSkills</span><span>()</span><span> </span><span>{</span></div></div><div><div><span> </span><span>return</span><span> [</span></div></div><div><div><span> </span><span>bundledSkills</span><span>,</span></div></div><div><div><span><span> </span></span><span>skills</span><span>.</span><span>r2</span><span>(</span><span>this</span><span>.</span><span>env</span><span>.</span><span>SKILLS_BUCKET</span><span>,</span><span> </span><span>{</span><span> prefix</span><span>:</span><span> </span><span>"skills/"</span><span> </span><span>}</span><span>)</span><span>,</span></div></div><div><div><span><span> </span></span><span>]</span><span>;</span></div></div><div><div><span> </span><span>}</span></div></div><div><div><span>}</span></div></div>
The agents:skills import bundles a local ./skills directory through the Agents Vite plugin (one directory per skill, each with a SKILL.md). Skills can also load from R2 or a manifest. When skills are available, Think exposes activate_skill, read_skill_resource, and an optional run_skill_script tool. Skill loading is resilient: a duplicate or failing source is skipped with a warning instead of breaking the agent.
Agent Skills are experimental, and script execution in particular is early. The API may change in a future release. We would love your feedback — tell us what you are building and what is missing in the Agents repository.
Messengers
Connect a Think agent directly to a chat platform. Think owns the webhook route, conversation routing, durable reply fiber, and streamed delivery back to the provider. Telegram ships as the first provider.
-
JavaScript
<div><div><span>import </span><span>{</span><span><span> </span><span>Think</span><span> </span></span><span>}</span><span> from </span><span>"@cloudflare/think"</span><span>;</span></div></div><div><div><span>import </span><span>{</span></div></div><div><div><span><span> </span></span><span>defineMessengers</span><span>,</span></div></div><div><div><span><span> </span></span><span>ThinkMessengerStateAgent</span><span>,</span></div></div><div><div><span>}</span><span> from </span><span>"@cloudflare/think/messengers"</span><span>;</span></div></div><div><div><span><span>import </span><span>telegramMessenger</span><span> from </span></span><span>"@cloudflare/think/messengers/telegram"</span><span>;</span></div></div><div><div> </div></div><div><div><span>export</span><span> </span><span>{</span><span> </span><span>ThinkMessengerStateAgent</span><span> </span><span>};</span></div></div><div><div> </div></div><div><div><span>export</span><span> </span><span>class</span><span> </span><span>SupportAgent</span><span> </span><span>extends</span><span> </span><span>Think</span><span> </span><span>{</span></div></div><div><div><span> </span><span>getMessengers</span><span>()</span><span> </span><span>{</span></div></div><div><div><span> </span><span>return</span><span> </span><span>defineMessengers</span><span>(</span><span>{</span></div></div><div><div><span><span> </span></span><span>telegram</span><span>:</span><span> </span><span>telegramMessenger</span><span>(</span><span>{</span></div></div><div><div><span><span> </span></span><span>token</span><span>:</span><span> </span><span>this</span><span>.</span><span>env</span><span>.</span><span>TELEGRAM_BOT_TOKEN</span><span>,</span></div></div><div><div><span><span> </span></span><span>userName</span><span>:</span><span> </span><span>"support_bot"</span><span>,</span></div></div><div><div><span><span> </span></span><span>secretToken</span><span>:</span><span> </span><span>this</span><span>.</span><span>env</span><span>.</span><span>TELEGRAM_WEBHOOK_SECRET_TOKEN</span><span>,</span></div></div><div><div><span> </span><span>}</span><span>)</span><span>,</span></div></div><div><div><span> </span><span>}</span><span>)</span><span>;</span></div></div><div><div><span> </span><span>}</span></div></div><div><div><span>}</span></div></div> -
TypeScript
<div><div><span>import </span><span>{</span><span><span> </span><span>Think</span><span> </span></span><span>}</span><span> from </span><span>"@cloudflare/think"</span><span>;</span></div></div><div><div><span>import </span><span>{</span></div></div><div><div><span><span> </span></span><span>defineMessengers</span><span>,</span></div></div><div><div><span><span> </span></span><span>ThinkMessengerStateAgent</span><span>,</span></div></div><div><div><span>}</span><span> from </span><span>"@cloudflare/think/messengers"</span><span>;</span></div></div><div><div><span><span>import </span><span>telegramMessenger</span><span> from </span></span><span>"@cloudflare/think/messengers/telegram"</span><span>;</span></div></div><div><div> </div></div><div><div><span>export</span><span> </span><span>{</span><span> </span><span>ThinkMessengerStateAgent</span><span> </span><span>};</span></div></div><div><div> </div></div><div><div><span>export</span><span> </span><span>class</span><span> </span><span>SupportAgent</span><span> </span><span>extends</span><span> </span><span>Think</span><span><</span><span>Env</span><span>></span><span> </span><span>{</span></div></div><div><div><span> </span><span>getMessengers</span><span>()</span><span> </span><span>{</span></div></div><div><div><span> </span><span>return</span><span> </span><span>defineMessengers</span><span>(</span><span>{</span></div></div><div><div><span><span> </span></span><span>telegram</span><span>:</span><span> </span><span>telegramMessenger</span><span>(</span><span>{</span></div></div><div><div><span><span> </span></span><span>token</span><span>:</span><span> </span><span>this</span><span>.</span><span>env</span><span>.</span><span>TELEGRAM_BOT_TOKEN</span><span>,</span></div></div><div><div><span><span> </span></span><span>userName</span><span>:</span><span> </span><span>"support_bot"</span><span>,</span></div></div><div><div><span><span> </span></span><span>secretToken</span><span>:</span><span> </span><span>this</span><span>.</span><span>env</span><span>.</span><span>TELEGRAM_WEBHOOK_SECRET_TOKEN</span><span>,</span></div></div><div><div><span> </span><span>}</span><span>)</span><span>,</span></div></div><div><div><span> </span><span>}</span><span>)</span><span>;</span></div></div><div><div><span> </span><span>}</span></div></div><div><div><span>}</span></div></div>
Each Chat SDK thread maps to its own Think sub-agent by default, so group chats and direct messages do not share memory. Multiple bots, custom conversation routing, and custom providers are all supported.
Scheduled tasks
Declare recurring, timezone-aware prompts and handlers with a typed domain-specific language (DSL). Think reconciles the declarations on startup and re-arms the next occurrence after each run, backed by durable idempotent submissions.
-
JavaScript
<div><div><span>import </span><span>{</span><span><span> </span><span>Think</span></span><span>,</span><span><span> </span><span>defineScheduledTasks</span><span> </span></span><span>}</span><span> from </span><span>"@cloudflare/think"</span><span>;</span></div></div><div><div> </div></div><div><div><span>export</span><span> </span><span>class</span><span> </span><span>DigestAgent</span><span> </span><span>extends</span><span> </span><span>Think</span><span> </span><span>{</span></div></div><div><div><span> </span><span>getScheduledTasks</span><span>()</span><span> </span><span>{</span></div></div><div><div><span> </span><span>return</span><span> </span><span>defineScheduledTasks</span><span>(</span><span>{</span></div></div><div><div><span><span> </span></span><span>weeklyCommitReport</span><span>:</span><span> </span><span>{</span></div></div><div><div><span><span> </span></span><span>schedule</span><span>:</span><span> </span><span>"every week on monday at 09:00"</span><span>,</span></div></div><div><div><span><span> </span></span><span>prompt</span><span>:</span></div></div><div><div><span> </span><span>"Compile my GitHub commits for the last week and summarize them."</span><span>,</span></div></div><div><div><span> </span><span>},</span></div></div><div><div><span><span> </span></span><span>workout</span><span>:</span><span> </span><span>{</span></div></div><div><div><span><span> </span></span><span>schedule</span><span>:</span><span> </span><span>"every day at 08:00 in Europe/London"</span><span>,</span></div></div><div><div><span><span> </span></span><span>prompt</span><span>:</span><span> </span><span>"Start my workout."</span><span>,</span></div></div><div><div><span> </span><span>},</span></div></div><div><div><span> </span><span>}</span><span>)</span><span>;</span></div></div><div><div><span> </span><span>}</span></div></div><div><div><span>}</span></div></div> -
TypeScript
<div><div><span>import </span><span>{</span><span><span> </span><span>Think</span></span><span>,</span><span><span> </span><span>defineScheduledTasks</span><span> </span></span><span>}</span><span> from </span><span>"@cloudflare/think"</span><span>;</span></div></div><div><div> </div></div><div><div><span>export</span><span> </span><span>class</span><span> </span><span>DigestAgent</span><span> </span><span>extends</span><span> </span><span>Think</span><span><</span><span>Env</span><span>></span><span> </span><span>{</span></div></div><div><div><span> </span><span>getScheduledTasks</span><span>()</span><span> </span><span>{</span></div></div><div><div><span> </span><span>return</span><span> </span><span>defineScheduledTasks</span><span>(</span><span>{</span></div></div><div><div><span><span> </span></span><span>weeklyCommitReport</span><span>:</span><span> </span><span>{</span></div></div><div><div><span><span> </span></span><span>schedule</span><span>:</span><span> </span><span>"every week on monday at 09:00"</span><span>,</span></div></div><div><div><span><span> </span></span><span>prompt</span><span>:</span></div></div><div><div><span> </span><span>"Compile my GitHub commits for the last week and summarize them."</span><span>,</span></div></div><div><div><span> </span><span>},</span></div></div><div><div><span><span> </span></span><span>workout</span><span>:</span><span> </span><span>{</span></div></div><div><div><span><span> </span></span><span>schedule</span><span>:</span><span> </span><span>"every day at 08:00 in Europe/London"</span><span>,</span></div></div><div><div><span><span> </span></span><span>prompt</span><span>:</span><span> </span><span>"Start my workout."</span><span>,</span></div></div><div><div><span> </span><span>},</span></div></div><div><div><span> </span><span>}</span><span>)</span><span>;</span></div></div><div><div><span> </span><span>}</span></div></div><div><div><span>}</span></div></div>
Think Workflows
Run a model-driven reasoning step inside a Cloudflare Workflow with ThinkWorkflow and step.prompt(), with durable typed structured output, long waits, and approval gates.
-
JavaScript
<div><div><span>import </span><span>{</span><span><span> </span><span>z</span><span> </span></span><span>}</span><span> from </span><span>"zod"</span><span>;</span></div></div><div><div><span>import </span><span>{</span><span><span> </span><span>ThinkWorkflow</span><span> </span></span><span>}</span><span> from </span><span>"@cloudflare/think/workflows"</span><span>;</span></div></div><div><div> </div></div><div><div><span>const</span><span> </span><span>draftSchema</span><span> </span><span>=</span><span> </span><span>z</span><span>.</span><span>object</span><span>(</span><span>{</span></div></div><div><div><span><span> </span></span><span>title</span><span>:</span><span> </span><span>z</span><span>.</span><span>string</span><span>()</span><span>,</span></div></div><div><div><span><span> </span></span><span>summary</span><span>:</span><span> </span><span>z</span><span>.</span><span>string</span><span>()</span><span>,</span></div></div><div><div><span><span> </span></span><span>labels</span><span>:</span><span> </span><span>z</span><span>.</span><span>array</span><span>(</span><span>z</span><span>.</span><span>string</span><span>())</span><span>,</span></div></div><div><div><span>}</span><span>)</span><span>;</span></div></div><div><div> </div></div><div><div><span>export</span><span> </span><span>class</span><span> </span><span>TriageWorkflow</span><span> </span><span>extends</span><span> </span><span>ThinkWorkflow</span><span> </span><span>{</span></div></div><div><div><span> </span><span>async</span><span> </span><span>run</span><span>(</span><span>event</span><span>,</span><span> </span><span>step</span><span>)</span><span> </span><span>{</span></div></div><div><div><span> </span><span>const</span><span> </span><span>draft</span><span> </span><span>=</span><span> </span><span>await</span><span> </span><span>step</span><span>.</span><span>prompt</span><span>(</span><span>"triage-issue"</span><span>,</span><span> </span><span>{</span></div></div><div><div><span><span> </span></span><span>prompt</span><span>:</span><span> </span><span>`Triage issue #</span><span>${</span><span>event</span><span>.</span><span>payload</span><span>.</span><span>issueNumber</span><span>}</span><span>`</span><span>,</span></div></div><div><div><span><span> </span></span><span>output</span><span>:</span><span> </span><span>draftSchema</span><span>,</span></div></div><div><div><span><span> </span></span><span>timeout</span><span>:</span><span> </span><span>"3 days"</span><span>,</span></div></div><div><div><span> </span><span>}</span><span>)</span><span>;</span></div></div><div><div> </div></div><div><div><span> </span><span>await</span><span> </span><span>step</span><span>.</span><span>do</span><span>(</span><span>"apply-labels"</span><span>,</span><span> </span><span>async</span><span> </span><span>()</span><span> </span><span>=></span><span> </span><span>{</span></div></div><div><div><span> </span><span>await</span><span> </span><span>this</span><span>.</span><span>agent</span><span>.</span><span>applyLabels</span><span>(</span><span>draft</span><span>.</span><span>labels</span><span>)</span><span>;</span></div></div><div><div><span> </span><span>}</span><span>)</span><span>;</span></div></div><div><div><span> </span><span>}</span></div></div><div><div><span>}</span></div></div> -
TypeScript
<div><div><span>import </span><span>{</span><span><span> </span><span>z</span><span> </span></span><span>}</span><span> from </span><span>"zod"</span><span>;</span></div></div><div><div><span>import </span><span>{</span><span><span> </span><span>ThinkWorkflow</span><span> </span></span><span>}</span><span> from </span><span>"@cloudflare/think/workflows"</span><span>;</span></div></div><div><div><span>import type </span><span>{</span><span><span> </span><span>ThinkWorkflowStep</span><span> </span></span><span>}</span><span> from </span><span>"@cloudflare/think/workflows"</span><span>;</span></div></div><div><div><span>import type </span><span>{</span><span><span> </span><span>AgentWorkflowEvent</span><span> </span></span><span>}</span><span> from </span><span>"agents/workflows"</span><span>;</span></div></div><div><div> </div></div><div><div><span>const</span><span> </span><span>draftSchema</span><span> </span><span>=</span><span> </span><span>z</span><span>.</span><span>object</span><span>(</span><span>{</span></div></div><div><div><span><span> </span></span><span>title</span><span>:</span><span> </span><span>z</span><span>.</span><span>string</span><span>()</span><span>,</span></div></div><div><div><span><span> </span></span><span>summary</span><span>:</span><span> </span><span>z</span><span>.</span><span>string</span><span>()</span><span>,</span></div></div><div><div><span><span> </span></span><span>labels</span><span>:</span><span> </span><span>z</span><span>.</span><span>array</span><span>(</span><span>z</span><span>.</span><span>string</span><span>())</span><span>,</span></div></div><div><div><span>}</span><span>)</span><span>;</span></div></div><div><div> </div></div><div><div><span>export</span><span> </span><span>class</span><span> </span><span>TriageWorkflow</span><span> </span><span>extends</span><span> </span><span>ThinkWorkflow</span><span><</span><span>TriageAgent</span><span>,</span><span> </span><span>Params</span><span>></span><span> </span><span>{</span></div></div><div><div><span> </span><span>async</span><span> </span><span>run</span><span>(</span><span>event</span><span>:</span><span> </span><span>AgentWorkflowEvent</span><span><</span><span>Params</span><span>>,</span><span> </span><span>step</span><span>:</span><span> </span><span>ThinkWorkflowStep</span><span>)</span><span> </span><span>{</span></div></div><div><div><span> </span><span>const</span><span> </span><span>draft</span><span> </span><span>=</span><span> </span><span>await</span><span> </span><span>step</span><span>.</span><span>prompt</span><span>(</span><span>"triage-issue"</span><span>,</span><span> </span><span>{</span></div></div><div><div><span><span> </span></span><span>prompt</span><span>:</span><span> </span><span>`Triage issue #</span><span>${</span><span>event</span><span>.</span><span>payload</span><span>.</span><span>issueNumber</span><span>}</span><span>`</span><span>,</span></div></div><div><div><span><span> </span></span><span>output</span><span>:</span><span> </span><span>draftSchema</span><span>,</span></div></div><div><div><span><span> </span></span><span>timeout</span><span>:</span><span> </span><span>"3 days"</span><span>,</span></div></div><div><div><span> </span><span>}</span><span>)</span><span>;</span></div></div><div><div> </div></div><div><div><span> </span><span>await</span><span> </span><span>step</span><span>.</span><span>do</span><span>(</span><span>"apply-labels"</span><span>,</span><span> </span><span>async</span><span> </span><span>()</span><span> </span><span>=></span><span> </span><span>{</span></div></div><div><div><span> </span><span>await</span><span> </span><span>this</span><span>.</span><span>agent</span><span>.</span><span>applyLabels</span><span>(</span><span>draft</span><span>.</span><span>labels</span><span>)</span><span>;</span></div></div><div><div><span> </span><span>}</span><span>)</span><span>;</span></div></div><div><div><span> </span><span>}</span></div></div><div><div><span>}</span></div></div>
Production hardening for durable chat recovery
Durable chat turns have always been designed to survive a mid-turn deploy or Durable Object eviction. This release is a major hardening pass on that machinery for production.
- Better recovery during deploys. Turns now ride through continuous deploys and evictions without losing completed work or re-running tools that already ran.
- A live "recovering…" signal.
useAgentChatexposes a newisRecoveringflag, so a recovering turn shows progress instead of looking frozen. Most UIs renderisStreaming || isRecoveringas "busy". - Stalled streams recover. Set
chatStreamStallTimeoutMsto route a hung provider stream into the same recovery path instead of leaving an infinite spinner. - Sub-agents re-attach. On parent recovery, an in-flight
agentTool()child is re-attached to its result rather than abandoned and re-run, so long-running children no longer lose work under deploys.
MCP transport improvements
- Resumable streams — In-flight tool calls over Server-Sent Events (SSE) survive a dropped connection. Clients reconnect with
Last-Event-IDand replay anything they missed. - Readable server IDs —
addMcpServeraccepts an optionalid, so tools surface as readable keys (for exampletool_github_create_pull_request) instead of opaque connection IDs. - Better handling of concurrent requests — Overlapping JSON-RPC requests are now correctly correlated to their responses across the HTTP and RPC transports.
Other improvements
- Compaction — A
Session'stokenCounternow also drives the compaction boundary decision ("what to compress"), not just the fire/no-fire trigger. @cloudflare/worker-bundler— Adds avirtualModulesoption tocreateWorkerto provide in-memory module source during bundling.- Client-tool continuations — Parallel tool results now coalesce into a single continuation, immediate resume requests attach to the pending continuation, and server-side
needsApprovalcontinuations resume reliably after approval.
Upgrade
To update to the latest version:
<span>npm</span><span> i agents@latest @cloudflare/think@latest @cloudflare/ai-chat@latest</span>
<span>yarn</span><span> add agents@latest @cloudflare/think@latest @cloudflare/ai-chat@latest</span>
<span>pnpm</span><span> add agents@latest @cloudflare/think@latest @cloudflare/ai-chat@latest</span>
<span>bun</span><span> add agents@latest @cloudflare/think@latest @cloudflare/ai-chat@latest</span>
Refer to the Agents API reference and Chat agents documentation for more information.
Fetched June 2, 2026

