> ## Documentation Index
> Fetch the complete documentation index at: https://docs.braintrust.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Cloudflare Think

> Trace @cloudflare/think agent runs in Braintrust to debug multi-turn reasoning, LLM calls, and tool use on Cloudflare Workers

[`@cloudflare/think`](https://developers.cloudflare.com/agents/harnesses/think/) is an agent framework for Cloudflare Workers built on Durable Objects. Each agent extends the `Think` class and runs multi-turn reasoning loops, delegating inference and tool execution to the AI SDK. Braintrust traces every `runTurn` call as a task span and nests the AI SDK calls and tool invocations beneath it.

> [!NOTE]
>
> For Cloudflare Workers deployments, use [manual instrumentation](#manual-instrumentation-typescript) with `wrapCloudflareThink()`. The `--import` auto-instrumentation hook only runs under Node, not in the Cloudflare Workers runtime (`workerd`). See the [Cloudflare setup guide](https://docs.braintrust.dev/sdks/typescript/install-and-instrument.md#cloudflare) for enabling `nodejs_compat` and flushing traces with `ctx.waitUntil()`.

**TypeScript**

## Setup

Install Braintrust alongside `@cloudflare/think`, then set your API keys. Requires `@cloudflare/think` v0.13.0 to v0.20.x. Versions v0.14.0 and later require Braintrust v3.39.0 or later.

**1. Install packages**

```bash pnpm theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
pnpm add braintrust @cloudflare/think
```

```bash npm theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
npm install braintrust @cloudflare/think
```

**2. Set environment variables**

```bash title=".env" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
BRAINTRUST_API_KEY=<your-braintrust-api-key>

# For organizations on the EU data plane, use https://api-eu.braintrust.dev
# For self-hosted deployments, use your data plane URL
# BRAINTRUST_API_URL=<your-braintrust-api-url>
```

## Manual instrumentation

Manual instrumentation is the recommended approach for Cloudflare Workers. Call `wrapCloudflareThink()` on the `@cloudflare/think` module at module scope, then extend the wrapped `Think` class so every agent instance receives Braintrust tracing without any changes to your agent logic. Initialize the logger inside `fetch` with your `env` bindings, then pass `logger.flush()` to `ctx.waitUntil()` so buffered traces ship after the response returns.

```typescript title="cloudflare-think-manual.ts" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
import * as cloudflareThink from "@cloudflare/think";
import { createOpenAI } from "@ai-sdk/openai";
import { initLogger, wrapCloudflareThink } from "braintrust";
import { tool } from "ai";
import { z } from "zod";

interface Env {
  BRAINTRUST_API_KEY: string;
  OPENAI_API_KEY: string;
  THINK_AGENT: DurableObjectNamespace<MyAgent>;
}

// Wrap the module at module scope so every agent instance is instrumented
const { Think } = wrapCloudflareThink(cloudflareThink);

export class MyAgent extends Think<Env> {
  getModel() {
    return createOpenAI({ apiKey: this.env.OPENAI_API_KEY }).chat("gpt-5-mini");
  }

  getSystemPrompt() {
    return "You are a helpful weather assistant.";
  }

  getTools() {
    return {
      lookup_weather: tool({
        description: "Get the weather for a city.",
        inputSchema: z.object({ city: z.string() }),
        execute: async ({ city }) => ({ city, condition: "sunny" }),
      }),
    };
  }
}

export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext) {
    const logger = initLogger({
      projectName: "cloudflare-think-example", // Replace with your project name
      apiKey: env.BRAINTRUST_API_KEY,
    });

    try {
      const agent = env.THINK_AGENT.getByName("default");
      const result = await agent.runTurn({
        input: "What is the weather in Vienna?",
        mode: "wait",
      });
      return Response.json(result);
    } finally {
      ctx.waitUntil(logger.flush());
    }
  },
};
```

`wrapCloudflareThink()` accepts the module namespace (`import * as cloudflareThink from "@cloudflare/think"`) and patches the `Think` prototype in place, so all subclasses inherit tracing without modifying your agent definitions.

Because `Think` agents are Durable Objects, your `wrangler.jsonc` needs the `nodejs_compat` compatibility flag, a Durable Object binding for your agent class, and a migration that registers it. Store `BRAINTRUST_API_KEY` as a Wrangler secret.

```json title="wrangler.jsonc" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
{
  "main": "src/cloudflare-think-manual.ts",
  "compatibility_flags": ["nodejs_compat"],
  "durable_objects": {
    "bindings": [{ "name": "THINK_AGENT", "class_name": "MyAgent" }]
  },
  "migrations": [{ "tag": "v1", "new_sqlite_classes": ["MyAgent"] }]
}
```

See the [Cloudflare setup guide](https://docs.braintrust.dev/sdks/typescript/install-and-instrument.md#cloudflare) for the full deployment configuration.

## Auto-instrumentation

Auto-instrumentation patches the SDK at runtime without modifying your application code, but the `--import` hook only runs under Node (local development or tests), not in the Cloudflare Workers runtime. For a deployed Worker, use manual instrumentation above.

**1. Initialize Braintrust and define your agent**

```javascript title="cloudflare-think-auto.js" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
import { createOpenAI } from "@ai-sdk/openai";
import { initLogger } from "braintrust";
import { Think } from "@cloudflare/think";

initLogger({
  projectName: "cloudflare-think-example", // Replace with your project name
  apiKey: process.env.BRAINTRUST_API_KEY,
});

export class MyAgent extends Think {
  getModel() {
    return createOpenAI({ apiKey: process.env.OPENAI_API_KEY }).chat(
      "gpt-5-mini",
    );
  }

  getSystemPrompt() {
    return "You are a helpful weather assistant.";
  }
}
```

**2. Run with the import hook**

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
node --import braintrust/hook.mjs cloudflare-think-auto.js
```

> [!WARNING]
>
> The `--import` hook only patches the SDK when your code runs under Node, such as local development or tests. It does not run in the Cloudflare Workers runtime (`workerd`), so a Worker deployed with Wrangler stays uninstrumented. To trace a deployed Worker, use [manual instrumentation](#manual-instrumentation-typescript) with `wrapCloudflareThink()`.

The auto-instrumentation example uses plain JavaScript so `node --import` can run the file directly. The Braintrust APIs work the same in TypeScript projects. Compile your TypeScript to JavaScript and run the compiled file with the import hook, or [run TypeScript directly](https://docs.braintrust.dev/instrument/trace-llm-calls.md#auto-instrumentation) with a TypeScript loader.

> [!NOTE]
>
> If you're using a bundler, see [Trace LLM calls](https://docs.braintrust.dev/instrument/trace-llm-calls.md#auto-instrumentation) for plugin and loader setup.

## What Braintrust traces

Braintrust captures:

* Task spans for each `Think.runTurn` call, with the turn input messages as input and the final assistant response as output.
* Model name and provider as metadata, and token usage as metrics, on the task span.
* Nested LLM spans for each AI SDK call issued during the turn, with messages, parameters, response content, and token usage.
* Tool call spans for each tool invoked during the turn, with tool name, arguments, and result.
* Errors captured on the span if the turn fails or the stream encounters an error.

## Resources

* [`@cloudflare/think` documentation](https://developers.cloudflare.com/agents/harnesses/think/)
* [`@cloudflare/think` on npm](https://www.npmjs.com/package/@cloudflare/think)
* [Trace LLM calls](https://docs.braintrust.dev/instrument/trace-llm-calls.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.