Agent Approval Protocol for Python
Put an AI agent's tool calls behind an AAP approval provider. Each call waits for the provider's decision, runs only if approved, and runs at most once.
pip install agentapprovalprotocol
Check a tool call
from agentapprovalprotocol import Call, Client, Gate
gate = Gate(Client("https://approvals.example.com/api/aap", token))
with gate.guard(Call(key=f"{run_id}:{tool_call.id}", tool=tool_call.name, arguments=tool_call.args)) as verdict:
if verdict:
result = run_tool(tool_call)
else:
result = verdict.reason # return this to the model as the tool result
key must identify the tool call within its run, and stay the same if the call is seen again after a retry or resume. guard reports whether the tool succeeded when the block exits.
AsyncGate and AsyncClient provide the same API for asyncio.
Pause instead of waiting
With mode="async", check returns Pending when there is no decision yet, so the run can pause and the process can exit. Mount a Receiver where the provider can reach it. When a decision arrives it wakes the run, and the gate checks the decision again before anything runs.
Framework integrations handle pausing and resuming for you.
LangChain, LangGraph and Deep Agents
pip install "agentapprovalprotocol[langgraph]"
from agentapprovalprotocol.langgraph import ApprovalMiddleware
approvals = ApprovalMiddleware("https://approvals.example.com/api/aap", token)
agent = create_agent(model, tools=tools, middleware=[approvals])
Every tool call the agent makes goes to the provider. A denied call returns the reason to the model as the tool result.
For Deep Agents, also add the middleware to every subagent:
from agentapprovalprotocol.langgraph import deep_agent_subagents
agent = create_deep_agent(model, tools=tools, middleware=[approvals], subagents=deep_agent_subagents(approvals, my_subagents))
To pause instead of waiting, use ApprovalMiddleware(..., mode="async") with a checkpointer, and mount a Receiver with resumers={"langgraph": resumer(agent)}. On LangSmith Deployment, use deployment_resumer(get_client()) in a custom route instead. Resuming a thread any other way cannot approve a call: the middleware asks the provider again.
Pydantic AI
pip install "agentapprovalprotocol[pydantic-ai]"
Needs Python 3.11 or later.
from agentapprovalprotocol.pydantic_ai import ApprovalCapability
approvals = ApprovalCapability("https://approvals.example.com/api/aap", token)
agent = Agent(model, tools=tools, capabilities=[approvals])
Every tool call the agent makes goes to the provider, including MCP and other toolset tools. A denied call returns the reason to the model as a failed tool result. Add the same capability to every agent you run as a sub-agent.
Tools that run at the model provider, such as native web search or code execution, cannot be sent for approval. A run that includes one stops with an error. Use a local tool instead.
To pause instead of waiting, use ApprovalCapability(..., mode="async") and add DeferredToolRequests to the agent's output_type. When a run ends with DeferredToolRequests, save result.conversation. Mount a Receiver with resumers={"pydantic-ai": resumer(agent, load=load, save=save)}, where load(conversation_id) returns the saved conversation and save(conversation) stores the resumed one. Calls inside a sub-agent wait instead of pausing. Continuing a conversation any other way cannot approve a call: the capability asks the provider again, and an approval with edited arguments is refused.
Metadata
Release files for agentapprovalprotocol 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| agentapprovalprotocol-0.1.0.tar.gz | 169.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| agentapprovalprotocol-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 194.2 kB
Release files / agentapprovalprotocol-0.1.0.tar.gz
| Download URL | agentapprovalprotocol-0.1.0.tar.gz |
|---|---|
| Size | 169.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8f37d98548a4f136594b3759f9383404495584e89eeff2d95094a0fbc22ddc4a
|
|
BLAKE2b-256 checksum How to use checksums |
0e1eba43ecc92f024494488f5a63e6490f60b9284cc6b9737b43d964046c72ef
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency logRelease files / agentapprovalprotocol-0.1.0-py3-none-any.whl
| Download URL | agentapprovalprotocol-0.1.0-py3-none-any.whl |
|---|---|
| Size | 24.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
526177bfb74778458f15d049593ca23536d4f5a300390b0c6e368bfc5d92ff81
|
|
BLAKE2b-256 checksum How to use checksums |
39d1bc2186b7000d0c5014202f8120cf75f771ee6c0c4fd3bcfaeaf0bf59b285
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency log