APAAI Protocol Python SDK — Action → Policy → Evidence
Project description
apaai-client
Python SDK for APAAI Protocol
Open, vendor-neutral SDK for the APAAI Protocol's Action → Policy → Evidence loop.
- 📦 Package:
apaai-client - 🔌 Protocol: HTTP/JSON (
/actions,/evidence,/policy) - 🧪 Minimal & testable: Class-based API
- 🧱 License: Apache-2.0
Install
pip install apaai-client
Reference server (for local development):
cd server npm i && npm run dev # → http://localhost:8787
Quickstart
from apaai_client import AccountabilityLayer
# Initialize the accountability layer
apaai = AccountabilityLayer(
endpoint="https://api.apaaiprotocol.org",
api_key=os.getenv("APAAI_API_KEY")
)
# 1) Propose an action
decision = apaai.propose(
type="send_email",
actor={"kind": "agent", "name": "mail-bot"},
target="mailto:client@acme.com",
params={"subject": "Proposal"}
)
# 2) Add evidence
apaai.evidence.add(decision["actionId"], [
{"name": "email_sent", "pass": True, "note": "msgId=123"}
])
with_action Helper
The with_action helper orchestrates the complete flow:
import asyncio
from apaai_client import AccountabilityLayer, with_action
apaai = AccountabilityLayer(
endpoint="https://api.apaaiprotocol.org",
api_key=os.getenv("APAAI_API_KEY")
)
async def main():
await with_action(
apaai=apaai,
type="send_email",
actor={"kind": "agent", "name": "mail-bot"},
target="mailto:client@acme.com",
params={"subject": "Proposal"},
on_approval=async (action_data) => {
# Handle approval workflow
await apaai.human.approve(action_data["actionId"], "@reviewer")
},
execute=async () => {
# Your business logic
return await send_email({"to": "client@acme.com", "subject": "Proposal"})
},
evidence_on_success=lambda result: [
{"name": "email_sent", "pass": True, "note": f"msgId={result['id']}"}
],
evidence_on_error=lambda err: [
{"name": "email_failed", "pass": False, "note": str(err)}
]
)
asyncio.run(main())
API Reference
AccountabilityLayer Class
apaai = AccountabilityLayer(
endpoint: Optional[str] = None,
api_key: Optional[str] = None
)
Core Methods
propose(action)- Propose an action and get a decisionevidence(action_id, checks)- Submit evidence for an actionpolicy(action_type?)- Get policy for an action typeapprove(action_id, approver?)- Approve an actionreject(action_id, reason?)- Reject an actionget_action(action_id)- Get action detailslist_actions(filters?)- List actions with filtersget_evidence(action_id)- Get evidence for an actionset_policy(policy)- Set a policy
Manager Interfaces
apaai.policies.evaluate(action_id)- Evaluate policy for an actionapaai.policies.enforce(action_type)- Enforce policy for an action typeapaai.policies.set(policy)- Set a policyapaai.human.approve(action_id, approver?)- Approve an actionapaai.human.reject(action_id, reason?)- Reject an actionapaai.evidence.add(action_id, checks)- Add evidence for an actionapaai.evidence.get(action_id)- Get evidence for an actionapaai.actions.get(action_id)- Get action detailsapaai.actions.list(filters?)- List actions with filters
Examples
Basic Flow
from apaai_client import AccountabilityLayer
apaai = AccountabilityLayer(endpoint="http://localhost:8787")
# Propose action
decision = apaai.propose(
type="send_email",
actor={"kind": "agent", "name": "mail-bot"},
target="mailto:client@acme.com",
params={"subject": "Proposal"}
)
# Handle approval if required
if decision["status"] == "requires_approval":
apaai.approve(decision["actionId"], "@reviewer")
# Submit evidence
apaai.evidence.add(decision["actionId"], [
{"name": "email_sent", "pass": True, "note": "msgId=123"}
])
Using Manager Interfaces
# Policy management
policy = apaai.policies.enforce("send_email")
apaai.policies.set({"rules": [...]})
# Human-in-the-loop
apaai.human.approve(action_id, "@reviewer")
apaai.human.reject(action_id, "Invalid recipient")
# Evidence management
apaai.evidence.add(action_id, [
{"name": "email_sent", "pass": True, "note": "msgId=123"}
])
evidence = apaai.evidence.get(action_id)
# Action management
action = apaai.actions.get(action_id)
actions = apaai.actions.list({"type": "send_email"})
Types
from typing import Dict, List, Optional, Any
Actor = Dict[str, Any] # {"kind": "agent", "name": "mail-bot", "provider": "openai"}
Action = Dict[str, Any] # {
"id": str,
"timestamp": str,
"type": str,
"actor": Actor,
"target": Optional[str],
"params": Optional[Dict[str, Any]],
"status": Optional[str],
"checks": Optional[List[str]]
}
Check = Dict[str, Any] # {"name": str, "pass": bool, "note": Optional[str]}
Evidence = Dict[str, Any] # {"actionId": str, "checks": List[Check]}
Decision = Dict[str, Any] # {"status": str, "checks": Optional[List[str]]}
PolicyRule = Dict[str, Any] # {
"when": Optional[Dict[str, str]], # {"action": str} or {"actionType": str}
"require": Optional[List[str]],
"mode": Optional[str] # "enforce" | "observe"
}
Policy = Dict[str, Any] # {"rules": List[PolicyRule]}
Testing
# Run tests
python -m pytest tests/
# Run tests with coverage
python -m pytest tests/ --cov=apaai_client
# Run specific test file
python -m pytest tests/test_client.py
Build & Publish
# Build the package
python -m build
# Publish to PyPI
python -m twine upload dist/*
License
Apache-2.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
apaai-0.1.0.tar.gz
(9.1 kB
view details)
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
apaai-0.1.0-py3-none-any.whl
(9.9 kB
view details)
File details
Details for the file apaai-0.1.0.tar.gz.
File metadata
- Download URL: apaai-0.1.0.tar.gz
- Upload date:
- Size: 9.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9a8a89a1420dc72b340cadaf434f08d430cb5c5c117b15e3c3157faf46cef4f5
|
|
| MD5 |
524fec15859787aec811cb79dc9bf36d
|
|
| BLAKE2b-256 |
afd7fdfc59bf7e48b809956443b207cc3df427d3636dc68d00dd9a68ef9ad705
|
File details
Details for the file apaai-0.1.0-py3-none-any.whl.
File metadata
- Download URL: apaai-0.1.0-py3-none-any.whl
- Upload date:
- Size: 9.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
71dcb6a341574d3e4aafe7e22594c0dd1ee806e8482bbf2307353fa7a19282e8
|
|
| MD5 |
7698ce54ef00991c55449cd733d0bca4
|
|
| BLAKE2b-256 |
ad5fe7cbcbb81361433d57612b1491b906bcc28b4f23fe459ccafae041ee6a6b
|