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.
The core contract is simple:
- keep the existing
pydantic_ai.Agent - expose it through ACP
- only publish ACP-visible state the runtime can actually honor
Entry Points
run_acp(...)create_acp_agent(...)AdapterConfigAcpSessionContextStaticAgentSourceFactoryAgentSourceMemorySessionStoreFileSessionStore
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 behaviorstructuredmode expects structuredTaskPlanoutput instead of exposingacp_set_plan- switch to
plan_generation_type="tools"when you explicitly want tool-based native plan recording - keep
plan_tools=Truewhen you also want progress tools such asacp_update_plan_entry
Projection Maps
Projection maps decide how known tool families render into ACP-visible updates.
Built-in projection helpers:
FileSystemProjectionMapHookProjectionMapWebToolProjectionMapBuiltinToolProjectionMap
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:
ThinkingBridgePrepareToolsBridgeThreadExecutorBridgeSetToolMetadataBridgeIncludeToolReturnSchemasBridgeWebSearchBridgeWebFetchBridgeImageGenerationBridgeMcpCapabilityBridgeToolsetBridgePrefixToolsBridgeOpenAICompactionBridgeAnthropicCompactionBridge
Use bridges when the runtime should gain upstream Pydantic AI capabilities and ACP-visible metadata without rewriting the adapter core.
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.
Maintained Examples
Maintained runnable examples:
Focused docs recipes:
Documentation
- Pydantic ACP Overview
- AdapterConfig
- Plans, Thinking, and Approvals
- Models, Modes, and Slash Commands
- Prompt Resources and Context
- Session State and Lifecycle
- Bridges
- Providers
- Host Backends and Projections
- API Reference
Compatibility Policy
pydantic-acp currently pins pydantic-ai-slim==1.83.0.
That pin is deliberate. The adapter is tested against a specific Pydantic AI surface and should still be upgraded deliberately, but the hook-compatibility seam is now isolated behind ACP Kit’s own compatibility layer instead of scattering private upstream imports through the runtime.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pydantic_acp-0.9.2.tar.gz.
File metadata
- Download URL: pydantic_acp-0.9.2.tar.gz
- Upload date:
- Size: 74.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c1247b4bacdb87fe4fa8b46f4aa878457de083a486e454264860832660f19efc
|
|
| MD5 |
be82ef7995af43f351a19e16e028d847
|
|
| BLAKE2b-256 |
6c5e576593681d793e74674caa9197c50b9d3fb90b59dff199b05039f876d1e6
|
File details
Details for the file pydantic_acp-0.9.2-py3-none-any.whl.
File metadata
- Download URL: pydantic_acp-0.9.2-py3-none-any.whl
- Upload date:
- Size: 106.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
96144e10b052c4c74cb473964dd0dac91da275a202192c75140b1dc9d6898311
|
|
| MD5 |
fee7532d3625462b71787943ee0dcbc6
|
|
| BLAKE2b-256 |
b579d08b9acf0a15e24c22fba06dc7f37b36585a7e7cc490bccc1b4ba7068da3
|