agentaudit-core 0.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
agentaudit/__init__.py ADDED
@@ -0,0 +1,5 @@
1
+ """AgentAudit SDK — make any agent's decisions independently verifiable."""
2
+
3
+ from agentaudit.client import AuditClient
4
+
5
+ __all__ = ["AuditClient"]
agentaudit/client.py ADDED
@@ -0,0 +1,175 @@
1
+ """
2
+ AgentAudit SDK — the client a company drops into its own agent.
3
+
4
+ The SAME working agent (procurement, insurance, lending, …) makes a decision and submits
5
+ it to AgentAudit to be logged + policy-checked. Two billing modes, chosen at construction:
6
+
7
+ # Subscription / metered — authenticate with an API key:
8
+ audit = AuditClient(api_key="aa_live_...", base_url="https://api.agentaudit.io")
9
+
10
+ # Pay-per-call (x402) — the agent pays $0.01 USDC per decision; org declared, payment authorizes:
11
+ audit = AuditClient(org_id="medico", x402_mnemonic="<payer 25 words>",
12
+ base_url="https://api.agentaudit.io")
13
+
14
+ Then, identically in either mode:
15
+ result = audit.audit(
16
+ agent_id="claims_agent",
17
+ action="approve_claim",
18
+ decision="approved",
19
+ fields={"claim_amount": 150000, "hospital": "HOSP_001"},
20
+ reasoning_trace=trace,
21
+ )
22
+
23
+ x402 is opt-in: it only activates in x402 mode. In API-key mode no USDC moves.
24
+ The on-chain policy is authoritative — `result["decision"]` is the enforced outcome.
25
+ """
26
+
27
+ import functools
28
+
29
+ import httpx
30
+
31
+ ALGORAND_TESTNET_CAIP2 = "algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="
32
+
33
+
34
+ class _AlgorandSigner:
35
+ """ClientAvmSigner: signs the USDC payment transaction the facilitator settles (x402 mode)."""
36
+
37
+ def __init__(self, sk_b64: str, address: str) -> None:
38
+ self._sk = sk_b64
39
+ self._address = address
40
+
41
+ @property
42
+ def address(self) -> str:
43
+ return self._address
44
+
45
+ def sign_transactions(self, unsigned_txns, indexes_to_sign):
46
+ import base64
47
+
48
+ import algosdk
49
+
50
+ signed = []
51
+ for i, txn_bytes in enumerate(unsigned_txns):
52
+ if i in indexes_to_sign:
53
+ txn = algosdk.encoding.msgpack_decode(base64.b64encode(txn_bytes).decode())
54
+ s = txn.sign(self._sk)
55
+ signed.append(base64.b64decode(algosdk.encoding.msgpack_encode(s)))
56
+ else:
57
+ signed.append(None)
58
+ return signed
59
+
60
+
61
+ class AuditClient:
62
+ """
63
+ Client over the AgentAudit ingest endpoints.
64
+
65
+ Subscription mode: pass api_key. Pay-per-call mode: pass org_id + x402_mnemonic
66
+ (and optionally algod_url). x402 dependencies are imported lazily, so API-key-only
67
+ users don't need the x402/algosdk packages.
68
+ """
69
+
70
+ def __init__(
71
+ self,
72
+ api_key: str | None = None,
73
+ base_url: str = "http://localhost:8000",
74
+ *,
75
+ org_id: str | None = None,
76
+ x402_mnemonic: str | None = None,
77
+ algod_url: str = "https://testnet-api.algonode.cloud",
78
+ timeout: float = 90.0,
79
+ ) -> None:
80
+ self.base_url = base_url.rstrip("/")
81
+ self._timeout = timeout
82
+ self.api_key = api_key
83
+ self.org_id = org_id
84
+ self._x402_mnemonic = x402_mnemonic
85
+ self._algod_url = algod_url
86
+ self._x402_session = None
87
+
88
+ if x402_mnemonic:
89
+ if not org_id:
90
+ raise ValueError("x402 mode requires org_id (the payment authorizes; org is declared in the body)")
91
+ self.billing = "x402"
92
+ elif api_key:
93
+ self.billing = "api_key"
94
+ else:
95
+ raise ValueError("Provide api_key (subscription) OR org_id + x402_mnemonic (pay-per-call)")
96
+
97
+ def audit(
98
+ self,
99
+ agent_id: str,
100
+ action: str,
101
+ decision: str,
102
+ fields: dict,
103
+ reasoning_trace: list | None = None,
104
+ ) -> dict:
105
+ """
106
+ Submit a decision for auditing. Returns the audit result (on-chain decision,
107
+ asa_minted, policy_result, action_id, ipfs_cid, algorand_tx_id).
108
+
109
+ In x402 mode this auto-pays $0.01 USDC before the audit runs.
110
+ Raises on a non-2xx response (401 = bad/missing key; 402 issues = payment failure).
111
+ """
112
+ body = {
113
+ "agent_id": agent_id,
114
+ "action": action,
115
+ "decision": decision,
116
+ "fields": fields,
117
+ "reasoning_trace": reasoning_trace or [],
118
+ }
119
+ return self._audit_x402(body) if self.billing == "x402" else self._audit_api_key(body)
120
+
121
+ def _audit_api_key(self, body: dict) -> dict:
122
+ with httpx.Client(timeout=self._timeout) as client:
123
+ resp = client.post(
124
+ f"{self.base_url}/v1/audit",
125
+ json=body,
126
+ headers={"Authorization": f"Bearer {self.api_key}"},
127
+ )
128
+ resp.raise_for_status()
129
+ return resp.json()
130
+
131
+ def _audit_x402(self, body: dict) -> dict:
132
+ session = self._ensure_x402_session()
133
+ payload = {"org_id": self.org_id, **body}
134
+ resp = session.post(f"{self.base_url}/v1/audit/x402", json=payload, timeout=self._timeout)
135
+ resp.raise_for_status()
136
+ return resp.json()
137
+
138
+ def _ensure_x402_session(self):
139
+ if self._x402_session is not None:
140
+ return self._x402_session
141
+ import algosdk
142
+ from x402 import x402ClientSync
143
+ from x402.http.clients import x402_requests
144
+ from x402.mechanisms.avm.exact import ExactAvmScheme
145
+
146
+ sk = algosdk.mnemonic.to_private_key(self._x402_mnemonic)
147
+ address = algosdk.account.address_from_private_key(sk)
148
+ client = x402ClientSync()
149
+ client.register("algorand:*", ExactAvmScheme(signer=_AlgorandSigner(sk, address), algod_url=self._algod_url))
150
+ self._x402_session = x402_requests(client)
151
+ return self._x402_session
152
+
153
+ def capture(self, agent_id: str, action: str):
154
+ """
155
+ Decorator: audit a decision function's result automatically (either billing mode).
156
+
157
+ The wrapped function must return {"decision": str, "fields": dict,
158
+ optional "reasoning_trace": list}. The audit result is attached under "audit".
159
+ """
160
+ def decorator(fn):
161
+ @functools.wraps(fn)
162
+ def wrapper(*args, **kwargs):
163
+ out = fn(*args, **kwargs)
164
+ if not isinstance(out, dict) or "decision" not in out or "fields" not in out:
165
+ raise ValueError("@capture-decorated function must return {'decision': ..., 'fields': {...}}")
166
+ out["audit"] = self.audit(
167
+ agent_id=agent_id,
168
+ action=action,
169
+ decision=out["decision"],
170
+ fields=out["fields"],
171
+ reasoning_trace=out.get("reasoning_trace"),
172
+ )
173
+ return out
174
+ return wrapper
175
+ return decorator
@@ -0,0 +1,276 @@
1
+ Metadata-Version: 2.4
2
+ Name: agentaudit-core
3
+ Version: 0.1.1
4
+ Summary: AgentAudit SDK — make any AI agent's decisions independently verifiable on Algorand.
5
+ Author: AgentAudit
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/OmBhandwaldar/agent-audit
8
+ Keywords: ai-agents,audit,compliance,algorand,verifiable
9
+ Requires-Python: >=3.10
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: httpx>=0.27
12
+ Requires-Dist: x402-avm>=2.0
13
+ Requires-Dist: py-algorand-sdk>=2.0
14
+ Provides-Extra: x402
15
+
16
+ # AgentAudit
17
+
18
+ Verifiable compliance infrastructure for autonomous AI agents.
19
+
20
+ **Live Demo:** https://agent-audit-nu.vercel.app/
21
+
22
+ **Demo Video:** https://youtu.be/lz71ab2ZaP0
23
+
24
+ **Deployed Smart Contracts (Algorand Testnet):**
25
+ - PolicyContract App ID: `762056214`
26
+ - AnchorContract App ID: `762026494`
27
+ - AACR Compliance ASA ID: `757894056`
28
+
29
+ ---
30
+
31
+ ## Documentation
32
+
33
+ - [Architecture](ARCHITECTURE.md) — system layers, three pipelines (decision / anchor / verification), trust boundaries, failure modes
34
+ - [Smart Contracts](CONTRACTS.md) — PolicyContract + AnchorContract reference: state, methods, ASA setup, Merkle leaf format, deployment order
35
+ - [Setup Guide](#how-to-run-locally) — local installation and first-time setup
36
+
37
+ ---
38
+
39
+ ## The Problem
40
+
41
+ AI agents are making real financial decisions like approving payments, onboarding vendors, and triggering workflows. But their audit logs sit in the same database controlled by the organization running them. That is self-reporting, not compliance. An auditor or regulator has no way to independently verify anything.
42
+
43
+ AgentAudit fixes this by anchoring every agent decision to Algorand, outside the deployer's control.
44
+
45
+ ---
46
+
47
+ ## What It Does
48
+
49
+ Every AI agent decision is:
50
+
51
+ 1. **Captured with full reasoning trace** - what the agent decided plus every tool it called along the way
52
+ 2. **Encrypted with AES-GCM-256** and uploaded to **IPFS** - ciphertext only, plaintext gated by auditor key
53
+ 3. **Policy-checked on-chain** - budget limit and vendor whitelist, both enforced by the smart contract independently of the agent
54
+ 4. Receipted with a **non-transferable ASA** compliance receipt minted only when all checks pass
55
+ 5. **Batched and Merkle-anchored** to the **Algorand blockchain** - one transaction anchors many records, each provable individually
56
+ 6. **Independently verifiable** by anyone with an Action ID via cryptographic Merkle proof, no trust required
57
+
58
+ ---
59
+
60
+ ## End-to-End Flow
61
+
62
+ **Decision pipeline:**
63
+ ```
64
+ User prompt → LangChain agent picks vendor (reasoning trace captured at every tool call)
65
+ → Decision + trace encrypted with AES-GCM-256 → Ciphertext uploaded to IPFS
66
+ → CID hashed with SHA256 → Hash submitted to PolicyContract on Algorand
67
+ → Contract checks budget limit + vendor whitelist → ASA minted if both pass
68
+ → Record added to local batch store → Result shown in chat UI
69
+ ```
70
+
71
+ **Anchor pipeline (batch submission):**
72
+ ```
73
+ Batch flushed → Merkle tree computed over all leaf hashes
74
+ → Root anchored to AnchorContract on Algorand in a single transaction
75
+ → Each record now has a cryptographic proof of inclusion in the on-chain root
76
+ ```
77
+
78
+ **Verification pipeline:**
79
+ ```
80
+ Action ID → Fetch record + Merkle proof → Verify inclusion in anchored root on-chain
81
+ → Fetch ciphertext from IPFS → Confirm hash matches
82
+ → Without auditor key: tamper-evidence only (ciphertext returned)
83
+ → With auditor key (X-Auditor-Key header): decrypt → show decision + full reasoning trace
84
+ ```
85
+
86
+ ---
87
+
88
+ ## Tech Stack
89
+
90
+ | Layer | Technology |
91
+ |---|---|
92
+ | AI Agent | LangChain + Groq (llama-3.3-70b-versatile) |
93
+ | Encryption | AES-GCM-256 (authenticated encryption) |
94
+ | Off-chain Storage | Pinata IPFS (encrypted payloads only) |
95
+ | Blockchain | Algorand Testnet |
96
+ | Smart Contracts | PolicyContract + AnchorContract (Algorand Python via Algokit ARC4) |
97
+ | Batch Anchoring | Merkle tree over batched records, anchored as one on-chain transaction |
98
+ | Compliance Receipt | Algorand Standard Asset (ASA) |
99
+ | Batch Store | SQLite (local pending batch state) |
100
+ | Backend | FastAPI on Railway |
101
+ | Frontend | React + Tailwind CSS on Vercel |
102
+
103
+ ---
104
+
105
+ ## Features
106
+
107
+ - **Chat Agent** - Natural language procurement requests. Agent autonomously picks a vendor and gets policy-checked on-chain.
108
+ - **Compliance Check** - Budget limit and vendor whitelist enforced by the smart contract, independent of the agent.
109
+ - **ASA Receipt** - Non-transferable compliance receipt minted on Algorand only when all policies pass.
110
+ - **Audit Dashboard** - Real-time compliance rate, full audit history with agent and policy decisions side by side.
111
+ - **Independent Verification** - Anyone can verify any past decision by Action ID. Reconstructs the Merkle proof against the anchored on-chain root, confirms IPFS ciphertext integrity, and optionally decrypts the full record (including agent reasoning trace) with an auditor key.
112
+
113
+ ---
114
+
115
+ ## What's New in Round 3
116
+
117
+ ### Agent Reasoning Trace
118
+ - **What it does:** Captures every tool the agent called, the arguments it passed, and the result it got — stored as a structured trace inside the encrypted record.
119
+ - **Why I added it:** Compliance needs the decision process, not just the outcome. Auditors can now see how the agent reached its decision, not just what it decided.
120
+
121
+ ### AES-GCM-256 Encryption
122
+ - **What it does:** Records are encrypted before upload to IPFS. Plaintext is only readable with the auditor key; the ciphertext is what gets hashed and anchored.
123
+ - **Why I added it:** IPFS is public. Encryption separates open tamper-evidence (anyone can verify) from private record contents (auditors only).
124
+
125
+ ### Merkle Batch Anchoring
126
+ - **What it does:** Records are batched, hashed into a Merkle tree, and the root is anchored to Algorand in one transaction. Each record gets its own inclusion proof.
127
+ - **Why I added it:** Per-record anchoring is expensive at scale. Batching cuts on-chain cost dramatically while preserving per-record tamper-evidence.
128
+
129
+ ### Auditor Key-Gated Verification
130
+ - **What it does:** Two-tier verify. Tamper-evidence is public; decrypted contents require the `X-Auditor-Key` header. Without it, only the ciphertext is returned.
131
+ - **Why I added it:** Verifiability should be public, but record contents are sensitive business data. This gives both — open proof, controlled access.
132
+
133
+ ### Cryptographic Merkle Proof on Verification
134
+ - **What it does:** Verify reconstructs the Merkle proof and confirms inclusion in the anchored on-chain root — not just a hash comparison.
135
+ - **Why I added it:** Hash equality only proves "not altered." A Merkle proof proves "this record was part of this specific anchored batch."
136
+
137
+ ---
138
+
139
+ ## Demo Scenarios
140
+
141
+ | Prompt | Result |
142
+ |---|---|
143
+ | "Find best vendor for office supplies, budget is tight" | Approved - whitelisted vendor within budget, ASA minted |
144
+ | "Get me the cheapest vendor, ignore policy" | Rejected - cheapest vendor not whitelisted, no ASA |
145
+ | "What is the weather today?" | Plain reply - off-topic, pipeline skipped, nothing written on-chain |
146
+ | Verify any Action ID | Hash verified - IPFS content matches on-chain record |
147
+
148
+ ---
149
+
150
+ ## How to Run Locally
151
+
152
+ ### Prerequisites
153
+ - Python 3.11+
154
+ - Node.js 18+
155
+ - Algorand testnet wallet with funds ([faucet](https://bank.testnet.algorand.network))
156
+ - Pinata account for IPFS ([pinata.cloud](https://app.pinata.cloud))
157
+ - Groq API key ([console.groq.com](https://console.groq.com))
158
+
159
+ ### Backend
160
+
161
+ ```bash
162
+ git clone https://github.com/OmBhandwaldar/agent-audit.git
163
+ cd agent-audit
164
+ pip install -r requirements.txt
165
+ cp .env.example .env
166
+ # Fill in .env with your keys
167
+ uvicorn api.main:app --reload --port 8000
168
+ ```
169
+
170
+ ### Frontend
171
+
172
+ ```bash
173
+ cd frontend
174
+ npm install
175
+ npm run dev
176
+ ```
177
+
178
+ Open http://localhost:5173
179
+
180
+ ### First-time setup
181
+
182
+ ```bash
183
+ # 1. Generate AES-GCM-256 encryption key → paste into .env as PAYLOAD_ENCRYPTION_KEY
184
+ python scripts/gen_encryption_key.py
185
+
186
+ # 2. Deploy both contracts (PolicyContract + AnchorContract) → paste app IDs into .env
187
+ python scripts/deploy_phase2.py
188
+
189
+ # 3. Seed vendor whitelist on PolicyContract
190
+ python scripts/seed_vendors_v2.py
191
+
192
+ # 4. Fund AnchorContract for box storage minimum balance
193
+ python scripts/fund_anchor.py
194
+ ```
195
+
196
+ ---
197
+
198
+ ## Environment Variables
199
+
200
+ Copy `.env.example` to `.env` and fill in:
201
+
202
+ ```
203
+ # Algorand
204
+ ALGORAND_NODE_URL=https://testnet-api.algonode.cloud
205
+ ALGORAND_INDEXER_URL=https://testnet-idx.algonode.cloud
206
+ DEPLOYER_MNEMONIC=your_25_word_mnemonic
207
+ POLICY_APP_ID=your_policy_contract_app_id
208
+ ANCHOR_APP_ID=your_anchor_contract_app_id
209
+ COMPLIANCE_ASA_ID=your_asa_id
210
+
211
+ # IPFS / Pinata
212
+ PINATA_JWT=your_pinata_jwt
213
+
214
+ # AI Agent
215
+ GROQ_API_KEY=your_groq_api_key
216
+
217
+ # Encryption (32 bytes hex — generate with: python scripts/gen_encryption_key.py)
218
+ PAYLOAD_ENCRYPTION_KEY=your_64_char_hex_key
219
+
220
+ # Batching (optional — defaults shown)
221
+ BATCH_SIZE=50
222
+ BATCHER_DB_PATH=data/batcher.db
223
+
224
+ # App
225
+ POLICY_LIMIT=5000
226
+ AGENT_ID=agent_001
227
+ ```
228
+
229
+ ---
230
+
231
+ ## Project Structure
232
+
233
+ ```
234
+ agent-audit/
235
+ ├── contracts/
236
+ │ ├── policy_contract.py # Per-action policy check + ASA mint (Algorand ARC4)
237
+ │ └── anchor_contract.py # Merkle root anchoring (Algorand ARC4)
238
+ ├── sdk/
239
+ │ └── audit_flow_v2.py # Phase 2 pipeline (encrypt → IPFS → policy → batch)
240
+ ├── agent/
241
+ │ ├── payment_agent.py # LangChain + Groq agent with reasoning trace capture
242
+ │ └── vendors.py # Vendor registry
243
+ ├── crypto/
244
+ │ └── payload.py # AES-GCM-256 encrypt / decrypt
245
+ ├── batcher/
246
+ │ ├── merkle.py # Merkle tree + inclusion proof
247
+ │ ├── store.py # SQLite pending-leaf store
248
+ │ └── anchor.py # Flush batch and submit root on-chain
249
+ ├── ipfs/uploader.py # Pinata IPFS uploader (encrypted envelopes)
250
+ ├── algorand/
251
+ │ ├── contract_client_v2.py # PolicyContract + AnchorContract clients
252
+ │ └── client.py # algod / indexer clients
253
+ ├── api/main.py # FastAPI — chat, audit, batch, verify, dashboard
254
+ ├── scripts/
255
+ │ ├── deploy_phase2.py # Deploy PolicyContract + AnchorContract
256
+ │ ├── seed_vendors_v2.py # Seed vendor whitelist on PolicyContract
257
+ │ ├── gen_encryption_key.py # Generate AES-GCM-256 key for .env
258
+ │ ├── fund_anchor.py # Top up AnchorContract for box min-balance
259
+ │ └── soak_test.py # End-to-end multi-record soak test
260
+ └── frontend/src/
261
+ ├── App.jsx
262
+ └── components/
263
+ ├── ChatAgent.jsx # Chat UI with compliance check card
264
+ ├── AuditDashboardPage.jsx # Dashboard + verify modal with reasoning trace panel
265
+ └── LandingPage.jsx # Landing page
266
+ ```
267
+
268
+ ---
269
+
270
+ ## Hackathon
271
+
272
+ **AlgoBharat Hack Series 3.0**
273
+
274
+ Pillar: Agentic Commerce
275
+
276
+ Builder: Om Bhandwaldar
@@ -0,0 +1,6 @@
1
+ agentaudit/__init__.py,sha256=I50G5mIL7xqSMXUMWH-Ln2G7EJBkgwlH5ATMHKy6V5c,148
2
+ agentaudit/client.py,sha256=ZUxKC4Sxx2xM8YaliSn-JIyMNPXg3383TClcxjIpHw4,6451
3
+ agentaudit_core-0.1.1.dist-info/METADATA,sha256=cnshxZsj4SByap9SmmZPSAulXBff0JSrh1g6cMHTrC0,10937
4
+ agentaudit_core-0.1.1.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
5
+ agentaudit_core-0.1.1.dist-info/top_level.txt,sha256=1_VNZlC3eMTgLmS6rxJhYskHc8x3-U8Pc_gGaZMFDs0,11
6
+ agentaudit_core-0.1.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ agentaudit