agenticdome-python-sdk 1.2.35__py3-none-any.whl → 1.2.37__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {agenticdome_python_sdk-1.2.35.dist-info → agenticdome_python_sdk-1.2.37.dist-info}/METADATA +74 -18
- {agenticdome_python_sdk-1.2.35.dist-info → agenticdome_python_sdk-1.2.37.dist-info}/RECORD +21 -17
- agenticdome_sdk/__init__.py +5 -0
- agenticdome_sdk/action_path_proof.py +263 -0
- agenticdome_sdk/catalog_snapshot.json +6 -6
- agenticdome_sdk/client.py +6 -0
- agenticdome_sdk/existing_integration.py +250 -0
- agenticdome_sdk/framework_edits.py +448 -0
- agenticdome_sdk/generic_python.py +149 -0
- agenticdome_sdk/guided_integration.py +226 -20
- agenticdome_sdk/hook_catalog.py +9 -9
- agenticdome_sdk/mcp_host.py +177 -91
- agenticdome_sdk/mcp_http_gateway.py +9 -10
- agenticdome_sdk/mcp_verification.py +5 -2
- agenticdome_sdk/onboarding_cli.py +382 -16
- agenticdome_sdk/openai_agents.py +7 -2
- {agenticdome_python_sdk-1.2.35.dist-info → agenticdome_python_sdk-1.2.37.dist-info}/WHEEL +0 -0
- {agenticdome_python_sdk-1.2.35.dist-info → agenticdome_python_sdk-1.2.37.dist-info}/entry_points.txt +0 -0
- {agenticdome_python_sdk-1.2.35.dist-info → agenticdome_python_sdk-1.2.37.dist-info}/licenses/LICENSE +0 -0
- {agenticdome_python_sdk-1.2.35.dist-info → agenticdome_python_sdk-1.2.37.dist-info}/licenses/NOTICE +0 -0
- {agenticdome_python_sdk-1.2.35.dist-info → agenticdome_python_sdk-1.2.37.dist-info}/top_level.txt +0 -0
{agenticdome_python_sdk-1.2.35.dist-info → agenticdome_python_sdk-1.2.37.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agenticdome-python-sdk
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.37
|
|
4
4
|
Summary: Official Python SDK for AgenticDome security guardrails, DLP, tool authorization, and multi-agent delegation enforcement.
|
|
5
5
|
Author: AgenticDome
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -33,7 +33,7 @@ Requires-Dist: requests>=2.31.0
|
|
|
33
33
|
Requires-Dist: urllib3>=2.0.0
|
|
34
34
|
Requires-Dist: cryptography>=42.0.0
|
|
35
35
|
Provides-Extra: crewai
|
|
36
|
-
Requires-Dist: crewai<=1.15.
|
|
36
|
+
Requires-Dist: crewai<=1.15.23,>=1.15.5; extra == "crewai"
|
|
37
37
|
Provides-Extra: redis
|
|
38
38
|
Requires-Dist: redis>=4.5.0; extra == "redis"
|
|
39
39
|
Provides-Extra: pop
|
|
@@ -46,7 +46,7 @@ Requires-Dist: pydantic-ai<=2.51.0,>=2.16.0; extra == "pydantic"
|
|
|
46
46
|
Requires-Dist: anyio>=4.0.0; extra == "pydantic"
|
|
47
47
|
Provides-Extra: langgraph
|
|
48
48
|
Requires-Dist: langgraph<=1.2.12,>=1.2.9; extra == "langgraph"
|
|
49
|
-
Requires-Dist: langchain-core<=1.6.
|
|
49
|
+
Requires-Dist: langchain-core<=1.6.6,>=1.5.0; extra == "langgraph"
|
|
50
50
|
Requires-Dist: langchain-openai==1.3.5; extra == "langgraph"
|
|
51
51
|
Requires-Dist: anyio>=4.0.0; extra == "langgraph"
|
|
52
52
|
Provides-Extra: microsoft
|
|
@@ -64,9 +64,9 @@ Requires-Dist: openai-agents<=0.22.3,>=0.18.3; extra == "openai-agents"
|
|
|
64
64
|
Provides-Extra: mcp
|
|
65
65
|
Requires-Dist: mcp<=2.2.0,>=1.26.0; extra == "mcp"
|
|
66
66
|
Provides-Extra: bedrock
|
|
67
|
-
Requires-Dist: boto3<=1.43.
|
|
67
|
+
Requires-Dist: boto3<=1.43.105,>=1.43.54; extra == "bedrock"
|
|
68
68
|
Provides-Extra: aws-bedrock
|
|
69
|
-
Requires-Dist: boto3<=1.43.
|
|
69
|
+
Requires-Dist: boto3<=1.43.105,>=1.43.54; extra == "aws-bedrock"
|
|
70
70
|
Provides-Extra: llamaindex
|
|
71
71
|
Requires-Dist: llama-index<=0.14.25,>=0.14.23; extra == "llamaindex"
|
|
72
72
|
Provides-Extra: llama-index
|
|
@@ -76,19 +76,19 @@ Requires-Dist: google-adk<=2.10.0,>=2.5.0; extra == "google-adk"
|
|
|
76
76
|
Provides-Extra: adk
|
|
77
77
|
Requires-Dist: google-adk<=2.10.0,>=2.5.0; extra == "adk"
|
|
78
78
|
Provides-Extra: claude
|
|
79
|
-
Requires-Dist: claude-agent-sdk<=0.2.
|
|
79
|
+
Requires-Dist: claude-agent-sdk<=0.2.162,>=0.2.126; extra == "claude"
|
|
80
80
|
Provides-Extra: claude-agent-sdk
|
|
81
|
-
Requires-Dist: claude-agent-sdk<=0.2.
|
|
81
|
+
Requires-Dist: claude-agent-sdk<=0.2.162,>=0.2.126; extra == "claude-agent-sdk"
|
|
82
82
|
Provides-Extra: smolagents
|
|
83
83
|
Requires-Dist: smolagents==1.26.0; extra == "smolagents"
|
|
84
84
|
Provides-Extra: all
|
|
85
|
-
Requires-Dist: crewai<=1.15.
|
|
85
|
+
Requires-Dist: crewai<=1.15.23,>=1.15.5; extra == "all"
|
|
86
86
|
Requires-Dist: redis>=4.5.0; extra == "all"
|
|
87
87
|
Requires-Dist: cryptography>=42.0.0; extra == "all"
|
|
88
88
|
Requires-Dist: pydantic-ai<=2.51.0,>=2.16.0; extra == "all"
|
|
89
89
|
Requires-Dist: anyio>=4.0.0; extra == "all"
|
|
90
90
|
Requires-Dist: langgraph<=1.2.12,>=1.2.9; extra == "all"
|
|
91
|
-
Requires-Dist: langchain-core<=1.6.
|
|
91
|
+
Requires-Dist: langchain-core<=1.6.6,>=1.5.0; extra == "all"
|
|
92
92
|
Requires-Dist: langchain-openai==1.3.5; extra == "all"
|
|
93
93
|
Requires-Dist: autogen-agentchat==0.7.5; extra == "all"
|
|
94
94
|
Requires-Dist: agno<=3.0.11,>=2.8.0; extra == "all"
|
|
@@ -96,10 +96,10 @@ Requires-Dist: azure-ai-projects<=2.7.0,>=2.3.0; extra == "all"
|
|
|
96
96
|
Requires-Dist: azure-identity==1.25.3; extra == "all"
|
|
97
97
|
Requires-Dist: openai-agents<=0.22.3,>=0.18.3; extra == "all"
|
|
98
98
|
Requires-Dist: mcp<=2.2.0,>=1.26.0; extra == "all"
|
|
99
|
-
Requires-Dist: boto3<=1.43.
|
|
99
|
+
Requires-Dist: boto3<=1.43.105,>=1.43.54; extra == "all"
|
|
100
100
|
Requires-Dist: llama-index<=0.14.25,>=0.14.23; extra == "all"
|
|
101
101
|
Requires-Dist: google-adk<=2.10.0,>=2.5.0; extra == "all"
|
|
102
|
-
Requires-Dist: claude-agent-sdk<=0.2.
|
|
102
|
+
Requires-Dist: claude-agent-sdk<=0.2.162,>=0.2.126; extra == "all"
|
|
103
103
|
Requires-Dist: smolagents==1.26.0; extra == "all"
|
|
104
104
|
Provides-Extra: dev
|
|
105
105
|
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
@@ -177,16 +177,60 @@ agenticdome inspect --output agenticdome-inspection.json
|
|
|
177
177
|
|
|
178
178
|
`init` writes the secret-free inspection and local configuration. For the
|
|
179
179
|
certified onboarding path, obtain the assigned sidecar and a dedicated
|
|
180
|
-
`integration_copilot` key, run `agenticdome integrate preview
|
|
180
|
+
`integration_copilot` key, run `agenticdome integrate preview` and
|
|
181
|
+
`agenticdome integrate status`, review the saved
|
|
181
182
|
local exact diff and change summary, explicitly approve a supported edit or
|
|
182
183
|
attach other boundaries manually, then run
|
|
183
184
|
`agenticdome verify --run-tests --output .agenticdome/verification.json`.
|
|
184
|
-
|
|
185
|
+
|
|
186
|
+
If a coding assistant has already made and tested the application edits,
|
|
187
|
+
import its canonical `AgenticDome_Integration.md` in the customer portal and
|
|
188
|
+
run `agenticdome validate-report --report AgenticDome_Integration.md` from
|
|
189
|
+
that same deployable workload. Import the two generated, hash-bound JSON files
|
|
190
|
+
in Onboarding. This avoids repeating the guided edit plan; the Markdown counts
|
|
191
|
+
remain AI-reported and a real action-path test is still required before
|
|
192
|
+
claiming protection. See the [customer onboarding guide](docs/customer-onboarding.md).
|
|
193
|
+
|
|
194
|
+
For the Pilot path, preview obtains the private, signed, catalog-bound semantic plan and keeps
|
|
185
195
|
application source on your machine. `agenticdome integrate apply` creates a
|
|
186
196
|
local Git review branch but never commits, pushes or deploys. Existing-source
|
|
187
|
-
automatic edits
|
|
188
|
-
|
|
197
|
+
automatic edits cover unambiguous CrewAI bootstrap, PydanticAI `Agent(...)`,
|
|
198
|
+
LangChain `create_agent(...)`, Google ADK agent construction, Claude options,
|
|
199
|
+
Agno `Agent(...)`, direct LlamaIndex `FunctionTool.from_defaults(...)`, direct
|
|
200
|
+
OpenAI Agents `FunctionTool(...)` handlers, explicit custom-Python tool
|
|
201
|
+
dispatchers, and the exact smolagents run pattern.
|
|
202
|
+
The CLI leaves dynamic construction,
|
|
203
|
+
existing handwritten AgenticDome calls, MCP forwarding and other framework
|
|
204
|
+
paths for explicit review; a patch never proves all routes are intercepted.
|
|
205
|
+
The older `agenticdome plan`
|
|
189
206
|
and `agenticdome scaffold` remain available as advanced review-only commands.
|
|
207
|
+
Preview auto-selects an application or pure-MCP review path and reports
|
|
208
|
+
existing Python SDK call-site candidates, including handwritten local
|
|
209
|
+
wrappers. Discovery uses the versioned framework hook catalog plus documented
|
|
210
|
+
prompt, tool, A2A/delegation, MCP and output API methods; categories may
|
|
211
|
+
overlap and TypeScript call sites are not parsed by this Python checker. Mixed
|
|
212
|
+
application/MCP workloads get a separate MCP review path.
|
|
213
|
+
Each preview rescans the selected workload. If code added a framework after
|
|
214
|
+
`init`, its certified hook contract is included in the new plan and flagged for
|
|
215
|
+
review without changing `.agenticdome/config.json`; a framework still in that
|
|
216
|
+
config but absent from the current scan is flagged for confirmation. Run
|
|
217
|
+
`agenticdome integrate status` for the saved next action and import a fresh
|
|
218
|
+
`agenticdome inspect --output agenticdome-inspection.json` after reviewing it.
|
|
219
|
+
These static observations do not prove interception; the CLI avoids
|
|
220
|
+
overlapping automatic rewrites and requires real blocked-action tests.
|
|
221
|
+
|
|
222
|
+
For one consequential tool, run your own safe integration test through the
|
|
223
|
+
actual application route with an `ExecutionSpy` around its test handler, then
|
|
224
|
+
correlate the SDK adapter call, live-mode verdict and handler invocation:
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
agenticdome verify-action --tool billing.refund --expect-verdict BLOCKED --expect-executed no -- pytest -q tests/test_blocked_refund.py
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
The test must call `spy.assert_calls(0)` (or `1` for an allowed test); see the
|
|
231
|
+
[real action-path test guide](docs/customer-onboarding.md#prove-one-real-action-path).
|
|
232
|
+
This opt-in command does not execute a business action itself, and a fixed
|
|
233
|
+
`agenticdome verify` probe is not a substitute for the real-path test.
|
|
190
234
|
|
|
191
235
|
For an MCP client, host, gateway or server workload, use the focused path:
|
|
192
236
|
|
|
@@ -224,6 +268,7 @@ openclaw plugins install npm:agenticdome-openclaw-security
|
|
|
224
268
|
openclaw plugins enable agenticdome-security
|
|
225
269
|
openclaw config set plugins.entries.agenticdome-security.hooks.allowConversationAccess true
|
|
226
270
|
openclaw gateway restart
|
|
271
|
+
openclaw gateway status --require-rpc
|
|
227
272
|
agenticdome openclaw protect
|
|
228
273
|
# With AGENTICDOME_API_BASE, AGENTICDOME_TENANT_ID and the dedicated
|
|
229
274
|
# AGENTICDOME_COPILOT_API_KEY set, generate and review the signed plan:
|
|
@@ -232,8 +277,11 @@ agenticdome plan
|
|
|
232
277
|
agenticdome openclaw verify --output .agenticdome/verification.json
|
|
233
278
|
```
|
|
234
279
|
|
|
235
|
-
`openclaw protect`
|
|
236
|
-
|
|
280
|
+
`openclaw protect` checks the AgenticDome plugin, explicit consent and exact
|
|
281
|
+
typed hooks in the inspecting CLI process. `gateway status` checks the serving
|
|
282
|
+
Gateway's RPC reachability; neither proves that this Gateway ran a hook on a
|
|
283
|
+
customer tool call. Exercise a safe tool through the actual Gateway and inspect
|
|
284
|
+
the matching AgenticDome runtime decision before claiming that route is protected.
|
|
237
285
|
The official `openclaw plugins install`, `enable`, `config set` and gateway
|
|
238
286
|
restart commands are the actual runtime configuration change; the Python CLI
|
|
239
287
|
does not apply or undo them. No application source patch is needed for native
|
|
@@ -246,7 +294,8 @@ includes the MCP transport rehearsal and both `mcp_verification` and
|
|
|
246
294
|
`openclaw_verification` in one report. Both sections must be ready before the
|
|
247
295
|
report is imported; `mcp verify` alone is not a combined-workload proof. The
|
|
248
296
|
customer Control Panel separately confirms tenant binding and retained
|
|
249
|
-
telemetry; neither command silently modifies customer source
|
|
297
|
+
telemetry for its probes; neither command silently modifies customer source or
|
|
298
|
+
proves that every live Gateway tool route was intercepted.
|
|
250
299
|
|
|
251
300
|
When `.agenticdome/inspection.json` is imported into Developer Integration,
|
|
252
301
|
the Control Panel adds its detected frameworks to the workload. Frameworks,
|
|
@@ -1582,6 +1631,13 @@ async def lookup_customer(customer_id: str) -> str:
|
|
|
1582
1631
|
)
|
|
1583
1632
|
```
|
|
1584
1633
|
|
|
1634
|
+
If you construct `agents.FunctionTool` directly, its `on_invoke_tool`
|
|
1635
|
+
handler receives JSON text. Use `handler_args_format="json"` with
|
|
1636
|
+
`wrap_tool_handler` so the approved or sanitized arguments reach the original
|
|
1637
|
+
handler in that same format. The guided integration preview offers this edit
|
|
1638
|
+
only for a direct, statically named `FunctionTool` with an identifiable
|
|
1639
|
+
handler; other tool factories require manual review and a real-route test.
|
|
1640
|
+
|
|
1585
1641
|
**Delegated specialist tool pattern:**
|
|
1586
1642
|
|
|
1587
1643
|
```python
|
|
@@ -1,42 +1,46 @@
|
|
|
1
|
-
agenticdome_python_sdk-1.2.
|
|
2
|
-
agenticdome_python_sdk-1.2.
|
|
3
|
-
agenticdome_sdk/__init__.py,sha256=
|
|
1
|
+
agenticdome_python_sdk-1.2.37.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
|
2
|
+
agenticdome_python_sdk-1.2.37.dist-info/licenses/NOTICE,sha256=obvKP6kV1Ny5R8_INFOpf0X5um9U2X43LGwQFobO9kg,550
|
|
3
|
+
agenticdome_sdk/__init__.py,sha256=1JY5ELhtp0zg-82xhgt6NxZ7k5CWL5e_Tm6BrsuCFXc,1102
|
|
4
4
|
agenticdome_sdk/_framework_firewall.py,sha256=W3gy7WsK50scE7ypJrmVJhHUOBsr0zAWQ85rghqaJk4,31963
|
|
5
5
|
agenticdome_sdk/_mode.py,sha256=XvOgh5sW-FG8S39V483h3uLiFh8wSt14OmYXz_6eDO8,1283
|
|
6
|
+
agenticdome_sdk/action_path_proof.py,sha256=5Zlghy7-LNhtRJM0Unb4NPUASzIsAC0LaWNVFR2yzzo,13497
|
|
6
7
|
agenticdome_sdk/agno.py,sha256=L3yfjTBHW47xzT67a1DsjtwmvrAoYBkbxADpsr85Cp0,60766
|
|
7
8
|
agenticdome_sdk/attestation.py,sha256=ij4cMff7nzLaIS0W02d2WURFcyKe72bcUlSz-dYkaLE,10310
|
|
8
9
|
agenticdome_sdk/autogen.py,sha256=KP4qlIcsNXB-4ZT9D7Slc1xWEeWXRIWkc5HGW0U6k2c,29018
|
|
9
10
|
agenticdome_sdk/aws_bedrock.py,sha256=2zD9j7xi0jna0sMeMf-hKZdc3Y4RPwzj6tMVOUGgIDQ,69581
|
|
10
|
-
agenticdome_sdk/catalog_snapshot.json,sha256=
|
|
11
|
+
agenticdome_sdk/catalog_snapshot.json,sha256=51ls_eO8qy5BCZRamVz6G7F265WYFO2LaOEerO1zcA0,951
|
|
11
12
|
agenticdome_sdk/claude.py,sha256=XeY9AUu61SYcJjQVz_AtL_WaN6X4KqP5nprEbbr4Q6A,17456
|
|
12
|
-
agenticdome_sdk/client.py,sha256=
|
|
13
|
+
agenticdome_sdk/client.py,sha256=SQk7BROrcedyHAfubGiwGNNGycq7W7L-Ncjroj1ugBg,69815
|
|
13
14
|
agenticdome_sdk/connect.py,sha256=MY30wXYA6OaZhs__E67KcFXEy7mZMBxMSV06BnlBjRg,18766
|
|
14
15
|
agenticdome_sdk/copilot_ir.py,sha256=zT13tOX8xu11yrOtIPMRFVud8CQ81Gu3WxsXxyQ4XT0,17928
|
|
15
16
|
agenticdome_sdk/copilot_ir_collector.cjs,sha256=oxLY8ByONo7Es4YjYiJuRz_A7IKL65Sy486UXnu-4Rs,9681
|
|
16
17
|
agenticdome_sdk/crewai.py,sha256=sSJQ49O7-8kqOAD2_jrsMtMOmBOcJmFkeOv7S3-ayMs,52490
|
|
17
18
|
agenticdome_sdk/demo.py,sha256=dyfqt2N_cJoyUWKnjPYuQxuw2hb2DrCNUf1jQKeYYoc,8350
|
|
19
|
+
agenticdome_sdk/existing_integration.py,sha256=be6xFqe3P9d98YOydHzDeyRSbuAim4bLBrfafLOJpJM,11465
|
|
20
|
+
agenticdome_sdk/framework_edits.py,sha256=4BgWHxWKEkex8_DMhjVxjovpUVkrMF7TsCZzlS94mpA,23344
|
|
21
|
+
agenticdome_sdk/generic_python.py,sha256=JtXRcYEZ6_Dgxnnv4QgqeMZR8dFVr8EqFDM-XYQ-GMA,6823
|
|
18
22
|
agenticdome_sdk/google_adk.py,sha256=2TA-tUhY0lOnkGcs1BN9CUEz67ebVX4HJ7mnNoRPcZs,57258
|
|
19
|
-
agenticdome_sdk/guided_integration.py,sha256=
|
|
20
|
-
agenticdome_sdk/hook_catalog.py,sha256=
|
|
23
|
+
agenticdome_sdk/guided_integration.py,sha256=m7EsgLrPEJhfrVMaVWO2DtjYp6S8PwpCKDYZPNbVZ2o,52259
|
|
24
|
+
agenticdome_sdk/hook_catalog.py,sha256=XRc_MeEE3LArX1R0xfO3Vo6nZbF3U-4cOkTOMfMOZS8,29272
|
|
21
25
|
agenticdome_sdk/identity.py,sha256=mrymGgZSVsKJ9THRde54qGmMT7j_uZHmPJ-HtWk7PXE,4635
|
|
22
26
|
agenticdome_sdk/langgraph.py,sha256=FUvF6DSA5aZP3eoBoNeldgGtPrz-dO5xcVmrPPSBEhI,84312
|
|
23
27
|
agenticdome_sdk/lifecycle.py,sha256=9LvxmUU1LC_tMchb5uVFBnZIkVFUxOv3VH9wG_9gPtA,12855
|
|
24
28
|
agenticdome_sdk/llamaindex.py,sha256=BHplSUIsgMi7k8tBztprzaV9iaOXiljXbdeMRax_2h8,42860
|
|
25
|
-
agenticdome_sdk/mcp_host.py,sha256=
|
|
26
|
-
agenticdome_sdk/mcp_http_gateway.py,sha256=
|
|
29
|
+
agenticdome_sdk/mcp_host.py,sha256=T9ICAyz8SjOhssuhXaiEuav5fduWriDhuZ4U_e8Jh9w,69389
|
|
30
|
+
agenticdome_sdk/mcp_http_gateway.py,sha256=XrTgj46ZHIKJ9xS3EQPsac2C9OGUZnrOXomcLdkMk_Y,13629
|
|
27
31
|
agenticdome_sdk/mcp_rehearsal_server.py,sha256=cox4XqUTL8d0gaDzqxDZcEALkaz8otjOjOqHvoUeeCo,2118
|
|
28
|
-
agenticdome_sdk/mcp_verification.py,sha256=
|
|
32
|
+
agenticdome_sdk/mcp_verification.py,sha256=WtRhAFVPTBqGOcHNf_db1m4jX9_TO0oxP98XWk4_ISY,14551
|
|
29
33
|
agenticdome_sdk/microsoft_agent_framework.py,sha256=GfIIuk0n-VhsZaTyoB7P6ilpz9bFLD95TWuX0rFSWeU,67219
|
|
30
34
|
agenticdome_sdk/microsoft_ai_foundry.py,sha256=YlO968s1dbAYcaEqhqufL92NFR66GuTtngnCv7-1mYc,56911
|
|
31
|
-
agenticdome_sdk/onboarding_cli.py,sha256=
|
|
32
|
-
agenticdome_sdk/openai_agents.py,sha256=
|
|
35
|
+
agenticdome_sdk/onboarding_cli.py,sha256=V1MKiiYudC48SgaZNYMmUysgRjwARGG6S0VUf4ZLLtU,150677
|
|
36
|
+
agenticdome_sdk/openai_agents.py,sha256=0z-7FDBIG4usxnILpan6yjQHF4zXIzm9YLsh3-bW8Lw,57678
|
|
33
37
|
agenticdome_sdk/outcomes.py,sha256=jadWDzQaZXrHNvpPme8lQY0jihYLCoM3s4CihAq0JRo,2507
|
|
34
38
|
agenticdome_sdk/proof.py,sha256=ECKc14xSE0V1HHmcpZjfVz8-Q2H_fooah3BfdblFV8M,2878
|
|
35
39
|
agenticdome_sdk/pydantic.py,sha256=WKb8X0Fgydfid-ep8E-M8Yslz2pWcCP6w7n_aBxt1rI,54961
|
|
36
40
|
agenticdome_sdk/simulation.py,sha256=UCbZy3u9AzfxQCfY38SCV3CxGxhinV9EA4aHMPlK4mc,8426
|
|
37
41
|
agenticdome_sdk/smolagents.py,sha256=wjMA1HVAQ-9wRNM38Jr9wlCpKMhF-9vxtTk6R-kwQhs,19094
|
|
38
|
-
agenticdome_python_sdk-1.2.
|
|
39
|
-
agenticdome_python_sdk-1.2.
|
|
40
|
-
agenticdome_python_sdk-1.2.
|
|
41
|
-
agenticdome_python_sdk-1.2.
|
|
42
|
-
agenticdome_python_sdk-1.2.
|
|
42
|
+
agenticdome_python_sdk-1.2.37.dist-info/METADATA,sha256=MYsYXQMJm4WcWtRlr7bhEtug7k6TuLhJHknT8WjPhoE,145282
|
|
43
|
+
agenticdome_python_sdk-1.2.37.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
44
|
+
agenticdome_python_sdk-1.2.37.dist-info/entry_points.txt,sha256=cRfCphkr5gLrkGIzXJEtL50HdHLajoZLbZtcMLE8NoY,113
|
|
45
|
+
agenticdome_python_sdk-1.2.37.dist-info/top_level.txt,sha256=LZbbjXco5mqDrGwlTJpIKI5Sp6R_njzHHjExxAs9c3s,16
|
|
46
|
+
agenticdome_python_sdk-1.2.37.dist-info/RECORD,,
|
agenticdome_sdk/__init__.py
CHANGED
|
@@ -3,6 +3,8 @@ from .identity import IDENTITY_CONTEXT_VERSION, canonicalize_identity_context, e
|
|
|
3
3
|
from .proof import create_dpop_proof, generate_rsa_proof_key, jwk_thumbprint
|
|
4
4
|
from ._mode import LIVE_MODE, LOCAL_SIM_MODE, is_local_sim_mode, resolve_mode
|
|
5
5
|
from .lifecycle import VerifiedActionContext, VerifiedActionDenied, VerifiedActionReporter, verified_action
|
|
6
|
+
from .action_path_proof import ExecutionSpy
|
|
7
|
+
from .generic_python import AgenticDomeActionDenied, guarded_tool_executor
|
|
6
8
|
|
|
7
9
|
__all__ = [
|
|
8
10
|
"AgenticDomeClient",
|
|
@@ -22,4 +24,7 @@ __all__ = [
|
|
|
22
24
|
"VerifiedActionDenied",
|
|
23
25
|
"VerifiedActionReporter",
|
|
24
26
|
"verified_action",
|
|
27
|
+
"ExecutionSpy",
|
|
28
|
+
"AgenticDomeActionDenied",
|
|
29
|
+
"guarded_tool_executor",
|
|
25
30
|
]
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
"""Opt-in, source-free evidence for a customer-run action-path test.
|
|
2
|
+
|
|
3
|
+
The test must install ExecutionSpy around the actual business handler. A
|
|
4
|
+
sidecar verdict on its own never proves that the handler did or did not run.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import functools
|
|
10
|
+
import hashlib
|
|
11
|
+
import inspect
|
|
12
|
+
import json
|
|
13
|
+
import os
|
|
14
|
+
import re
|
|
15
|
+
import stat
|
|
16
|
+
import subprocess
|
|
17
|
+
import sys
|
|
18
|
+
import tempfile
|
|
19
|
+
import time
|
|
20
|
+
from datetime import datetime, timezone
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
from typing import Any, Callable, Dict, Optional, Sequence, Tuple
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
_ADAPTERS = frozenset({
|
|
26
|
+
"crewai", "pydantic", "langgraph", "microsoft_agent_framework",
|
|
27
|
+
"autogen", "microsoft_ai_foundry", "openai_agents", "claude",
|
|
28
|
+
"smolagents", "agno", "google_adk", "llamaindex", "aws_bedrock",
|
|
29
|
+
"mcp_host", "generic_python", "_framework_firewall",
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _hook_frame() -> Tuple[str, str]:
|
|
34
|
+
frame = sys._getframe(2)
|
|
35
|
+
generic = ("", "")
|
|
36
|
+
try:
|
|
37
|
+
while frame:
|
|
38
|
+
module = str(frame.f_globals.get("__name__", ""))
|
|
39
|
+
if module.startswith("agenticdome_sdk.") and module.rsplit(".", 1)[-1] in _ADAPTERS:
|
|
40
|
+
if module != "agenticdome_sdk._framework_firewall":
|
|
41
|
+
return module, frame.f_code.co_name
|
|
42
|
+
if not generic[0]:
|
|
43
|
+
generic = (module, frame.f_code.co_name)
|
|
44
|
+
frame = frame.f_back
|
|
45
|
+
finally:
|
|
46
|
+
del frame
|
|
47
|
+
return generic
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _append_event(event: Dict[str, Any]) -> None:
|
|
51
|
+
path = os.environ.get("AGENTICDOME_ACTION_PROOF_FILE", "")
|
|
52
|
+
if not path or not os.path.isabs(path):
|
|
53
|
+
return
|
|
54
|
+
event = {"schema": "agenticdome.action-path-event.v1", **event}
|
|
55
|
+
encoded = (json.dumps(event, sort_keys=True, separators=(",", ":")) + "\n").encode("utf-8")
|
|
56
|
+
if len(encoded) > 2048:
|
|
57
|
+
return
|
|
58
|
+
flags = os.O_WRONLY | os.O_APPEND | os.O_CREAT
|
|
59
|
+
if hasattr(os, "O_NOFOLLOW"):
|
|
60
|
+
flags |= os.O_NOFOLLOW
|
|
61
|
+
try:
|
|
62
|
+
fd = os.open(path, flags, 0o600)
|
|
63
|
+
try:
|
|
64
|
+
info = os.fstat(fd)
|
|
65
|
+
if not stat.S_ISREG(info.st_mode) or info.st_size > 262144:
|
|
66
|
+
return
|
|
67
|
+
os.write(fd, encoded)
|
|
68
|
+
finally:
|
|
69
|
+
os.close(fd)
|
|
70
|
+
except OSError:
|
|
71
|
+
# Proof is optional instrumentation; it must not change enforcement.
|
|
72
|
+
return
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def record_policy_decision(*, tool_name: Optional[str], platform: Optional[str],
|
|
76
|
+
direction: str, response: Dict[str, Any], live: bool) -> None:
|
|
77
|
+
"""Record no prompt, arguments, identity, token, or raw response."""
|
|
78
|
+
if not os.environ.get("AGENTICDOME_ACTION_PROOF_FILE") or not tool_name:
|
|
79
|
+
return
|
|
80
|
+
module, function = _hook_frame()
|
|
81
|
+
envelope = response.get("result") if isinstance(response.get("result"), dict) else response
|
|
82
|
+
verdict = str(envelope.get("verdict") or envelope.get("decision") or "UNKNOWN").upper()
|
|
83
|
+
decision_id = str(envelope.get("decision_id") or response.get("decision_id") or "")
|
|
84
|
+
_append_event({
|
|
85
|
+
"kind": "policy_decision", "tool_name": str(tool_name)[:160],
|
|
86
|
+
"platform": str(platform or "")[:80], "direction": str(direction)[:24],
|
|
87
|
+
"verdict": verdict if verdict in {"ALLOWED", "BLOCKED", "REDACTED"} else "UNKNOWN",
|
|
88
|
+
"live": bool(live), "hook_module": module, "hook_function": function,
|
|
89
|
+
"decision_id": decision_id if re.fullmatch(r"[A-Za-z0-9._:-]{1,100}", decision_id) else "",
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class ExecutionSpy:
|
|
94
|
+
"""Wrap the real test handler, then assert its invocation count in the test."""
|
|
95
|
+
|
|
96
|
+
def __init__(self, tool_name: str):
|
|
97
|
+
if not tool_name or len(tool_name) > 160:
|
|
98
|
+
raise ValueError("tool_name must contain 1-160 characters")
|
|
99
|
+
self.tool_name = tool_name
|
|
100
|
+
self.calls = 0
|
|
101
|
+
|
|
102
|
+
def wrap(self, handler: Callable[..., Any]) -> Callable[..., Any]:
|
|
103
|
+
if inspect.iscoroutinefunction(handler):
|
|
104
|
+
@functools.wraps(handler)
|
|
105
|
+
async def async_wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
106
|
+
self.calls += 1
|
|
107
|
+
_append_event({"kind": "handler_attempt", "tool_name": self.tool_name})
|
|
108
|
+
return await handler(*args, **kwargs)
|
|
109
|
+
return async_wrapper
|
|
110
|
+
|
|
111
|
+
@functools.wraps(handler)
|
|
112
|
+
def sync_wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
113
|
+
self.calls += 1
|
|
114
|
+
_append_event({"kind": "handler_attempt", "tool_name": self.tool_name})
|
|
115
|
+
return handler(*args, **kwargs)
|
|
116
|
+
return sync_wrapper
|
|
117
|
+
|
|
118
|
+
def assert_calls(self, expected: int) -> None:
|
|
119
|
+
if not isinstance(expected, int) or expected < 0:
|
|
120
|
+
raise ValueError("expected must be a non-negative integer")
|
|
121
|
+
if self.calls != expected:
|
|
122
|
+
raise AssertionError(f"Expected {expected} handler calls; observed {self.calls}")
|
|
123
|
+
_append_event({"kind": "handler_assertion", "tool_name": self.tool_name, "calls": self.calls})
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def run_action_path_test(root: Path, *, tool_name: str, expected_verdict: str,
|
|
127
|
+
expected_calls: int, command: Sequence[str],
|
|
128
|
+
timeout_seconds: int = 600) -> Tuple[int, Dict[str, Any]]:
|
|
129
|
+
"""Run an explicit customer test command, never a shell, and inspect evidence."""
|
|
130
|
+
if not tool_name or len(tool_name) > 160:
|
|
131
|
+
raise ValueError("tool_name must contain 1-160 characters")
|
|
132
|
+
expected_verdict = expected_verdict.upper()
|
|
133
|
+
if expected_verdict not in {"ALLOWED", "BLOCKED", "REDACTED"}:
|
|
134
|
+
raise ValueError("expected_verdict must be ALLOWED, BLOCKED or REDACTED")
|
|
135
|
+
if expected_calls not in {0, 1}:
|
|
136
|
+
raise ValueError("expected_calls must be 0 or 1 for an isolated action test")
|
|
137
|
+
if (expected_verdict == "BLOCKED" and expected_calls != 0) or (expected_verdict != "BLOCKED" and expected_calls != 1):
|
|
138
|
+
raise ValueError("Blocked actions must not execute; allowed/redacted actions need one observed test-handler call")
|
|
139
|
+
if not command or command[0] == "--" or any(not item or "\x00" in item for item in command):
|
|
140
|
+
raise ValueError("Provide one explicit test command after --; a shell is not used")
|
|
141
|
+
required = ("AGENTICDOME_API_BASE", "AGENTICDOME_API_KEY", "AGENTICDOME_TENANT_ID")
|
|
142
|
+
missing = [key for key in required if not os.environ.get(key, "").strip()]
|
|
143
|
+
if missing:
|
|
144
|
+
raise ValueError("Live action-path proof requires " + ", ".join(missing))
|
|
145
|
+
if os.environ.get("AGENTICDOME_MODE", "").strip().lower() in {"local_sim", "simulation", "sim"}:
|
|
146
|
+
raise ValueError("Action-path proof requires a live assigned sidecar, not local simulation")
|
|
147
|
+
started = time.monotonic()
|
|
148
|
+
with tempfile.TemporaryDirectory(prefix="agenticdome-action-proof-") as temporary:
|
|
149
|
+
journal = Path(temporary) / "events.jsonl"
|
|
150
|
+
environment = os.environ.copy()
|
|
151
|
+
environment["AGENTICDOME_ACTION_PROOF_FILE"] = str(journal)
|
|
152
|
+
try:
|
|
153
|
+
completed = subprocess.run(list(command), cwd=root, env=environment,
|
|
154
|
+
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
|
|
155
|
+
timeout=timeout_seconds, check=False)
|
|
156
|
+
test_exit = completed.returncode
|
|
157
|
+
timeout = False
|
|
158
|
+
except subprocess.TimeoutExpired:
|
|
159
|
+
test_exit = None
|
|
160
|
+
timeout = True
|
|
161
|
+
events = []
|
|
162
|
+
if journal.exists():
|
|
163
|
+
for line in journal.read_text(encoding="utf-8").splitlines()[:200]:
|
|
164
|
+
try:
|
|
165
|
+
value = json.loads(line)
|
|
166
|
+
except json.JSONDecodeError:
|
|
167
|
+
continue
|
|
168
|
+
if isinstance(value, dict) and value.get("schema") == "agenticdome.action-path-event.v1":
|
|
169
|
+
events.append(value)
|
|
170
|
+
decisions = [item for item in events if item.get("kind") == "policy_decision" and item.get("tool_name") == tool_name]
|
|
171
|
+
attempts = [item for item in events if item.get("kind") == "handler_attempt" and item.get("tool_name") == tool_name]
|
|
172
|
+
assertions = [item for item in events if item.get("kind") == "handler_assertion" and item.get("tool_name") == tool_name]
|
|
173
|
+
decision = decisions[0] if len(decisions) == 1 else {}
|
|
174
|
+
assertion = assertions[0] if len(assertions) == 1 else {}
|
|
175
|
+
reasons = []
|
|
176
|
+
if timeout:
|
|
177
|
+
reasons.append("The customer test timed out")
|
|
178
|
+
elif test_exit != 0:
|
|
179
|
+
reasons.append("The customer test did not pass")
|
|
180
|
+
if len(decisions) != 1:
|
|
181
|
+
reasons.append("Expected exactly one SDK tool decision for this action")
|
|
182
|
+
elif not decision.get("live") or decision.get("direction") != "output":
|
|
183
|
+
reasons.append("The decision was not a live outbound tool decision")
|
|
184
|
+
elif not decision.get("hook_module"):
|
|
185
|
+
reasons.append("No certified SDK framework hook was observed; a direct client call is insufficient")
|
|
186
|
+
elif decision.get("verdict") != expected_verdict:
|
|
187
|
+
reasons.append("Observed verdict differs from the expected verdict")
|
|
188
|
+
if len(assertions) != 1 or assertion.get("calls") != expected_calls or len(attempts) != expected_calls:
|
|
189
|
+
reasons.append("The real-handler spy did not establish the expected execution count")
|
|
190
|
+
elif len(decisions) == 1:
|
|
191
|
+
decision_index = events.index(decision)
|
|
192
|
+
assertion_index = events.index(assertion)
|
|
193
|
+
if assertion_index <= decision_index or any(events.index(attempt) <= decision_index or events.index(attempt) >= assertion_index for attempt in attempts):
|
|
194
|
+
reasons.append("Handler evidence was not ordered after the policy decision and before the test assertion")
|
|
195
|
+
report = {
|
|
196
|
+
"schema": "agenticdome.action-path-proof.v1", "status": "passed" if not reasons else "incomplete",
|
|
197
|
+
"tool_name": tool_name, "expected_verdict": expected_verdict,
|
|
198
|
+
"observed_verdict": decision.get("verdict"),
|
|
199
|
+
"decision_id": decision.get("decision_id") or None,
|
|
200
|
+
"hook_module": decision.get("hook_module"), "hook_function": decision.get("hook_function"),
|
|
201
|
+
"expected_handler_calls": expected_calls,
|
|
202
|
+
"observed_handler_calls": len(attempts),
|
|
203
|
+
"handler_assertion_passed": bool(assertion) and assertion.get("calls") == expected_calls,
|
|
204
|
+
"customer_test_exit_code": test_exit, "timed_out": timeout,
|
|
205
|
+
"duration_ms": round((time.monotonic() - started) * 1000),
|
|
206
|
+
"observed_at": datetime.now(timezone.utc).isoformat(),
|
|
207
|
+
"reasons": reasons,
|
|
208
|
+
"next_action": (
|
|
209
|
+
"Run the same safe test command directly to inspect its logs, then check the selected hook and spy placement. No test output was retained."
|
|
210
|
+
if reasons else
|
|
211
|
+
"Review the corresponding retained sidecar decision and repeat with an allowed/blocked counterpart before promoting this route."
|
|
212
|
+
),
|
|
213
|
+
"qualification": "The SDK hook and live verdict were observed locally. Handler execution is established by a customer-installed spy around the actual test handler; verify that this test exercises the production route. No business action is run by the CLI itself.",
|
|
214
|
+
}
|
|
215
|
+
report["proof_sha256"] = hashlib.sha256(
|
|
216
|
+
json.dumps(report, sort_keys=True, separators=(",", ":")).encode("utf-8")
|
|
217
|
+
).hexdigest()
|
|
218
|
+
return (0 if not reasons else 2), report
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def load_action_path_proof(root: Path) -> Optional[Dict[str, Any]]:
|
|
222
|
+
"""Load a current, intact customer-run report without trusting free text."""
|
|
223
|
+
path = root / ".agenticdome" / "action-proof.json"
|
|
224
|
+
try:
|
|
225
|
+
if path.is_symlink() or not path.is_file() or path.stat().st_size > 16384:
|
|
226
|
+
return None
|
|
227
|
+
report = json.loads(path.read_text(encoding="utf-8"))
|
|
228
|
+
if not isinstance(report, dict) or report.get("schema") != "agenticdome.action-path-proof.v1":
|
|
229
|
+
return None
|
|
230
|
+
expected = str(report.get("proof_sha256") or "")
|
|
231
|
+
source = {key: value for key, value in report.items() if key != "proof_sha256"}
|
|
232
|
+
digest = hashlib.sha256(json.dumps(source, sort_keys=True, separators=(",", ":")).encode("utf-8")).hexdigest()
|
|
233
|
+
if digest != expected:
|
|
234
|
+
return None
|
|
235
|
+
observed_at = datetime.fromisoformat(str(report.get("observed_at") or ""))
|
|
236
|
+
age = datetime.now(timezone.utc) - observed_at.astimezone(timezone.utc)
|
|
237
|
+
if age.total_seconds() < -300 or age.total_seconds() > 7 * 86400:
|
|
238
|
+
return None
|
|
239
|
+
if report.get("status") != "passed" or report.get("hook_module") not in {
|
|
240
|
+
"agenticdome_sdk." + adapter for adapter in _ADAPTERS
|
|
241
|
+
}:
|
|
242
|
+
return None
|
|
243
|
+
if report.get("observed_verdict") not in {"ALLOWED", "BLOCKED", "REDACTED"}:
|
|
244
|
+
return None
|
|
245
|
+
if report.get("expected_handler_calls") not in {0, 1} or report.get("observed_handler_calls") != report.get("expected_handler_calls"):
|
|
246
|
+
return None
|
|
247
|
+
return {
|
|
248
|
+
"schema": "agenticdome.action-path-proof.v1", "status": "passed",
|
|
249
|
+
"tool_name": str(report.get("tool_name") or "")[:160],
|
|
250
|
+
"observed_verdict": report["observed_verdict"],
|
|
251
|
+
"decision_id": str(report.get("decision_id") or "")[:100] or None,
|
|
252
|
+
"hook_module": report["hook_module"],
|
|
253
|
+
"hook_function": str(report.get("hook_function") or "")[:100],
|
|
254
|
+
"observed_handler_calls": report["observed_handler_calls"],
|
|
255
|
+
"observed_at": report["observed_at"],
|
|
256
|
+
"proof_sha256": expected,
|
|
257
|
+
"evidence_origin": "customer_test",
|
|
258
|
+
}
|
|
259
|
+
except (OSError, ValueError, TypeError, OverflowError, json.JSONDecodeError):
|
|
260
|
+
return None
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
__all__ = ["ExecutionSpy", "run_action_path_test", "record_policy_decision", "load_action_path_proof"]
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": "agenticdome.catalog-snapshot.v1",
|
|
3
3
|
"catalog_schema": "agenticdome.hook-catalog.v1",
|
|
4
|
-
"verified_at": "2026-
|
|
5
|
-
"python_sdk_version": "1.2.
|
|
4
|
+
"verified_at": "2026-10-02",
|
|
5
|
+
"python_sdk_version": "1.2.37",
|
|
6
6
|
"published_packages": {
|
|
7
7
|
"agenticdome-python-sdk": {
|
|
8
8
|
"registry": "pypi",
|
|
9
|
-
"version": "1.2.
|
|
10
|
-
"url": "https://pypi.org/project/agenticdome-python-sdk/1.2.
|
|
9
|
+
"version": "1.2.37",
|
|
10
|
+
"url": "https://pypi.org/project/agenticdome-python-sdk/1.2.37/"
|
|
11
11
|
},
|
|
12
12
|
"agenticdome-sdk": {
|
|
13
13
|
"registry": "npm",
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
},
|
|
22
22
|
"openclaw": {
|
|
23
23
|
"registry": "npm",
|
|
24
|
-
"version": "2026.9.
|
|
25
|
-
"url": "https://www.npmjs.com/package/openclaw/v/2026.9.
|
|
24
|
+
"version": "2026.9.7",
|
|
25
|
+
"url": "https://www.npmjs.com/package/openclaw/v/2026.9.7"
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
}
|
agenticdome_sdk/client.py
CHANGED
|
@@ -805,6 +805,12 @@ class AgenticDomeClient:
|
|
|
805
805
|
raise AgenticDomeError(
|
|
806
806
|
"AgenticDome execution broker did not return a verified, atomically consumed decision"
|
|
807
807
|
)
|
|
808
|
+
if tool_name and os.environ.get("AGENTICDOME_ACTION_PROOF_FILE"):
|
|
809
|
+
from .action_path_proof import record_policy_decision
|
|
810
|
+
record_policy_decision(
|
|
811
|
+
tool_name=tool_name, platform=platform, direction=normalized_direction,
|
|
812
|
+
response=response, live=not self.is_simulation,
|
|
813
|
+
)
|
|
808
814
|
return response
|
|
809
815
|
|
|
810
816
|
@staticmethod
|