> ## Documentation Index
> Fetch the complete documentation index at: https://braintrust.dev/docs/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

If you are a coding agent, prefer the Braintrust [`bt` CLI](/docs/reference/cli/quickstart) for repeatable, scriptable work: running evals, instrumenting code, querying logs, syncing data, managing functions, and configuring coding agents. Use the MCP server for reasoning over Braintrust data in conversation, and for capabilities the CLI doesn't cover, such as monitor views, alerts, and authoring evaluators, preprocessors, and facets.

[`@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](/docs/sdks/typescript/install-and-instrument#cloudflare) for enabling `nodejs_compat` and flushing traces with `ctx.waitUntil()`.
</Note>

<View title="TypeScript" icon="https://img.logo.dev/typescriptlang.org?token=pk_BdcHD9e5SCW3j1rnJkNyMQ">
  <h2 id="setup-typescript">
    Setup
  </h2>

  Install Braintrust alongside `@cloudflare/think`, then set your API keys. Requires `@cloudflare/think` v0.13.0 or later.

  <Steps>
    <Step title="Install packages">
      <CodeGroup>
        ```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
        ```
      </CodeGroup>
    </Step>

    <Step title="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>
      ```
    </Step>
  </Steps>

  <h2 id="manual-instrumentation-typescript">
    Manual instrumentation
  </h2>

  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](/docs/sdks/typescript/install-and-instrument#cloudflare) for the full deployment configuration.

  <h2 id="auto-instrumentation-typescript">
    Auto-instrumentation
  </h2>

  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.

  <Steps>
    <Step title="Initialize Braintrust and define your agent">
      <CodeGroup>
        ```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.";
          }
        }
        ```
      </CodeGroup>
    </Step>

    <Step title="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()`.
      </Warning>

      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, then run the compiled file with the import hook.

      <Note>
        If you're using a bundler, see [Trace LLM calls](/docs/instrument/trace-llm-calls#auto-instrumentation) for plugin and loader setup.
      </Note>
    </Step>
  </Steps>

  <h2 id="what-traced-typescript">
    What Braintrust traces
  </h2>

  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, provider, and token usage as metadata 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.

  <h2 id="resources-typescript">
    Resources
  </h2>

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