---
title: Agent Bridge
llms-description: Integrating agents from third-party frameworks like OpenAI Agents SDK, LangChain, and Pydantic AI.
code-annotations: select
---

## Overview

While Inspect provides facilities for native agent development, you can also very easily integrate agents created with 3rd party frameworks like [OpenAI Agents SDK](https://openai.github.io/openai-agents-python/), [Pydantic AI](https://ai.pydantic.dev/), and [LangChain](https://python.langchain.com/docs/introduction/), or use fully custom agents you have developed or ported from a research paper. You can also use CLI based agents that run within sandboxes (e.g. [Claude Code](https://www.anthropic.com/claude-code), [Codex CLI](https://github.com/openai/codex), or [Gemini CLI](https://github.com/google-gemini/gemini-cli)).

Agents are *bridged* into Inspect such that their native model calling functions are routed through the current Inspect model provider. There are two types of agent bridges supported:

1.  Bridging to Python-based agents that run in the same process as Inspect via the `agent_bridge()` context manager.

2.  Bridging to agents that run in a sandbox via the `sandbox_agent_bridge()` context manager (these agents can be written in any language).

We'll cover each of these configurations in turn below. You can also learn from the following examples:

|  |  |
|-----------------------------|-------------------------------------------|
| [OpenAI Agents SDK](https://github.com/UKGovernmentBEIS/inspect_ai/tree/main/examples/bridge/agentsdk) | Demonstrates using a native [Open AI Agents SDK](https://openai.github.io/openai-agents-python/) agent to perform Q/A using web search. |
| [LangChain](https://github.com/UKGovernmentBEIS/inspect_ai/tree/main/examples/bridge/langchain) | Demonstrates using a native [LangChain](https://www.langchain.com/) agent to perform Q/A using the [Tavili Search API](https://tavily.com/) |
| [Pydantic AI](https://github.com/UKGovernmentBEIS/inspect_ai/tree/main/examples/bridge/pydantic-ai) | Demonstrates using a native [Pydantic AI](https://ai.pydantic.dev/) agent to perform Q/A using web search.|
| [Claude Code](https://meridianlabs-ai.github.io/inspect_swe/claude_code.html) | Demonstrates using a [Claude Code](https://www.anthropic.com/claude-code) agent to explore a Kali Linux system. |
| [Codex CLI](https://meridianlabs-ai.github.io/inspect_swe/codex_cli.html) | Demonstrates using a [Codex CLI](https://github.com/openai/codex) agent to explore a Kali Linux system. |

: {tbl-colwidths=\[30,70\]}

## Agent Bridge

The `agent_bridge()` can bridge agents written against the Python APIs for OpenAI Completions, OpenAI Responses, Anthropic, and Google. To bridge a Python based agent running in the same process as Inspect:

1.  Write your custom Python agent as normal using the OpenAI, Anthropic, or Google connector provided by your agent system, specifying "inspect" as the model name.

2.  Run your custom Python agent within the `agent_bridge()` context manager which redirects OpenAI calls to the current Inspect model provider.

For example, here we build an agent that uses the OpenAI SDK directly (imaging using your favourite agent framework in its place):

``` python
from openai import AsyncOpenAI
from inspect_ai.agent import (
    Agent, AgentState, agent, agent_bridge
)
from inspect_ai.model import messages_to_openai

@agent
def my_agent() -> Agent:
    async def execute(state: AgentState) -> AgentState:
        async with agent_bridge(state) as bridge: # <1>
            client = AsyncOpenAI()
            
            await client.chat.completions.create(
                model="inspect", # <2>
                messages=messages_to_openai(state.messages) # <3>
            )

            return bridge.state # <4>

    return execute
```

1.  Use the `agent_bridge()` context manager to redirect the OpenAI API to the Inspect model provider. Pass the `state` so that the bridge can automatically keep track of changes to `messages` and `output` based on model calls passing through the bridge.
2.  Use the OpenAI API with `model="inspect"`, which enables Inspect to intercept the request and send it to the Inspect model being evaluated for the task.
3.  Convert the `state.messages` input into native OpenAI messages using the `messages_to_openai()` function.
4.  Return the `state` changes automatically tracked by the `bridge` .

The [OpenAI Agents SDK](https://github.com/UKGovernmentBEIS/inspect_ai/tree/main/examples/bridge/agentsdk), [PydanticAI](https://github.com/UKGovernmentBEIS/inspect_ai/tree/main/examples/bridge/pydantic-ai) [LangChain](https://github.com/UKGovernmentBEIS/inspect_ai/tree/main/examples/bridge/langchain) example provide a more in-depth demonstration of using the Python agent bridge with Inspect.


## Sandbox Bridge

The `sandbox_agent_bridge()` can bridge agents written against the OpenAI Completions, OpenAI Responses, Anthropic API, or Google API. To bridge an agent running in a sandbox to Inspect:

1.  Configure your sandbox (e.g. via its Dockerfile) to contain the agent that you want to run. The agent should be configured to talk to the OpenAI, Anthropic, or Gemini API on localhost port 13131 (e.g. `OPENAI_BASE_URL=http://localhost:13131/v1`, `ANTHROPIC_BASE_URL=http://localhost:13131`, or `GOOGLE_GEMINI_BASE_URL=http://localhost:13131/v1beta`).

2.  Write a standard Inspect agent that uses the `sandbox_agent_bridge()` context manager and the `sandbox().exec()` method to invoke the custom agent.

The sandbox bridge works via running a proxy server inside the sandbox container which receives requests for the OpenAI, Anthropic, and Google APIs. This proxy server in turn relays requests to the current Inspect model provider.

For example, here we build an agent that runs a custom agent binary (passing it input on the command line and reading output from stdout):

``` python
from openai import AsyncOpenAI
from inspect_ai.agent import (
    Agent, AgentState, agent, sandbox_agent_bridge
)
from inspect_ai.model import user_prompt
from inspect_ai.util import sandbox

@agent
def my_agent() -> Agent:
    async def execute(state: AgentState) -> AgentState:
        async with sandbox_agent_bridge(state) as bridge: # <1>
            
            prompt = user_prompt(state.messages) # <2>
            
            result = sandbox().exec(   # <3>
                cmd=[
                    "/opt/my_agent",
                    "--prompt",
                    prompt.text
                ],
                env={"OPENAI_BASE_URL": f"http://localhost:{bridge.port}/v1"} # <4>
            )
            if not result.success:
                raise RuntimeError(f"Agent error: {result.stderr}")

            return bridge.state # <5>

    return execute
```

1.  Use the `sandbox_agent_bridge()` context manager to redirect the OpenAI API to the Inspect model provider. Pass the `state` so that the bridge can automatically keep track of changes to `messages` and `output` based on model calls passing through the bridge.
2.  Extract the last user message from the message history with `user_prompt()`.
3.  Run the agent, using a CLI argument for input and stdout for output (other agents may use more sophisticated encoding schemes for messages in and out).
4.  Redirect the OpenAI API to talk to a proxy server that communicates back to the current Inspect model provider. Note that we read the `port` to listen on from the `bridge` yielded by the context manager.
5.  Return the `state` changes automatically tracked by the `bridge`.

The [Claude Code](https://meridianlabs-ai.github.io/inspect_swe/claude_code.html) and [Codex CLI](https://meridianlabs-ai.github.io/inspect_swe/codex_cli.html) agents in the Inspect SWE package provide more in-depth demonstrations of running custom agents in sandboxes.

## Bridged Tools

Host-side Inspect tools can be exposed as MCP tools to sandboxed agents using the `bridged_tools` parameter. This is useful when you have Inspect tools that need to run on the host (e.g. tools that access host resources, databases, or APIs) but want them available to agents running in a sandbox.

To bridge tools, wrap them in a `BridgedToolsSpec` and pass to `sandbox_agent_bridge()`:

``` python
from inspect_ai.tool import tool
from inspect_ai.agent import (
    Agent, AgentState, agent, sandbox_agent_bridge, BridgedToolsSpec
)
from inspect_ai.util import sandbox

@tool
def search_database():
    async def execute(query: str) -> str:
        """Search the internal database.

        Args:
            query: The search query.
        """
        # Runs on the host, not the sandbox
        return f"Results for: {query}"
    return execute

@agent
def my_agent() -> Agent:
    async def execute(state: AgentState) -> AgentState:
        async with sandbox_agent_bridge(
            state,
            bridged_tools=[
                BridgedToolsSpec(
                    name="host_tools",
                    tools=[search_database()]
                )
            ]
        ) as bridge:
            # bridge.mcp_server_configs contains resolved MCPServerConfigStdio
            # objects that can be passed to CLI agents
            return bridge.state

    return execute
```

The bridge handles:

- Starting a host-side service that executes the Inspect tools
- Writing an MCP server script to the sandbox that forwards tool calls to the host
- Returning `MCPServerConfigStdio` configs that CLI agents can use to connect

## Models

As demonstrated above, communication with Inspect models is done by using the OpenAI API with `model="inspect"`. You can use the same technique to interface with other Inspect models. To do this, preface the model name with "inspect" followed by the rest of the fully qualified model name.

For example, in a LangChain agent, you would do this to utilise the Inspect interface to Gemini:

``` python
model = ChatOpenAI(model="inspect/google/gemini-1.5-pro")
```

## Transcript

Custom agents run through a bridge still get most of the benefit of the Inspect transcript and log viewer. All model calls are captured and produce the same transcript output as when using conventional agents.

If you want to use additional features of Inspect transcripts (e.g. spans, markdown output, etc.) you can still import and use the `transcript` function as normal. For example:

``` python
from inspect_ai.log import transcript

transcript().info("custom *markdown* content")
```