agentseal-gateframe 1.0.0__tar.gz

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.
Files changed (42) hide show
  1. agentseal_gateframe-1.0.0/PKG-INFO +25 -0
  2. agentseal_gateframe-1.0.0/agentseal/__init__.py +43 -0
  3. agentseal_gateframe-1.0.0/agentseal/chain.py +194 -0
  4. agentseal_gateframe-1.0.0/agentseal/export.py +473 -0
  5. agentseal_gateframe-1.0.0/agentseal/integrations/__init__.py +0 -0
  6. agentseal_gateframe-1.0.0/agentseal/integrations/autogen_hook.py +135 -0
  7. agentseal_gateframe-1.0.0/agentseal/integrations/crewai_callback.py +127 -0
  8. agentseal_gateframe-1.0.0/agentseal/integrations/langchain_callback.py +127 -0
  9. agentseal_gateframe-1.0.0/agentseal/policies.py +215 -0
  10. agentseal_gateframe-1.0.0/agentseal/profiles/__init__.py +1 -0
  11. agentseal_gateframe-1.0.0/agentseal/profiles/adverse_action.py +326 -0
  12. agentseal_gateframe-1.0.0/agentseal/schema.py +149 -0
  13. agentseal_gateframe-1.0.0/agentseal/setup.py +2 -0
  14. agentseal_gateframe-1.0.0/agentseal/wrapper.py +303 -0
  15. agentseal_gateframe-1.0.0/agentseal_gateframe.egg-info/PKG-INFO +25 -0
  16. agentseal_gateframe-1.0.0/agentseal_gateframe.egg-info/SOURCES.txt +40 -0
  17. agentseal_gateframe-1.0.0/agentseal_gateframe.egg-info/dependency_links.txt +1 -0
  18. agentseal_gateframe-1.0.0/agentseal_gateframe.egg-info/requires.txt +10 -0
  19. agentseal_gateframe-1.0.0/agentseal_gateframe.egg-info/top_level.txt +4 -0
  20. agentseal_gateframe-1.0.0/api/__init__.py +0 -0
  21. agentseal_gateframe-1.0.0/api/auth.py +86 -0
  22. agentseal_gateframe-1.0.0/api/main.py +379 -0
  23. agentseal_gateframe-1.0.0/api/main_bkp200526.py +299 -0
  24. agentseal_gateframe-1.0.0/api/main_old.py +64 -0
  25. agentseal_gateframe-1.0.0/api/routes/__init__.py +0 -0
  26. agentseal_gateframe-1.0.0/api/routes/batch_sign.py +300 -0
  27. agentseal_gateframe-1.0.0/api/routes/chain_verify.py +213 -0
  28. agentseal_gateframe-1.0.0/api/routes/claims_reconstruct.py +434 -0
  29. agentseal_gateframe-1.0.0/api/routes/dpr_registry.py +217 -0
  30. agentseal_gateframe-1.0.0/api/routes/evidence_pack.py +148 -0
  31. agentseal_gateframe-1.0.0/api/routes/sign.py +119 -0
  32. agentseal_gateframe-1.0.0/api/routes/validate.py +108 -0
  33. agentseal_gateframe-1.0.0/core/__init__.py +0 -0
  34. agentseal_gateframe-1.0.0/core/dpr.py +173 -0
  35. agentseal_gateframe-1.0.0/core/reason_codes.py +873 -0
  36. agentseal_gateframe-1.0.0/core/signing.py +221 -0
  37. agentseal_gateframe-1.0.0/models/__init__.py +0 -0
  38. agentseal_gateframe-1.0.0/models/database.py +243 -0
  39. agentseal_gateframe-1.0.0/models/database_old.py +93 -0
  40. agentseal_gateframe-1.0.0/models/schemas.py +184 -0
  41. agentseal_gateframe-1.0.0/setup.cfg +4 -0
  42. agentseal_gateframe-1.0.0/setup.py +22 -0
@@ -0,0 +1,25 @@
1
+ Metadata-Version: 2.4
2
+ Name: agentseal-gateframe
3
+ Version: 1.0.0
4
+ Summary: GateFrame AgentSeal — Cryptographic evidence receipts for AI agent decisions
5
+ Home-page: https://gateframe-api.netlify.app
6
+ Author: Shankar Anand
7
+ Author-email: shankar@gateframe.io
8
+ Requires-Python: >=3.9
9
+ Requires-Dist: requests>=2.28
10
+ Provides-Extra: langchain
11
+ Requires-Dist: langchain-core>=0.1; extra == "langchain"
12
+ Provides-Extra: autogen
13
+ Requires-Dist: autogen-agentchat>=0.4; extra == "autogen"
14
+ Provides-Extra: crewai
15
+ Requires-Dist: crewai>=0.28; extra == "crewai"
16
+ Dynamic: author
17
+ Dynamic: author-email
18
+ Dynamic: description
19
+ Dynamic: home-page
20
+ Dynamic: provides-extra
21
+ Dynamic: requires-dist
22
+ Dynamic: requires-python
23
+ Dynamic: summary
24
+
25
+ Ed25519 + SHA-256 Merkle chain. EU AI Act Art. 12. ECOA Reg B. DIFC Reg 10. Patent Pending USPTO 64/067,547.
@@ -0,0 +1,43 @@
1
+ """
2
+ AgentSeal by GateFrame
3
+ Cryptographic evidence receipts for regulated AI agents.
4
+ One line of code. Any framework. Any jurisdiction.
5
+
6
+ "Logs tell you what happened. GateFrame proves what AI did."
7
+
8
+ Quickstart:
9
+ from agentseal import GateFrameClient
10
+
11
+ client = GateFrameClient(
12
+ api_key="sk-ant-...",
13
+ agent_id="loan-underwriter-v3",
14
+ regulatory_framework="ECOA",
15
+ )
16
+ chain = client.start_session(session_id="APP-2026-90412")
17
+
18
+ response = client.messages_create(
19
+ model="claude-opus-4-5",
20
+ messages=[{"role": "user", "content": "Evaluate this application..."}],
21
+ max_tokens=1024,
22
+ )
23
+
24
+ evidence = client.get_evidence()
25
+ verification = client.verify()
26
+ # {"valid": True, "total_records": 3}
27
+ """
28
+
29
+ from .schema import AgentAction
30
+ from .chain import EvidenceChain
31
+ from .wrapper import GateFrameClient
32
+ from .policies import SEED_POLICIES, PolicyEngine, CompliancePolicy
33
+
34
+ __version__ = "0.1.0"
35
+ __author__ = "Shankar Anand <shankar@gateframe.io>"
36
+ __all__ = [
37
+ "AgentAction",
38
+ "EvidenceChain",
39
+ "GateFrameClient",
40
+ "SEED_POLICIES",
41
+ "PolicyEngine",
42
+ "CompliancePolicy",
43
+ ]
@@ -0,0 +1,194 @@
1
+ """
2
+ agentseal/chain.py
3
+ EvidenceChain — append-only, hash-linked sequence of AgentActions.
4
+ A single bit-flip anywhere breaks verify_chain().
5
+ This is the artifact regulators verify.
6
+ """
7
+
8
+ from dataclasses import asdict
9
+ from datetime import datetime, timezone
10
+ from typing import Optional, List
11
+ import json
12
+ import uuid
13
+
14
+ from .schema import AgentAction
15
+
16
+
17
+ class EvidenceChain:
18
+ """
19
+ Append-only, hash-linked chain of AgentActions.
20
+
21
+ Each record's prev_hash points to the previous record's record_hash.
22
+ The chain is tamper-evident: any modification anywhere invalidates
23
+ all subsequent links and is detected by verify_chain().
24
+
25
+ Usage:
26
+ chain = EvidenceChain(chain_id="APP-2026-90412", agent_id="underwriter-v3")
27
+ action = chain.record(
28
+ action_type="CREDIT_DENIAL",
29
+ action_payload={"dti": 0.48, "utilization": 0.82},
30
+ outcome={"decision": "denied"},
31
+ regulatory_context={"framework": "ECOA", "evidence_format": "CFPB_MODEL_C1"}
32
+ )
33
+ result = chain.verify_chain()
34
+ # {"valid": True, "total_records": 1, "broken_at": None}
35
+ """
36
+
37
+ SCHEMA_VERSION = "gateframe-agentseal-v1"
38
+
39
+ def __init__(self, chain_id: Optional[str] = None, agent_id: str = ""):
40
+ self.chain_id: str = chain_id or str(uuid.uuid4())
41
+ self.agent_id: str = agent_id
42
+ self.records: List[AgentAction] = []
43
+ self.created_at: str = datetime.now(timezone.utc).isoformat()
44
+ self._session_metadata: dict = {}
45
+
46
+ # ── Core API ──────────────────────────────────────────────────────────────
47
+
48
+ def record(
49
+ self,
50
+ action_type: str,
51
+ action_payload: dict,
52
+ outcome: dict,
53
+ regulatory_context: Optional[dict] = None,
54
+ reasoning: Optional[list] = None,
55
+ agent_version: str = "",
56
+ authorized_by: str = "",
57
+ authorized_at: str = "",
58
+ operator_id: str = "",
59
+ operator_name: str = "",
60
+ institution_id: str = "",
61
+ institution_name: str = "",
62
+ delegation_present: bool = False,
63
+ decision_confidence: float = 0.0,
64
+ input_hash: Optional[str] = None,
65
+ ) -> AgentAction:
66
+ """
67
+ Append a new evidence record to the chain.
68
+ Automatically sets prev_hash to link it to the previous record.
69
+ Calls .seal() to compute and store record_hash before appending.
70
+ Returns the sealed AgentAction.
71
+ """
72
+ prev_hash = self.records[-1].record_hash if self.records else None
73
+
74
+ action = AgentAction(
75
+ agent_id=self.agent_id,
76
+ agent_version=agent_version,
77
+ action_type=action_type,
78
+ action_payload=action_payload,
79
+ outcome=outcome,
80
+ decision_confidence=decision_confidence,
81
+ authorized_by=authorized_by,
82
+ authorized_at=authorized_at,
83
+ operator_id=operator_id,
84
+ operator_name=operator_name,
85
+ institution_id=institution_id,
86
+ institution_name=institution_name,
87
+ delegation_present=delegation_present,
88
+ regulatory_context=regulatory_context or {
89
+ "framework": "DORA",
90
+ "specific_articles": ["Article 8(1)"],
91
+ "evidence_format": "DORA_ICT",
92
+ "policy_version": "",
93
+ },
94
+ reasoning=reasoning or [],
95
+ prev_hash=prev_hash,
96
+ input_hash=input_hash,
97
+ ).seal()
98
+
99
+ self.records.append(action)
100
+ return action
101
+
102
+ def set_metadata(self, **kwargs) -> None:
103
+ """Attach arbitrary session-level metadata (not part of the hash chain)."""
104
+ self._session_metadata.update(kwargs)
105
+
106
+ # ── Verification ──────────────────────────────────────────────────────────
107
+
108
+ def verify_chain(self) -> dict:
109
+ """
110
+ Verify the integrity of every record and every link in the chain.
111
+
112
+ Returns:
113
+ {
114
+ "valid": bool,
115
+ "total_records": int,
116
+ "broken_at": int | None, # index of first broken record
117
+ "reason": str | None,
118
+ }
119
+
120
+ A regulator calls this. Green means the evidence is admissible.
121
+ Red means something was modified after signing.
122
+ """
123
+ for i, record in enumerate(self.records):
124
+ # 1. Verify record self-integrity
125
+ if not record.verify():
126
+ return {
127
+ "valid": False,
128
+ "total_records": len(self.records),
129
+ "broken_at": i,
130
+ "reason": "record_hash_mismatch",
131
+ "action_id": record.action_id,
132
+ }
133
+ # 2. Verify chain link
134
+ if i > 0:
135
+ expected_prev = self.records[i - 1].record_hash
136
+ if record.prev_hash != expected_prev:
137
+ return {
138
+ "valid": False,
139
+ "total_records": len(self.records),
140
+ "broken_at": i,
141
+ "reason": "chain_link_broken",
142
+ "action_id": record.action_id,
143
+ }
144
+
145
+ return {
146
+ "valid": True,
147
+ "total_records": len(self.records),
148
+ "broken_at": None,
149
+ "reason": None,
150
+ }
151
+
152
+ # ── Export ────────────────────────────────────────────────────────────────
153
+
154
+ def export_for_regulator(self) -> dict:
155
+ """
156
+ Full examiner-ready export.
157
+ This is what you hand to a regulator, an auditor, or a law firm.
158
+ """
159
+ return {
160
+ "schema_version": self.SCHEMA_VERSION,
161
+ "chain_id": self.chain_id,
162
+ "agent_id": self.agent_id,
163
+ "created_at": self.created_at,
164
+ "exported_at": datetime.now(timezone.utc).isoformat(),
165
+ "chain_integrity": self.verify_chain(),
166
+ "record_count": len(self.records),
167
+ "regulatory_coverage": self._coverage_summary(),
168
+ "session_metadata": self._session_metadata,
169
+ "records": [asdict(r) for r in self.records],
170
+ }
171
+
172
+ def export_json(self, indent: int = 2) -> str:
173
+ return json.dumps(self.export_for_regulator(), indent=indent, default=str)
174
+
175
+ def _coverage_summary(self) -> dict:
176
+ """Count records grouped by regulatory framework."""
177
+ frameworks: dict = {}
178
+ for r in self.records:
179
+ fw = r.regulatory_context.get("framework", "UNKNOWN")
180
+ frameworks[fw] = frameworks.get(fw, 0) + 1
181
+ return frameworks
182
+
183
+ # ── Convenience ───────────────────────────────────────────────────────────
184
+
185
+ def __len__(self) -> int:
186
+ return len(self.records)
187
+
188
+ def __repr__(self) -> str:
189
+ integrity = self.verify_chain()
190
+ return (
191
+ f"EvidenceChain(chain_id={self.chain_id!r}, "
192
+ f"records={len(self.records)}, "
193
+ f"valid={integrity['valid']})"
194
+ )