Skip to main content

ACP adapter for pydantic-ai agents.

Project description

pydantic-acp

pydantic-acp adapts pydantic_ai.Agent instances to the ACP agent interface without rewriting the underlying agent.

Install the stable v1 package with optional harness integration:

uv add "pydantic-acp[harness]>=1.0.0,<2.0.0"
pip install "pydantic-acp[harness]>=1.0.0,<2.0.0"

The core contract is simple:

  1. keep the existing pydantic_ai.Agent
  2. expose it through ACP
  3. only publish ACP-visible state the runtime can actually honor

The final v1 stability boundary is defined by the ACP Kit versioning policy.

Entry Points

  • run_acp(...)
  • create_acp_agent(...)
  • AdapterConfig
  • AcpSessionContext
  • StaticAgentSource
  • FactoryAgentSource
  • MemorySessionStore
  • FileSessionStore

What It Covers

pydantic-acp includes:

  • ACP session lifecycle, replay, resume, and persistence
  • session-local model selection
  • mode and slash-command control
  • native ACP plan state with structured TaskPlan
  • approval bridging
  • prompt resources including files, embedded resources, images, and audio
  • projection maps for filesystem, hooks, web tools, and builtin tool families
  • capability bridges for upstream Pydantic AI capabilities
  • client-backed filesystem and terminal helpers

Quick Start

from pydantic_ai import Agent
from pydantic_acp import run_acp

agent = Agent("openai:gpt-5", name="demo-agent")
run_acp(agent=agent)

If another runtime should own transport lifecycle:

from acp import run_agent
from pydantic_ai import Agent
from pydantic_acp import AdapterConfig, MemorySessionStore, create_acp_agent

agent = Agent("openai:gpt-5", name="composable-agent")

acp_agent = create_acp_agent(
    agent=agent,
    config=AdapterConfig(session_store=MemorySessionStore()),
)

run_agent(acp_agent)

If you are using Codex-backed Pydantic models through codex-auth-helper, pass explicit instructions when building the model. That is the preferred seam for Codex-specific system behavior:

from codex_auth_helper import create_codex_responses_model
from pydantic_ai import Agent

model = create_codex_responses_model(
    "gpt-5.4",
    instructions="You are a careful coding assistant.",
)
agent = Agent(model, name="codex-agent")

On the Pydantic path, Agent(instructions=...) is also valid and may still be useful for agent-specific behavior layered on top of the model:

from codex_auth_helper import create_codex_responses_model
from pydantic_ai import Agent

model = create_codex_responses_model(
    "gpt-5.4",
    instructions="You are a careful coding assistant.",
)
agent = Agent(
    model,
    name="codex-agent",
    instructions="Ask for clarification when the task is underspecified.",
)

In short: Codex-backed Pydantic models should not rely on an implicit default instruction string. Set instructions explicitly at the factory level, and add Agent(instructions=...) when you want extra agent-owned behavior.

Native Plan Mode

TaskPlan is the structured native plan output surface.

Use PrepareToolsBridge to expose plan mode:

from pydantic_ai import Agent
from pydantic_ai.tools import RunContext, ToolDefinition
from pydantic_acp import (
    AdapterConfig,
    PrepareToolsBridge,
    PrepareToolsMode,
    run_acp,
)


def read_only_tools(
    ctx: RunContext[None],
    tool_defs: list[ToolDefinition],
) -> list[ToolDefinition]:
    del ctx
    return list(tool_defs)


agent = Agent("openai:gpt-5", name="plan-agent")

run_acp(
    agent=agent,
    config=AdapterConfig(
        capability_bridges=[
            PrepareToolsBridge(
                default_mode_id="plan",
                default_plan_generation_type="structured",
                modes=[
                    PrepareToolsMode(
                        id="plan",
                        name="Plan",
                        description="Return a structured ACP task plan.",
                        prepare_func=read_only_tools,
                        plan_mode=True,
                    ),
                ],
            ),
        ],
    ),
)

Important behavior:

  • plan_generation_type="structured" is the default plan-mode behavior
  • structured mode expects structured TaskPlan output instead of exposing acp_set_plan
  • switch to plan_generation_type="tools" when you explicitly want tool-based native plan recording
  • keep plan_tools=True when you also want progress tools such as acp_update_plan_entry

Projection Maps

Projection maps decide how known tool families render into ACP-visible updates.

Built-in projection helpers:

  • FileSystemProjectionMap
  • HookProjectionMap
  • WebToolProjectionMap
  • BuiltinToolProjectionMap

Example:

from pydantic_acp import (
    AdapterConfig,
    BuiltinToolProjectionMap,
    FileSystemProjectionMap,
    HookProjectionMap,
    run_acp,
)

run_acp(
    agent=agent,
    config=AdapterConfig(
        projection_maps=[
            FileSystemProjectionMap(
                default_read_tool="read_file",
                default_write_tool="write_file",
            ),
            HookProjectionMap(
                hidden_event_ids=frozenset({"after_model_request"}),
                event_labels={"before_model_request": "Preparing Request"},
            ),
            BuiltinToolProjectionMap(),
        ],
    ),
)

Capability Bridges

Current built-in bridges include:

  • ThinkingBridge
  • PrepareToolsBridge
  • ThreadExecutorBridge
  • SetToolMetadataBridge
  • IncludeToolReturnSchemasBridge
  • WebSearchBridge
  • WebFetchBridge
  • ImageGenerationBridge
  • McpCapabilityBridge
  • ToolsetBridge
  • PrefixToolsBridge
  • OpenAICompactionBridge
  • AnthropicCompactionBridge

Use bridges when the runtime should gain upstream Pydantic AI capabilities and ACP-visible metadata without rewriting the adapter core.

Harness-backed Capabilities

pydantic-acp also ships a maintained bridge and projection layer for pydantic-ai-harness.

Public seams:

  • HarnessFileSystemBridge
  • HarnessShellBridge
  • HarnessCodeModeBridge
  • HarnessFileSystemProjectionMap
  • HarnessShellProjectionMap
  • HarnessCodeModeProjectionMap

Minimal example:

from pathlib import Path

from pydantic_ai import Agent
from pydantic_acp import (
    AdapterConfig,
    HarnessFileSystemBridge,
    HarnessFileSystemProjectionMap,
    HarnessShellBridge,
    HarnessShellProjectionMap,
    MemorySessionStore,
    run_acp,
)

workspace_root = Path(".harness-agent")

agent = Agent(
    "openai:gpt-5",
    name="harness-agent",
    instructions="Use the harness filesystem and shell tools inside the workspace only.",
)

run_acp(
    agent=agent,
    config=AdapterConfig(
        session_store=MemorySessionStore(),
        capability_bridges=[
            HarnessFileSystemBridge(root_dir=workspace_root),
            HarnessShellBridge(cwd=workspace_root),
        ],
        projection_maps=[
            HarnessFileSystemProjectionMap(),
            HarnessShellProjectionMap(),
        ],
    ),
)

Use HarnessCodeModeBridge only when the run should expose CodeMode. The maintained example keeps that bridge opt-in so the native ACP target stays limited to filesystem and shell by default:

The harness filesystem projection now renders read_file as a read-specific preview instead of a fake diff, which makes ACP transcript output much more truthful for inspection-only tool calls.

Factories, Sources, And Host-owned State

Use agent_factory= when the ACP session should influence which agent gets built:

from pydantic_ai import Agent
from pydantic_acp import AcpSessionContext, AdapterConfig, MemorySessionStore, run_acp


def build_agent(session: AcpSessionContext) -> Agent[None, str]:
    workspace_name = session.cwd.name
    model_name = "openai:gpt-5.4-mini"
    if workspace_name.endswith("-deep"):
        model_name = "openai:gpt-5.4"
    return Agent(model_name, name=f"workspace-{workspace_name}")


run_acp(
    agent_factory=build_agent,
    config=AdapterConfig(session_store=MemorySessionStore()),
)

Use AgentSource when the agent and its dependencies should be built separately. Use providers when models, modes, config values, plans, or approvals belong to the host layer instead of the adapter.

Session Store Notes

Use MemorySessionStore for ephemeral local runs and FileSessionStore when ACP sessions should survive process restarts. FileSessionStore is a local durable store, not a distributed coordination layer.

File-backed session ids are constrained before they become filenames:

  • allowed characters are ASCII letters, digits, _, and -
  • maximum length is 128 characters
  • path separators, dot-prefixed ids, whitespace, and shell metacharacters are rejected

The file store writes through a temp file, fsync, and atomic replace. Malformed or partially written session files are skipped by public load/list flows.

Maintained Examples

Maintained runnable examples:

Focused docs recipes:

Documentation

Compatibility Policy

pydantic-acp supports pydantic-ai-slim>=2.0.0,<=2.4.0. Pydantic AI V1 is no longer supported.

Every supported minor is exercised by the repository's runtime and type-check compatibility matrix. The adapter keeps upstream compatibility behind ACP Kit's bridge and runtime seams instead of scattering version checks through callers.

Pydantic AI V2 defaults agent dependency and output generics to object. When your tools or hooks explicitly use RunContext[None] or Hooks[None], also declare the dependency type on the agent:

from pydantic_ai import Agent

agent: Agent[None, str] = Agent(
    "openai:gpt-5",
    deps_type=type(None),
    name="typed-agent",
)

The supported surface includes tool and output-tool preparation, output validation and processing hooks, deferred tool-call hooks, run metadata, conversation IDs, and the run_stream_events() lifecycle used through 2.4.0.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pydantic_acp-1.0.0.tar.gz (80.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pydantic_acp-1.0.0-py3-none-any.whl (112.6 kB view details)

Uploaded Python 3

File details

Details for the file pydantic_acp-1.0.0.tar.gz.

File metadata

  • Download URL: pydantic_acp-1.0.0.tar.gz
  • Upload date:
  • Size: 80.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.7

File hashes

Hashes for pydantic_acp-1.0.0.tar.gz
Algorithm Hash digest
SHA256 3581762515fee9ec92ded313f1a5a2c9091c69b49f1f62f4b47efc4b57c40191
MD5 173de4f6447da6f5ad1d9251baae4541
BLAKE2b-256 959353d974d25abc85ecde60c745b68dbd423af1b7e62445036970883c32c7ff

See more details on using hashes here.

File details

Details for the file pydantic_acp-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: pydantic_acp-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 112.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.7

File hashes

Hashes for pydantic_acp-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2dafae8fefe9034f7fb735a334c41adad27752184853a1b9cf0ebec5e6857027
MD5 bd1169177252b5ce4ace5fd0f4af1920
BLAKE2b-256 16af3a69a5ddd2ed97e48db80f37069911289c5016e8dd18657fa82e8d81626a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page