Models, Modes, And Slash Commands
pydantic-acp exposes a small ACP control plane on top of normal prompts.
These controls exist to keep session state explicit and inspectable from the client UI.
Slash Commands
The adapter exposes a small fixed command set plus dynamic mode commands.
Fixed commands
| Command | Purpose |
|---|---|
/model |
Show the current model |
/model <provider:model> |
Set the current model |
/thinking |
Show the current thinking effort |
/thinking <effort> |
Set the current thinking effort |
/tools |
List visible tools on the active agent |
/hooks |
List registered visible hook callbacks |
/mcp-servers |
List MCP servers derived from toolsets and session metadata |
Dynamic mode commands
Mode commands are registered from the current session’s available modes. If your session exposes:
reviewexecute
then ACP publishes:
/review/execute
The adapter no longer hardcodes ask, plan, and agent as global commands. They are only published when those modes actually exist.
Mode ids must remain compatible with slash-command addressing:
- they cannot be empty
- they cannot contain whitespace
- they cannot collide with reserved commands such as
model,thinking,tools,hooks, ormcp-servers - they should stay specific enough that the command still reads clearly in the UI
Mode Changes Update ACP State
Mode commands do more than print text.
When a mode changes, the adapter updates:
- current mode state
- ACP config options when the mode is mirrored as a config option
- plan state visibility
- available commands
- session metadata
This is why /plan or /agent affects the UI surface as well as the next prompt.
Model Selection
Model selection can be provided by either:
- built-in
available_models - a
SessionModelsProvider
If model selection is enabled, the adapter also mirrors it into ACP config options unless that behavior is disabled or the provider owns it already.
Example built-in model config:
from pydantic_acp import AdapterConfig, AdapterModel
config = AdapterConfig(
allow_model_selection=True,
available_models=[
AdapterModel(
model_id="fast",
name="Fast",
description="Lower latency.",
override="openai:gpt-5-mini",
),
AdapterModel(
model_id="smart",
name="Smart",
description="More capable model.",
override="openai:gpt-5",
),
],
)
Thinking Effort
ThinkingBridge exposes a session-local ACP config option named thinking.
Supported values:
defaultoffminimallowmediumhighxhigh
Example:
from pydantic_acp import AdapterConfig, ThinkingBridge
config = AdapterConfig(capability_bridges=[ThinkingBridge()])
From the UI:
/thinking high
The bridge uses Pydantic AI’s native Thinking capability to generate model settings rather than inventing provider-specific request payloads itself.
Mode-aware Tool Surfaces
The common pattern is:
ask: read-only, inspection-focusedplan: inspect and draft ACP plan stateagent: full tool surface plus plan progress tools
This is usually implemented with PrepareToolsBridge.
from pydantic_acp import PrepareToolsBridge, PrepareToolsMode
from pydantic_ai.tools import RunContext, ToolDefinition
def ask_tools(
ctx: RunContext[None],
tool_defs: list[ToolDefinition],
) -> list[ToolDefinition]:
del ctx
return [tool_def for tool_def in tool_defs if not tool_def.name.startswith("write_")]
prepare_bridge = PrepareToolsBridge(
default_mode_id="ask",
modes=[
PrepareToolsMode(
id="ask",
name="Ask",
description="Read-only repo inspection.",
prepare_func=ask_tools,
),
PrepareToolsMode(
id="plan",
name="Plan",
description="Draft ACP plan state.",
prepare_func=ask_tools,
plan_mode=True,
),
],
)
What /tools Actually Lists
/tools lists currently registered visible tools on the active agent.
Important detail:
- internal ACP tools such as
acp_get_planare intentionally hidden from/tools - the list reflects the agent after mode-aware prepare-tools filtering
That makes /tools a good debugging surface for “why can the model see this tool right now?”
What /mcp-servers Actually Lists
The MCP server listing is assembled from:
- active agent toolsets
- session MCP server payloads
- bridge-contributed MCP metadata
It is primarily intended as a client-visible observability surface, not as the source of truth for server wiring.
Common Failure Modes
/thinkingdoes not appear unless aThinkingBridge()is configured/modelonly appears when model state is actually available- mode commands are not global; if a mode is not present in current session state, its slash command is not published
- mode ids like
modelorthinkingare rejected because they would collide with reserved slash commands