> ## 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.

# Google ADK (Agent Development Kit)

> Trace Google ADK agents in Braintrust to debug prompts, tool calls, and multi-step reasoning

If you are a coding agent, prefer the Braintrust [`bt` CLI](/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, such as ad-hoc lookups and exploration from your IDE.

[Google ADK (Agent Development Kit)](https://google.github.io/adk-docs/) is Google's framework for building AI agents powered by Gemini models. Braintrust traces ADK agent executions, including tool calls and multi-step reasoning.

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

  Install the Braintrust and `@google/adk` packages, then set your API keys. Auto-instrumentation supports `@google/adk` v0.6.1 to v0.6.x and v1.0.0 to v1.x. Versions v0.7.0 through v0.9.x aren't supported.

  <Steps>
    <Step title="Install packages">
      <CodeGroup>
        ```bash pnpm theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
        pnpm add braintrust @google/adk
        ```

        ```bash npm theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
        npm install braintrust @google/adk
        ```
      </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>
      GEMINI_API_KEY=<your-gemini-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="auto-instrumentation-typescript">
    Auto-instrumentation
  </h2>

  To trace ADK agents without modifying your application code, initialize Braintrust normally, then run your app with Braintrust's import hook to patch the ADK SDK at runtime.

  <Steps>
    <Step title="Initialize Braintrust and call ADK">
      <CodeGroup>
        ```javascript title="trace-adk-auto.js" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
        import { initLogger } from "braintrust";
        import * as adk from "@google/adk";

        initLogger({
          projectName: "my-adk-project",
          apiKey: process.env.BRAINTRUST_API_KEY,
        });

        const { LlmAgent, InMemoryRunner, FunctionTool } = adk;

        // Create the tools
        const getWeatherTool = new FunctionTool({
          name: "get_weather",
          description: "Get weather for a city.",
          parameters: {
            type: "object",
            properties: {
              city: {
                type: "string",
                description: "The city to look up weather for",
              },
            },
            required: ["city"],
          },
          execute: ({ city }) => {
            return { temperature: 72, condition: "sunny", city };
          },
        });

        const getCurrentTimeTool = new FunctionTool({
          name: "get_current_time",
          description: "Get the current time.",
          parameters: {
            type: "object",
            properties: {},
          },
          execute: () => {
            return new Date().toLocaleTimeString("en-US", {
              hour: "numeric",
              minute: "2-digit",
              hour12: true,
            });
          },
        });

        // Create the agent
        const agent = new LlmAgent({
          name: "weather_time_assistant",
          model: "gemini-2.5-flash",
          instruction: "You are a helpful assistant that can check weather and time.",
          tools: [getWeatherTool, getCurrentTimeTool],
        });

        // Create the runner and a session
        const runner = new InMemoryRunner({ agent, appName: "weather_app" });
        const userId = "user123";
        const sessionId = "session123";
        await runner.sessionService.createSession({
          appName: runner.appName,
          userId,
          sessionId,
        });

        // Run the agent
        for await (const event of runner.runAsync({
          userId,
          sessionId,
          newMessage: {
            role: "user",
            parts: [{ text: "What's the weather like in New York?" }],
          },
        })) {
          console.log(event);
        }
        ```
      </CodeGroup>
    </Step>

    <Step title="Run with the import hook">
      ```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
      node --import braintrust/hook.mjs trace-adk-auto.js
      ```

      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](/instrument/trace-llm-calls#auto-instrumentation) for plugin and loader setup.
      </Note>
    </Step>
  </Steps>

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

  To trace the ADK module manually, wrap it yourself with `wrapGoogleADK()` and destructure the wrapped classes from the result.

  <Note>
    Manual instrumentation traces runner, agent, and tool spans, but not LLM call spans. ADK constructs its model client internally, so user-side wrapping cannot intercept the underlying model calls. To capture LLM spans, use auto-instrumentation instead.
  </Note>

  <CodeGroup>
    ```javascript title="trace-adk-wrap.js" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    import { initLogger, wrapGoogleADK } from "braintrust";
    import * as adk from "@google/adk";

    initLogger({
      projectName: "my-adk-project",
      apiKey: process.env.BRAINTRUST_API_KEY,
    });

    const { LlmAgent, InMemoryRunner, FunctionTool } = wrapGoogleADK(adk);

    // Create the tools
    const getWeatherTool = new FunctionTool({
      name: "get_weather",
      description: "Get weather for a city.",
      parameters: {
        type: "object",
        properties: {
          city: {
            type: "string",
            description: "The city to look up weather for",
          },
        },
        required: ["city"],
      },
      execute: ({ city }) => {
        return { temperature: 72, condition: "sunny", city };
      },
    });

    const getCurrentTimeTool = new FunctionTool({
      name: "get_current_time",
      description: "Get the current time.",
      parameters: {
        type: "object",
        properties: {},
      },
      execute: () => {
        return new Date().toLocaleTimeString("en-US", {
          hour: "numeric",
          minute: "2-digit",
          hour12: true,
        });
      },
    });

    // Create the agent
    const agent = new LlmAgent({
      name: "weather_time_assistant",
      model: "gemini-2.5-flash",
      instruction: "You are a helpful assistant that can check weather and time.",
      tools: [getWeatherTool, getCurrentTimeTool],
    });

    // Create the runner and a session
    const runner = new InMemoryRunner({ agent, appName: "weather_app" });
    const userId = "user123";
    const sessionId = "session123";
    await runner.sessionService.createSession({
      appName: runner.appName,
      userId,
      sessionId,
    });

    // Run the agent
    for await (const event of runner.runAsync({
      userId,
      sessionId,
      newMessage: {
        role: "user",
        parts: [{ text: "What's the weather like in New York?" }],
      },
    })) {
      console.log(event);
    }
    ```
  </CodeGroup>

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

  Braintrust captures:

  * Runner execution as a task span, with the new message as input, the final event as output, and the user and session IDs in metadata
  * Agent invocations as task spans nested under the runner, with the agent name and model in metadata
  * Tool calls as tool spans nested under the agent, with arguments as input, the result as output, and the tool name plus call ID in metadata
  * Token usage (prompt, completion, total, cached, and reasoning tokens) aggregated across the run on the runner span
  * LLM calls inside ADK as nested LLM spans, traced via Braintrust's Google GenAI integration since ADK uses Google GenAI internally for model calls

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

  * [Google ADK for TypeScript](https://github.com/google/adk-js)
  * [Google Gemini models](https://ai.google.dev/)
</View>

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

  Install the Braintrust and `google-adk` packages, then set your API keys. Requires `google-adk` v1.14.1 or later.

  <Steps>
    <Step title="Install packages">
      <CodeGroup>
        ```bash uv theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
        uv add braintrust google-adk
        ```

        ```bash pip theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
        pip install braintrust google-adk
        ```
      </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>
      GEMINI_API_KEY=<your-gemini-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="auto-instrumentation-python">
    Auto-instrumentation
  </h2>

  Call `setup_adk()` at startup to enable tracing for ADK agents.

  <CodeGroup>
    ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    import asyncio
    import os

    from braintrust.wrappers.adk import setup_adk
    from google.adk import Runner
    from google.adk.agents import LlmAgent
    from google.adk.sessions import InMemorySessionService
    from google.genai import types

    # Call setup_adk() to enable automatic tracing for all ADK agent interactions
    setup_adk(
        project_name="my-adk-project",
        api_key=os.environ.get("BRAINTRUST_API_KEY"),
    )

    # Create your ADK agent as normal
    def get_weather(city: str) -> dict:
        """Get weather for a city."""
        return {"temperature": 72, "condition": "sunny", "city": city}

    def get_current_time() -> str:
        """Get the current time."""
        from datetime import datetime

        return datetime.now().strftime("%I:%M %p")

    async def main():
        # Create the agent
        agent = LlmAgent(
            name="weather_time_assistant",
            tools=[get_weather, get_current_time],
            model="gemini-2.5-flash",
            instruction="You are a helpful assistant that can check weather and time.",
        )
        # Create a session service and a runner
        session_service = InMemorySessionService()
        runner = Runner(app_name="weather_app", agent=agent, session_service=session_service)
        # Create a fake session
        user_id = "user123"
        session_id = "session123"
        await session_service.create_session(app_name="weather_app", user_id=user_id, session_id=session_id)
        # Create the message to send
        new_message = types.Content(
            parts=[types.Part(text="What's the weather like in New York?")],
            role="user",
        )
        # Run the agent with the query
        events = runner.run(
            user_id=user_id,
            session_id=session_id,
            new_message=new_message,
        )
        # Process the events and print the agent's response
        for event in events:
            print(event)

    if __name__ == "__main__":
        asyncio.run(main())
    ```
  </CodeGroup>

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

  Braintrust captures:

  * Runner invocations as task spans named `invocation [<app_name>]`, with the new message as input, the final event as output, and the user and session IDs in metadata
  * Agent runs as task spans named `agent_run [<agent_name>]`, nested under the runner
  * Each model call cycle as a task span named `call_llm`
  * Individual model invocations as LLM spans named `llm_call [<call_type>]`, where `<call_type>` is one of `direct_response`, `tool_selection`, or `response_generation`. The span captures the model request, the response, and the model name in metadata
  * Token usage (prompt, completion, total, cached, and reasoning tokens) plus `time_to_first_token` on the LLM span
  * Tool calls as tool spans named `tool [<tool_name>]`, with the tool name and arguments as input and the result as output
  * MCP tool calls as tool spans named `mcp_tool [<tool_name>]`

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

  * [Google ADK documentation for Python](https://github.com/google/adk-python)
  * [Google Gemini models](https://ai.google.dev/)
</View>

<View title="Go" icon="https://img.logo.dev/go.dev?token=pk_BdcHD9e5SCW3j1rnJkNyMQ">
  <h2 id="setup-go">
    Setup
  </h2>

  Install the Braintrust Go SDK and the ADK contrib package, then set your API keys. Requires `google.golang.org/adk` v0.4.0 or later.

  <Steps>
    <Step title="Install packages">
      ```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
      go get github.com/braintrustdata/braintrust-sdk-go
      go get github.com/braintrustdata/braintrust-sdk-go/trace/contrib/adk
      ```
    </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>
      GEMINI_API_KEY=<your-gemini-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-go">
    Manual instrumentation
  </h2>

  Call `traceadk.AddLLMAgentCallbacks(&cfg)` on the agent config before constructing the agent.

  <CodeGroup>
    ```go Go theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    package main

    import (
    	"context"
    	"fmt"
    	"log"
    	"os"
    	"time"

    	"go.opentelemetry.io/otel"
    	"go.opentelemetry.io/otel/sdk/trace"
    	"google.golang.org/adk/agent"
    	"google.golang.org/adk/agent/llmagent"
    	"google.golang.org/adk/model/gemini"
    	"google.golang.org/adk/runner"
    	"google.golang.org/adk/session"
    	"google.golang.org/adk/tool"
    	"google.golang.org/adk/tool/functiontool"
    	"google.golang.org/genai"

    	"github.com/braintrustdata/braintrust-sdk-go"
    	traceadk "github.com/braintrustdata/braintrust-sdk-go/trace/contrib/adk"
    )

    type getWeatherArgs struct {
    	City string `json:"city" jsonschema:"city to look up weather for"`
    }

    type getWeatherResult struct {
    	Temperature int    `json:"temperature"`
    	Condition   string `json:"condition"`
    	City        string `json:"city"`
    }

    func getWeather(ctx tool.Context, args getWeatherArgs) (getWeatherResult, error) {
    	return getWeatherResult{
    		Temperature: 72,
    		Condition:   "sunny",
    		City:        args.City,
    	}, nil
    }

    type getCurrentTimeArgs struct{}

    type getCurrentTimeResult struct {
    	Time string `json:"time"`
    }

    func getCurrentTime(ctx tool.Context, args getCurrentTimeArgs) (getCurrentTimeResult, error) {
    	return getCurrentTimeResult{
    		Time: time.Now().Format("3:04 PM"),
    	}, nil
    }

    func main() {
    	// Set up OpenTelemetry tracer
    	tp := trace.NewTracerProvider()
    	defer tp.Shutdown(context.Background())
    	otel.SetTracerProvider(tp)

    	// Initialize Braintrust tracing, WithBlockingLogin is just for local testing
    	bt, err := braintrust.New(tp,
    		braintrust.WithProject("my-adk-project"),
    		braintrust.WithAPIKey(os.Getenv("BRAINTRUST_API_KEY")),
    		braintrust.WithBlockingLogin(true),
    	)
    	if err != nil {
    		log.Fatal(err)
    	}

    	ctx := context.Background()
    	tracer := otel.Tracer("adk-example")
    	ctx, span := tracer.Start(ctx, "adk-agent-run")
    	defer span.End()

    	// Set up ADK model
    	model, err := gemini.NewModel(ctx, "gemini-2.5-flash", &genai.ClientConfig{
    		APIKey: os.Getenv("GEMINI_API_KEY"),
    	})
    	if err != nil {
    		log.Fatalf("Failed to create model: %v", err)
    	}

    	// Create the tools
    	weatherTool, err := functiontool.New(
    		functiontool.Config{
    			Name:        "get_weather",
    			Description: "Get weather for a city.",
    		},
    		getWeather,
    	)
    	if err != nil {
    		log.Fatalf("Failed to create weather tool: %v", err)
    	}

    	currentTimeTool, err := functiontool.New(
    		functiontool.Config{
    			Name:        "get_current_time",
    			Description: "Get the current time.",
    		},
    		getCurrentTime,
    	)
    	if err != nil {
    		log.Fatalf("Failed to create time tool: %v", err)
    	}

    	// Create agent with tracing callbacks
    	cfg := llmagent.Config{
    		Name:        "weather_time_assistant",
    		Model:       model,
    		Description: "Weather and time helper",
    		Instruction: "You are a helpful assistant that can check weather and time.",
    		Tools:       []tool.Tool{weatherTool, currentTimeTool},
    	}
    	traceadk.AddLLMAgentCallbacks(&cfg)
    	a, err := llmagent.New(cfg)
    	if err != nil {
    		log.Fatalf("Failed to create agent: %v", err)
    	}

    	// Create session and runner
    	sessionSvc := session.InMemoryService()
    	sessionSvc.Create(ctx, &session.CreateRequest{
    		AppName:   "weather_app",
    		UserID:    "user123",
    		SessionID: "session123",
    	})

    	runner, err := runner.New(runner.Config{
    		AppName:        "weather_app",
    		Agent:          a,
    		SessionService: sessionSvc,
    	})
    	if err != nil {
    		log.Fatalf("Failed to create runner: %v", err)
    	}

    	// Run the agent
    	msg := genai.NewContentFromText("What's the weather like in New York?", genai.RoleUser)
    	for ev, err := range runner.Run(ctx, "user123", "session123", msg, agent.RunConfig{}) {
    		if err != nil {
    			log.Printf("Error: %v", err)
    			return
    		}
    		if ev.Content != nil {
    			for _, p := range ev.Content.Parts {
    				if p.Text != "" {
    					fmt.Printf("Response: %s\n", p.Text)
    				}
    			}
    		}
    	}

    	fmt.Printf("View trace: %s\n", bt.Permalink(span))
    }
    ```
  </CodeGroup>

  <h2 id="avoiding-duplicate-spans-go">
    Avoiding duplicate spans
  </h2>

  Google ADK has built-in OpenTelemetry support that emits spans under the `gcp.vertex.agent` instrumentation scope. Braintrust drops these by default to avoid duplicating the spans produced by Braintrust's ADK callbacks (found in `trace/contrib/adk`).

  If you're not using `traceadk.AddLLMAgentCallbacks` (from the Braintrust ADK package), and you're instead relying solely on ADK's native telemetry, opt in to receive those spans by passing an option to `braintrust.New`:

  ```go #skip-compile theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  braintrust.New(tp, braintrust.EnableBuiltinAdkTraces())
  ```

  Or by setting an environment variable:

  ```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  export BRAINTRUST_OTEL_ENABLE_BUILTIN_ADK_TRACES=true
  ```

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

  Braintrust captures:

  * Agent runs as task spans named `agent_run [<agent_name>]`, with the agent name, invocation ID, session ID, and branch in metadata
  * LLM model calls as LLM spans named `call_llm`, with the request as input, the response as output, the model name and finish reason in metadata, and token usage (prompt, completion, and total tokens)
  * Tool calls as tool spans named `tool [<tool_name>]`, with the tool name and description, arguments as input, and the result as output

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

  * [Google ADK documentation for Go](https://github.com/google/adk-go)
  * [Google Gemini models](https://ai.google.dev/)
</View>
