Think·续

// submit — durable acceptance, check status later const submission = await this.runTurn({ mode: "submit", input: "Process this webhook", idempotencyKey: inboundEventId, // dedupe; safe to retry }); // submission.accepted is true on first accept; submission.status is "pending"

// stream — drive a callback (the same surface as chat()) await this.runTurn({ mode: "stream", input: "Stream me", callback: { onStart({ requestId }) {}, onEvent(json) {}, // UIMessageChunk JSON onDone() {}, onError(error) {}, }, });

// continuation — continue the last assistant turn instead of sending input await this.runTurn({ continuation: true }); } }


Key behaviors:

- **Blocking modes cannot nest.** Calling `wait`/ `stream`/ `continuation` (or the equivalent shortcut) from *inside* an active turn — for example, from a tool's `execute` — throws, because it would deadlock the turn queue. From inside a turn, use `runTurn({ mode: "submit" })` (durable, runs after the current turn frees the queue) or [`addMessages()`](#add-messages-without-a-turn) (transcript only, no inference).
- **`submit` is idempotent.** Pass `submissionId` and/or `idempotencyKey`; re-submitting a known key returns the existing record with `accepted: false` instead of starting a second turn. See [Programmatic submissions](https://developers.cloudflare.com/agents/harnesses/think/programmatic-submissions/).
- **Recovery-safe.** The `wait`, `stream`, and drained `submit` paths run inference inside a recovery fiber, so an interrupted turn resumes after eviction.

`runTurn` is exported alongside its option and result types: `RunTurnOptions`, `RunTurnWait`, `RunTurnSubmit`, `RunTurnStream`, `TurnInputMessages`, and `TurnResult`.

### Pick a shortcut

The table below maps each scenario to the most direct call. Each shortcut has an unchanged signature; reach for them when you want the narrower surface, or use `runTurn()` when you want one mental model.

| Use case | API |
| --- | --- |
| A browser user sends chat messages | `useAgentChat` over the WebSocket chat protocol |
| Server code can wait for the model response | `saveMessages()` |
| Server code needs fast durable acceptance and later status | `submitMessages()` |
| Code should create recurring prompt-driven turns or handlers | `getScheduledTasks()` |
| Parent code needs direct streaming RPC to a specific child | `subAgent(...).chat()` |
| A parent delegates work to a retained child agent | `agentTool()` or `runAgentTool()` |
| Surround a turn with idempotent app-owned side effects | `startFiber()` |
| Coordinate multi-step durable orchestration | Workflows |
| Add context or messages without starting a model turn | `addMessages()` |
| Advanced subclass or recovery code continues an assistant turn | `continueLastTurn()` |

Use `saveMessages()` when the caller owns the trigger and can wait for the turn to finish. Use [`submitMessages()`](https://developers.cloudflare.com/agents/harnesses/think/programmatic-submissions/) when timeout ambiguity would make retries unsafe.

### Add messages without a turn

Use `addMessages()` to write to the transcript **without** starting a model turn — for importing prior history or injecting background context the next turn should see:

```js
export class Assistant extends Think {
    async importContext() {
        await this.addMessages([
            {
                id: crypto.randomUUID(),
                role: "user",
                parts: [{ type: "text", text: "Imported context" }],
            },
        ]);
    }
}
export class Assistant extends Think<Env> {
    async importContext() {
        await this.addMessages([
            {
                id: crypto.randomUUID(),
                role: "user",
                parts: [{ type: "text", text: "Imported context" }],
            },
        ]);
    }
}

addMessages() appends (or upserts) into the Session tree:

  • It does not run inference and does not enter the turn queue, so it is safe to call from inside a tool's execute without deadlocking.
  • Array entries are appended linearly (each attaches under the previous one), so imported history stays a single path. By default the first message attaches to the latest committed leaf; pass parentId to attach elsewhere, or null for a root message.
  • Appends are idempotent by message id. Pass { mode: "upsert" } to update an existing message in place instead.

The supported pattern is "add context, then run a turn": call addMessages(), then runTurn().

Use chat() for low-level parent-to-child streaming when your code owns forwarding, cancellation, and replay policy. Use Agents as tools when a parent model or workflow delegates to a child agent and you want retained child runs, event replay, abort bridging, and UI drill-in.

Use startFiber() outside Think when the durable unit is an application job around a turn: accepting a webhook once, restoring a serialized channel or thread target, posting a visible reply, or recording app-level recovery policy. Think submissions own conversation admission and turn serialization; managed fibers own external job acceptance, idempotent side effects, and application recovery.

In this section

Getting started

Build a Think agent step by step.

Configuration

Configuration overrides, dynamic configuration, and Session integration.

Tools

Workspace tools, code execution, browser tools, and extensions.

Actions

Server actions with idempotency, approvals, authorization, and reply attachments.

Channels

Per-channel policy, channel selection, and out-of-band notices.

Lifecycle hooks

beforeTurn, beforeStep, onStepFinish, onChatResponse, and more.

Client tools

Browser-side tools, approvals, and concurrency.

Messengers

Receive and reply to Chat SDK messenger webhooks.

Scheduled tasks

Declarative recurring prompts and handlers.

Workflows

Durable model-driven reasoning steps inside Cloudflare Workflows.

Sub-agent RPC

chat() streaming, saveMessages, continueLastTurn, and abort.

Programmatic submissions

Durable turn admission for webhooks and RPC callers.

Durable recovery

Chat recovery, stream-stall watchdog, and stability detection.

Agent Skills

On-demand instructions, resources, and scripts via getSkills().

Acknowledgments

Think's design is inspired by Pi ↗︎.

Example

Assistant example

Explore a multi-session Think assistant with sub-agent routing, shared workspace, MCP, chat recovery, and GitHub OAuth.

  • Sessions — context blocks, compaction, search, multi-session (the storage layer Think builds on)
  • Sub-agents — subAgent(), abortSubAgent(), deleteSubAgent() (the base Agent methods for spawning children)
  • Chat agents — AIChatAgent for when you need full control over the LLM call
  • Long-running agents — sub-agent delegation patterns for multi-week agent lifetimes
  • Durable execution — runFiber() and crash recovery (used by chatRecovery)
  • Browse the web — full CDP helper API reference

Was this helpful?

YesNo

On this page

Think·续 - 图1Docs

{"@context":"https://schema.org","@type":"WebPage","@id":"https://developers.cloudflare.com/agents/harnesses/think/#page","headline":"Think","description":"Opinionated chat agent framework with built-in tools, persistent memory, lifecycle hooks, streaming, messengers, scheduled tasks, Workflows, and sub-agent RPC.","url":"https://developers.cloudflare.com/agents/harnesses/think/","inLanguage":"en","image":"https://developers.cloudflare.com/agents/harnesses/think/og.png?v=e3ee81dca3f64261","dateModified":"2026-10-22","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"},"keywords":["AI"]}


description: Server-side Think tools with idempotency, human approvals, authorization, and reply attachments. title: Actions image: https://developers.cloudflare.com/agents/harnesses/think/actions/og.png?v=e3979758f52a77d8


Skip to content

Documentation Index
Fetch the complete documentation index at: https://developers.cloudflare.com/agents/llms.txt
Use this file to discover all available pages before exploring further.