Skip to main content

APAAI Protocol Python SDK — Action → Policy → Evidence

Project description

apaai-client

PyPI version License

Python SDK for APAAI Protocol

Open, vendor-neutral SDK for the APAAI Protocol's Action → Policy → Evidence loop.

  • 📦 Package: apaai
  • 🔌 Protocol: HTTP/JSON (/actions, /evidence, /policy)
  • 🧪 Minimal & testable: Class-based API
  • 🧱 License: Apache-2.0

Install

pip install apaai

Reference server (for local development):

cd server
npm i && npm run dev    # → http://localhost:8787

Quickstart

from apaai import AccountabilityLayer, AccountabilityLayerOptions
import os

# Initialize the accountability layer
apaai = AccountabilityLayer(AccountabilityLayerOptions(
    endpoint="http://localhost:8787",
    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(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 import AccountabilityLayer, AccountabilityLayerOptions, with_action
import os

apaai = AccountabilityLayer(AccountabilityLayerOptions(
    endpoint="http://localhost:8787",
    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 decision
  • evidence(action_id, checks) - Submit evidence for an action
  • policy(action_type?) - Get policy for an action type
  • approve(action_id, approver?) - Approve an action
  • reject(action_id, reason?) - Reject an action
  • get_action(action_id) - Get action details
  • list_actions(filters?) - List actions with filters
  • get_evidence(action_id) - Get evidence for an action
  • set_policy(policy) - Set a policy

Manager Interfaces

  • apaai.policies.evaluate(action_id) - Evaluate policy for an action
  • apaai.policies.enforce(action_type) - Enforce policy for an action type
  • apaai.policies.set(policy) - Set a policy
  • apaai.human.approve(action_id, approver?) - Approve an action
  • apaai.human.reject(action_id, reason?) - Reject an action
  • apaai.evidence.add(action_id, checks) - Add evidence for an action
  • apaai.evidence.get(action_id) - Get evidence for an action
  • apaai.actions.get(action_id) - Get action details
  • apaai.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.2.tar.gz (10.6 kB view details)

Uploaded Source

Built Distribution

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

apaai-0.1.2-py3-none-any.whl (9.8 kB view details)

Uploaded Python 3

File details

Details for the file apaai-0.1.2.tar.gz.

File metadata

  • Download URL: apaai-0.1.2.tar.gz
  • Upload date:
  • Size: 10.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for apaai-0.1.2.tar.gz
Algorithm Hash digest
SHA256 8dad86b3858f2c06837e811f0cd2a0b865275d498fab572368e0fdcafbfc5837
MD5 c137570f959b12b3d2e84582627ab7e9
BLAKE2b-256 656d3dc2ebba3b72aaaed78c2fb46ac442f499a4c9b9e0d80c3e5f4c06380d89

See more details on using hashes here.

File details

Details for the file apaai-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: apaai-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 9.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for apaai-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 26e5fa2fde9073d3eb35d6428ff7af9cd42af92415a8f559c5f6707c692169da
MD5 5b9f39c14aec3ea3d75d6efaa1b8cd19
BLAKE2b-256 dc048a5e45c9d84053a2153db9d3c39e8bad1643c10da3bfa4aa759acd5dc73a

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