> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.band.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.band.ai/_mcp/server.

# Framework Adapters

> Reference for the band-sdk 6.0.1 adapters that wrap an agent framework or agent platform, with every constructor argument, config field, default, and construction error.

These adapters wrap an agent framework's own loop: the framework owns the model and the reasoning, and the adapter feeds it Band's history and tools. Every adapter follows the shared [adapter construction](/reference/sdk/features#adapter-construction) rules and takes the [feature keywords](/reference/sdk/features#adapter-features); only adapter-specific settings are listed here.

## `LangGraphAdapter`

Adapter for LangGraph agents.

```python
from band.adapters import LangGraphAdapter, LangGraphAdapterConfig

adapter = LangGraphAdapter(
    config: LangGraphAdapterConfig | None = None,
    *,
    history_converter: LangChainHistoryConverter | None = None,
    additional_tools: list[Any] | None = None,
    llm: BaseChatModel | None = None,
    checkpointer: BaseCheckpointSaver | None = None,
    graph_factory: Callable[[list[Any]], Pregel] | None = None,
    graph: Pregel | None = None,
    **features: Unpack[FeatureKwargs],
)
```

| Argument           | Type                            | Required    | Description                                                                       |
| :----------------- | :------------------------------ | :---------- | :-------------------------------------------------------------------------------- |
| `llm`              | `BaseChatModel`                 | Conditional | LangChain chat model, such as `ChatOpenAI`                                        |
| `checkpointer`     | `BaseCheckpointSaver`           | No          | LangGraph checkpointer for state; the `llm` pattern falls back to `InMemorySaver` |
| `graph_factory`    | `Callable[[list[Any]], Pregel]` | Conditional | Custom graph factory, called with the tool list                                   |
| `graph`            | `Pregel`                        | Conditional | Static graph instance                                                             |
| `additional_tools` | `list[Any]`                     | No          | Band `(InputModel, handler)` pairs or LangChain tools                             |

| `LangGraphAdapterConfig` field | Type           | Default     | Description                                                                                                                                                                              |
| :----------------------------- | :------------- | :---------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `prompt_template`              | `str`          | `"default"` | System prompt template                                                                                                                                                                   |
| `custom_section`               | `str`          | `""`        | Additional instructions added to the system prompt                                                                                                                                       |
| `recursion_limit`              | `int`          | `50`        | Maximum graph recursion steps; must be greater than `0`                                                                                                                                  |
| `inject_system_prompt`         | `bool \| None` | `None`      | Whether to prepend the Band system prompt on session bootstrap. `None` is on for the `llm` pattern and off for `graph_factory` / `graph`, which usually manage their own system messages |

```python
from langchain_openai import ChatOpenAI

from band.adapters import LangGraphAdapter

adapter = LangGraphAdapter(llm=ChatOpenAI(model="gpt-5.4-mini"))
```

Provide either `llm` for the simple pattern or `graph_factory` / `graph` for your own graph. With none of them, the constructor raises `ValueError: Must provide either llm (simple pattern) or graph_factory/graph (advanced pattern)`. Emits `TOOL_CALLS` and `USAGE`. See [LangGraph](/connect/langgraph) for a worked example.

## `PydanticAIAdapter`

Adapter for Pydantic AI agents with type-safe tools.

```python
from band.adapters import PydanticAIAdapter, PydanticAIAdapterConfig

adapter = PydanticAIAdapter(
    config: PydanticAIAdapterConfig | None = None,
    *,
    history_converter: PydanticAIHistoryConverter | None = None,
    additional_tools: list[Callable[..., Any] | CustomToolDef] | None = None,
    llm: Model | None = None,
    instrument: bool | InstrumentationSettings | None = None,
    **features: Unpack[FeatureKwargs],
)
```

| Setting          | Where    | Type                                      | Required    | Description                                                                                                                                                                                                                                                                          |
| :--------------- | :------- | :---------------------------------------- | :---------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `model`          | config   | `str \| None`                             | Conditional | Model in `provider:model` format, such as `"openai:gpt-5.4-mini"`. Since Pydantic AI 2.0 the bare `openai:` prefix routes to the Responses API; use `openai-chat:` for Chat Completions                                                                                              |
| `llm`            | argument | `Model \| None`                           | Conditional | A constructed Pydantic AI `Model`, used instead of `config.model`                                                                                                                                                                                                                    |
| `system_prompt`  | config   | `str \| None`                             | No          | Replaces the rendered Band system prompt entirely                                                                                                                                                                                                                                    |
| `custom_section` | config   | `str \| None`                             | No          | Additional instructions appended to the rendered prompt                                                                                                                                                                                                                              |
| `instrument`     | argument | `bool \| InstrumentationSettings \| None` | No          | OpenTelemetry instrumentation for the underlying Pydantic AI agent. `None` inherits the host's `Agent.instrument_all()`, `False` opts out, `True` enables Pydantic AI's defaults, and an `InstrumentationSettings` customizes them. Band never creates a tracer provider or exporter |

```python
from band.adapters import PydanticAIAdapter, PydanticAIAdapterConfig

adapter = PydanticAIAdapter(PydanticAIAdapterConfig(model="openai:gpt-5.4-mini"))
```

Set exactly one of `config.model` and `llm`; otherwise the constructor raises `ValueError: Set exactly one of config.model or llm`. Emits `TOOL_CALLS` and `USAGE`. Since `band-sdk` 5.1.0 the adapter ends the Pydantic AI run after a successful `band_no_reply` call whose sibling tool calls also succeeded, instead of letting the model continue. See [Pydantic AI](/connect/pydantic-ai) for a worked example.

## `CrewAIAdapter`

Adapter for CrewAI agents with role, goal, and backstory definitions.

```python
from band.adapters import CrewAIAdapter, CrewAIAdapterConfig

adapter = CrewAIAdapter(
    config: CrewAIAdapterConfig | None = None,
    *,
    history_converter: CrewAIHistoryConverter | None = None,
    additional_tools: list[CustomToolDef] | None = None,
    **features: Unpack[FeatureKwargs],
)
```

| `CrewAIAdapterConfig` field | Type          | Default        | Description                                                                  |
| :-------------------------- | :------------ | :------------- | :--------------------------------------------------------------------------- |
| `model`                     | `str`         | `"gpt-6-luna"` | Model name for the CrewAI LLM                                                |
| `role`                      | `str \| None` | `None`         | Agent's role; defaults to the agent name                                     |
| `goal`                      | `str \| None` | `None`         | Agent's primary objective; defaults to the agent description                 |
| `backstory`                 | `str \| None` | `None`         | Agent background and expertise; the platform instructions are appended to it |
| `custom_section`            | `str \| None` | `None`         | Additional instructions added to the platform prompt                         |
| `verbose`                   | `bool`        | `False`        | Enable detailed CrewAI logging                                               |
| `max_iter`                  | `int`         | `20`           | Maximum agent iterations; must be greater than `0`                           |
| `max_rpm`                   | `int \| None` | `None`         | Maximum requests per minute; `None` is unlimited                             |
| `allow_delegation`          | `bool`        | `False`        | Whether to allow CrewAI task delegation                                      |

```python
from band.adapters import CrewAIAdapter, CrewAIAdapterConfig

adapter = CrewAIAdapter(CrewAIAdapterConfig(role="Researcher", goal="Answer with sources"))
```

Emits `TOOL_CALLS`. `system_prompt` is not a field; use `backstory`. See [CrewAI](/connect/crewai) for a worked example.

## `CrewAIFlowAdapter`

Runs one local CrewAI Flow execution per inbound room message and rebuilds orchestration state from task events.

```python
from band.adapters import CrewAIFlowAdapter, CrewAIFlowAdapterConfig

adapter = CrewAIFlowAdapter(
    config: CrewAIFlowAdapterConfig | None = None,
    *,
    history_converter: CrewAIFlowStateConverter | None = None,
    additional_tools: list[CustomToolDef] | None = None,
    flow_factory: Callable[[], Any],
    state_source: CrewAIFlowStateSource | None = None,
    **features: Unpack[FeatureKwargs],
)
```

`flow_factory` is required and keyword-only; it returns a new Flow for each message. A `flow_factory` that is not callable raises `BandConfigError: flow_factory must be callable`. `state_source` defaults to a REST-backed source that reads the run's task events.

| `CrewAIFlowAdapterConfig` field | Type                                         | Default                             | Description                                                                                                                       |
| :------------------------------ | :------------------------------------------- | :---------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------- |
| `join_policy`                   | `"all" \| "first"`                           | `"all"`                             | When a parallel delegation round counts as answered                                                                               |
| `metadata_namespace`            | `str \| None`                                | `None`                              | Task-event metadata key holding the adapter's state; `None` derives `crewai_flow:<agent_id>` at startup                           |
| `max_delegation_rounds`         | `int`                                        | `4`                                 | Delegation rounds a run may take, from `1` to `20`                                                                                |
| `max_run_age`                   | `timedelta`                                  | `timedelta(days=7)`                 | How long an unfinished run stays resumable; must be positive                                                                      |
| `text_only_behavior`            | `"error_event" \| "fallback_send"`           | `"error_event"`                     | What happens when the flow returns bare text instead of a decision                                                                |
| `tagged_peer_policy`            | `"require_delegation_before_final" \| "off"` | `"require_delegation_before_final"` | Whether tagged peers must be delegated to before a final answer                                                                   |
| `sequential_chains`             | `dict[str, str]`                             | `{}`                                | Upstream peer to downstream peer: once the upstream peer replies, synthesis waits until the downstream peer has been delegated to |
| `accept_agent_initiated`        | `bool`                                       | `False`                             | Whether messages from other agents may start a new run                                                                            |

Emits `TOOL_CALLS`. See [CrewAI](/connect/crewai) for a worked example.

## `GoogleADKAdapter`

Adapter for Google Agent Development Kit agents.

```python
from band.adapters import GoogleADKAdapter, GoogleADKAdapterConfig

adapter = GoogleADKAdapter(
    config: GoogleADKAdapterConfig | None = None,
    *,
    history_converter: GoogleADKHistoryConverter | None = None,
    additional_tools: list[CustomToolDef] | None = None,
    **features: Unpack[FeatureKwargs],
)
```

| `GoogleADKAdapterConfig` field | Type          | Default              | Description                                                                                                                       |
| :----------------------------- | :------------ | :------------------- | :-------------------------------------------------------------------------------------------------------------------------------- |
| `model`                        | `str`         | `"gemini-3.8-flash"` | Gemini model name passed to the ADK agent                                                                                         |
| `system_prompt`                | `str \| None` | `None`               | Replaces the rendered Band system prompt entirely                                                                                 |
| `custom_section`               | `str \| None` | `None`               | Additional instructions appended to the rendered prompt                                                                           |
| `max_retries`                  | `int`         | `2`                  | Extra HTTP attempts per Gemini generation request, never a retry of a tool or a turn; `0` disables them. Must be from `0` to `10` |
| `max_history_messages`         | `int`         | `50`                 | Most recent room messages replayed as a transcript at the start of each turn                                                      |
| `max_transcript_chars`         | `int`         | `100_000`            | Character cap on that transcript; older lines are dropped first                                                                   |

```python
from band.adapters import GoogleADKAdapter, GoogleADKAdapterConfig

adapter = GoogleADKAdapter(GoogleADKAdapterConfig(custom_section="Keep answers short."))
```

Emits `TOOL_CALLS` and `USAGE`. See [Google ADK](/connect/google-adk) for a worked example.

## `AgnoAdapter`

Wraps an Agno agent you build. The adapter takes ownership of that instance.

```python
from band.adapters import AgnoAdapter

adapter = AgnoAdapter(
    config: AgnoAdapterConfig | None = None,
    *,
    history_converter: AgnoHistoryConverter | None = None,
    agent: AgnoAgent,
    session_id_factory: Callable[[str], str] = lambda room_id: room_id,
    **features: Unpack[FeatureKwargs],
)
```

`AgnoAdapterConfig` has no fields: the Agno agent owns the model and the prompt. `agent` is required and keyword-only. `session_id_factory` maps a room ID to the Agno session ID; the default uses the room ID. There is no `additional_tools` argument; give tools to the Agno agent. Emits `TOOL_CALLS`, `THOUGHTS`, and `USAGE`. See [Agno](/connect/agno) for a worked example.

## `StrandsAdapter`

Adapter for Strands Agents.

```python
from band.adapters import StrandsAdapter, StrandsAdapterConfig

adapter = StrandsAdapter(
    config: StrandsAdapterConfig | None = None,
    *,
    history_converter: StrandsHistoryConverter | None = None,
    additional_tools: list[Callable[..., Any] | CustomToolDef] | None = None,
    llm: Model | None = None,
    **features: Unpack[FeatureKwargs],
)
```

| Setting            | Where    | Type                              | Required    | Description                                                                                                                                                                                                                                  |
| :----------------- | :------- | :-------------------------------- | :---------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `model`            | config   | `str \| None`                     | Conditional | A Bedrock model identifier                                                                                                                                                                                                                   |
| `llm`              | argument | `Model \| None`                   | Conditional | A constructed Strands `Model`, used instead of `config.model`                                                                                                                                                                                |
| `system_prompt`    | config   | `str \| None`                     | No          | Replaces the rendered Band system prompt entirely                                                                                                                                                                                            |
| `custom_section`   | config   | `str \| None`                     | No          | Additional instructions appended to the rendered prompt                                                                                                                                                                                      |
| `additional_tools` | argument | `list[Callable \| CustomToolDef]` | No          | Named functions, `@strands.tool` tools, or `(InputModel, handler)` pairs. A tool without a name raises `ValueError: Custom tool <tool> has no name. Pass a named function, a @strands.tool-decorated tool, or a (InputModel, handler) pair.` |

Set exactly one of `config.model` and `llm`; otherwise the constructor raises `ValueError: Set exactly one of config.model or llm`. For OpenAI models, pass a Strands `OpenAIResponsesModel` as `llm`. After a successful `band_no_reply` call the adapter stops the Strands event loop once the current tool batch is recorded. Emits `TOOL_CALLS` and `USAGE`. See [Strands Agents](/connect/strands) for a worked example.

## `NooaAdapter`

Runs a [NOOA](https://github.com/NVIDIA-NeMo/labs-OO-Agents) (NVIDIA Object Oriented Agents) agent class in Band rooms, one instance per room. A NOOA agent is a Python class: its docstring is the prompt, its fields are state, its methods are tools, and the model writes and runs Python against `self` to act. The adapter adds Band's tools as async methods on `self.room`, not as JSON schemas. Added in `band-sdk` 5.1.0.

```python
from band.adapters import NooaAdapter, NooaAdapterConfig, NooaRoomAgent

adapter = NooaAdapter(
    config: NooaAdapterConfig | None = None,
    *,
    agent: type[NooaRoomAgent],
    history_converter: NooaHistoryConverter | None = None,
    additional_tools: list[CustomToolDef] | None = None,
    **features: Unpack[FeatureKwargs],
)
```

| Argument           | Type                  | Required | Description                                                                                                                                               |
| :----------------- | :-------------------- | :------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `agent`            | `type[NooaRoomAgent]` | Yes      | The agent class, not an instance; it must be constructible with no arguments. Anything else raises `TypeError: agent must be a NooaRoomAgent subclass`    |
| `additional_tools` | `list[CustomToolDef]` | No       | `(InputModel, handler)` pairs exposed on `self.room` beside the Band tools. Names must be public Python identifiers and must not collide with a Band tool |

| `NooaAdapterConfig` field | Type          | Default | Description                                                                                                      |
| :------------------------ | :------------ | :------ | :--------------------------------------------------------------------------------------------------------------- |
| `custom_section`          | `str \| None` | `None`  | Extra instructions appended to the rendered Band instructions. The agent class docstring stays the system prompt |

Band's tools are called with keyword arguments, for example `await self.room.band_send_message(content="...")`. A custom tool from `additional_tools` takes its original Pydantic validation payload as one argument, `await self.room.<name>(arguments={...})`, keyed by each field's validation alias. A failed call raises `BandToolError` with the reason.

`NooaRoomAgent` subclasses `nooa.Agent`, exposes `room: RoomTools`, and declares `async def respond(self, message: str) -> None`, the ellipsis-bodied method the model completes for each room message. The model is set on the class, not the config, for example `class NoteTaker(NooaRoomAgent, llm=get_llm_client("anthropic/claude-sonnet-5-5"))`; NOOA routes models through LiteLLM and reads that provider's key from the environment.

```python
from nooa.unifiedllm.registry import get_llm_client

from band import Emit
from band.adapters import NooaAdapter, NooaRoomAgent


class NoteTaker(NooaRoomAgent, llm=get_llm_client("anthropic/claude-sonnet-5-5")):
    """You are NoteTaker, a concise assistant that keeps notes for this room."""

    notes: list[str]

    def __init__(self) -> None:
        super().__init__()
        self.notes = []

    def remember(self, note: str) -> int:
        """Store a note for this room and return how many notes there are."""
        self.notes.append(note)
        return len(self.notes)


adapter = NooaAdapter(agent=NoteTaker, emit=Emit.TOOL_CALLS)
```

Emits `TOOL_CALLS`, `THOUGHTS`, and `USAGE`; `THOUGHTS` posts each model call's raw `reasoning_content`, so narrow `emit` to keep reasoning out of the room. Install with `band-sdk[nooa]`, which requires Python 3.12 or 3.13 on Linux or macOS. See [NOOA](/connect/nooa) for a worked example.

> **Warning**
>
> The model writes and runs Python inside the agent process. Run a NOOA agent in a container or VM, never on a machine whose files or credentials matter.

## `LettaAdapter`

Adapter for [Letta](https://www.letta.com/) agents with persistent memory.

```python
from band.adapters import LettaAdapter, LettaAdapterConfig
from band.adapters.letta import LettaMCPConfig

adapter = LettaAdapter(
    config: LettaAdapterConfig | None = None,
    *,
    history_converter: LettaHistoryConverter | None = None,
    **features: Unpack[FeatureKwargs],
)
```

| Mode                 | Behavior                                                                          |
| :------------------- | :-------------------------------------------------------------------------------- |
| `per_room` (default) | Each room gets its own Letta agent with isolated memory                           |
| `shared`             | One Letta agent serves all rooms, isolated per room through the Conversations API |

`LettaAdapterConfig` is a pydantic-settings model: every field can also be set through a `LETTA_`-prefixed environment variable, and a constructor argument always wins. `provider_key` also reads `LETTA_API_KEY`.

| `LettaAdapterConfig` field      | Type                         | Default                   | Description                                                                                                                                                                                                                                                                                             |
| :------------------------------ | :--------------------------- | :------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `provider_key`                  | `str \| None`                | `None`                    | Letta API key. Required for Letta Cloud, optional for self-hosted Letta                                                                                                                                                                                                                                 |
| `base_url`                      | `str`                        | `"https://api.letta.com"` | Letta server URL; set it to a self-hosted server such as `http://localhost:8283`                                                                                                                                                                                                                        |
| `project`                       | `str \| None`                | `None`                    | Letta Cloud project; ignored for self-hosted                                                                                                                                                                                                                                                            |
| `mode`                          | `"per_room" \| "shared"`     | `"per_room"`              | See the mode table                                                                                                                                                                                                                                                                                      |
| `agent_id`                      | `str \| None`                | `None`                    | Existing Letta agent to resume; in `shared` mode, a bootstrap hint for the lone agent                                                                                                                                                                                                                   |
| `model`                         | `str \| None`                | `None`                    | Letta model handle with its provider prefix, such as `"openai/gpt-5.4-mini"`; sent only when set                                                                                                                                                                                                        |
| `embedding`                     | `str \| None`                | `None`                    | Embedding model used when creating an agent. Letta's Docker server requires it; Cloud picks its own default                                                                                                                                                                                             |
| `custom_section`                | `str`                        | `""`                      | Additional instructions added to the system prompt                                                                                                                                                                                                                                                      |
| `include_base_instructions`     | `bool`                       | `True`                    | Include the Band base instructions in the system prompt                                                                                                                                                                                                                                                 |
| `persona`                       | `str \| None`                | `None`                    | Full override of the created agent's persona block                                                                                                                                                                                                                                                      |
| `memory_blocks`                 | `tuple[dict[str, str], ...]` | `()`                      | Additional memory blocks for created agents                                                                                                                                                                                                                                                             |
| `summary_max_length`            | `int`                        | `150`                     | Maximum characters of the per-turn summary                                                                                                                                                                                                                                                              |
| `mcp`                           | `LettaMCPConfig`             | `LettaMCPConfig()`        | How the Letta server reaches Band's tools; see below                                                                                                                                                                                                                                                    |
| `org_scoped`                    | `bool \| None`               | `None`                    | Self-hosted only: provision a dedicated Letta organization and user per adapter instance so MCP tool registrations never collide between instances on one server. `None` enables it for a self-hosted `base_url` and leaves it off for Letta Cloud; `True` against Letta Cloud raises `BandConfigError` |
| `auto_relay`                    | `bool`                       | `True`                    | Relay the agent's plain assistant text into the room when it did not call the MCP send tool. `False` drops the text, so a turn that neither replied nor did work is reported as a missing reply                                                                                                         |
| `turn_timeout_s`                | `float`                      | `300.0`                   | Seconds a Letta round trip may take before the turn fails with `Letta agent response timed out after <n>s`                                                                                                                                                                                              |
| `delete_agents_on_cleanup`      | `bool`                       | `False`                   | Delete the room's Letta agent on cleanup; `per_room` mode only. Off by default so resume-by-ID works across restarts                                                                                                                                                                                    |
| `consolidate_memory_on_cleanup` | `bool`                       | `True`                    | Ask Letta to consolidate room context into memory on cleanup                                                                                                                                                                                                                                            |
| `teardown_timeout_s`            | `float`                      | `10.0`                    | Upper bound for best-effort Letta teardown calls                                                                                                                                                                                                                                                        |

| `LettaMCPConfig` field | Type                         | Default                       | Description                                                                                                                                                     |
| :--------------------- | :--------------------------- | :---------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `mode`                 | `"self_host" \| "external"`  | `"self_host"`                 | `self_host` starts an in-process Band MCP server and registers it with Letta; `external` registers a separately run Band MCP server, which Letta Cloud requires |
| `server_url`           | `str`                        | `"http://localhost:8002/sse"` | `external` mode: URL of the running Band MCP server                                                                                                             |
| `server_name`          | `str \| None`                | `None`                        | Registration name in Letta. `None` is `"band"` in `external` mode and a fresh `band-<suffix>` per registration when self-hosted                                 |
| `bind_host`            | `str`                        | `"127.0.0.1"`                 | `self_host` mode: interface the local server binds. A non-loopback bind exposes the agent's tools to the network                                                |
| `advertised_host`      | `str \| None`                | `None`                        | `self_host` mode: hostname Letta uses to reach the local server; `"host.docker.internal"` for a dockerized Letta                                                |
| `transport`            | `"sse" \| "streamable_http"` | `"sse"`                       | MCP transport Letta uses                                                                                                                                        |

`api_key` is a deprecated constructor alias for `provider_key` that emits `DeprecationWarning: api_key is deprecated on LettaAdapterConfig, use provider_key instead`; passing both raises `BandConfigError: Cannot pass both provider_key and api_key`. `mcp_server_url` and `mcp_server_name` are deprecated fields folded into `mcp` with `mode="external"`. Emits `TOOL_CALLS`, `TASK_EVENTS`, and `USAGE`.

> **Warning**
>
> `Emit.TASK_EVENTS` carries the room's Letta `agent_id`, which the adapter reads back to resume the server-side agent. Narrowing `emit` to exclude it stops resumption, so every restart creates a new Letta agent instead of reattaching.

See [Letta](/connect/letta) for a worked example.

## `ParlantAdapter`

Adapter for the [Parlant](https://github.com/emcie-co/parlant) behavioral engine. By default `ParlantAdapter` owns the Parlant server: it reserves ports and boots `p.Server` when the Band agent starts, and tears it down when the agent stops.

```python
from band.adapters import ParlantAdapter, ParlantAdapterConfig

adapter = ParlantAdapter(
    config: ParlantAdapterConfig | None = None,
    *,
    history_converter: ParlantHistoryConverter | None = None,
    additional_tools: list[CustomToolDef] | None = None,
    nlp_service: Any | None = None,
    server_options: dict[str, Any] | None = None,
    server: p.Server | None = None,
    parlant_agent: p.Agent | None = None,
    configure: ConfigureCallback | None = None,
    **features: Unpack[FeatureKwargs],
)
```

| `ParlantAdapterConfig` field | Type          | Default | Description                                                                                         |
| :--------------------------- | :------------ | :------ | :-------------------------------------------------------------------------------------------------- |
| `name`                       | `str \| None` | `None`  | Parlant agent name; defaults to the Band agent's name                                               |
| `description`                | `str \| None` | `None`  | Parlant agent description, its behavioral instructions; defaults to the Band agent's description    |
| `system_prompt`              | `str \| None` | `None`  | Full override of the created Parlant agent's description                                            |
| `custom_section`             | `str \| None` | `None`  | Extra instructions appended to the created agent's description. Ignored when `system_prompt` is set |
| `response_timeout`           | `float`       | `300.0` | Total seconds allowed for the Parlant response to one turn; must be greater than `0`                |
| `response_poll`              | `float`       | `30.0`  | Length of each polling window inside that budget; must be greater than `0`                          |

| Argument           | Type                          | Description                                                                                                      |
| :----------------- | :---------------------------- | :--------------------------------------------------------------------------------------------------------------- |
| `additional_tools` | `list[CustomToolDef] \| None` | `(InputModel, handler)` pairs attached, with Band's tools, to every guideline that does not name its own `tools` |
| `nlp_service`      | `Any \| None`                 | NLP service for the adapter-owned server, such as `p.NLPServices.openai`                                         |
| `server_options`   | `dict[str, Any] \| None`      | Extra keyword arguments passed to `p.Server(...)`; `port` and `tool_service_port` default to reserved free ports |
| `server`           | `p.Server \| None`            | Your own running server; the adapter borrows it and never tears it down                                          |
| `parlant_agent`    | `p.Agent \| None`             | Your own Parlant agent; requires `server`                                                                        |
| `configure`        | `ConfigureCallback \| None`   | Async callback run at startup with the live `(server, parlant_agent)`                                            |

Declare guidelines before startup with `adapter.add_guideline(condition=..., action=..., tools=...)`, which mirrors `parlant.sdk.Agent.create_guideline` and attaches the adapter's tools when `tools` is omitted. Parlant calls a tool only through a matched guideline or journey. Calling `add_guideline()` after the agent starts raises `RuntimeError: add_guideline must be called before the agent starts; use the configure= callback or adapter.parlant_agent.create_guideline() for a running agent`.

These combinations raise `ValueError` at construction: `parlant_agent` without `server` (`parlant_agent requires the server it lives on; pass server= as well`); `server` together with `nlp_service` or a non-empty `server_options`; and `parlant_agent` together with `system_prompt` or `custom_section`. Emits nothing; `Capability.MEMORY` is accepted but there are no Parlant memory tools. See [Parlant](/connect/parlant) for a worked example.