agenticdome-python-sdk 1.2.40__tar.gz → 1.2.43__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 (100) hide show
  1. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/PKG-INFO +5 -6
  2. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/README.md +4 -5
  3. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_python_sdk.egg-info/PKG-INFO +5 -6
  4. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_python_sdk.egg-info/SOURCES.txt +2 -0
  5. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/_framework_firewall.py +12 -5
  6. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/catalog_snapshot.json +7 -7
  7. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/client.py +6 -0
  8. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/connect.py +2 -2
  9. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/guided_integration.py +3 -2
  10. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/hook_catalog.py +1 -1
  11. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/lifecycle.py +52 -18
  12. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/mcp_host.py +23 -4
  13. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/onboarding_cli.py +98 -16
  14. agenticdome_python_sdk-1.2.43/agenticdome_sdk/onboarding_observations.py +74 -0
  15. agenticdome_python_sdk-1.2.43/agenticdome_sdk/report_scope.py +58 -0
  16. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/docs/customer-onboarding.md +44 -7
  17. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/pyproject.toml +1 -1
  18. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/CONTRIBUTING.md +0 -0
  19. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/LICENSE +0 -0
  20. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/MANIFEST.in +0 -0
  21. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/NOTICE +0 -0
  22. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/SECURITY.md +0 -0
  23. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_python_sdk.egg-info/dependency_links.txt +0 -0
  24. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_python_sdk.egg-info/entry_points.txt +0 -0
  25. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_python_sdk.egg-info/requires.txt +0 -0
  26. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_python_sdk.egg-info/top_level.txt +0 -0
  27. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/__init__.py +0 -0
  28. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/_mode.py +0 -0
  29. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/action_path_proof.py +0 -0
  30. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/agno.py +0 -0
  31. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/attestation.py +0 -0
  32. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/autogen.py +0 -0
  33. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/aws_bedrock.py +0 -0
  34. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/claude.py +0 -0
  35. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/copilot_ir.py +0 -0
  36. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/copilot_ir_collector.cjs +0 -0
  37. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/crewai.py +0 -0
  38. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/demo.py +0 -0
  39. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/existing_integration.py +0 -0
  40. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/framework_edits.py +0 -0
  41. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/generic_python.py +0 -0
  42. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/google_adk.py +0 -0
  43. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/identity.py +0 -0
  44. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/langgraph.py +0 -0
  45. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/llamaindex.py +0 -0
  46. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/mcp_http_gateway.py +0 -0
  47. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/mcp_rehearsal_server.py +0 -0
  48. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/mcp_verification.py +0 -0
  49. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/microsoft_agent_framework.py +0 -0
  50. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/microsoft_ai_foundry.py +0 -0
  51. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/openai_agents.py +0 -0
  52. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/outcomes.py +0 -0
  53. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/proof.py +0 -0
  54. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/pydantic.py +0 -0
  55. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/simulation.py +0 -0
  56. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/agenticdome_sdk/smolagents.py +0 -0
  57. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/docs/frameworks/README.md +0 -0
  58. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/docs/frameworks/agno.md +0 -0
  59. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/docs/frameworks/autogen.md +0 -0
  60. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/docs/frameworks/aws-bedrock.md +0 -0
  61. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/docs/frameworks/claude-agent-sdk.md +0 -0
  62. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/docs/frameworks/crewai.md +0 -0
  63. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/docs/frameworks/custom-python.md +0 -0
  64. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/docs/frameworks/google-adk.md +0 -0
  65. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/docs/frameworks/langgraph.md +0 -0
  66. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/docs/frameworks/llamaindex.md +0 -0
  67. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/docs/frameworks/microsoft-agent-framework.md +0 -0
  68. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/docs/frameworks/microsoft-ai-foundry.md +0 -0
  69. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/docs/frameworks/openai-agents.md +0 -0
  70. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/docs/frameworks/pydanticai.md +0 -0
  71. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/docs/frameworks/smolagents.md +0 -0
  72. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/docs/mcp-integration.md +0 -0
  73. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/docs/performance-evidence.md +0 -0
  74. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/docs/runtime-deployment.md +0 -0
  75. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/examples/PRODUCTION_INTEGRATION.md +0 -0
  76. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/examples/README.md +0 -0
  77. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/examples/attack_demo.py +0 -0
  78. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/examples/crewai_agenticdome_firewall.py +0 -0
  79. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/examples/frameworks/README.md +0 -0
  80. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/examples/frameworks/_shared.py +0 -0
  81. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/examples/frameworks/agno.py +0 -0
  82. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/examples/frameworks/autogen.py +0 -0
  83. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/examples/frameworks/aws_bedrock.py +0 -0
  84. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/examples/frameworks/claude_agent_sdk.py +0 -0
  85. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/examples/frameworks/crewai.py +0 -0
  86. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/examples/frameworks/custom_python.py +0 -0
  87. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/examples/frameworks/google_adk.py +0 -0
  88. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/examples/frameworks/langgraph.py +0 -0
  89. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/examples/frameworks/llamaindex.py +0 -0
  90. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/examples/frameworks/mcp.py +0 -0
  91. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/examples/frameworks/microsoft_agent_framework.py +0 -0
  92. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/examples/frameworks/microsoft_ai_foundry.py +0 -0
  93. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/examples/frameworks/openai_agents.py +0 -0
  94. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/examples/frameworks/pydanticai.py +0 -0
  95. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/examples/frameworks/smolagents.py +0 -0
  96. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/examples/langgraph_agenticdome_firewall.py +0 -0
  97. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/examples/local_simulation_gallery.py +0 -0
  98. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/examples/mcp_gateway_action_firewall.py +0 -0
  99. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/setup.cfg +0 -0
  100. {agenticdome_python_sdk-1.2.40 → agenticdome_python_sdk-1.2.43}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agenticdome-python-sdk
3
- Version: 1.2.40
3
+ Version: 1.2.43
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
@@ -2845,10 +2845,7 @@ Plus, for every production deployment:
2845
2845
 
2846
2846
  Use `VerifiedActionReporter` for executable tool calls, function calls, MCP operations and external side effects that should appear in **Verified Actions**. It is not intended for health checks or every policy lookup.
2847
2847
 
2848
- ```bash
2849
- export AGENTICDOME_EVIDENCE_API_BASE="https://your-control-plane.example"
2850
- export AGENTICDOME_EVIDENCE_TOKEN="<portal-token-scoped-to-evidence:write>"
2851
- ```
2848
+ Framework tool wrappers and the MCP host report lifecycle evidence automatically using the existing `AGENTICDOME_API_BASE`, `AGENTICDOME_API_KEY` and `AGENTICDOME_TENANT_ID`. No separate portal credential is required. Upgrade both the SDK and assigned runtime to use automatic reporting. Set `AGENTICDOME_EVIDENCE_ENABLED=false` to opt out.
2852
2849
 
2853
2850
  ```python
2854
2851
  from agenticdome_sdk import VerifiedActionReporter, verified_action
@@ -2865,7 +2862,9 @@ def refresh_customer_record(customer_id: str):
2865
2862
  ...
2866
2863
  ```
2867
2864
 
2868
- The reporter uses a bounded, non-blocking queue and retains hashes plus normalized lifecycle metadata only. It never sends raw arguments, results, prompts, source, or credentials. The dedicated evidence token is separate from the Runtime / SDK key: authorization stays on the assigned sidecar and evidence-delivery failure never changes its allow/deny decision. Integrations built on the shared framework `secure_tool` / `wrap_tool_handler` boundary and the MCP host/gateway wrapper report the same lifecycle automatically when these optional evidence variables are present; other custom boundaries can use the decorator above.
2865
+ The reporter uses a bounded, non-blocking queue and retains hashes plus normalized lifecycle metadata only. It never sends raw arguments, results, prompts, source, or credentials. The runtime queues accepted records in persistent Redis; its delivery worker relays them to the owning control plane using the existing per-sidecar service token. Network and storage failures remain pending for retry. Inspect `evidence.stats()` and call `evidence.flush()` before a short-lived process exits. SDK delivery failures and dropped records are counted and never change the protected operation's allow/deny decision.
2866
+
2867
+ Retained outcomes are labeled `sdk_reported`. Policy lookups alone do not prove execution, and streaming acceptance does not prove final completion. Existing `AGENTICDOME_EVIDENCE_API_BASE` plus `AGENTICDOME_EVIDENCE_TOKEN` remains an explicit legacy portal override. Automatic reporting starts with new wrapped calls; it does not backfill historical telemetry.
2869
2868
 
2870
2869
  ---
2871
2870
 
@@ -2732,10 +2732,7 @@ Plus, for every production deployment:
2732
2732
 
2733
2733
  Use `VerifiedActionReporter` for executable tool calls, function calls, MCP operations and external side effects that should appear in **Verified Actions**. It is not intended for health checks or every policy lookup.
2734
2734
 
2735
- ```bash
2736
- export AGENTICDOME_EVIDENCE_API_BASE="https://your-control-plane.example"
2737
- export AGENTICDOME_EVIDENCE_TOKEN="<portal-token-scoped-to-evidence:write>"
2738
- ```
2735
+ Framework tool wrappers and the MCP host report lifecycle evidence automatically using the existing `AGENTICDOME_API_BASE`, `AGENTICDOME_API_KEY` and `AGENTICDOME_TENANT_ID`. No separate portal credential is required. Upgrade both the SDK and assigned runtime to use automatic reporting. Set `AGENTICDOME_EVIDENCE_ENABLED=false` to opt out.
2739
2736
 
2740
2737
  ```python
2741
2738
  from agenticdome_sdk import VerifiedActionReporter, verified_action
@@ -2752,7 +2749,9 @@ def refresh_customer_record(customer_id: str):
2752
2749
  ...
2753
2750
  ```
2754
2751
 
2755
- The reporter uses a bounded, non-blocking queue and retains hashes plus normalized lifecycle metadata only. It never sends raw arguments, results, prompts, source, or credentials. The dedicated evidence token is separate from the Runtime / SDK key: authorization stays on the assigned sidecar and evidence-delivery failure never changes its allow/deny decision. Integrations built on the shared framework `secure_tool` / `wrap_tool_handler` boundary and the MCP host/gateway wrapper report the same lifecycle automatically when these optional evidence variables are present; other custom boundaries can use the decorator above.
2752
+ The reporter uses a bounded, non-blocking queue and retains hashes plus normalized lifecycle metadata only. It never sends raw arguments, results, prompts, source, or credentials. The runtime queues accepted records in persistent Redis; its delivery worker relays them to the owning control plane using the existing per-sidecar service token. Network and storage failures remain pending for retry. Inspect `evidence.stats()` and call `evidence.flush()` before a short-lived process exits. SDK delivery failures and dropped records are counted and never change the protected operation's allow/deny decision.
2753
+
2754
+ Retained outcomes are labeled `sdk_reported`. Policy lookups alone do not prove execution, and streaming acceptance does not prove final completion. Existing `AGENTICDOME_EVIDENCE_API_BASE` plus `AGENTICDOME_EVIDENCE_TOKEN` remains an explicit legacy portal override. Automatic reporting starts with new wrapped calls; it does not backfill historical telemetry.
2756
2755
 
2757
2756
  ---
2758
2757
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agenticdome-python-sdk
3
- Version: 1.2.40
3
+ Version: 1.2.43
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
@@ -2845,10 +2845,7 @@ Plus, for every production deployment:
2845
2845
 
2846
2846
  Use `VerifiedActionReporter` for executable tool calls, function calls, MCP operations and external side effects that should appear in **Verified Actions**. It is not intended for health checks or every policy lookup.
2847
2847
 
2848
- ```bash
2849
- export AGENTICDOME_EVIDENCE_API_BASE="https://your-control-plane.example"
2850
- export AGENTICDOME_EVIDENCE_TOKEN="<portal-token-scoped-to-evidence:write>"
2851
- ```
2848
+ Framework tool wrappers and the MCP host report lifecycle evidence automatically using the existing `AGENTICDOME_API_BASE`, `AGENTICDOME_API_KEY` and `AGENTICDOME_TENANT_ID`. No separate portal credential is required. Upgrade both the SDK and assigned runtime to use automatic reporting. Set `AGENTICDOME_EVIDENCE_ENABLED=false` to opt out.
2852
2849
 
2853
2850
  ```python
2854
2851
  from agenticdome_sdk import VerifiedActionReporter, verified_action
@@ -2865,7 +2862,9 @@ def refresh_customer_record(customer_id: str):
2865
2862
  ...
2866
2863
  ```
2867
2864
 
2868
- The reporter uses a bounded, non-blocking queue and retains hashes plus normalized lifecycle metadata only. It never sends raw arguments, results, prompts, source, or credentials. The dedicated evidence token is separate from the Runtime / SDK key: authorization stays on the assigned sidecar and evidence-delivery failure never changes its allow/deny decision. Integrations built on the shared framework `secure_tool` / `wrap_tool_handler` boundary and the MCP host/gateway wrapper report the same lifecycle automatically when these optional evidence variables are present; other custom boundaries can use the decorator above.
2865
+ The reporter uses a bounded, non-blocking queue and retains hashes plus normalized lifecycle metadata only. It never sends raw arguments, results, prompts, source, or credentials. The runtime queues accepted records in persistent Redis; its delivery worker relays them to the owning control plane using the existing per-sidecar service token. Network and storage failures remain pending for retry. Inspect `evidence.stats()` and call `evidence.flush()` before a short-lived process exits. SDK delivery failures and dropped records are counted and never change the protected operation's allow/deny decision.
2866
+
2867
+ Retained outcomes are labeled `sdk_reported`. Policy lookups alone do not prove execution, and streaming acceptance does not prove final completion. Existing `AGENTICDOME_EVIDENCE_API_BASE` plus `AGENTICDOME_EVIDENCE_TOKEN` remains an explicit legacy portal override. Automatic reporting starts with new wrapped calls; it does not backfill historical telemetry.
2869
2868
 
2870
2869
  ---
2871
2870
 
@@ -45,10 +45,12 @@ agenticdome_sdk/mcp_verification.py
45
45
  agenticdome_sdk/microsoft_agent_framework.py
46
46
  agenticdome_sdk/microsoft_ai_foundry.py
47
47
  agenticdome_sdk/onboarding_cli.py
48
+ agenticdome_sdk/onboarding_observations.py
48
49
  agenticdome_sdk/openai_agents.py
49
50
  agenticdome_sdk/outcomes.py
50
51
  agenticdome_sdk/proof.py
51
52
  agenticdome_sdk/pydantic.py
53
+ agenticdome_sdk/report_scope.py
52
54
  agenticdome_sdk/simulation.py
53
55
  agenticdome_sdk/smolagents.py
54
56
  docs/customer-onboarding.md
@@ -202,7 +202,8 @@ class FrameworkFirewallBase:
202
202
  timeout=config.timeout_s,
203
203
  )
204
204
  self.token_store = token_store or build_token_store(config, logger)
205
- self.lifecycle_reporter = VerifiedActionReporter.from_env(tenant_id=config.tenant_id)
205
+ self.lifecycle_reporter = VerifiedActionReporter.from_env(tenant_id=config.tenant_id, api_base=config.api_base, api_key=config.api_key,
206
+ sender=getattr(self.client, "report_action_evidence", None))
206
207
  self.denied_error = denied_error
207
208
  self.label = label
208
209
  self.logger = logger
@@ -623,14 +624,17 @@ class FrameworkFirewallBase:
623
624
  decision = await self.aauthorize_tool_call(
624
625
  session_id=sid, agent_id=aid, tool_name=tool_name, tool_args=call_args,
625
626
  tool_platform=tool_platform, text=f"[{self.label}] {aid} calls {tool_name}",
627
+ policy_context={"chain_id": lifecycle.chain_id, "action_id": lifecycle.action_id, "decision_id": lifecycle.action_id},
626
628
  )
627
629
  except Exception:
628
630
  self.lifecycle_reporter.phase(lifecycle, "authorised", "blocked")
629
631
  self.lifecycle_reporter.outcome(lifecycle, "not_attempted")
630
632
  raise
631
- self.lifecycle_reporter.phase(lifecycle, "authorised", "allowed")
632
- self.lifecycle_reporter.phase(lifecycle, "admitted", "admitted")
633
633
  clean = self.sanitized_args(decision, call_args)
634
+ lifecycle = self.lifecycle_reporter.with_arguments(lifecycle, clean)
635
+ if self.verdict(decision) in {"ALLOWED", "REDACTED"} and self.reason(decision) != "fail-open":
636
+ self.lifecycle_reporter.phase(lifecycle, "authorised", "allowed")
637
+ self.lifecycle_reporter.phase(lifecycle, "admitted", "admitted")
634
638
  self.lifecycle_reporter.phase(lifecycle, "attempted", "attempted")
635
639
  try:
636
640
  if kwargs:
@@ -659,14 +663,17 @@ class FrameworkFirewallBase:
659
663
  decision = self.authorize_tool_call(
660
664
  session_id=sid, agent_id=aid, tool_name=tool_name, tool_args=call_args,
661
665
  tool_platform=tool_platform, text=f"[{self.label}] {aid} calls {tool_name}",
666
+ policy_context={"chain_id": lifecycle.chain_id, "action_id": lifecycle.action_id, "decision_id": lifecycle.action_id},
662
667
  )
663
668
  except Exception:
664
669
  self.lifecycle_reporter.phase(lifecycle, "authorised", "blocked")
665
670
  self.lifecycle_reporter.outcome(lifecycle, "not_attempted")
666
671
  raise
667
- self.lifecycle_reporter.phase(lifecycle, "authorised", "allowed")
668
- self.lifecycle_reporter.phase(lifecycle, "admitted", "admitted")
669
672
  clean = self.sanitized_args(decision, call_args)
673
+ lifecycle = self.lifecycle_reporter.with_arguments(lifecycle, clean)
674
+ if self.verdict(decision) in {"ALLOWED", "REDACTED"} and self.reason(decision) != "fail-open":
675
+ self.lifecycle_reporter.phase(lifecycle, "authorised", "allowed")
676
+ self.lifecycle_reporter.phase(lifecycle, "admitted", "admitted")
670
677
  self.lifecycle_reporter.phase(lifecycle, "attempted", "attempted")
671
678
  try:
672
679
  if kwargs:
@@ -2,22 +2,22 @@
2
2
  "schema": "agenticdome.catalog-snapshot.v1",
3
3
  "catalog_schema": "agenticdome.hook-catalog.v1",
4
4
  "verified_at": "2026-10-02",
5
- "python_sdk_version": "1.2.40",
5
+ "python_sdk_version": "1.2.43",
6
6
  "published_packages": {
7
7
  "agenticdome-python-sdk": {
8
8
  "registry": "pypi",
9
- "version": "1.2.40",
10
- "url": "https://pypi.org/project/agenticdome-python-sdk/1.2.40/"
9
+ "version": "1.2.43",
10
+ "url": "https://pypi.org/project/agenticdome-python-sdk/1.2.43/"
11
11
  },
12
12
  "agenticdome-sdk": {
13
13
  "registry": "npm",
14
- "version": "0.6.3",
15
- "url": "https://www.npmjs.com/package/agenticdome-sdk/v/0.6.3"
14
+ "version": "0.6.14",
15
+ "url": "https://www.npmjs.com/package/agenticdome-sdk/v/0.6.14"
16
16
  },
17
17
  "agenticdome-openclaw-security": {
18
18
  "registry": "npm",
19
- "version": "1.0.2",
20
- "url": "https://www.npmjs.com/package/agenticdome-openclaw-security/v/1.0.2"
19
+ "version": "1.0.13",
20
+ "url": "https://www.npmjs.com/package/agenticdome-openclaw-security/v/1.0.13"
21
21
  },
22
22
  "openclaw": {
23
23
  "registry": "npm",
@@ -375,6 +375,12 @@ class AgenticDomeClient:
375
375
  if tool_digest is not None and not re.fullmatch(r"sha256:[0-9a-f]{64}", str(tool_digest)):
376
376
  raise ValueError("'tool_digest' must be sha256 followed by 64 lowercase hexadecimal characters")
377
377
 
378
+ def report_action_evidence(self, kind: str, payload: Dict[str, Any]) -> Dict[str, Any]:
379
+ """Use the existing tenant SDK transport; runtime durably relays evidence."""
380
+ if kind not in {"events", "outcomes"}:
381
+ raise ValueError("Evidence kind must be events or outcomes")
382
+ return self._request("POST", "/mesh/evidence/" + kind, json_body=payload, timeout=5)
383
+
378
384
  def _request(
379
385
  self,
380
386
  method: str,
@@ -253,9 +253,9 @@ def run_connect(root: Path, args: Any) -> Dict[str, Any]:
253
253
  broker_setup["sdk_mode"] = effective_config.get("execution_broker_mode", "existing_sdk_or_environment_default")
254
254
  cross_part_review_required = semantic.get("workload_coverage", {}).get("cross_part_flow_proven") is False
255
255
  next_action = (
256
- "Review the generated pull request and run agenticdome verify. Then review cross-part call paths and workload-specific tests in the portal before activation."
256
+ "Review the generated pull request and run agenticdome verify. Cross-part limitations will be recorded as optional observations in .agenticdome/DISCLAIMER.md; no acknowledgement is required solely for them."
257
257
  if args.open_pr else
258
- "Review the generated patch, apply it on a branch, and run agenticdome verify. Then review cross-part call paths and workload-specific tests in the portal before activation."
258
+ "Review the generated patch, apply it on a branch, and run agenticdome verify. Cross-part limitations will be recorded as optional observations in .agenticdome/DISCLAIMER.md; no acknowledgement is required solely for them."
259
259
  ) if cross_part_review_required else (
260
260
  "Review the generated pull request and run agenticdome verify."
261
261
  if args.open_pr else "Review the generated patch, apply it on a branch, then run agenticdome verify."
@@ -490,9 +490,10 @@ def preview(root: Path, plan: Optional[Dict[str, Any]] = None, *, target: str =
490
490
  + ", A2A " + str(existing.get("a2a_call_candidates", 0))
491
491
  + ", MCP " + str(existing_surfaces.get("mcp", 0))
492
492
  + " (categories may overlap; no customer action was exercised)",
493
- "- Action-required semantic findings: " + str(semantic_gate.get("action_required", "not assessed")),
494
- "- Review-required semantic findings: " + str(semantic_gate.get("review_required", "not assessed")),
493
+ "- Raw semantic action candidates (lower severity may be optional): " + str(semantic_gate.get("action_required", "not assessed")),
494
+ "- Optional review observations: " + str(semantic_gate.get("review_required", "not assessed")),
495
495
  "",
496
+ "Optional observations are written to .agenticdome/DISCLAIMER.md on verification; high-severity and required protection/test failures remain blocking.", "",
496
497
  "## Framework hooks to attach or verify", "",
497
498
  ]
498
499
  for recommendation in plan.get("hook_recommendations", []):
@@ -325,7 +325,7 @@ FRAMEWORK_HOOK_CATALOG: Dict[str, Dict[str, Any]] = {
325
325
  "adapter_module": "agenticdome-openclaw-security",
326
326
  "adapter_class": "OpenClawFirewall",
327
327
  "attachment_methods": ["protectedExecute", "sanitizeOutput"],
328
- "native_hooks": ["before_agent_run", "before_tool_call", "tool_result_persist"],
328
+ "native_hooks": ["before_agent_run", "before_tool_call", "after_tool_call", "tool_result_persist"],
329
329
  "docs": "agenticdome-openclaw-security package README",
330
330
  },
331
331
  "mcp-ts": {
@@ -1,7 +1,7 @@
1
1
  """Privacy-bounded Verified Action lifecycle reporting.
2
2
 
3
3
  The runtime authorization path remains authoritative. This module reports only
4
- minimized lifecycle evidence through a separately scoped portal credential and
4
+ minimized lifecycle evidence through the existing tenant runtime credential and
5
5
  never sends tool arguments, prompts, responses, credentials, or source code.
6
6
  """
7
7
 
@@ -15,9 +15,11 @@ import logging
15
15
  import os
16
16
  import queue
17
17
  import threading
18
+ import time
19
+ import urllib.error
18
20
  import urllib.request
19
21
  import uuid
20
- from dataclasses import dataclass
22
+ from dataclasses import dataclass, replace
21
23
  from datetime import datetime, timezone
22
24
  from typing import Any, Callable, Dict, Optional, TypeVar
23
25
 
@@ -72,33 +74,46 @@ class VerifiedActionDenied(RuntimeError):
72
74
  class VerifiedActionReporter:
73
75
  """Non-blocking, bounded reporter for one tenant's Verified Actions.
74
76
 
75
- Configure ``AGENTICDOME_EVIDENCE_API_BASE`` and a portal token containing
76
- only ``evidence:write``. Missing evidence credentials disable reporting;
77
- they never weaken or bypass the primary AgenticDome authorization call.
77
+ SDK credentials enable reporting to the assigned runtime by default.
78
+ Explicit portal evidence credentials remain supported for existing callers.
78
79
  """
79
80
 
80
- def __init__(self, portal: str = "", access_token: str = "", *, tenant_id: str = "", timeout: float = 5.0, queue_size: int = 256) -> None:
81
+ def __init__(self, portal: str = "", access_token: str = "", *, tenant_id: str = "", timeout: float = 5.0, queue_size: int = 256,
82
+ runtime_base: str = "", api_key: str = "", sender: Optional[Callable[..., Any]] = None) -> None:
81
83
  self.portal = portal.rstrip("/")
82
84
  self.access_token = access_token.strip()
83
85
  self.tenant_id = tenant_id.strip()
86
+ self.runtime_base = runtime_base.rstrip("/")
87
+ self.api_key = api_key.strip()
88
+ self.sender = sender
89
+ self.runtime_mode = not (self.portal and self.access_token)
84
90
  self.timeout = max(1.0, min(float(timeout), 30.0))
85
91
  self._queue: "queue.Queue[tuple[str, Dict[str, Any]] | None]" = queue.Queue(maxsize=max(16, min(int(queue_size), 4096)))
86
92
  self._worker: Optional[threading.Thread] = None
87
93
  self._lock = threading.Lock()
94
+ self._stats = {"queued": 0, "delivered": 0, "failed": 0, "dropped": 0}
88
95
 
89
96
  @classmethod
90
- def from_env(cls, *, tenant_id: str = "") -> "VerifiedActionReporter":
97
+ def from_env(cls, *, tenant_id: str = "", api_base: str = "", api_key: str = "", sender: Optional[Callable[..., Any]] = None) -> "VerifiedActionReporter":
98
+ if os.getenv("AGENTICDOME_EVIDENCE_ENABLED", "true").lower() in {"0", "false", "off", "no"}:
99
+ return cls()
91
100
  return cls(
92
101
  os.getenv("AGENTICDOME_EVIDENCE_API_BASE", ""),
93
102
  os.getenv("AGENTICDOME_EVIDENCE_TOKEN", ""),
94
103
  tenant_id=tenant_id or os.getenv("AGENTICDOME_TENANT_ID", ""),
95
104
  timeout=float(os.getenv("AGENTICDOME_EVIDENCE_TIMEOUT_S", "5") or "5"),
96
105
  queue_size=int(os.getenv("AGENTICDOME_EVIDENCE_QUEUE_SIZE", "256") or "256"),
106
+ runtime_base=api_base or os.getenv("AGENTICDOME_API_BASE", ""),
107
+ api_key=api_key or os.getenv("AGENTICDOME_API_KEY", ""), sender=sender,
97
108
  )
98
109
 
99
110
  @property
100
111
  def enabled(self) -> bool:
101
- return bool(self.portal and self.access_token and self.tenant_id)
112
+ return bool(self.tenant_id and ((self.portal and self.access_token) or
113
+ (self.runtime_base.startswith(("https://", "http://")) and self.api_key)))
114
+
115
+ def stats(self) -> Dict[str, Any]:
116
+ return dict(self._stats, pending=self._queue.unfinished_tasks, enabled=self.enabled, transport="runtime" if self.runtime_mode else "portal")
102
117
 
103
118
  def new_context(self, *, operation_type: str, tool_name: Optional[str] = None, tool_version: Optional[str] = None,
104
119
  arguments: Any = None, destination: Optional[str] = None, chain_id: Optional[str] = None,
@@ -141,6 +156,10 @@ class VerifiedActionReporter:
141
156
  }
142
157
  return self._enqueue("/api/agentguard/verified-actions/events", payload)
143
158
 
159
+ def with_arguments(self, context: VerifiedActionContext, arguments: Any) -> VerifiedActionContext:
160
+ """Keep correlation IDs while hashing the arguments actually admitted for execution."""
161
+ return replace(context, arguments_sha256=_digest(arguments))
162
+
144
163
  def outcome(self, context: VerifiedActionContext, outcome_class: str, *, side_effect_reference: Optional[str] = None) -> bool:
145
164
  allowed = {"not_attempted", "rejected", "accepted", "succeeded", "partially_succeeded", "failed", "rolled_back", "unknown"}
146
165
  outcome = _token(outcome_class, allowed, "unknown")
@@ -150,8 +169,8 @@ class VerifiedActionReporter:
150
169
  "chain_id": context.chain_id, "action_id": context.action_id,
151
170
  "jti": "sdk_" + uuid.uuid4().hex, "outcome_class": outcome,
152
171
  "assurance_level": "sdk_reported", "authorised_action_sha256": context.arguments_sha256,
153
- "observed_action_sha256": context.arguments_sha256, "destination_sha256": context.destination_sha256,
154
- "side_effect_ref_sha256": _digest(side_effect_reference), "attempted_at": now, "completed_at": now,
172
+ "observed_action_sha256": None if outcome == "not_attempted" else context.arguments_sha256, "destination_sha256": context.destination_sha256,
173
+ "side_effect_ref_sha256": _digest(side_effect_reference), "completed_at": now,
155
174
  }
156
175
  return self._enqueue("/api/agentguard/verified-actions/outcomes", payload)
157
176
 
@@ -162,7 +181,7 @@ class VerifiedActionReporter:
162
181
  marker = {"_flush_event": completed}
163
182
  if not self._enqueue("", marker):
164
183
  return False
165
- return completed.wait(max(0.1, timeout))
184
+ return completed.wait(max(0.1, timeout)) and self._stats["failed"] == 0
166
185
 
167
186
  def _enqueue(self, path: str, payload: Dict[str, Any]) -> bool:
168
187
  if not self.enabled:
@@ -170,8 +189,10 @@ class VerifiedActionReporter:
170
189
  self._ensure_worker()
171
190
  try:
172
191
  self._queue.put_nowait((path, payload))
192
+ if path:self._stats["queued"] += 1
173
193
  return True
174
194
  except queue.Full:
195
+ self._stats["dropped"] += 1
175
196
  logger.warning("Verified Action evidence queue is full; authorization behavior is unchanged.")
176
197
  return False
177
198
 
@@ -193,14 +214,27 @@ class VerifiedActionReporter:
193
214
  if isinstance(marker, threading.Event):
194
215
  marker.set()
195
216
  continue
196
- request = urllib.request.Request(
197
- self.portal + path, data=json.dumps(payload, separators=(",", ":")).encode("utf-8"), method="POST",
198
- headers={"Authorization": "Bearer " + self.access_token, "Content-Type": "application/json", "Accept": "application/json"},
199
- )
200
- with urllib.request.urlopen(request, timeout=self.timeout) as response: # noqa: S310 - configured AgenticDome portal
201
- response.read(1)
217
+ for attempt in range(3):
218
+ try:
219
+ if self.runtime_mode and self.sender:
220
+ self.sender(path.rsplit("/", 1)[-1], payload)
221
+ else:
222
+ endpoint = (self.runtime_base + "/mesh/evidence/" + path.rsplit("/", 1)[-1]) if self.runtime_mode else self.portal + path
223
+ headers = {"Content-Type": "application/json", "Accept": "application/json", "X-Tenant-Id": self.tenant_id}
224
+ headers.update({"X-API-Key": self.api_key} if self.runtime_mode else {"Authorization": "Bearer " + self.access_token})
225
+ request = urllib.request.Request(endpoint, data=json.dumps(payload, separators=(",", ":")).encode("utf-8"), method="POST", headers=headers)
226
+ with urllib.request.urlopen(request, timeout=self.timeout) as response:
227
+ response.read(1)
228
+ self._stats["delivered"] += 1
229
+ break
230
+ except Exception as exc:
231
+ status = getattr(exc, "code", getattr(exc, "status_code", None))
232
+ if attempt == 2 or status is not None and status not in {429, 500, 502, 503, 504}:
233
+ raise
234
+ time.sleep(.1 * (2 ** attempt))
202
235
  except Exception as exc: # evidence must never alter the protected operation
203
- logger.warning("Verified Action evidence delivery failed; authorization behavior is unchanged: %s", exc)
236
+ self._stats["failed"] += 1
237
+ logger.warning("Verified Action evidence delivery failed; authorization behavior is unchanged (%s)", type(exc).__name__)
204
238
  finally:
205
239
  self._queue.task_done()
206
240
 
@@ -13,6 +13,7 @@ import time
13
13
  import uuid
14
14
  import re
15
15
  from collections import defaultdict, deque
16
+ from contextvars import ContextVar
16
17
  from dataclasses import dataclass
17
18
  from datetime import date
18
19
  from inspect import isawaitable
@@ -23,6 +24,8 @@ from .client import AgenticDomeClient
23
24
  from ._mode import credentials_or_local_sim
24
25
  from .lifecycle import VerifiedActionReporter
25
26
 
27
+ _lifecycle_decision: ContextVar[Optional[Dict[str, Any]]] = ContextVar("agenticdome_mcp_lifecycle_decision", default=None)
28
+
26
29
  try:
27
30
  from .exceptions import AgenticDomeHTTPError
28
31
  except Exception: # pragma: no cover - compatibility with older package layouts
@@ -375,7 +378,8 @@ class AgenticDomeMCPHostFirewall:
375
378
  timeout=self.config.timeout_s,
376
379
  )
377
380
  self.token_store = token_store or _build_token_store(self.config)
378
- self.lifecycle_reporter = lifecycle_reporter or VerifiedActionReporter.from_env(tenant_id=self.config.tenant_id)
381
+ self.lifecycle_reporter = lifecycle_reporter or VerifiedActionReporter.from_env(tenant_id=self.config.tenant_id,
382
+ api_base=self.config.api_base, api_key=self.config.api_key, sender=getattr(self.client, "report_action_evidence", None))
379
383
  self.provider_action_rules = dict(provider_action_rules or {})
380
384
  self.resolve_provider_facts = resolve_provider_facts
381
385
  self._rate_lock = Lock()
@@ -975,6 +979,9 @@ class AgenticDomeMCPHostFirewall:
975
979
  )
976
980
 
977
981
  async def _handle_blocking_decision(self, *, decision: Dict[str, Any], rid: Any, context: Dict[str, Any], method: str, operation: str) -> Optional[Dict[str, Any]]:
982
+ evidence = _lifecycle_decision.get()
983
+ if evidence is not None:
984
+ evidence.update(verdict=self._verdict(decision), reason=self._reason(decision))
978
985
  verdict = self._verdict(decision)
979
986
  if verdict == "ALLOWED" or (verdict == "REDACTED" and self._sanitized_args(decision, explicit_only=True) is not None):
980
987
  return None
@@ -1433,7 +1440,7 @@ class AgenticDomeMCPHostFirewall:
1433
1440
  lifecycle = self.lifecycle_reporter.new_context(
1434
1441
  operation_type="mcp_operation", tool_name=tool_name, arguments=arguments,
1435
1442
  destination=self.config.mcp_server_url or self.config.mcp_server_id,
1436
- chain_id=self._safe_str(local_context.get("verified_chain_id") or local_context.get("action_chain_id")) or None,
1443
+ chain_id=self._safe_str(local_context.get("verified_chain_id") or local_context.get("action_chain_id") or local_context.get("chain_id")) or None,
1437
1444
  action_id=self._safe_str(local_context.get("verified_action_id") or local_context.get("action_id")) or None,
1438
1445
  parent_action_id=self._safe_str(local_context.get("parent_action_id")) or None,
1439
1446
  initiator_type="human" if self._safe_str(local_context.get("user_id")) else "agent",
@@ -1441,13 +1448,25 @@ class AgenticDomeMCPHostFirewall:
1441
1448
  )
1442
1449
  self.lifecycle_reporter.phase(lifecycle, "requested", "requested")
1443
1450
 
1444
- gated = await self.preflight_request(mcp_request=mcp_request, context=context)
1451
+ local_context.update(chain_id=lifecycle.chain_id, action_id=lifecycle.action_id, decision_id=lifecycle.action_id)
1452
+ decision_evidence: Dict[str, Any] = {}
1453
+ decision_token = _lifecycle_decision.set(decision_evidence)
1454
+ try:
1455
+ gated = await self.preflight_request(mcp_request=mcp_request, context=local_context)
1456
+ except Exception:
1457
+ self.lifecycle_reporter.outcome(lifecycle, "not_attempted")
1458
+ raise
1459
+ finally:
1460
+ _lifecycle_decision.reset(decision_token)
1445
1461
  if isinstance(gated, dict) and "error" in gated:
1446
1462
  self.lifecycle_reporter.phase(lifecycle, "authorised", "blocked")
1447
1463
  self.lifecycle_reporter.outcome(lifecycle, "not_attempted")
1448
1464
  return gated
1449
1465
 
1450
- self.lifecycle_reporter.phase(lifecycle, "authorised", "allowed")
1466
+ admitted_arguments = self._extract_tool_call(gated)[1] if method == "tools/call" else self._params(gated)
1467
+ lifecycle = self.lifecycle_reporter.with_arguments(lifecycle, admitted_arguments)
1468
+ if decision_evidence.get("verdict") in {"ALLOWED", "REDACTED"} and decision_evidence.get("reason") != "fail-open":
1469
+ self.lifecycle_reporter.phase(lifecycle, "authorised", "allowed")
1451
1470
  self.lifecycle_reporter.phase(lifecycle, "admitted", "admitted")
1452
1471
  self.lifecycle_reporter.phase(lifecycle, "attempted", "attempted")
1453
1472