aynigma 0.3.1__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. aynigma-0.3.1/.gitignore +77 -0
  2. aynigma-0.3.1/CHANGELOG.md +38 -0
  3. aynigma-0.3.1/PKG-INFO +218 -0
  4. aynigma-0.3.1/README.md +173 -0
  5. aynigma-0.3.1/pyproject.toml +40 -0
  6. aynigma-0.3.1/src/aynigma/__init__.py +61 -0
  7. aynigma-0.3.1/src/aynigma/agent_errors.py +89 -0
  8. aynigma-0.3.1/src/aynigma/agent_tokens.py +404 -0
  9. aynigma-0.3.1/src/aynigma/agents.py +1366 -0
  10. aynigma-0.3.1/src/aynigma/approval_checkpoints.py +170 -0
  11. aynigma-0.3.1/src/aynigma/assess.py +94 -0
  12. aynigma-0.3.1/src/aynigma/assess_plugins.py +42 -0
  13. aynigma-0.3.1/src/aynigma/audit_verify.py +491 -0
  14. aynigma-0.3.1/src/aynigma/client.py +529 -0
  15. aynigma-0.3.1/src/aynigma/discover.py +41 -0
  16. aynigma-0.3.1/src/aynigma/discover_azure.py +48 -0
  17. aynigma-0.3.1/src/aynigma/discover_cloud.py +46 -0
  18. aynigma-0.3.1/src/aynigma/discover_refresh.py +59 -0
  19. aynigma-0.3.1/src/aynigma/discover_vertex.py +43 -0
  20. aynigma-0.3.1/src/aynigma/mcp_oauth.py +61 -0
  21. aynigma-0.3.1/src/aynigma/package_verify.py +369 -0
  22. aynigma-0.3.1/src/aynigma/py.typed +0 -0
  23. aynigma-0.3.1/tests/_fake_agent_api.py +181 -0
  24. aynigma-0.3.1/tests/test_agents.py +1241 -0
  25. aynigma-0.3.1/tests/test_agents_receipts.py +225 -0
  26. aynigma-0.3.1/tests/test_approval_checkpoint_cli.py +42 -0
  27. aynigma-0.3.1/tests/test_approval_checkpoints.py +73 -0
  28. aynigma-0.3.1/tests/test_approval_resume.py +158 -0
  29. aynigma-0.3.1/tests/test_assess.py +42 -0
  30. aynigma-0.3.1/tests/test_assess_plugins.py +24 -0
  31. aynigma-0.3.1/tests/test_audit_verify.py +390 -0
  32. aynigma-0.3.1/tests/test_client.py +513 -0
  33. aynigma-0.3.1/tests/test_discover.py +24 -0
  34. aynigma-0.3.1/tests/test_discover_azure.py +51 -0
  35. aynigma-0.3.1/tests/test_discover_cloud.py +31 -0
  36. aynigma-0.3.1/tests/test_discover_refresh.py +34 -0
  37. aynigma-0.3.1/tests/test_discover_vertex.py +28 -0
  38. aynigma-0.3.1/tests/test_google_adk_approval.py +358 -0
  39. aynigma-0.3.1/tests/test_langgraph_postgres.py +67 -0
  40. aynigma-0.3.1/tests/test_mcp_oauth.py +23 -0
  41. aynigma-0.3.1/tests/test_openai_approval_bridge.py +187 -0
  42. aynigma-0.3.1/tests/test_tokens.py +359 -0
@@ -0,0 +1,77 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ *.egg-info/
24
+ .installed.cfg
25
+ *.egg
26
+
27
+ # Django stuff:
28
+ *.log
29
+ local_settings.py
30
+ db.sqlite3
31
+ db.sqlite3-journal
32
+ /media
33
+ /staticfiles
34
+
35
+ # Environment
36
+ .env
37
+ .venv
38
+ env/
39
+ venv/
40
+ ENV/
41
+ env.bak/
42
+ venv.bak/
43
+
44
+ # IDEs
45
+ .vscode/
46
+ .idea/
47
+ *.swp
48
+ *.swo
49
+ *~
50
+
51
+ # Testing
52
+ .coverage
53
+ .pytest_cache/
54
+ htmlcov/
55
+
56
+ # Celery
57
+ celerybeat-schedule
58
+ celerybeat.pid
59
+
60
+ # macOS
61
+ .DS_Store
62
+
63
+ # Redis
64
+ dump.rdb
65
+
66
+ # Logs directory
67
+ logs/
68
+
69
+ # Token/credential files
70
+ token.txt
71
+ login_output.txt
72
+
73
+ # Test results
74
+ test_results_*.json
75
+
76
+ # Rendered Cerbos agent policies (generated at runtime, not source)
77
+ cerbos/policies/agent_*.yaml
@@ -0,0 +1,38 @@
1
+ # Changelog
2
+
3
+ ## Unreleased
4
+
5
+ - `aynigma-audit-verify verify-package <zip>` (module `aynigma.package_verify`): verifies a signed Aynigma evidence package offline. Checks the manifest signature (RS256, key from the package or from `--jwks`), every file's sha256 and size, the audit chain segment (order, hash links, head hash, optional full recompute with the chain key), the signed anchors against the segment, and assurance sign-off hashes. Standard library only. Exit 0 pass, 1 failed check, 3 unusable input. See `docs/EVIDENCE_PACKAGE.md`.
6
+ - New command `aynigma-audit-verify` (module `aynigma.audit_verify`): verifies an audit JSON export and a signed chain anchor offline. Recomputes hash v2 rows with the customer-held chain key and hash v1 rows without one, rejects v1 rows above the cutover signed in a verified anchor (or after a v2 row) as downgrades (the unsigned export header never grants trust; legacy-only exports without a verified anchor are inconclusive), checks linkage (`--full-chain` for an unfiltered export) and the anchor's RS256 signature against the JWKS. Standard library only. Exit 0 pass, 1 failed check, 2 inconclusive (no key and no anchor pinning the export), 3 unusable input. See `docs/AUDIT_CHAIN.md` in the backend repo.
7
+
8
+ ## 0.3.1 - 2026-10-16
9
+
10
+ - `ApprovalRequired` now has `run_id` and `tool_name` (keyword-friendly, default None; `approval_id` and `call_id` stay first) and a message that says who can approve, what to call next and which run to resume in. `run_id` is the provider's current run, None with the legacy `X-AGENT-KEY` header.
11
+ - `AgentAuthorizer(..., run_id=...)` continues an earlier run, so a new process can consume an approval that is bound to the run it was raised in. Without it a resumed call is denied with `run_mismatch`. It raises `ValueError` when combined with `token_provider` or with the legacy header.
12
+ - `ToolDenied` adds a short hint after the code for common denials (`no_policy`, `run_mismatch`, `payload_mismatch`, `approval_already_used`, `approval_expired`, `approval_not_approved`, `policy_version_changed`, `environment`, `rate_limited`) and a `hint` attribute. `str(error)` still starts with `Agent tool call denied: <code>` and `reason` is unchanged.
13
+ - README: install from the portal-hosted wheel until the package is on PyPI, and an approvals pause and resume example.
14
+
15
+ ## 0.3.0 - 2026-10-06
16
+
17
+ - Agent tokens: `AgentTokenProvider` (client credentials, cached, refreshed at 80 % of the lifetime or once on a 401, thread safe) and `DelegatedToken` (RFC 8693 exchange).
18
+ - `AgentAuthorizer` takes `token_provider`, `agent_id` and `use_legacy_key`. With an agent ID and key it now sends `Authorization: Bearer <token>` instead of `X-AGENT-KEY` (set `use_legacy_key=True` or `AYNIGMA_USE_LEGACY_KEY=1` to keep the header). New `delegate()`, `delegate_to()`, `auth_headers()` and `mcp_call()`.
19
+ - `acting_for_user` and `initiator_token_provider` exchange the user JWT for a delegated token when tokens are in use.
20
+ - `RunKilled(ToolDenied)` for `run_killed` decisions; cached tokens are dropped. `TokenError` for token endpoint refusals.
21
+ - Run liveness: only a killed run raises `RunKilled`; an ended run is rotated and the request retried once, logged at INFO. `AgentAuthorizer.mcp_call` returns None for a 202, raises `MCPError` for a 400 and tracks `Mcp-Session-Id`.
22
+ - An explicit key without `agent_id` stays on the legacy header; `AYNIGMA_AGENT_ID` is read from the environment only with an environment key.
23
+ - New command `aynigma-agents-token`. New environment variables `AYNIGMA_AGENT_ID` and `AYNIGMA_USE_LEGACY_KEY`.
24
+
25
+ ## 0.2.0 — 2026-09-28
26
+
27
+ - Add the Protect v2 `X-Aynigma-Source: sdk` header and `end_user_id` support.
28
+ - Expose `user_message` and `quarantined` on `ValidationResult`; use the
29
+ configured user message for `BlockedError` when supplied by the API.
30
+ - Deprecate the classic `validate_input()` and `validate_output()` methods with
31
+ `DeprecationWarning`; use `guard()` with the `prompt` or `response` stage.
32
+ ## Unreleased: mandatory receipts
33
+
34
+ - `ToolExecutor(require_receipt=True)` is the default. A call without a receipt raises `ToolDenied("receipt_required")` and no handler runs before `verify`. `require_receipt=False` is an explicit opt-out for backends run with `AGENT_REQUIRE_EXECUTION_RECEIPT=False`.
35
+ - New `AgentAuthorizer.run_tool(tool_name, params, handler)`: authorize, verify, run, report. A handler error reports FAILED (no error text) and is re-raised; a failed report no longer hides it.
36
+ - New `RemoteTool.local(authorizer, tool_name, handler)` for tools that run in the agent's process. All framework adapters go through `RemoteTool`, so they use `run_tool`. A `RemoteTool` with an `executor_url` is unchanged: your executor service does verify and report.
37
+ - `ExecutionReceipt` keeps extra fields the backend issued (`extra`, `as_dict()`) and forwards them unchanged to the executor.
38
+ - `mcp_call` recovers from an expired gateway session: on a 404 for a request that carried an `Mcp-Session-Id` it drops the session, runs `initialize` once and retries once, then raises `MCPError` if that fails too. TypeScript `mcpCall` does the same.
aynigma-0.3.1/PKG-INFO ADDED
@@ -0,0 +1,218 @@
1
+ Metadata-Version: 2.4
2
+ Name: aynigma
3
+ Version: 0.3.1
4
+ Summary: Python SDK for Aynigma: IAM for AI agents and AI security guardrails
5
+ Requires-Python: >=3.9
6
+ Requires-Dist: httpx>=0.25
7
+ Provides-Extra: approval-postgres
8
+ Requires-Dist: cryptography<51,>=42; extra == 'approval-postgres'
9
+ Requires-Dist: psycopg[binary]<4,>=3.2; extra == 'approval-postgres'
10
+ Provides-Extra: claude-agent
11
+ Requires-Dist: claude-agent-sdk<0.3,>=0.2.160; extra == 'claude-agent'
12
+ Requires-Dist: pydantic<3,>=2.7; extra == 'claude-agent'
13
+ Provides-Extra: crewai
14
+ Requires-Dist: crewai<1.16,>=1.15; extra == 'crewai'
15
+ Requires-Dist: pydantic<3,>=2.7; extra == 'crewai'
16
+ Provides-Extra: dev
17
+ Requires-Dist: pytest>=7; extra == 'dev'
18
+ Provides-Extra: google-adk
19
+ Requires-Dist: google-adk<1.40,>=1.39; extra == 'google-adk'
20
+ Requires-Dist: pydantic<3,>=2.7; extra == 'google-adk'
21
+ Provides-Extra: google-adk-postgres
22
+ Requires-Dist: asyncpg<1,>=0.30; extra == 'google-adk-postgres'
23
+ Requires-Dist: google-adk<1.40,>=1.39; extra == 'google-adk-postgres'
24
+ Requires-Dist: psycopg[binary]<4,>=3.2; extra == 'google-adk-postgres'
25
+ Requires-Dist: pydantic<3,>=2.7; extra == 'google-adk-postgres'
26
+ Requires-Dist: sqlalchemy[asyncio]<3,>=2; extra == 'google-adk-postgres'
27
+ Provides-Extra: langchain
28
+ Requires-Dist: langchain-core<1,>=0.3; extra == 'langchain'
29
+ Requires-Dist: pydantic<3,>=2.7; extra == 'langchain'
30
+ Provides-Extra: langgraph
31
+ Requires-Dist: langgraph<1.3,>=1.2; extra == 'langgraph'
32
+ Requires-Dist: pydantic<3,>=2.7; extra == 'langgraph'
33
+ Provides-Extra: langgraph-postgres
34
+ Requires-Dist: langgraph-checkpoint-postgres<3.2,>=3.1; extra == 'langgraph-postgres'
35
+ Requires-Dist: langgraph<1.3,>=1.2; extra == 'langgraph-postgres'
36
+ Requires-Dist: psycopg[binary]<4,>=3.2; extra == 'langgraph-postgres'
37
+ Requires-Dist: pydantic<3,>=2.7; extra == 'langgraph-postgres'
38
+ Provides-Extra: openai-agents
39
+ Requires-Dist: openai-agents<0.23,>=0.22; extra == 'openai-agents'
40
+ Requires-Dist: pydantic<3,>=2.7; extra == 'openai-agents'
41
+ Provides-Extra: semantic-kernel
42
+ Requires-Dist: pydantic<3,>=2.7; extra == 'semantic-kernel'
43
+ Requires-Dist: semantic-kernel<1.45,>=1.44; extra == 'semantic-kernel'
44
+ Description-Content-Type: text/markdown
45
+
46
+ # Aynigma Python SDK
47
+
48
+ Python SDK for Aynigma: IAM for AI agents and AI security guardrails.
49
+
50
+ Authorize agent tool calls, handle human approvals, enforce execution receipts,
51
+ and scan prompts and responses with Protect.
52
+
53
+ ```bash
54
+ python -m pip install aynigma
55
+ # Or, from a source checkout of the backend repo:
56
+ python -m pip install ./sdk/python
57
+ export AYNIGMA_API_KEY=psk_your_project_key
58
+ ```
59
+
60
+ ```python
61
+ from aynigma import Aynigma
62
+
63
+ client = Aynigma()
64
+ result = client.guard("Hello", stage="prompt")
65
+ print(result.allowed)
66
+ ```
67
+
68
+ The default API URL is `https://api.aynigma.ai/api/v1`. Supply `base_url` or
69
+ set `AYNIGMA_API_URL` to use another deployment. Validation endpoints are
70
+ `/guardrails/validate/input/` and `/guardrails/validate/output/`; project keys
71
+ are sent in the `X-API-KEY` header.
72
+ These classic validation endpoints are deprecated. `validate_input()` and
73
+ `validate_output()` continue to work but emit `DeprecationWarning`; migrate to
74
+ `guard(text, stage="prompt")` and `guard(text, stage="response")` respectively.
75
+
76
+ Protect v2 stage-aware scans are also available from both sync and async
77
+ clients. `guard()` accepts `prompt`, `response`, `tool_call`, `tool_result`,
78
+ `retrieval`, or `document`; scope can be bound with `company_id`, `project_id`,
79
+ `system_id`, `environment_id`, `policy_id`, and a per-generation
80
+ `conversation_id`. When environment token pricing is enabled, direct `guard()`
81
+ calls for prompt/response billing also require a fresh unique `generation_id`;
82
+ the OpenAI wrappers create one automatically and reuse it across that model
83
+ call's stages. Keep a stable conversation ID across turns, but never reuse a
84
+ generation ID for a different provider call. A blocked scan raises the same
85
+ `BlockedError` as v1. V1 remains available for existing integrations.
86
+
87
+ Pass `end_user_id="customer-42"` to `guard()` to associate detections with an
88
+ end user for per-policy repeat-offender quarantine; IDs may be at most 128
89
+ characters and the server hashes them. SDK v2 guard calls automatically send
90
+ `X-Aynigma-Source: sdk`, which is recorded on detection events. A
91
+ `ValidationResult` exposes `user_message` and `quarantined`; when a blocked
92
+ response includes `user_message`, it is also used as `str(BlockedError)` and is
93
+ available on the exception's `user_message` attribute.
94
+
95
+ ```python
96
+ with Aynigma() as client:
97
+ result = client.guard(
98
+ "Retrieve customer account details",
99
+ "prompt",
100
+ system_id=4,
101
+ environment_id=12,
102
+ conversation_id="support-session-42",
103
+ generation_id="support-session-42-generation-1",
104
+ )
105
+ ```
106
+
107
+ `guard_openai_chat_v2()` scans prompt, previous tool results, response, and
108
+ proposed tool calls as separate stages. It rejects streaming rather than
109
+ releasing unchecked chunks; use the TypeScript wrapper or bounded LiteLLM
110
+ gateway for hold-back streaming.
111
+
112
+ ## Agent IAM quickstart
113
+
114
+ ```bash
115
+ python -m pip install aynigma
116
+ # Or, from a source checkout of the backend repo:
117
+ python -m pip install ./sdk/python
118
+ export AYNIGMA_AGENT_ID=<agent uuid>
119
+ export AYNIGMA_AGENT_KEY=agt_...
120
+ ```
121
+
122
+ With an agent ID and key the SDK trades the key for a 15 minute token, caches it, refreshes it at 80 % of its lifetime (or once after a 401), and sends `Authorization: Bearer <token>` on tool calls, receipt checks and MCP calls. The key is sent only to the token endpoint.
123
+
124
+ ```python
125
+ from aynigma import AgentAuthorizer, AgentTokenProvider, RemoteTool, acting_for_user
126
+
127
+ authorizer = AgentAuthorizer() # reads AYNIGMA_AGENT_ID, AYNIGMA_AGENT_KEY, AYNIGMA_API_URL
128
+ create_ticket = RemoteTool(authorizer, "https://executor.internal.example", "ticket.create")
129
+
130
+ # Delegation: act for a signed-in person. Their JWT is exchanged for a delegated token
131
+ # (RFC 8693); the raw JWT is never forwarded and the backend records a verified chain.
132
+ with acting_for_user(current_user_jwt):
133
+ create_ticket(title="Investigate alert")
134
+
135
+ # Narrow what the delegation may do, or hand it to a sub-agent.
136
+ scoped = authorizer.delegate(current_user_jwt, scope="db.read")
137
+ sub_authorizer = scoped.delegate_to(AgentTokenProvider(SUB_AGENT_ID, SUB_AGENT_KEY))
138
+ ```
139
+
140
+ Receipts: every ALLOW returns a one-use receipt bound to the exact arguments and, with tokens, to the agent run. The executor calls `ToolExecutor.execute` (verify, run, report) with its own `AgentAuthorizer`. If an administrator kills the run, verify and tool calls fail with `RunKilled` (a `ToolDenied`), the SDK drops its cached tokens, and the next call starts a new run. A report for an already consumed receipt is still accepted after a kill and is recorded as `after_kill`. A run that only ended (idle) is replaced transparently and logged at INFO on the `aynigma.agents` logger.
141
+
142
+ ### Approvals: pause and resume
143
+
144
+ A rule with effect REVIEW raises `ApprovalRequired` until a person approves the call in Agent IAM > Activity. The approval belongs to the run it was raised in, so save `approval_id` and `run_id` when you catch it. If the work continues in another process (a queue worker, a restart), build the new authorizer with that `run_id`. Without it the new process starts a fresh run and the call is denied with `run_mismatch`.
145
+
146
+ ```python
147
+ from aynigma import AgentAuthorizer, ApprovalRequired
148
+
149
+ authorizer = AgentAuthorizer(agent_id=AGENT_ID, agent_key=AGENT_KEY, base_url=BASE_URL)
150
+ try:
151
+ authorizer.run_tool(tool, params, handler)
152
+ except ApprovalRequired as pending:
153
+ saved_approval_id, saved_run_id = pending.approval_id, pending.run_id # store these with your task
154
+
155
+ # Later, after a reviewer approved it, possibly in a new process:
156
+ resumed = AgentAuthorizer(agent_id=AGENT_ID, agent_key=AGENT_KEY, base_url=BASE_URL, run_id=saved_run_id)
157
+ resumed.run_tool(tool, params, handler, approval_id=saved_approval_id) # same tool, same params
158
+ ```
159
+
160
+ `run_id` is None with the legacy `X-AGENT-KEY` header, which has no runs and needs no `run_id` to resume. If you pass your own `token_provider`, give that `AgentTokenProvider` the `run_id` instead; passing `run_id` to `AgentAuthorizer` as well raises `ValueError`. The arguments must match what was approved, or the call is denied with `payload_mismatch`.
161
+
162
+ Denials explain themselves: `str(ToolDenied)` starts with `Agent tool call denied: <code>` and adds a short hint for common codes (`no_policy`, `run_mismatch`, `payload_mismatch`, `approval_already_used`, `approval_expired`, `environment`, `rate_limited`). `error.reason` is the bare code and `error.hint` the hint, or None.
163
+
164
+ Debug a token from a shell: `AYNIGMA_AGENT_KEY=agt_... aynigma-agents-token --agent-id <uuid> --claims`. The key is never printed.
165
+
166
+ ## Verify an audit export offline
167
+
168
+ Auditors can check an audit export and its signed anchor without trusting the API. Standard library only.
169
+
170
+ ```bash
171
+ aynigma-audit-verify --export audit.json --anchor anchor.json \
172
+ --jwks https://api.aynigma.ai/api/v1/agents/.well-known/jwks.json \
173
+ --chain-key-file chain.key --full-chain
174
+ ```
175
+
176
+ `audit.json` is `GET /api/v1/audit/export/?log_type=audit&export_format=json` (an object with a `chain` header and `records`) and `anchor.json` is `GET /api/v1/audit/anchors/<id>/`. With the chain key (`--chain-key-file`, or `AYNIGMA_AUDIT_CHAIN_KEY`; `--chain-key` works but shows in the process list) every row is recomputed; without it only legacy rows are, and the report lists what was skipped. Legacy (v1) rows need no key, so they are trusted only up to the `last_v1_entry_id` signed inside a verified anchor (the export header's value is unsigned and never grants trust); a v1 row above it, or after a keyed row, is a forgery and fails. An export of only legacy rows with no verified anchor is INCONCLUSIVE. `--full-chain` means the export is the unfiltered chain, so each row must follow its predecessor.
177
+
178
+ Exit status: 0 pass, 1 a check failed, 2 inconclusive, 3 unusable input. PASS needs every row recomputed with the key, or an anchor whose head is in the export with an unbroken chain back from it (printed as "structure only", since v2 contents are not recomputed without the key). With neither the result is INCONCLUSIVE, never a pass. The hashing rules are in `docs/AUDIT_CHAIN.md` in the backend repo.
179
+
180
+ Migrating from `X-AGENT-KEY`: nothing breaks. A key with no agent ID keeps sending the header, and `use_legacy_key=True` (or `AYNIGMA_USE_LEGACY_KEY=1`) keeps it even when an agent ID is set. Since 0.3.0, `AgentAuthorizer` switches to tokens as soon as it has both an agent ID and a key. An explicit `agent_key=` with no `agent_id=` stays legacy, and `AYNIGMA_AGENT_ID` from the environment counts only together with `AYNIGMA_AGENT_KEY` from the environment. To move over, pass `agent_id=` or set both variables, and watch the `agent.legacy_key_used` audit event stop. `acting_for_user` and `initiator_token_provider` now exchange the user JWT instead of forwarding it; with the legacy header they forward it as before. Delegated tokens carry the delegation depth counted from the human (a direct human to agent hop is depth 1), so review `max_delegation_depth` conditions. See `docs/AGENT_TOOL_EXECUTOR.md` and `docs/AGENT_IDENTITY.md`.
181
+
182
+ Beyond the quickstart, use `AgentAuthorizer` and `RemoteTool` with a separately deployed receipt-enforcing executor. Optional adapters are `as_langchain_tool`, `as_openai_agents_tool`, `as_crewai_tool`, `as_claude_agent_tool`, `as_google_adk_tool`, and `as_semantic_kernel_function`; install their corresponding extras and pass a Pydantic argument model. `OpenAIAgentsApprovalBridge` uses the OpenAI Agents SDK's native approval interruption to preserve the exact model-selected call through backend REVIEW and receipt-backed resume. `build_crewai_approval_flow` uses CrewAI Flow human feedback and explicit persistence for the same handoff. `ClaudeAgentApprovalBridge` pairs the Claude Agent SDK's native `PreToolUse` defer hook with a receipt-backed MCP tool and caller-owned pending state. `SemanticKernelApprovalBridge` intercepts Semantic Kernel auto function invocation before a model-selected call and supports exact-call REVIEW resume through a caller-owned checkpoint. `as_google_adk_approval_tool` uses ADK's native confirmation event and persisted session state. Install `aynigma[google-adk-postgres]` for ADK's PostgreSQL session service; a local restart contract passed against a disposable PostgreSQL database. `build_langgraph_approval_workflow` adds a checkpointed pause/resume graph for REVIEW decisions and requires an explicit checkpointer. Install `aynigma[langgraph-postgres]` and use LangGraph's `PostgresSaver` for durable resume. See `docs/AGENT_TOOL_EXECUTOR.md` in the backend repository for the executor boundary and examples.
183
+
184
+ `PostgresApprovalCheckpointStore` is an optional encrypted store for serializable pending approval state shared across workers. Install `aynigma[approval-postgres]`, call `setup()` once, then `save()` and one-use `claim()` with authenticated tenant and agent UUIDs. Schedule `aynigma-approval-checkpoints-purge` daily with `AYNIGMA_APPROVAL_CHECKPOINT_DATABASE_URL` supplied from the operator's secret store; it prints only the number purged. The application still serializes framework-specific session state and authorizes its resume endpoint. See the executor guide for retention and recovery rules.
185
+
186
+ ```python
187
+ from aynigma import Aynigma, guard_openai_chat_v2
188
+
189
+ with Aynigma() as client:
190
+ response = guard_openai_chat_v2(
191
+ client,
192
+ openai_client,
193
+ messages,
194
+ model="gpt-4o-mini",
195
+ guard_options={"system_id": 4, "environment_id": 12},
196
+ )
197
+ ```
198
+ # Bedrock agent inventory
199
+
200
+ On a paid plan, run `aynigma-agents-discover-cloud --company-id 42 --account-id 123456789012 --region us-east-1` with `AYNIGMA_USER_JWT`, `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and optional `AWS_SESSION_TOKEN` set. The command sends the credentials once and prints only the bounded agent inventory. The backend checks the AWS account through STS before `ListAgents` and does not retain the credentials. See `docs/AGENT_BEDROCK_DISCOVERY.md` for scope and limits.
201
+
202
+ For Vertex Agent Engine, set `AYNIGMA_USER_JWT` and `GOOGLE_ACCESS_TOKEN`, then run `aynigma-agents-discover-vertex --company-id 42 --project-id sample-project --region us-central1`. The backend confirms the active Google Cloud project before listing reasoning engines. See `docs/AGENT_VERTEX_DISCOVERY.md`.
203
+
204
+ For a known Azure AI Foundry project, set `AYNIGMA_USER_JWT` and `AZURE_ACCESS_TOKEN`, then run `aynigma-agents-discover-azure --company-id 42 --project-endpoint https://account.services.ai.azure.com/api/projects/project`. See `docs/AGENT_AZURE_DISCOVERY.md`.
205
+
206
+ To find Foundry projects in a subscription first, set a separate `AZURE_ARM_ACCESS_TOKEN` and run `aynigma-agents-discover-azure --company-id 42 --subscription-id 11111111-2222-4333-8444-555555555555`. This lists bounded project metadata only; use a project token and endpoint to list agents.
207
+
208
+ For aggregate native Assess plugin review coverage, run `aynigma-assess-plugin-performance --project-id 42 --days 90` with `AYNIGMA_USER_JWT`. It returns counts only; see `docs/ASSESS_PLUGIN_PERFORMANCE.md` for interpretation.
209
+
210
+ When registering an agent through the dashboard API, an administrator may provide a same-company `project` ID to attribute approvals and incidents to that project's compliance evidence. The project cannot be changed after registration. See `docs/AGENT_COMPLIANCE_EVIDENCE.md`.
211
+
212
+ Administrators can read registered-agent slot usage at `GET /api/v1/agents/usage/?company=<id>`. Free includes two slots; current paid caps are documented in `docs/AGENT_PLAN_LIMITS.md`.
213
+
214
+ For agent tools acting on behalf of an authenticated person, wrap the tool invocation in `with acting_for_user(user_jwt):` after importing `acting_for_user` from `aynigma`. The binding is scoped to the current Python task and carries through async framework adapters; see `docs/AGENT_TOOL_EXECUTOR.md`.
215
+
216
+ ## Receipts are required
217
+
218
+ Run in-process tools with `auth.run_tool("ticket.create", {"title": "x"}, handler)` or `RemoteTool.local(auth, "ticket.create", handler)`. Both authorize, verify the one-use receipt, run the handler and report SUCCEEDED or FAILED. `ToolExecutor` refuses a call without a receipt unless you pass `require_receipt=False`, which is only for a backend running with `AGENT_REQUIRE_EXECUTION_RECEIPT=False`. See `docs/AGENT_TOOL_EXECUTOR.md`.
@@ -0,0 +1,173 @@
1
+ # Aynigma Python SDK
2
+
3
+ Python SDK for Aynigma: IAM for AI agents and AI security guardrails.
4
+
5
+ Authorize agent tool calls, handle human approvals, enforce execution receipts,
6
+ and scan prompts and responses with Protect.
7
+
8
+ ```bash
9
+ python -m pip install aynigma
10
+ # Or, from a source checkout of the backend repo:
11
+ python -m pip install ./sdk/python
12
+ export AYNIGMA_API_KEY=psk_your_project_key
13
+ ```
14
+
15
+ ```python
16
+ from aynigma import Aynigma
17
+
18
+ client = Aynigma()
19
+ result = client.guard("Hello", stage="prompt")
20
+ print(result.allowed)
21
+ ```
22
+
23
+ The default API URL is `https://api.aynigma.ai/api/v1`. Supply `base_url` or
24
+ set `AYNIGMA_API_URL` to use another deployment. Validation endpoints are
25
+ `/guardrails/validate/input/` and `/guardrails/validate/output/`; project keys
26
+ are sent in the `X-API-KEY` header.
27
+ These classic validation endpoints are deprecated. `validate_input()` and
28
+ `validate_output()` continue to work but emit `DeprecationWarning`; migrate to
29
+ `guard(text, stage="prompt")` and `guard(text, stage="response")` respectively.
30
+
31
+ Protect v2 stage-aware scans are also available from both sync and async
32
+ clients. `guard()` accepts `prompt`, `response`, `tool_call`, `tool_result`,
33
+ `retrieval`, or `document`; scope can be bound with `company_id`, `project_id`,
34
+ `system_id`, `environment_id`, `policy_id`, and a per-generation
35
+ `conversation_id`. When environment token pricing is enabled, direct `guard()`
36
+ calls for prompt/response billing also require a fresh unique `generation_id`;
37
+ the OpenAI wrappers create one automatically and reuse it across that model
38
+ call's stages. Keep a stable conversation ID across turns, but never reuse a
39
+ generation ID for a different provider call. A blocked scan raises the same
40
+ `BlockedError` as v1. V1 remains available for existing integrations.
41
+
42
+ Pass `end_user_id="customer-42"` to `guard()` to associate detections with an
43
+ end user for per-policy repeat-offender quarantine; IDs may be at most 128
44
+ characters and the server hashes them. SDK v2 guard calls automatically send
45
+ `X-Aynigma-Source: sdk`, which is recorded on detection events. A
46
+ `ValidationResult` exposes `user_message` and `quarantined`; when a blocked
47
+ response includes `user_message`, it is also used as `str(BlockedError)` and is
48
+ available on the exception's `user_message` attribute.
49
+
50
+ ```python
51
+ with Aynigma() as client:
52
+ result = client.guard(
53
+ "Retrieve customer account details",
54
+ "prompt",
55
+ system_id=4,
56
+ environment_id=12,
57
+ conversation_id="support-session-42",
58
+ generation_id="support-session-42-generation-1",
59
+ )
60
+ ```
61
+
62
+ `guard_openai_chat_v2()` scans prompt, previous tool results, response, and
63
+ proposed tool calls as separate stages. It rejects streaming rather than
64
+ releasing unchecked chunks; use the TypeScript wrapper or bounded LiteLLM
65
+ gateway for hold-back streaming.
66
+
67
+ ## Agent IAM quickstart
68
+
69
+ ```bash
70
+ python -m pip install aynigma
71
+ # Or, from a source checkout of the backend repo:
72
+ python -m pip install ./sdk/python
73
+ export AYNIGMA_AGENT_ID=<agent uuid>
74
+ export AYNIGMA_AGENT_KEY=agt_...
75
+ ```
76
+
77
+ With an agent ID and key the SDK trades the key for a 15 minute token, caches it, refreshes it at 80 % of its lifetime (or once after a 401), and sends `Authorization: Bearer <token>` on tool calls, receipt checks and MCP calls. The key is sent only to the token endpoint.
78
+
79
+ ```python
80
+ from aynigma import AgentAuthorizer, AgentTokenProvider, RemoteTool, acting_for_user
81
+
82
+ authorizer = AgentAuthorizer() # reads AYNIGMA_AGENT_ID, AYNIGMA_AGENT_KEY, AYNIGMA_API_URL
83
+ create_ticket = RemoteTool(authorizer, "https://executor.internal.example", "ticket.create")
84
+
85
+ # Delegation: act for a signed-in person. Their JWT is exchanged for a delegated token
86
+ # (RFC 8693); the raw JWT is never forwarded and the backend records a verified chain.
87
+ with acting_for_user(current_user_jwt):
88
+ create_ticket(title="Investigate alert")
89
+
90
+ # Narrow what the delegation may do, or hand it to a sub-agent.
91
+ scoped = authorizer.delegate(current_user_jwt, scope="db.read")
92
+ sub_authorizer = scoped.delegate_to(AgentTokenProvider(SUB_AGENT_ID, SUB_AGENT_KEY))
93
+ ```
94
+
95
+ Receipts: every ALLOW returns a one-use receipt bound to the exact arguments and, with tokens, to the agent run. The executor calls `ToolExecutor.execute` (verify, run, report) with its own `AgentAuthorizer`. If an administrator kills the run, verify and tool calls fail with `RunKilled` (a `ToolDenied`), the SDK drops its cached tokens, and the next call starts a new run. A report for an already consumed receipt is still accepted after a kill and is recorded as `after_kill`. A run that only ended (idle) is replaced transparently and logged at INFO on the `aynigma.agents` logger.
96
+
97
+ ### Approvals: pause and resume
98
+
99
+ A rule with effect REVIEW raises `ApprovalRequired` until a person approves the call in Agent IAM > Activity. The approval belongs to the run it was raised in, so save `approval_id` and `run_id` when you catch it. If the work continues in another process (a queue worker, a restart), build the new authorizer with that `run_id`. Without it the new process starts a fresh run and the call is denied with `run_mismatch`.
100
+
101
+ ```python
102
+ from aynigma import AgentAuthorizer, ApprovalRequired
103
+
104
+ authorizer = AgentAuthorizer(agent_id=AGENT_ID, agent_key=AGENT_KEY, base_url=BASE_URL)
105
+ try:
106
+ authorizer.run_tool(tool, params, handler)
107
+ except ApprovalRequired as pending:
108
+ saved_approval_id, saved_run_id = pending.approval_id, pending.run_id # store these with your task
109
+
110
+ # Later, after a reviewer approved it, possibly in a new process:
111
+ resumed = AgentAuthorizer(agent_id=AGENT_ID, agent_key=AGENT_KEY, base_url=BASE_URL, run_id=saved_run_id)
112
+ resumed.run_tool(tool, params, handler, approval_id=saved_approval_id) # same tool, same params
113
+ ```
114
+
115
+ `run_id` is None with the legacy `X-AGENT-KEY` header, which has no runs and needs no `run_id` to resume. If you pass your own `token_provider`, give that `AgentTokenProvider` the `run_id` instead; passing `run_id` to `AgentAuthorizer` as well raises `ValueError`. The arguments must match what was approved, or the call is denied with `payload_mismatch`.
116
+
117
+ Denials explain themselves: `str(ToolDenied)` starts with `Agent tool call denied: <code>` and adds a short hint for common codes (`no_policy`, `run_mismatch`, `payload_mismatch`, `approval_already_used`, `approval_expired`, `environment`, `rate_limited`). `error.reason` is the bare code and `error.hint` the hint, or None.
118
+
119
+ Debug a token from a shell: `AYNIGMA_AGENT_KEY=agt_... aynigma-agents-token --agent-id <uuid> --claims`. The key is never printed.
120
+
121
+ ## Verify an audit export offline
122
+
123
+ Auditors can check an audit export and its signed anchor without trusting the API. Standard library only.
124
+
125
+ ```bash
126
+ aynigma-audit-verify --export audit.json --anchor anchor.json \
127
+ --jwks https://api.aynigma.ai/api/v1/agents/.well-known/jwks.json \
128
+ --chain-key-file chain.key --full-chain
129
+ ```
130
+
131
+ `audit.json` is `GET /api/v1/audit/export/?log_type=audit&export_format=json` (an object with a `chain` header and `records`) and `anchor.json` is `GET /api/v1/audit/anchors/<id>/`. With the chain key (`--chain-key-file`, or `AYNIGMA_AUDIT_CHAIN_KEY`; `--chain-key` works but shows in the process list) every row is recomputed; without it only legacy rows are, and the report lists what was skipped. Legacy (v1) rows need no key, so they are trusted only up to the `last_v1_entry_id` signed inside a verified anchor (the export header's value is unsigned and never grants trust); a v1 row above it, or after a keyed row, is a forgery and fails. An export of only legacy rows with no verified anchor is INCONCLUSIVE. `--full-chain` means the export is the unfiltered chain, so each row must follow its predecessor.
132
+
133
+ Exit status: 0 pass, 1 a check failed, 2 inconclusive, 3 unusable input. PASS needs every row recomputed with the key, or an anchor whose head is in the export with an unbroken chain back from it (printed as "structure only", since v2 contents are not recomputed without the key). With neither the result is INCONCLUSIVE, never a pass. The hashing rules are in `docs/AUDIT_CHAIN.md` in the backend repo.
134
+
135
+ Migrating from `X-AGENT-KEY`: nothing breaks. A key with no agent ID keeps sending the header, and `use_legacy_key=True` (or `AYNIGMA_USE_LEGACY_KEY=1`) keeps it even when an agent ID is set. Since 0.3.0, `AgentAuthorizer` switches to tokens as soon as it has both an agent ID and a key. An explicit `agent_key=` with no `agent_id=` stays legacy, and `AYNIGMA_AGENT_ID` from the environment counts only together with `AYNIGMA_AGENT_KEY` from the environment. To move over, pass `agent_id=` or set both variables, and watch the `agent.legacy_key_used` audit event stop. `acting_for_user` and `initiator_token_provider` now exchange the user JWT instead of forwarding it; with the legacy header they forward it as before. Delegated tokens carry the delegation depth counted from the human (a direct human to agent hop is depth 1), so review `max_delegation_depth` conditions. See `docs/AGENT_TOOL_EXECUTOR.md` and `docs/AGENT_IDENTITY.md`.
136
+
137
+ Beyond the quickstart, use `AgentAuthorizer` and `RemoteTool` with a separately deployed receipt-enforcing executor. Optional adapters are `as_langchain_tool`, `as_openai_agents_tool`, `as_crewai_tool`, `as_claude_agent_tool`, `as_google_adk_tool`, and `as_semantic_kernel_function`; install their corresponding extras and pass a Pydantic argument model. `OpenAIAgentsApprovalBridge` uses the OpenAI Agents SDK's native approval interruption to preserve the exact model-selected call through backend REVIEW and receipt-backed resume. `build_crewai_approval_flow` uses CrewAI Flow human feedback and explicit persistence for the same handoff. `ClaudeAgentApprovalBridge` pairs the Claude Agent SDK's native `PreToolUse` defer hook with a receipt-backed MCP tool and caller-owned pending state. `SemanticKernelApprovalBridge` intercepts Semantic Kernel auto function invocation before a model-selected call and supports exact-call REVIEW resume through a caller-owned checkpoint. `as_google_adk_approval_tool` uses ADK's native confirmation event and persisted session state. Install `aynigma[google-adk-postgres]` for ADK's PostgreSQL session service; a local restart contract passed against a disposable PostgreSQL database. `build_langgraph_approval_workflow` adds a checkpointed pause/resume graph for REVIEW decisions and requires an explicit checkpointer. Install `aynigma[langgraph-postgres]` and use LangGraph's `PostgresSaver` for durable resume. See `docs/AGENT_TOOL_EXECUTOR.md` in the backend repository for the executor boundary and examples.
138
+
139
+ `PostgresApprovalCheckpointStore` is an optional encrypted store for serializable pending approval state shared across workers. Install `aynigma[approval-postgres]`, call `setup()` once, then `save()` and one-use `claim()` with authenticated tenant and agent UUIDs. Schedule `aynigma-approval-checkpoints-purge` daily with `AYNIGMA_APPROVAL_CHECKPOINT_DATABASE_URL` supplied from the operator's secret store; it prints only the number purged. The application still serializes framework-specific session state and authorizes its resume endpoint. See the executor guide for retention and recovery rules.
140
+
141
+ ```python
142
+ from aynigma import Aynigma, guard_openai_chat_v2
143
+
144
+ with Aynigma() as client:
145
+ response = guard_openai_chat_v2(
146
+ client,
147
+ openai_client,
148
+ messages,
149
+ model="gpt-4o-mini",
150
+ guard_options={"system_id": 4, "environment_id": 12},
151
+ )
152
+ ```
153
+ # Bedrock agent inventory
154
+
155
+ On a paid plan, run `aynigma-agents-discover-cloud --company-id 42 --account-id 123456789012 --region us-east-1` with `AYNIGMA_USER_JWT`, `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and optional `AWS_SESSION_TOKEN` set. The command sends the credentials once and prints only the bounded agent inventory. The backend checks the AWS account through STS before `ListAgents` and does not retain the credentials. See `docs/AGENT_BEDROCK_DISCOVERY.md` for scope and limits.
156
+
157
+ For Vertex Agent Engine, set `AYNIGMA_USER_JWT` and `GOOGLE_ACCESS_TOKEN`, then run `aynigma-agents-discover-vertex --company-id 42 --project-id sample-project --region us-central1`. The backend confirms the active Google Cloud project before listing reasoning engines. See `docs/AGENT_VERTEX_DISCOVERY.md`.
158
+
159
+ For a known Azure AI Foundry project, set `AYNIGMA_USER_JWT` and `AZURE_ACCESS_TOKEN`, then run `aynigma-agents-discover-azure --company-id 42 --project-endpoint https://account.services.ai.azure.com/api/projects/project`. See `docs/AGENT_AZURE_DISCOVERY.md`.
160
+
161
+ To find Foundry projects in a subscription first, set a separate `AZURE_ARM_ACCESS_TOKEN` and run `aynigma-agents-discover-azure --company-id 42 --subscription-id 11111111-2222-4333-8444-555555555555`. This lists bounded project metadata only; use a project token and endpoint to list agents.
162
+
163
+ For aggregate native Assess plugin review coverage, run `aynigma-assess-plugin-performance --project-id 42 --days 90` with `AYNIGMA_USER_JWT`. It returns counts only; see `docs/ASSESS_PLUGIN_PERFORMANCE.md` for interpretation.
164
+
165
+ When registering an agent through the dashboard API, an administrator may provide a same-company `project` ID to attribute approvals and incidents to that project's compliance evidence. The project cannot be changed after registration. See `docs/AGENT_COMPLIANCE_EVIDENCE.md`.
166
+
167
+ Administrators can read registered-agent slot usage at `GET /api/v1/agents/usage/?company=<id>`. Free includes two slots; current paid caps are documented in `docs/AGENT_PLAN_LIMITS.md`.
168
+
169
+ For agent tools acting on behalf of an authenticated person, wrap the tool invocation in `with acting_for_user(user_jwt):` after importing `acting_for_user` from `aynigma`. The binding is scoped to the current Python task and carries through async framework adapters; see `docs/AGENT_TOOL_EXECUTOR.md`.
170
+
171
+ ## Receipts are required
172
+
173
+ Run in-process tools with `auth.run_tool("ticket.create", {"title": "x"}, handler)` or `RemoteTool.local(auth, "ticket.create", handler)`. Both authorize, verify the one-use receipt, run the handler and report SUCCEEDED or FAILED. `ToolExecutor` refuses a call without a receipt unless you pass `require_receipt=False`, which is only for a backend running with `AGENT_REQUIRE_EXECUTION_RECEIPT=False`. See `docs/AGENT_TOOL_EXECUTOR.md`.
@@ -0,0 +1,40 @@
1
+ [build-system]
2
+ requires = ["hatchling==1.27.0"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "aynigma"
7
+ version = "0.3.1"
8
+ description = "Python SDK for Aynigma: IAM for AI agents and AI security guardrails"
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ dependencies = ["httpx>=0.25"]
12
+
13
+ [project.scripts]
14
+ aynigma-assess = "aynigma.assess:main"
15
+ aynigma-assess-plugin-performance = "aynigma.assess_plugins:main"
16
+ aynigma-agents-token = "aynigma.agent_tokens:main"
17
+ aynigma-agents-discover = "aynigma.discover:main"
18
+ aynigma-agents-discover-refresh = "aynigma.discover_refresh:main"
19
+ aynigma-agents-mcp-oauth = "aynigma.mcp_oauth:main"
20
+ aynigma-agents-discover-cloud = "aynigma.discover_cloud:main"
21
+ aynigma-agents-discover-vertex = "aynigma.discover_vertex:main"
22
+ aynigma-agents-discover-azure = "aynigma.discover_azure:main"
23
+ aynigma-approval-checkpoints-purge = "aynigma.approval_checkpoints:main"
24
+ aynigma-audit-verify = "aynigma.audit_verify:main"
25
+
26
+ [project.optional-dependencies]
27
+ dev = ["pytest>=7"]
28
+ langchain = ["langchain-core>=0.3,<1", "pydantic>=2.7,<3"]
29
+ langgraph = ["langgraph>=1.2,<1.3", "pydantic>=2.7,<3"]
30
+ langgraph-postgres = ["langgraph>=1.2,<1.3", "langgraph-checkpoint-postgres>=3.1,<3.2", "psycopg[binary]>=3.2,<4", "pydantic>=2.7,<3"]
31
+ openai-agents = ["openai-agents>=0.22,<0.23", "pydantic>=2.7,<3"]
32
+ crewai = ["crewai>=1.15,<1.16", "pydantic>=2.7,<3"]
33
+ claude-agent = ["claude-agent-sdk>=0.2.160,<0.3", "pydantic>=2.7,<3"]
34
+ google-adk = ["google-adk>=1.39,<1.40", "pydantic>=2.7,<3"]
35
+ google-adk-postgres = ["google-adk>=1.39,<1.40", "sqlalchemy[asyncio]>=2,<3", "asyncpg>=0.30,<1", "psycopg[binary]>=3.2,<4", "pydantic>=2.7,<3"]
36
+ approval-postgres = ["psycopg[binary]>=3.2,<4", "cryptography>=42,<51"]
37
+ semantic-kernel = ["semantic-kernel>=1.44,<1.45", "pydantic>=2.7,<3"]
38
+
39
+ [tool.hatch.build.targets.wheel]
40
+ packages = ["src/aynigma"]
@@ -0,0 +1,61 @@
1
+ from .client import (
2
+ APIError,
3
+ AsyncAynigma,
4
+ AuthenticationError,
5
+ Aynigma,
6
+ AynigmaError,
7
+ BlockedError,
8
+ QuotaExceededError,
9
+ ValidationResult,
10
+ aguard_openai_chat,
11
+ aguard_openai_chat_v2,
12
+ guard_openai_chat,
13
+ guard_openai_chat_v2,
14
+ )
15
+ from .agent_errors import MCPError, TokenError
16
+ from .agent_tokens import AgentTokenProvider, DelegatedToken
17
+ from .agents import AgentAuthorizer, ApprovalRequired, RunKilled, ClaudeAgentApprovalBridge, ExecutionReceipt, RemoteTool, ToolDenied, ToolExecutor, OpenAIAgentsApprovalBridge, SemanticKernelApprovalBridge, acting_for_user, as_langchain_tool, build_langgraph_approval_workflow, build_crewai_approval_flow, as_openai_agents_tool, as_crewai_tool, as_claude_agent_tool, as_google_adk_tool, as_google_adk_approval_tool, as_semantic_kernel_function
18
+ from .approval_checkpoints import PostgresApprovalCheckpointStore
19
+
20
+ async_guard_openai_chat = aguard_openai_chat
21
+
22
+ __all__ = [
23
+ "APIError",
24
+ "AgentAuthorizer",
25
+ "AgentTokenProvider",
26
+ "DelegatedToken",
27
+ "RunKilled",
28
+ "TokenError",
29
+ "MCPError",
30
+ "ApprovalRequired",
31
+ "ClaudeAgentApprovalBridge",
32
+ "AsyncAynigma",
33
+ "AuthenticationError",
34
+ "Aynigma",
35
+ "AynigmaError",
36
+ "BlockedError",
37
+ "ExecutionReceipt",
38
+ "OpenAIAgentsApprovalBridge",
39
+ "PostgresApprovalCheckpointStore",
40
+ "SemanticKernelApprovalBridge",
41
+ "QuotaExceededError",
42
+ "RemoteTool",
43
+ "ToolDenied",
44
+ "ToolExecutor",
45
+ "acting_for_user",
46
+ "as_langchain_tool",
47
+ "build_langgraph_approval_workflow",
48
+ "build_crewai_approval_flow",
49
+ "as_openai_agents_tool",
50
+ "as_crewai_tool",
51
+ "as_claude_agent_tool",
52
+ "as_google_adk_tool",
53
+ "as_google_adk_approval_tool",
54
+ "as_semantic_kernel_function",
55
+ "ValidationResult",
56
+ "aguard_openai_chat",
57
+ "aguard_openai_chat_v2",
58
+ "async_guard_openai_chat",
59
+ "guard_openai_chat",
60
+ "guard_openai_chat_v2",
61
+ ]