aegiscore-ai 0.1.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.
@@ -0,0 +1,17 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ Copyright 2026 AegisCore Contributors
6
+
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ you may not use this file except in compliance with the License.
9
+ You may obtain a copy of the License at
10
+
11
+ http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ Unless required by applicable law or agreed to in writing, software
14
+ distributed under the License is distributed on an "AS IS" BASIS,
15
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ See the License for the specific language governing permissions and
17
+ limitations under the License.
@@ -0,0 +1,124 @@
1
+ Metadata-Version: 2.4
2
+ Name: aegiscore-ai
3
+ Version: 0.1.0
4
+ Summary: Deterministic Agent Governance Gateway - Zero-Trust Policy Enclave for AI Agents
5
+ Author: Sandeep Hipparagi & AegisCore Contributors
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/Sandeep-Hipparagi/aegis-core
8
+ Project-URL: Repository, https://github.com/Sandeep-Hipparagi/aegis-core.git
9
+ Project-URL: Issues, https://github.com/Sandeep-Hipparagi/aegis-core/issues
10
+ Keywords: ai-agent,governance,security,zero-trust,langgraph,openai,mcp,dpdp
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
22
+ Classifier: Topic :: Security
23
+ Requires-Python: >=3.8
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Dynamic: license-file
27
+
28
+ # aegiscore-py
29
+
30
+ Official, zero-dependency Python client for **AegisCore** — the Deterministic Zero-Trust Policy & Cryptographic WORM Audit Gateway for AI Agents.
31
+
32
+ [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
33
+ [![Python Version](https://img.shields.io/badge/python-3.8+-blue.svg)](https://pypi.org/project/aegiscore-ai/)
34
+
35
+ ## Installation
36
+
37
+ ```bash
38
+ pip install aegiscore-ai
39
+ ```
40
+
41
+ *Note: `aegiscore-ai` is 100% zero-dependency, implemented purely using Python's standard library (`urllib.request`, `json`, `dataclasses`).*
42
+
43
+ ## Quick Start
44
+
45
+ ### 1. Direct Tool Proposal Dispatch
46
+
47
+ ```python
48
+ from aegiscore import AegisGateway
49
+
50
+ gateway = AegisGateway("http://localhost:8080")
51
+
52
+ # Dispatch tool intent: evaluates schema, invariants, tokenizes PII, logs WORM audit
53
+ result = gateway.dispatch(
54
+ tool="transfer_funds",
55
+ arguments={"amount": 2500, "recipient": "ACC-PAYROLL"},
56
+ session_id="sess_01"
57
+ )
58
+
59
+ if result.is_success:
60
+ print("Action Approved & Executed:", result.output)
61
+ elif result.requires_hitl:
62
+ print(f"Action escalated to human approval. Ticket ID: {result.ticket_id}")
63
+ else:
64
+ print(f"Action BLOCKED: {result.reason}")
65
+ for violation in result.violations:
66
+ print(f" - {violation}")
67
+ ```
68
+
69
+ ### 2. LangGraph & LangChain Integration
70
+
71
+ ```python
72
+ from aegiscore import AegisGateway
73
+ from aegiscore.integrations import AegisLangGraphWrapper
74
+
75
+ gateway = AegisGateway("http://localhost:8080")
76
+ wrapper = AegisLangGraphWrapper(gateway=gateway)
77
+
78
+ # Wrap any native function or tool
79
+ @wrapper.wrap_tool("query_database", raw_query_func)
80
+ def safe_query_database(query: str):
81
+ return raw_query_func(query)
82
+
83
+ # Calls are intercepted and verified against policy invariants before invocation
84
+ safe_query_database(query="SELECT * FROM users")
85
+ ```
86
+
87
+ ### 3. OpenAI Function Call Interception
88
+
89
+ ```python
90
+ from aegiscore import AegisGateway
91
+ from aegiscore.integrations import AegisOpenAIInterceptor
92
+
93
+ gateway = AegisGateway("http://localhost:8080")
94
+ interceptor = AegisOpenAIInterceptor(gateway=gateway)
95
+
96
+ # In your chat completion loop:
97
+ for tool_call in response.choices[0].message.tool_calls:
98
+ # Evaluates policy and returns tool response dict formatted for OpenAI
99
+ tool_message = interceptor.intercept_tool_call(tool_call)
100
+ messages.append(tool_message)
101
+ ```
102
+
103
+ ### 4. Human-in-the-Loop (HITL) Resolution
104
+
105
+ ```python
106
+ # Check pending ticket and resolve with cryptographic signature
107
+ gateway.resolve_hitl(
108
+ ticket_id="ticket-12345",
109
+ decision="APPROVED",
110
+ signature="sig-supervisor-ed25519"
111
+ )
112
+ ```
113
+
114
+ ### 5. Forensic Cryptographic Ledger Verification
115
+
116
+ ```python
117
+ # Verifies the tamper-evident WORM Merkle chain
118
+ audit = gateway.verify_audit_integrity()
119
+ print(f"Ledger Valid: {audit['isValid']}")
120
+ ```
121
+
122
+ ## License
123
+
124
+ Apache-2.0
@@ -0,0 +1,97 @@
1
+ # aegiscore-py
2
+
3
+ Official, zero-dependency Python client for **AegisCore** — the Deterministic Zero-Trust Policy & Cryptographic WORM Audit Gateway for AI Agents.
4
+
5
+ [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
6
+ [![Python Version](https://img.shields.io/badge/python-3.8+-blue.svg)](https://pypi.org/project/aegiscore-ai/)
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ pip install aegiscore-ai
12
+ ```
13
+
14
+ *Note: `aegiscore-ai` is 100% zero-dependency, implemented purely using Python's standard library (`urllib.request`, `json`, `dataclasses`).*
15
+
16
+ ## Quick Start
17
+
18
+ ### 1. Direct Tool Proposal Dispatch
19
+
20
+ ```python
21
+ from aegiscore import AegisGateway
22
+
23
+ gateway = AegisGateway("http://localhost:8080")
24
+
25
+ # Dispatch tool intent: evaluates schema, invariants, tokenizes PII, logs WORM audit
26
+ result = gateway.dispatch(
27
+ tool="transfer_funds",
28
+ arguments={"amount": 2500, "recipient": "ACC-PAYROLL"},
29
+ session_id="sess_01"
30
+ )
31
+
32
+ if result.is_success:
33
+ print("Action Approved & Executed:", result.output)
34
+ elif result.requires_hitl:
35
+ print(f"Action escalated to human approval. Ticket ID: {result.ticket_id}")
36
+ else:
37
+ print(f"Action BLOCKED: {result.reason}")
38
+ for violation in result.violations:
39
+ print(f" - {violation}")
40
+ ```
41
+
42
+ ### 2. LangGraph & LangChain Integration
43
+
44
+ ```python
45
+ from aegiscore import AegisGateway
46
+ from aegiscore.integrations import AegisLangGraphWrapper
47
+
48
+ gateway = AegisGateway("http://localhost:8080")
49
+ wrapper = AegisLangGraphWrapper(gateway=gateway)
50
+
51
+ # Wrap any native function or tool
52
+ @wrapper.wrap_tool("query_database", raw_query_func)
53
+ def safe_query_database(query: str):
54
+ return raw_query_func(query)
55
+
56
+ # Calls are intercepted and verified against policy invariants before invocation
57
+ safe_query_database(query="SELECT * FROM users")
58
+ ```
59
+
60
+ ### 3. OpenAI Function Call Interception
61
+
62
+ ```python
63
+ from aegiscore import AegisGateway
64
+ from aegiscore.integrations import AegisOpenAIInterceptor
65
+
66
+ gateway = AegisGateway("http://localhost:8080")
67
+ interceptor = AegisOpenAIInterceptor(gateway=gateway)
68
+
69
+ # In your chat completion loop:
70
+ for tool_call in response.choices[0].message.tool_calls:
71
+ # Evaluates policy and returns tool response dict formatted for OpenAI
72
+ tool_message = interceptor.intercept_tool_call(tool_call)
73
+ messages.append(tool_message)
74
+ ```
75
+
76
+ ### 4. Human-in-the-Loop (HITL) Resolution
77
+
78
+ ```python
79
+ # Check pending ticket and resolve with cryptographic signature
80
+ gateway.resolve_hitl(
81
+ ticket_id="ticket-12345",
82
+ decision="APPROVED",
83
+ signature="sig-supervisor-ed25519"
84
+ )
85
+ ```
86
+
87
+ ### 5. Forensic Cryptographic Ledger Verification
88
+
89
+ ```python
90
+ # Verifies the tamper-evident WORM Merkle chain
91
+ audit = gateway.verify_audit_integrity()
92
+ print(f"Ledger Valid: {audit['isValid']}")
93
+ ```
94
+
95
+ ## License
96
+
97
+ Apache-2.0
@@ -0,0 +1,26 @@
1
+ """
2
+ AegisCore Python Client SDK
3
+ Zero-dependency client for deterministic agent governance.
4
+ """
5
+
6
+ from .client import AegisGateway, AegisClient
7
+ from .models import DispatchResult
8
+ from .exceptions import (
9
+ AegisError,
10
+ AegisGatewayError,
11
+ AegisPolicyBlockedError,
12
+ AegisSchemaError,
13
+ AegisHitlRequiredError,
14
+ )
15
+
16
+ __version__ = "0.1.0"
17
+ __all__ = [
18
+ "AegisGateway",
19
+ "AegisClient",
20
+ "DispatchResult",
21
+ "AegisError",
22
+ "AegisGatewayError",
23
+ "AegisPolicyBlockedError",
24
+ "AegisSchemaError",
25
+ "AegisHitlRequiredError",
26
+ ]
@@ -0,0 +1,222 @@
1
+ """
2
+ AegisCore Python Client - Zero-dependency gateway wrapper
3
+ """
4
+
5
+ import json
6
+ import urllib.request
7
+ import urllib.error
8
+ from typing import Any, Dict, List, Optional, Union
9
+ import uuid
10
+
11
+ from .exceptions import (
12
+ AegisGatewayError,
13
+ AegisPolicyBlockedError,
14
+ AegisSchemaError,
15
+ AegisHitlRequiredError,
16
+ )
17
+ from .models import DispatchResult
18
+
19
+
20
+ class AegisGateway:
21
+ """
22
+ Zero-dependency Python client for the AegisCore Deterministic Governance Gateway.
23
+ """
24
+
25
+ def __init__(
26
+ self,
27
+ base_url: str = "http://localhost:8080",
28
+ agent_id: str = "python-agent",
29
+ role: str = "operator",
30
+ default_headers: Optional[Dict[str, str]] = None,
31
+ timeout: float = 30.0,
32
+ ):
33
+ self.base_url = base_url.rstrip("/")
34
+ self.agent_id = agent_id
35
+ self.role = role
36
+ self.default_headers = default_headers or {}
37
+ self.timeout = timeout
38
+
39
+ def _request(
40
+ self,
41
+ method: str,
42
+ path: str,
43
+ data: Optional[Dict[str, Any]] = None,
44
+ headers: Optional[Dict[str, str]] = None,
45
+ ) -> Dict[str, Any]:
46
+ """Internal helper for standard HTTP requests using urllib."""
47
+ url = f"{self.base_url}{path}"
48
+ req_headers = {
49
+ "Content-Type": "application/json",
50
+ "User-Agent": "aegiscore-python/0.1.0",
51
+ **self.default_headers,
52
+ }
53
+ if headers:
54
+ req_headers.update(headers)
55
+
56
+ body_bytes = json.dumps(data).encode("utf-8") if data is not None else None
57
+ req = urllib.request.Request(url, data=body_bytes, headers=req_headers, method=method)
58
+
59
+ try:
60
+ with urllib.request.urlopen(req, timeout=self.timeout) as response:
61
+ resp_text = response.read().decode("utf-8")
62
+ return json.loads(resp_text) if resp_text else {}
63
+ except urllib.error.HTTPError as err:
64
+ err_text = err.read().decode("utf-8") if err.fp else ""
65
+ try:
66
+ parsed = json.loads(err_text)
67
+ except Exception:
68
+ parsed = None
69
+
70
+ # 403 Forbidden is used for BLOCKED actions
71
+ if err.code == 403 and parsed and isinstance(parsed, dict):
72
+ return parsed
73
+
74
+ # 400 Bad Request is used for SCHEMA_ERROR
75
+ if err.code == 400 and parsed and isinstance(parsed, dict) and parsed.get("status") == "SCHEMA_ERROR":
76
+ return parsed
77
+
78
+ raise AegisGatewayError(
79
+ f"AegisCore Gateway HTTP {err.code}: {err.reason} - {err_text}",
80
+ status_code=err.code,
81
+ response_body=err_text,
82
+ ) from err
83
+ except urllib.error.URLError as err:
84
+ raise AegisGatewayError(f"Connection to AegisCore Gateway failed ({url}): {err.reason}") from err
85
+
86
+ def dispatch(
87
+ self,
88
+ tool: str,
89
+ arguments: Optional[Dict[str, Any]] = None,
90
+ session_id: Optional[str] = None,
91
+ agent_id: Optional[str] = None,
92
+ role: Optional[str] = None,
93
+ metadata: Optional[Dict[str, Any]] = None,
94
+ raise_on_blocked: bool = False,
95
+ ) -> DispatchResult:
96
+ """
97
+ Dispatches a proposed tool invocation to AegisCore for invariant checking,
98
+ DPDP PII tokenization, policy evaluation, WORM audit logging, and sandbox execution.
99
+ """
100
+ sid = session_id or f"sess-{uuid.uuid4().hex[:12]}"
101
+ aid = agent_id or self.agent_id
102
+ r = role or self.role
103
+ params = arguments if arguments is not None else {}
104
+
105
+ payload = {
106
+ "tool": tool,
107
+ "parameters": params,
108
+ "metadata": metadata or {},
109
+ "context": {
110
+ "sessionId": sid,
111
+ "agentId": aid,
112
+ "role": r,
113
+ },
114
+ }
115
+
116
+ raw = self._request("POST", "/v1/gateway/dispatch", data=payload)
117
+ status = raw.get("status", "UNKNOWN")
118
+ reason = raw.get("reason")
119
+ violations = raw.get("violations", [])
120
+ challenge = raw.get("challenge")
121
+ audit_entry = raw.get("auditEntry")
122
+
123
+ output = None
124
+ if "execution" in raw and isinstance(raw["execution"], dict):
125
+ output = raw["execution"].get("output")
126
+
127
+ result = DispatchResult(
128
+ status=status,
129
+ intent_id=raw.get("intentId"),
130
+ session_id=sid,
131
+ tool=tool,
132
+ reason=reason,
133
+ output=output,
134
+ violations=violations,
135
+ challenge=challenge,
136
+ audit_entry=audit_entry,
137
+ raw=raw,
138
+ )
139
+
140
+ if raise_on_blocked and status == "BLOCKED":
141
+ raise AegisPolicyBlockedError(
142
+ f"Tool invocation '{tool}' was BLOCKED: {reason}",
143
+ violations=violations,
144
+ raw_result=raw,
145
+ )
146
+
147
+ if raise_on_blocked and status == "SCHEMA_ERROR":
148
+ raise AegisSchemaError(
149
+ f"Tool invocation '{tool}' failed schema validation: {reason}",
150
+ raw_result=raw,
151
+ )
152
+
153
+ return result
154
+
155
+ def evaluate_intent(
156
+ self,
157
+ tool: str,
158
+ parameters: Optional[Dict[str, Any]] = None,
159
+ session_id: Optional[str] = None,
160
+ agent_id: Optional[str] = None,
161
+ role: Optional[str] = None,
162
+ metadata: Optional[Dict[str, Any]] = None,
163
+ ) -> Dict[str, Any]:
164
+ """Submits an intent to /v1/intent/evaluate returning canonical IntentEvaluationResponse."""
165
+ aid = agent_id or self.agent_id
166
+ payload = {
167
+ "tool": tool,
168
+ "parameters": parameters or {},
169
+ "metadata": metadata or {},
170
+ "agent": {
171
+ "agentId": aid,
172
+ "role": role or self.role,
173
+ "sessionId": session_id or f"sess-{uuid.uuid4().hex[:12]}",
174
+ },
175
+ }
176
+ return self._request("POST", "/v1/intent/evaluate", data=payload, headers={"X-Agent-Id": aid})
177
+
178
+ def execute_tool(
179
+ self,
180
+ tool_call_id: str,
181
+ name: str,
182
+ arguments: Union[str, Dict[str, Any]],
183
+ agent_id: Optional[str] = None,
184
+ role: Optional[str] = None,
185
+ ) -> Dict[str, Any]:
186
+ """Proxies an OpenAI tool call to /v1/tools/execute."""
187
+ aid = agent_id or self.agent_id
188
+ payload = {
189
+ "tool_call_id": tool_call_id,
190
+ "name": name,
191
+ "arguments": arguments,
192
+ "agent_id": aid,
193
+ "role": role or self.role,
194
+ }
195
+ return self._request("POST", "/v1/tools/execute", data=payload, headers={"x-agent-id": aid})
196
+
197
+ def resolve_hitl(
198
+ self,
199
+ ticket_id: str,
200
+ decision: str = "APPROVED",
201
+ signature: str = "sig-officer-signature",
202
+ scoped_credentials: Optional[Dict[str, str]] = None,
203
+ ) -> Dict[str, Any]:
204
+ """Resolves an asynchronous Human-in-the-Loop challenge ticket."""
205
+ payload = {
206
+ "decision": decision,
207
+ "approverSignature": signature,
208
+ "scopedCredentials": scoped_credentials or {},
209
+ }
210
+ return self._request("POST", f"/v1/hitl/challenges/{ticket_id}/resolve", data=payload)
211
+
212
+ def verify_audit_integrity(self) -> Dict[str, Any]:
213
+ """Queries the cryptographic WORM ledger to verify Merkle chain integrity."""
214
+ return self._request("GET", "/v1/audit/integrity")
215
+
216
+ def health(self) -> Dict[str, Any]:
217
+ """Checks gateway daemon health."""
218
+ return self._request("GET", "/health")
219
+
220
+
221
+ # Alias for developer ergonomics
222
+ AegisClient = AegisGateway
@@ -0,0 +1,41 @@
1
+ """
2
+ AegisCore Python Exceptions
3
+ """
4
+
5
+ from typing import Any, Dict, List, Optional
6
+
7
+
8
+ class AegisError(Exception):
9
+ """Base exception for all AegisCore errors."""
10
+ pass
11
+
12
+
13
+ class AegisGatewayError(AegisError):
14
+ """Raised when the AegisCore gateway returns an HTTP or network error."""
15
+ def __init__(self, message: str, status_code: Optional[int] = None, response_body: Optional[str] = None):
16
+ super().__init__(message)
17
+ self.status_code = status_code
18
+ self.response_body = response_body
19
+
20
+
21
+ class AegisPolicyBlockedError(AegisError):
22
+ """Raised when an action is blocked by a deterministic policy invariant."""
23
+ def __init__(self, message: str, violations: Optional[List[Dict[str, Any]]] = None, raw_result: Optional[Dict[str, Any]] = None):
24
+ super().__init__(message)
25
+ self.violations = violations or []
26
+ self.raw_result = raw_result or {}
27
+
28
+
29
+ class AegisSchemaError(AegisError):
30
+ """Raised when a tool argument payload fails fail-closed schema validation."""
31
+ def __init__(self, message: str, raw_result: Optional[Dict[str, Any]] = None):
32
+ super().__init__(message)
33
+ self.raw_result = raw_result or {}
34
+
35
+
36
+ class AegisHitlRequiredError(AegisError):
37
+ """Raised when an action requires human-in-the-loop escalation before execution."""
38
+ def __init__(self, message: str, ticket_id: str, challenge: Dict[str, Any]):
39
+ super().__init__(message)
40
+ self.ticket_id = ticket_id
41
+ self.challenge = challenge
@@ -0,0 +1,4 @@
1
+ from .langgraph import AegisLangGraphWrapper
2
+ from .openai import AegisOpenAIInterceptor
3
+
4
+ __all__ = ["AegisLangGraphWrapper", "AegisOpenAIInterceptor"]
@@ -0,0 +1,42 @@
1
+ """
2
+ LangGraph and LangChain Integration for AegisCore
3
+ """
4
+
5
+ from typing import Any, Callable, Dict, Optional
6
+ from ..client import AegisGateway
7
+ from ..exceptions import AegisPolicyBlockedError
8
+
9
+
10
+ class AegisLangGraphWrapper:
11
+ """
12
+ Wraps standard LangChain/LangGraph tools with AegisCore deterministic governance.
13
+ """
14
+
15
+ def __init__(self, gateway: Optional[AegisGateway] = None, gateway_url: str = "http://localhost:8080"):
16
+ self.gateway = gateway or AegisGateway(base_url=gateway_url)
17
+
18
+ def wrap_tool(self, tool_name: str, tool_func: Callable[..., Any]) -> Callable[..., Any]:
19
+ """
20
+ Wraps a Python function/tool so that all calls are evaluated by AegisCore before execution.
21
+ """
22
+ gateway = self.gateway
23
+
24
+ def governed_tool(**kwargs: Any) -> Any:
25
+ # 1. Pre-flight evaluation
26
+ result = gateway.dispatch(tool=tool_name, arguments=kwargs, raise_on_blocked=False)
27
+ if not result.is_success:
28
+ raise AegisPolicyBlockedError(
29
+ f"Action '{tool_name}' was rejected by AegisCore: {result.reason}",
30
+ violations=result.violations,
31
+ raw_result=result.raw
32
+ )
33
+
34
+ # 2. If the gateway executed in sandbox, return that output; otherwise run the wrapped func
35
+ if result.output is not None:
36
+ return result.output
37
+
38
+ return tool_func(**kwargs)
39
+
40
+ governed_tool.__name__ = getattr(tool_func, "__name__", tool_name)
41
+ governed_tool.__doc__ = getattr(tool_func, "__doc__", "")
42
+ return governed_tool
@@ -0,0 +1,61 @@
1
+ """
2
+ OpenAI Tool-Call Interceptor for AegisCore
3
+ """
4
+
5
+ import json
6
+ from typing import Any, Dict, List, Optional
7
+ from ..client import AegisGateway
8
+
9
+
10
+ class AegisOpenAIInterceptor:
11
+ """
12
+ Intercepts and governs OpenAI-style function tool calls through AegisCore.
13
+ """
14
+
15
+ def __init__(self, gateway: Optional[AegisGateway] = None, gateway_url: str = "http://localhost:8080"):
16
+ self.gateway = gateway or AegisGateway(base_url=gateway_url)
17
+
18
+ def intercept_tool_call(self, tool_call: Any) -> Dict[str, Any]:
19
+ """
20
+ Intercepts a single OpenAI tool_call object and executes through AegisCore.
21
+ Returns a dict suitable for appending to OpenAI conversation messages.
22
+ """
23
+ # Support dict or pydantic/object structure
24
+ if isinstance(tool_call, dict):
25
+ tool_id = tool_call.get("id", "")
26
+ func = tool_call.get("function", {})
27
+ name = func.get("name", "")
28
+ arguments = func.get("arguments", "{}")
29
+ else:
30
+ tool_id = getattr(tool_call, "id", "")
31
+ func = getattr(tool_call, "function", None)
32
+ name = getattr(func, "name", "") if func else ""
33
+ arguments = getattr(func, "arguments", "{}") if func else "{}"
34
+
35
+ raw_resp = self.gateway.execute_tool(
36
+ tool_call_id=tool_id,
37
+ name=name,
38
+ arguments=arguments
39
+ )
40
+
41
+ allowed = raw_resp.get("allowed", False)
42
+ verdict = raw_resp.get("verdict", "BLOCKED")
43
+ reason = raw_resp.get("reason", "Policy invariant violation")
44
+ execution = raw_resp.get("execution")
45
+
46
+ if not allowed:
47
+ content = json.dumps({
48
+ "error": "AEGIS_GOVERNANCE_BLOCKED",
49
+ "verdict": verdict,
50
+ "message": reason
51
+ })
52
+ else:
53
+ output = execution.get("output") if isinstance(execution, dict) else {"status": "SUCCESS"}
54
+ content = json.dumps(output)
55
+
56
+ return {
57
+ "tool_call_id": tool_id,
58
+ "role": "tool",
59
+ "name": name,
60
+ "content": content
61
+ }
@@ -0,0 +1,39 @@
1
+ """
2
+ AegisCore Python Models & Dataclasses
3
+ """
4
+
5
+ from dataclasses import dataclass, field
6
+ from typing import Any, Dict, List, Optional
7
+
8
+
9
+ @dataclass
10
+ class DispatchResult:
11
+ """Represents the response of a tool dispatch through AegisCore Gateway."""
12
+ status: str # 'SUCCESS', 'BLOCKED', 'REQUIRES_HITL', 'SCHEMA_ERROR', 'EXECUTION_FAILED'
13
+ intent_id: Optional[str] = None
14
+ session_id: Optional[str] = None
15
+ tool: Optional[str] = None
16
+ reason: Optional[str] = None
17
+ output: Optional[Any] = None
18
+ violations: List[Dict[str, Any]] = field(default_factory=list)
19
+ challenge: Optional[Dict[str, Any]] = None
20
+ audit_entry: Optional[Dict[str, Any]] = None
21
+ raw: Dict[str, Any] = field(default_factory=dict)
22
+
23
+ @property
24
+ def is_success(self) -> bool:
25
+ return self.status == "SUCCESS"
26
+
27
+ @property
28
+ def is_blocked(self) -> bool:
29
+ return self.status == "BLOCKED"
30
+
31
+ @property
32
+ def requires_hitl(self) -> bool:
33
+ return self.status == "REQUIRES_HITL"
34
+
35
+ @property
36
+ def ticket_id(self) -> Optional[str]:
37
+ if self.challenge and isinstance(self.challenge, dict):
38
+ return self.challenge.get("ticketId")
39
+ return None
@@ -0,0 +1,124 @@
1
+ Metadata-Version: 2.4
2
+ Name: aegiscore-ai
3
+ Version: 0.1.0
4
+ Summary: Deterministic Agent Governance Gateway - Zero-Trust Policy Enclave for AI Agents
5
+ Author: Sandeep Hipparagi & AegisCore Contributors
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/Sandeep-Hipparagi/aegis-core
8
+ Project-URL: Repository, https://github.com/Sandeep-Hipparagi/aegis-core.git
9
+ Project-URL: Issues, https://github.com/Sandeep-Hipparagi/aegis-core/issues
10
+ Keywords: ai-agent,governance,security,zero-trust,langgraph,openai,mcp,dpdp
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
22
+ Classifier: Topic :: Security
23
+ Requires-Python: >=3.8
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Dynamic: license-file
27
+
28
+ # aegiscore-py
29
+
30
+ Official, zero-dependency Python client for **AegisCore** — the Deterministic Zero-Trust Policy & Cryptographic WORM Audit Gateway for AI Agents.
31
+
32
+ [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
33
+ [![Python Version](https://img.shields.io/badge/python-3.8+-blue.svg)](https://pypi.org/project/aegiscore-ai/)
34
+
35
+ ## Installation
36
+
37
+ ```bash
38
+ pip install aegiscore-ai
39
+ ```
40
+
41
+ *Note: `aegiscore-ai` is 100% zero-dependency, implemented purely using Python's standard library (`urllib.request`, `json`, `dataclasses`).*
42
+
43
+ ## Quick Start
44
+
45
+ ### 1. Direct Tool Proposal Dispatch
46
+
47
+ ```python
48
+ from aegiscore import AegisGateway
49
+
50
+ gateway = AegisGateway("http://localhost:8080")
51
+
52
+ # Dispatch tool intent: evaluates schema, invariants, tokenizes PII, logs WORM audit
53
+ result = gateway.dispatch(
54
+ tool="transfer_funds",
55
+ arguments={"amount": 2500, "recipient": "ACC-PAYROLL"},
56
+ session_id="sess_01"
57
+ )
58
+
59
+ if result.is_success:
60
+ print("Action Approved & Executed:", result.output)
61
+ elif result.requires_hitl:
62
+ print(f"Action escalated to human approval. Ticket ID: {result.ticket_id}")
63
+ else:
64
+ print(f"Action BLOCKED: {result.reason}")
65
+ for violation in result.violations:
66
+ print(f" - {violation}")
67
+ ```
68
+
69
+ ### 2. LangGraph & LangChain Integration
70
+
71
+ ```python
72
+ from aegiscore import AegisGateway
73
+ from aegiscore.integrations import AegisLangGraphWrapper
74
+
75
+ gateway = AegisGateway("http://localhost:8080")
76
+ wrapper = AegisLangGraphWrapper(gateway=gateway)
77
+
78
+ # Wrap any native function or tool
79
+ @wrapper.wrap_tool("query_database", raw_query_func)
80
+ def safe_query_database(query: str):
81
+ return raw_query_func(query)
82
+
83
+ # Calls are intercepted and verified against policy invariants before invocation
84
+ safe_query_database(query="SELECT * FROM users")
85
+ ```
86
+
87
+ ### 3. OpenAI Function Call Interception
88
+
89
+ ```python
90
+ from aegiscore import AegisGateway
91
+ from aegiscore.integrations import AegisOpenAIInterceptor
92
+
93
+ gateway = AegisGateway("http://localhost:8080")
94
+ interceptor = AegisOpenAIInterceptor(gateway=gateway)
95
+
96
+ # In your chat completion loop:
97
+ for tool_call in response.choices[0].message.tool_calls:
98
+ # Evaluates policy and returns tool response dict formatted for OpenAI
99
+ tool_message = interceptor.intercept_tool_call(tool_call)
100
+ messages.append(tool_message)
101
+ ```
102
+
103
+ ### 4. Human-in-the-Loop (HITL) Resolution
104
+
105
+ ```python
106
+ # Check pending ticket and resolve with cryptographic signature
107
+ gateway.resolve_hitl(
108
+ ticket_id="ticket-12345",
109
+ decision="APPROVED",
110
+ signature="sig-supervisor-ed25519"
111
+ )
112
+ ```
113
+
114
+ ### 5. Forensic Cryptographic Ledger Verification
115
+
116
+ ```python
117
+ # Verifies the tamper-evident WORM Merkle chain
118
+ audit = gateway.verify_audit_integrity()
119
+ print(f"Ledger Valid: {audit['isValid']}")
120
+ ```
121
+
122
+ ## License
123
+
124
+ Apache-2.0
@@ -0,0 +1,15 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ aegiscore/__init__.py
5
+ aegiscore/client.py
6
+ aegiscore/exceptions.py
7
+ aegiscore/models.py
8
+ aegiscore/integrations/__init__.py
9
+ aegiscore/integrations/langgraph.py
10
+ aegiscore/integrations/openai.py
11
+ aegiscore_ai.egg-info/PKG-INFO
12
+ aegiscore_ai.egg-info/SOURCES.txt
13
+ aegiscore_ai.egg-info/dependency_links.txt
14
+ aegiscore_ai.egg-info/top_level.txt
15
+ tests/test_client.py
@@ -0,0 +1 @@
1
+ aegiscore
@@ -0,0 +1,44 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "aegiscore-ai"
7
+ version = "0.1.0"
8
+ description = "Deterministic Agent Governance Gateway - Zero-Trust Policy Enclave for AI Agents"
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ license = "Apache-2.0"
12
+ authors = [
13
+ { name = "Sandeep Hipparagi & AegisCore Contributors" }
14
+ ]
15
+ keywords = [
16
+ "ai-agent",
17
+ "governance",
18
+ "security",
19
+ "zero-trust",
20
+ "langgraph",
21
+ "openai",
22
+ "mcp",
23
+ "dpdp"
24
+ ]
25
+ classifiers = [
26
+ "Development Status :: 4 - Beta",
27
+ "Intended Audience :: Developers",
28
+ "Programming Language :: Python :: 3",
29
+ "Programming Language :: Python :: 3.8",
30
+ "Programming Language :: Python :: 3.9",
31
+ "Programming Language :: Python :: 3.10",
32
+ "Programming Language :: Python :: 3.11",
33
+ "Programming Language :: Python :: 3.12",
34
+ "Programming Language :: Python :: 3.13",
35
+ "Programming Language :: Python :: 3.14",
36
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
37
+ "Topic :: Security"
38
+ ]
39
+ dependencies = []
40
+
41
+ [project.urls]
42
+ Homepage = "https://github.com/Sandeep-Hipparagi/aegis-core"
43
+ Repository = "https://github.com/Sandeep-Hipparagi/aegis-core.git"
44
+ Issues = "https://github.com/Sandeep-Hipparagi/aegis-core/issues"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,196 @@
1
+ """
2
+ Unit tests for AegisCore Python SDK
3
+ """
4
+
5
+ import json
6
+ import unittest
7
+ from unittest.mock import patch, MagicMock
8
+ import io
9
+ import urllib.error
10
+
11
+ from aegiscore import (
12
+ AegisGateway,
13
+ AegisClient,
14
+ DispatchResult,
15
+ AegisPolicyBlockedError,
16
+ AegisSchemaError,
17
+ )
18
+ from aegiscore.integrations import (
19
+ AegisLangGraphWrapper,
20
+ AegisOpenAIInterceptor,
21
+ )
22
+
23
+
24
+ class TestAegisPythonSDK(unittest.TestCase):
25
+
26
+ def setUp(self):
27
+ self.gateway = AegisGateway(base_url="http://127.0.0.1:8080", agent_id="test-agent", role="tester")
28
+
29
+ def test_client_alias(self):
30
+ self.assertIs(AegisClient, AegisGateway)
31
+ client = AegisClient(base_url="http://localhost:9090")
32
+ self.assertEqual(client.base_url, "http://localhost:9090")
33
+
34
+ def test_dispatch_result_helpers(self):
35
+ res_success = DispatchResult(
36
+ status="SUCCESS",
37
+ tool="check_balance",
38
+ output={"balance": 5000}
39
+ )
40
+ self.assertTrue(res_success.is_success)
41
+ self.assertFalse(res_success.is_blocked)
42
+ self.assertFalse(res_success.requires_hitl)
43
+ self.assertIsNone(res_success.ticket_id)
44
+
45
+ res_hitl = DispatchResult(
46
+ status="REQUIRES_HITL",
47
+ tool="transfer_funds",
48
+ challenge={"ticketId": "tick-999", "status": "PENDING"}
49
+ )
50
+ self.assertFalse(res_hitl.is_success)
51
+ self.assertTrue(res_hitl.requires_hitl)
52
+ self.assertEqual(res_hitl.ticket_id, "tick-999")
53
+
54
+ res_blocked = DispatchResult(
55
+ status="BLOCKED",
56
+ tool="purge_data",
57
+ reason="Unauthorized role"
58
+ )
59
+ self.assertTrue(res_blocked.is_blocked)
60
+
61
+ @patch("urllib.request.urlopen")
62
+ def test_dispatch_success(self, mock_urlopen):
63
+ mock_response = MagicMock()
64
+ mock_response.read.return_value = json.dumps({
65
+ "status": "SUCCESS",
66
+ "intentId": "int-101",
67
+ "execution": {
68
+ "status": "SUCCESS",
69
+ "output": {"txId": "tx-12345", "amount": 100}
70
+ }
71
+ }).encode("utf-8")
72
+ mock_urlopen.return_value.__enter__.return_value = mock_response
73
+
74
+ res = self.gateway.dispatch("transfer_funds", {"amount": 100, "recipient": "bob"})
75
+ self.assertTrue(res.is_success)
76
+ self.assertEqual(res.output, {"txId": "tx-12345", "amount": 100})
77
+ self.assertEqual(res.intent_id, "int-101")
78
+
79
+ @patch("urllib.request.urlopen")
80
+ def test_dispatch_blocked_without_raise(self, mock_urlopen):
81
+ err_body = json.dumps({
82
+ "status": "BLOCKED",
83
+ "reason": "Exceeds daily budget",
84
+ "violations": [{"ruleId": "RULE-01", "message": "Limit exceeded"}]
85
+ }).encode("utf-8")
86
+ mock_fp = io.BytesIO(err_body)
87
+ http_err = urllib.error.HTTPError("http://127.0.0.1:8080/v1/gateway/dispatch", 403, "Forbidden", {}, mock_fp)
88
+ mock_urlopen.side_effect = http_err
89
+
90
+ res = self.gateway.dispatch("transfer_funds", {"amount": 1000000}, raise_on_blocked=False)
91
+ self.assertTrue(res.is_blocked)
92
+ self.assertEqual(res.reason, "Exceeds daily budget")
93
+ self.assertEqual(len(res.violations), 1)
94
+
95
+ @patch("urllib.request.urlopen")
96
+ def test_dispatch_blocked_with_raise(self, mock_urlopen):
97
+ err_body = json.dumps({
98
+ "status": "BLOCKED",
99
+ "reason": "Target table blacklisted",
100
+ "violations": [{"ruleId": "RULE-SENSITIVE"}]
101
+ }).encode("utf-8")
102
+ mock_fp = io.BytesIO(err_body)
103
+ http_err = urllib.error.HTTPError("http://127.0.0.1:8080/v1/gateway/dispatch", 403, "Forbidden", {}, mock_fp)
104
+ mock_urlopen.side_effect = http_err
105
+
106
+ with self.assertRaises(AegisPolicyBlockedError) as ctx:
107
+ self.gateway.dispatch("query_database", {"targetTable": "users.credentials"}, raise_on_blocked=True)
108
+
109
+ self.assertIn("Target table blacklisted", str(ctx.exception))
110
+
111
+ @patch("urllib.request.urlopen")
112
+ def test_evaluate_intent(self, mock_urlopen):
113
+ mock_response = MagicMock()
114
+ mock_response.read.return_value = json.dumps({
115
+ "decision": {"status": "APPROVED", "executionAllowed": True}
116
+ }).encode("utf-8")
117
+ mock_urlopen.return_value.__enter__.return_value = mock_response
118
+
119
+ res = self.gateway.evaluate_intent("check_balance", {"accountId": "ACC-01"})
120
+ self.assertEqual(res["decision"]["status"], "APPROVED")
121
+
122
+ @patch("urllib.request.urlopen")
123
+ def test_execute_tool(self, mock_urlopen):
124
+ mock_response = MagicMock()
125
+ mock_response.read.return_value = json.dumps({
126
+ "tool_call_id": "call_123",
127
+ "allowed": True,
128
+ "verdict": "APPROVED"
129
+ }).encode("utf-8")
130
+ mock_urlopen.return_value.__enter__.return_value = mock_response
131
+
132
+ res = self.gateway.execute_tool("call_123", "check_balance", {"accountId": "ACC-01"})
133
+ self.assertTrue(res["allowed"])
134
+
135
+ @patch("urllib.request.urlopen")
136
+ def test_resolve_hitl(self, mock_urlopen):
137
+ mock_response = MagicMock()
138
+ mock_response.read.return_value = json.dumps({
139
+ "resolution": {"status": "APPROVED"},
140
+ "execution": {"status": "SUCCESS"}
141
+ }).encode("utf-8")
142
+ mock_urlopen.return_value.__enter__.return_value = mock_response
143
+
144
+ res = self.gateway.resolve_hitl("ticket-01", "APPROVED", "sig-123")
145
+ self.assertEqual(res["resolution"]["status"], "APPROVED")
146
+
147
+ @patch("urllib.request.urlopen")
148
+ def test_audit_integrity(self, mock_urlopen):
149
+ mock_response = MagicMock()
150
+ mock_response.read.return_value = json.dumps({
151
+ "isValid": True,
152
+ "totalEntries": 42
153
+ }).encode("utf-8")
154
+ mock_urlopen.return_value.__enter__.return_value = mock_response
155
+
156
+ res = self.gateway.verify_audit_integrity()
157
+ self.assertTrue(res["isValid"])
158
+ self.assertEqual(res["totalEntries"], 42)
159
+
160
+ def test_langgraph_wrapper_approved(self):
161
+ wrapper = AegisLangGraphWrapper(gateway=self.gateway)
162
+ with patch.object(self.gateway, "dispatch") as mock_dispatch:
163
+ mock_dispatch.return_value = DispatchResult(
164
+ status="SUCCESS",
165
+ tool="calc",
166
+ output=42
167
+ )
168
+ raw_fn = MagicMock(return_value=42)
169
+ governed = wrapper.wrap_tool("calc", raw_fn)
170
+ output = governed(x=20, y=22)
171
+ self.assertEqual(output, 42)
172
+ mock_dispatch.assert_called_once()
173
+
174
+ def test_openai_interceptor_blocked(self):
175
+ interceptor = AegisOpenAIInterceptor(gateway=self.gateway)
176
+ with patch.object(self.gateway, "execute_tool") as mock_exec:
177
+ mock_exec.return_value = {
178
+ "tool_call_id": "tc_1",
179
+ "allowed": False,
180
+ "verdict": "BLOCKED",
181
+ "reason": "High risk action"
182
+ }
183
+ msg = interceptor.intercept_tool_call({
184
+ "id": "tc_1",
185
+ "function": {
186
+ "name": "delete_all",
187
+ "arguments": "{}"
188
+ }
189
+ })
190
+ self.assertEqual(msg["role"], "tool")
191
+ parsed = json.loads(msg["content"])
192
+ self.assertEqual(parsed["verdict"], "BLOCKED")
193
+
194
+
195
+ if __name__ == "__main__":
196
+ unittest.main()