agenticdome-python-sdk 1.1.3__py3-none-any.whl → 1.2.0__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.
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agenticdome-python-sdk
3
- Version: 1.1.3
3
+ Version: 1.2.0
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: Proprietary
7
- Project-URL: Homepage, https://au.agenticdome.io
7
+ Project-URL: Homepage, https://www.agenticdome.io
8
8
  Project-URL: Repository, https://github.com/agenticdome/agenticdome-python-sdk
9
9
  Project-URL: Documentation, https://github.com/agenticdome/agenticdome-python-sdk#readme
10
10
  Project-URL: Issues, https://github.com/agenticdome/agenticdome-python-sdk/issues
@@ -27,58 +27,62 @@ License-File: LICENSE
27
27
  Requires-Dist: requests>=2.31.0
28
28
  Requires-Dist: urllib3>=2.0.0
29
29
  Provides-Extra: crewai
30
- Requires-Dist: crewai>=1.15.2; extra == "crewai"
30
+ Requires-Dist: crewai==1.15.5; extra == "crewai"
31
31
  Provides-Extra: redis
32
32
  Requires-Dist: redis>=4.5.0; extra == "redis"
33
+ Provides-Extra: pop
34
+ Requires-Dist: cryptography>=42.0.0; extra == "pop"
33
35
  Provides-Extra: pydanticai
34
- Requires-Dist: pydantic-ai>=2.10.0; extra == "pydanticai"
36
+ Requires-Dist: pydantic-ai==2.14.1; extra == "pydanticai"
35
37
  Requires-Dist: anyio>=4.0.0; extra == "pydanticai"
36
38
  Provides-Extra: pydantic
37
- Requires-Dist: pydantic-ai>=2.10.0; extra == "pydantic"
39
+ Requires-Dist: pydantic-ai==2.14.1; extra == "pydantic"
38
40
  Requires-Dist: anyio>=4.0.0; extra == "pydantic"
39
41
  Provides-Extra: langgraph
40
- Requires-Dist: langgraph>=1.2.9; extra == "langgraph"
41
- Requires-Dist: langchain-core>=1.4.9; extra == "langgraph"
42
+ Requires-Dist: langgraph==1.2.9; extra == "langgraph"
43
+ Requires-Dist: langchain-core==1.5.0; extra == "langgraph"
42
44
  Requires-Dist: anyio>=4.0.0; extra == "langgraph"
43
45
  Provides-Extra: microsoft
44
46
  Provides-Extra: foundry
45
- Requires-Dist: azure-ai-projects>=2.3.0; extra == "foundry"
46
- Requires-Dist: azure-identity>=1.25.3; extra == "foundry"
47
+ Requires-Dist: azure-ai-projects==2.3.0; extra == "foundry"
48
+ Requires-Dist: azure-identity==1.25.3; extra == "foundry"
47
49
  Provides-Extra: agno
48
- Requires-Dist: agno>=2.7.3; extra == "agno"
50
+ Requires-Dist: agno==2.8.0; extra == "agno"
49
51
  Provides-Extra: openai-agents
50
- Requires-Dist: openai-agents>=0.18.2; extra == "openai-agents"
52
+ Requires-Dist: openai-agents==0.18.3; extra == "openai-agents"
51
53
  Provides-Extra: mcp
52
- Requires-Dist: mcp>=1.26.0; extra == "mcp"
54
+ Requires-Dist: mcp<=1.28.1,>=1.26.0; extra == "mcp"
53
55
  Provides-Extra: bedrock
54
- Requires-Dist: boto3>=1.43.48; extra == "bedrock"
56
+ Requires-Dist: boto3==1.43.52; extra == "bedrock"
55
57
  Provides-Extra: aws-bedrock
56
- Requires-Dist: boto3>=1.43.48; extra == "aws-bedrock"
58
+ Requires-Dist: boto3==1.43.52; extra == "aws-bedrock"
57
59
  Provides-Extra: llamaindex
58
- Requires-Dist: llama-index>=0.14.23; extra == "llamaindex"
60
+ Requires-Dist: llama-index==0.14.23; extra == "llamaindex"
59
61
  Provides-Extra: llama-index
60
- Requires-Dist: llama-index>=0.14.23; extra == "llama-index"
62
+ Requires-Dist: llama-index==0.14.23; extra == "llama-index"
61
63
  Provides-Extra: google-adk
62
- Requires-Dist: google-adk>=2.4.0; extra == "google-adk"
64
+ Requires-Dist: google-adk==2.5.0; extra == "google-adk"
63
65
  Provides-Extra: adk
64
- Requires-Dist: google-adk>=2.4.0; extra == "adk"
66
+ Requires-Dist: google-adk==2.5.0; extra == "adk"
65
67
  Provides-Extra: all
66
- Requires-Dist: crewai>=1.15.2; extra == "all"
68
+ Requires-Dist: crewai==1.15.5; extra == "all"
67
69
  Requires-Dist: redis>=4.5.0; extra == "all"
68
- Requires-Dist: pydantic-ai>=2.10.0; extra == "all"
70
+ Requires-Dist: cryptography>=42.0.0; extra == "all"
71
+ Requires-Dist: pydantic-ai==2.14.1; extra == "all"
69
72
  Requires-Dist: anyio>=4.0.0; extra == "all"
70
- Requires-Dist: langgraph>=1.2.9; extra == "all"
71
- Requires-Dist: langchain-core>=1.4.9; extra == "all"
72
- Requires-Dist: agno>=2.7.3; extra == "all"
73
- Requires-Dist: azure-ai-projects>=2.3.0; extra == "all"
74
- Requires-Dist: azure-identity>=1.25.3; extra == "all"
75
- Requires-Dist: openai-agents>=0.18.2; extra == "all"
76
- Requires-Dist: mcp>=1.26.0; extra == "all"
77
- Requires-Dist: boto3>=1.43.48; extra == "all"
78
- Requires-Dist: llama-index>=0.14.23; extra == "all"
79
- Requires-Dist: google-adk>=2.4.0; extra == "all"
73
+ Requires-Dist: langgraph==1.2.9; extra == "all"
74
+ Requires-Dist: langchain-core==1.5.0; extra == "all"
75
+ Requires-Dist: agno==2.8.0; extra == "all"
76
+ Requires-Dist: azure-ai-projects==2.3.0; extra == "all"
77
+ Requires-Dist: azure-identity==1.25.3; extra == "all"
78
+ Requires-Dist: openai-agents==0.18.3; extra == "all"
79
+ Requires-Dist: mcp<=1.28.1,>=1.26.0; extra == "all"
80
+ Requires-Dist: boto3==1.43.52; extra == "all"
81
+ Requires-Dist: llama-index==0.14.23; extra == "all"
82
+ Requires-Dist: google-adk==2.5.0; extra == "all"
80
83
  Provides-Extra: dev
81
84
  Requires-Dist: pytest>=8.0.0; extra == "dev"
85
+ Requires-Dist: tomli>=2.0.0; python_version < "3.11" and extra == "dev"
82
86
  Requires-Dist: ruff>=0.5.0; extra == "dev"
83
87
  Requires-Dist: mypy>=1.8.0; extra == "dev"
84
88
  Requires-Dist: build>=1.0.0; extra == "dev"
@@ -155,7 +159,7 @@ Your local Python runtime executes agents, tools, workflows, and framework-speci
155
159
  [ LOCAL ENTERPRISE RUNTIME PERIMETER ] [ AGENTICDOME CENTRAL PLANE ]
156
160
 
157
161
  +-------------------------------------------------+ +-----------------------------+
158
- | Python Agent Runtime | | https://au.agenticdome.io |
162
+ | Python Agent Runtime | | https://demo-sidecar.agenticdome.io |
159
163
  | CrewAI / PydanticAI / LangGraph / Microsoft AF / AI Foundry / Agno / OpenAI Agents / MCP Hosts / Bedrock / Google ADK / LlamaIndex | | Centralized Policy Engine |
160
164
  +-------------------------------------------------+ +-----------------------------+
161
165
  | | ^ ^
@@ -225,15 +229,48 @@ Authorizes tool calls before execution using:
225
229
 
226
230
  AgenticDome can transparently authorize multi-agent delegation workflows and issue decision tokens that bind:
227
231
 
232
+ - Originating human subject, when present
233
+ - Ordered and nested agent actor chain
228
234
  - Source manager agent
229
235
  - Target specialist agent
230
236
  - Tool name
231
237
  - Tool arguments
232
238
  - Session ID
239
+ - Trace and lineage root/parent IDs
240
+ - Intent digest, policy binding, authorized scopes, and trust epochs
233
241
  - Tenant context
234
242
  - Policy decision
235
243
 
236
- This helps prevent unauthorized lateral privilege escalation between agents.
244
+ Execution verification consumes the server-side call budget and checks revocation state. Optional proof-bound decisions use a DPoP-style signed JWT tied to the decision token hash; sending the public-key thumbprint alone is not treated as proof.
245
+
246
+ Install the proof helper extra and create a runtime-held key:
247
+
248
+ ```bash
249
+ pip install "agenticdome-python-sdk[pop]"
250
+ ```
251
+
252
+ ```python
253
+ from agenticdome_sdk import create_dpop_proof, generate_rsa_proof_key
254
+
255
+ proof_key = generate_rsa_proof_key()
256
+ # Pass proof_key["thumbprint"] as proof_thumbprint when authorizing.
257
+ proof = create_dpop_proof(
258
+ proof_key["private_key_pem"],
259
+ access_token=decision_token,
260
+ method="POST",
261
+ uri="/a2a",
262
+ )
263
+ client.a2a_verify_decision_token_rpc(
264
+ decision_token,
265
+ tool_name=tool_name,
266
+ tool_args=tool_args,
267
+ agent_id=worker_id,
268
+ source_agent_id=manager_id,
269
+ proof_token=proof,
270
+ )
271
+ ```
272
+
273
+ This helps prevent unauthorized lateral privilege escalation and stolen-token replay between agents.
237
274
 
238
275
  ### Inline Output Data Loss Prevention, DLP
239
276
 
@@ -302,6 +339,7 @@ Install the extra for the framework you use:
302
339
  | AWS Bedrock / Bedrock Agents | `pip install "agenticdome-python-sdk[bedrock]"` |
303
340
  | MCP host / gateway | `pip install "agenticdome-python-sdk[mcp]"` |
304
341
  | Redis token storage | `pip install "agenticdome-python-sdk[redis]"` |
342
+ | Proof-of-possession helpers | `pip install "agenticdome-python-sdk[pop]"` |
305
343
  | All optional integrations | `pip install "agenticdome-python-sdk[all]"` |
306
344
 
307
345
  Some adapters are dependency-light at import time. Google ADK, LlamaIndex, Bedrock, MCP, and Microsoft helpers can wrap local boundaries without forcing one exact runtime stack; install the framework packages your application actually uses.
@@ -315,8 +353,8 @@ Set these environment variables in your local shell, container, CI/CD environmen
315
353
  ### Required Variables
316
354
 
317
355
  ```bash
318
- # Regional gateway base URL.
319
- export AGENTICDOME_API_BASE="https://au.agenticdome.io"
356
+ # Tenant runtime sidecar URL. Do not use the control-plane website URL here.
357
+ export AGENTICDOME_API_BASE="https://demo-sidecar.agenticdome.io"
320
358
 
321
359
  # Secure access token generated in the AgenticDome console.
322
360
  export AGENTICDOME_API_KEY="your_api_key_abc123..."
@@ -409,7 +447,7 @@ Set these values in the same place you configure your Python application runtime
409
447
  Minimum production configuration:
410
448
 
411
449
  ```bash
412
- export AGENTICDOME_API_BASE="https://au.agenticdome.io"
450
+ export AGENTICDOME_API_BASE="https://demo-sidecar.agenticdome.io"
413
451
  export AGENTICDOME_API_KEY="your_api_key"
414
452
  export AGENTICDOME_TENANT_ID="your_tenant_id"
415
453
  export AGENTICDOME_FAIL_CLOSED="true"
@@ -569,7 +607,7 @@ secure_refund = firewall.wrap_delegated_tool_handler(
569
607
 
570
608
  | Environment Variable | Type | Default | Description |
571
609
  | :--- | :--- | :--- | :--- |
572
- | `AGENTICDOME_API_BASE` | string | required | AgenticDome regional API and console endpoint, for example `https://au.agenticdome.io`. |
610
+ | `AGENTICDOME_API_BASE` | string | required | Tenant runtime sidecar origin, for example `https://demo-sidecar.agenticdome.io`. This is separate from the control-plane console URL. |
573
611
  | `AGENTICDOME_API_KEY` | string | required | API key generated in the AgenticDome console. |
574
612
  | `AGENTICDOME_TENANT_ID` | string | required | Tenant or organization isolation namespace. |
575
613
  | `AGENTICDOME_PLATFORM` | string | framework-specific | Runtime platform label included in policy context. |
@@ -777,7 +815,7 @@ Use the core client when you own the runtime loop or have a custom gateway. This
777
815
  from agenticdome_sdk.client import AgentGuardClient
778
816
 
779
817
  client = AgentGuardClient(
780
- api_base="https://au.agenticdome.io",
818
+ api_base="https://demo-sidecar.agenticdome.io",
781
819
  api_key="your-api-key",
782
820
  tenant_id="your-tenant-id",
783
821
  timeout=20,
@@ -1132,7 +1170,7 @@ pip install "agenticdome-python-sdk[pydanticai]"
1132
1170
  [ PYDANTICAI AGENT RUNTIME PERIMETER ] [ AGENTICDOME CONTROL PLANE ]
1133
1171
 
1134
1172
  +-------------------------------------------------+ +-----------------------------+
1135
- | Agent.run() Execution Loop | | https://au.agenticdome.io |
1173
+ | Agent.run() Execution Loop | | https://demo-sidecar.agenticdome.io |
1136
1174
  +-------------------------------------------------+ +-----------------------------+
1137
1175
  | | ^ ^
1138
1176
  | 1. before_runner_init | 4. after | Verdict / DLP |
@@ -1261,7 +1299,7 @@ PydanticAI lifecycle hook APIs have evolved. Current PydanticAI documents `pydan
1261
1299
  - If compatible legacy lifecycle decorators are available, `attach_to_agent()` attaches prompt ingress and egress DLP hooks.
1262
1300
  - If native `Hooks` capabilities are available, `create_hooks()` returns a capability object you can pass into `Agent(..., capabilities=[...])`.
1263
1301
  - If lifecycle decorators are not available, `@firewall.secure_tool(...)` still protects tool execution.
1264
- - In production mode, configure API base, API key, tenant ID, and stable session IDs.
1302
+ - In production mode, configure the tenant runtime sidecar, API key, tenant ID, and stable session IDs.
1265
1303
  - `AGENTICDOME_BLOCK_ON_SENSITIVE_OUTPUT=true` means AgenticDome may ask Mesh to block sensitive output; the SDK only blocks when the policy response verdict is `BLOCKED`.
1266
1304
 
1267
1305
  ---
@@ -1297,7 +1335,7 @@ pip install "agenticdome-python-sdk[langgraph]"
1297
1335
  [ LANGGRAPH STATEGRAPH RUNTIME ] [ AGENTICDOME CONTROL PLANE ]
1298
1336
 
1299
1337
  +-----------------------------------------------+ +-----------------------------+
1300
- | StateGraph / CompiledStateGraph | | https://au.agenticdome.io |
1338
+ | StateGraph / CompiledStateGraph | | https://demo-sidecar.agenticdome.io |
1301
1339
  +-----------------------------------------------+ +-----------------------------+
1302
1340
  | | ^ ^
1303
1341
  | 1. user message | 2. tool calls | 4. verdict / token | validate
@@ -1512,7 +1550,7 @@ Install the Microsoft Agent Framework packages used by your application separate
1512
1550
  [ MICROSOFT AGENT FRAMEWORK PYTHON RUNTIME ] [ AGENTICDOME CONTROL PLANE ]
1513
1551
 
1514
1552
  +------------------------------------------------+ +-----------------------------+
1515
- | Agent.run / Workflow.run / Function Tool | | https://au.agenticdome.io |
1553
+ | Agent.run / Workflow.run / Function Tool | | https://demo-sidecar.agenticdome.io |
1516
1554
  +------------------------------------------------+ +-----------------------------+
1517
1555
  | | ^ ^
1518
1556
  | 1. input text | 2. tool args | verdict / token | validate
@@ -1709,7 +1747,7 @@ The Foundry integration supports:
1709
1747
  - Direct tool-argument stripping, lightweight JSON-schema validation, and sanitized-argument execution when AgenticDome returns safer arguments
1710
1748
  - Enterprise identity context propagation for Entra IDs, roles/scopes, Foundry project IDs, and Purview or sensitivity labels
1711
1749
  - Production-mode stable session ID enforcement and output-sanitization requirements
1712
- - Output DLP through Mesh using the required AgenticDome API base URL, API key, and tenant ID
1750
+ - Output DLP through Mesh using the required tenant runtime sidecar URL, API key, and tenant ID
1713
1751
  - Structured-output preservation by parsing sanitized JSON back to dictionaries/lists where possible
1714
1752
  - Local rate limits, input/output/tool-argument size limits, retries, circuit breaker behavior, audit logging, and OpenTelemetry span events
1715
1753
  - Streaming response sanitization through `sanitize_streaming_response()`
@@ -1735,7 +1773,7 @@ If your application uses Microsoft Agent Framework hosted agents, install the Fo
1735
1773
  Foundry threat-contract calls use bearer authentication:
1736
1774
 
1737
1775
  ```bash
1738
- export AGENTICDOME_API_BASE="https://au.agenticdome.io"
1776
+ export AGENTICDOME_API_BASE="https://demo-sidecar.agenticdome.io"
1739
1777
  export AGENTICDOME_BEARER_TOKEN="your_foundry_threat_contract_bearer_token"
1740
1778
  ```
1741
1779
 
@@ -1894,7 +1932,7 @@ from agenticdome_sdk.microsoft_ai_foundry import (
1894
1932
  - Production deployments should pass a stable `session_id`, `run_id`, `trace_id`, `conversation_id`, or `thread_id`; generated fallback IDs are intended for local development only.
1895
1933
  - Pass Entra identity, roles/scopes, Foundry project IDs, and Purview/sensitivity labels on `ctx` or `policy_context` so server-side policy can make identity-aware decisions.
1896
1934
  - If a Foundry hosted tool executes entirely inside a remote provider runtime, this local Python SDK can protect the local request/response boundary but cannot inspect inside the remote execution environment.
1897
- - Microsoft AI Foundry requires the standard AgenticDome API base URL, API key, and tenant ID. Threat-contract prompt and tool analysis also require `AGENTICDOME_BEARER_TOKEN`.
1935
+ - Microsoft AI Foundry requires the tenant runtime sidecar URL, API key, and tenant ID. Threat-contract prompt and tool analysis also require `AGENTICDOME_BEARER_TOKEN`.
1898
1936
 
1899
1937
  Official references:
1900
1938
 
@@ -2991,7 +3029,7 @@ If you need to call AgenticDome APIs manually, use the core SDK client.
2991
3029
  from agenticdome_sdk.client import AgentGuardClient
2992
3030
 
2993
3031
  client = AgentGuardClient(
2994
- api_base="https://au.agenticdome.io",
3032
+ api_base="https://demo-sidecar.agenticdome.io",
2995
3033
  api_key="your-api-key",
2996
3034
  tenant_id="your-tenant-id",
2997
3035
  timeout=20,
@@ -3012,7 +3050,7 @@ client.report_incident(
3012
3050
  from agenticdome_sdk.client import AgentGuardClient
3013
3051
 
3014
3052
  client = AgentGuardClient(
3015
- api_base="https://au.agenticdome.io",
3053
+ api_base="https://demo-sidecar.agenticdome.io",
3016
3054
  api_key="your-api-key",
3017
3055
  tenant_id="your-tenant-id",
3018
3056
  timeout=20,
@@ -3040,7 +3078,7 @@ print(result)
3040
3078
  from agenticdome_sdk.client import AgentGuardClient
3041
3079
 
3042
3080
  client = AgentGuardClient(
3043
- api_base="https://au.agenticdome.io",
3081
+ api_base="https://demo-sidecar.agenticdome.io",
3044
3082
  api_key="your-api-key",
3045
3083
  tenant_id="your-tenant-id",
3046
3084
  timeout=20,
@@ -3076,7 +3114,7 @@ print(result)
3076
3114
  from agenticdome_sdk.client import AgentGuardClient
3077
3115
 
3078
3116
  client = AgentGuardClient(
3079
- api_base="https://au.agenticdome.io",
3117
+ api_base="https://demo-sidecar.agenticdome.io",
3080
3118
  api_key="your-api-key",
3081
3119
  tenant_id="your-tenant-id",
3082
3120
  timeout=20,
@@ -3113,7 +3151,7 @@ print(authorization)
3113
3151
  from agenticdome_sdk.client import AgentGuardClient
3114
3152
 
3115
3153
  client = AgentGuardClient(
3116
- api_base="https://au.agenticdome.io",
3154
+ api_base="https://demo-sidecar.agenticdome.io",
3117
3155
  api_key="your-api-key",
3118
3156
  tenant_id="your-tenant-id",
3119
3157
  timeout=20,
@@ -3144,7 +3182,7 @@ print(verification)
3144
3182
  from agenticdome_sdk.client import AgentGuardClient
3145
3183
 
3146
3184
  client = AgentGuardClient(
3147
- api_base="https://au.agenticdome.io",
3185
+ api_base="https://demo-sidecar.agenticdome.io",
3148
3186
  api_key="your-api-key",
3149
3187
  tenant_id="your-tenant-id",
3150
3188
  timeout=20,
@@ -3193,7 +3231,7 @@ In-memory token storage is suitable for local development and single-process wor
3193
3231
  ## Recommended Production Settings
3194
3232
 
3195
3233
  ```bash
3196
- export AGENTICDOME_API_BASE="https://au.agenticdome.io"
3234
+ export AGENTICDOME_API_BASE="https://demo-sidecar.agenticdome.io"
3197
3235
  export AGENTICDOME_API_KEY="your_api_key"
3198
3236
  export AGENTICDOME_TENANT_ID="your_tenant_id"
3199
3237
 
@@ -3418,7 +3456,7 @@ For strict security-policy validation, add:
3418
3456
  export AGENTICDOME_LIVE_EXPECT_STRICT=1
3419
3457
  ```
3420
3458
 
3421
- The live tenant test performs real `guardrail_validate()` and `mesh_validate()` calls through the core client. Framework-specific behavior remains covered by the offline adapter test matrix above, because those tests assert where each framework boundary calls the shared AgenticDome client and how it handles policy decisions.
3459
+ The live tenant suite performs real `guardrail_validate()` and `mesh_validate()` calls, verifies that one request can carry an originating human subject and upstream agent actor together, and queries the tenant's active threat-signature bundle through the public SDK method. With `AGENTICDOME_LIVE_EXPECT_STRICT=1`, it additionally requires sensitive output enforcement plus a signed bundle whose provenance is `agenticdome_private_collection`. Framework-specific behavior remains covered by the offline adapter test matrix above.
3422
3460
 
3423
3461
  ---
3424
3462
 
@@ -0,0 +1,21 @@
1
+ agenticdome_python_sdk-1.2.0.dist-info/licenses/LICENSE,sha256=lqAH8G9tU2WPK9fzrnM_QMd4XUrh9fsmPqKE_hniKpM,718
2
+ agenticdome_sdk/__init__.py,sha256=6eOHJkY_Ir51dRKTktObXS40PjUsHrWMEQ2V3N0ItN4,576
3
+ agenticdome_sdk/agno.py,sha256=3gbc5URNTAHyNVAaAH882CpQpMecTv0R6S0CNMDOgos,60686
4
+ agenticdome_sdk/aws_bedrock.py,sha256=Z1Rcbps7VgvETmq_wrUbIvg6lJxsoe7YJEPZYkBKr80,69498
5
+ agenticdome_sdk/client.py,sha256=rRFqW5zXVDYGqDrchy3D-HxRaDINttcgYu8VRQXnceU,48658
6
+ agenticdome_sdk/crewai.py,sha256=7o7yapjbGfxfHGrmKtnpERIeJlDKIRgqz2h1WpLQJkQ,52389
7
+ agenticdome_sdk/google_adk.py,sha256=U23uSvUxgeQRUX6fGewls0CU0GI8mru67O1mHti7RkA,57175
8
+ agenticdome_sdk/identity.py,sha256=mrymGgZSVsKJ9THRde54qGmMT7j_uZHmPJ-HtWk7PXE,4635
9
+ agenticdome_sdk/langgraph.py,sha256=9zRAjA2KeDRS28PuPiVj5XrPm2-vONfkqNvXOVoIILY,84234
10
+ agenticdome_sdk/llamaindex.py,sha256=uFDzeYNz4Y72W-5XdluhdHvKAc8xkPJRkPaLFvwhlSk,42777
11
+ agenticdome_sdk/mcp_host.py,sha256=bEGamFhnUEL-V_qP1FLTqrItpx7p9NQWlJyzUzqQcYw,59484
12
+ agenticdome_sdk/microsoft_agent_framework.py,sha256=uSO7cOl9rWC99KaNkLv0ciU7EWpxAxNBGmolP_CVpaA,67140
13
+ agenticdome_sdk/microsoft_ai_foundry.py,sha256=GkfdfW0ajSpRRoLXyo5FYAp5img0JVDUJO52wZvew1I,56803
14
+ agenticdome_sdk/openai_agents.py,sha256=bWoJ2hjCyXDWl5Eo4pjeRr_MOQgNOZW7QE9WRDo6oDw,57243
15
+ agenticdome_sdk/proof.py,sha256=ECKc14xSE0V1HHmcpZjfVz8-Q2H_fooah3BfdblFV8M,2878
16
+ agenticdome_sdk/pydantic.py,sha256=7R6X0JgPIMLcWO682wcpN0X8dSMVEiwvVc4ydUN111s,54882
17
+ agenticdome_sdk/scenarios.py,sha256=QROC_JWKwub5AdpP9pLXdJCpotEACkF-qgKAnDAo8XA,7882
18
+ agenticdome_python_sdk-1.2.0.dist-info/METADATA,sha256=iwagZJxQCG6zRMaF_5G10T2o4k2dCKdKlR9Enr7_sHE,166047
19
+ agenticdome_python_sdk-1.2.0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
20
+ agenticdome_python_sdk-1.2.0.dist-info/top_level.txt,sha256=LZbbjXco5mqDrGwlTJpIKI5Sp6R_njzHHjExxAs9c3s,16
21
+ agenticdome_python_sdk-1.2.0.dist-info/RECORD,,
@@ -1,4 +1,6 @@
1
1
  from .client import AgentGuardClient, AgentGuardError, AgentGuardHTTPError
2
+ from .identity import IDENTITY_CONTEXT_VERSION, canonicalize_identity_context, enrich_policy_context
3
+ from .proof import create_dpop_proof, generate_rsa_proof_key, jwk_thumbprint
2
4
 
3
5
  GuardrailClient = AgentGuardClient
4
6
 
@@ -7,4 +9,10 @@ __all__ = [
7
9
  "GuardrailClient",
8
10
  "AgentGuardError",
9
11
  "AgentGuardHTTPError",
12
+ "IDENTITY_CONTEXT_VERSION",
13
+ "canonicalize_identity_context",
14
+ "enrich_policy_context",
15
+ "create_dpop_proof",
16
+ "generate_rsa_proof_key",
17
+ "jwk_thumbprint",
10
18
  ]
agenticdome_sdk/client.py CHANGED
@@ -6,6 +6,8 @@ import requests
6
6
  from requests.adapters import HTTPAdapter
7
7
  from urllib3.util.retry import Retry
8
8
 
9
+ from .identity import enrich_policy_context
10
+
9
11
 
10
12
  class AgentGuardError(Exception):
11
13
  """Base SDK exception."""
@@ -49,12 +51,13 @@ class AgentGuardClient:
49
51
  tenant_id: Optional[Union[str, int]] = None,
50
52
  bearer_token: Optional[str] = None,
51
53
  timeout: int = 20,
52
- user_agent: str = "agenticdome-python-sdk/0.4.0",
54
+ user_agent: str = "agenticdome-python-sdk/1.1.3",
53
55
  max_retries: int = 3,
54
56
  connect_timeout: Optional[float] = None,
55
57
  pool_connections: int = 20,
56
58
  pool_maxsize: int = 100,
57
59
  pool_block: bool = False,
60
+ service_token: Optional[str] = None,
58
61
  ):
59
62
  self.api_base = self._require_nonempty("api_base", api_base).rstrip("/")
60
63
  self.api_key = self._require_nonempty(
@@ -69,6 +72,11 @@ class AgentGuardClient:
69
72
  bearer_token
70
73
  or os.getenv("AGENTICDOME_BEARER_TOKEN")
71
74
  )
75
+ self.service_token = (
76
+ service_token
77
+ or os.getenv("AGENTICDOME_SERVICE_TOKEN")
78
+ or os.getenv("SERVICE_SECRET")
79
+ )
72
80
  self.timeout = timeout
73
81
  self.connect_timeout = self._positive_float(
74
82
  "connect_timeout",
@@ -194,7 +202,11 @@ class AgentGuardClient:
194
202
  for key, value in top_level_values.items():
195
203
  if value is not None:
196
204
  pc[key] = value
197
- return pc
205
+ return enrich_policy_context(
206
+ pc,
207
+ platform=pc.get("platform"),
208
+ target_agent_id=pc.get("target_agent_id") or pc.get("agent_id"),
209
+ )
198
210
 
199
211
  def _validate_guardrail_args(
200
212
  self,
@@ -226,9 +238,6 @@ class AgentGuardClient:
226
238
 
227
239
  normalized_direction = self._normalize_direction(direction)
228
240
 
229
- if source_agent_id and user_id:
230
- raise ValueError("Provide either 'source_agent_id' or 'user_id', not both")
231
-
232
241
  if tool_name and tool_args is None:
233
242
  raise ValueError("'tool_args' is required when 'tool_name' is provided")
234
243
  if tool_args is not None and not tool_name:
@@ -302,6 +311,24 @@ class AgentGuardClient:
302
311
  except Exception as exc:
303
312
  raise AgentGuardError(f"Failed to decode JSON response from {url}: {exc}") from exc
304
313
 
314
+ def _protected_request(
315
+ self,
316
+ method: str,
317
+ path: str,
318
+ *,
319
+ json_body: Optional[Dict[str, Any]] = None,
320
+ tenant_id: Optional[Union[str, int]] = None,
321
+ ) -> Dict[str, Any]:
322
+ headers = {"X-Service-Token": self.service_token} if self.service_token else None
323
+ return self._request(
324
+ method,
325
+ path,
326
+ json_body=json_body,
327
+ tenant_id=tenant_id,
328
+ use_bearer=bool(not self.service_token and self.bearer_token),
329
+ extra_headers=headers,
330
+ )
331
+
305
332
  # ------------------------------------------------------------------
306
333
  # SaaS Scan Endpoints
307
334
  # ------------------------------------------------------------------
@@ -478,6 +505,7 @@ class AgentGuardClient:
478
505
 
479
506
  merged_policy_context = self._merge_policy_context(
480
507
  policy_context,
508
+ agent_id=agent_id,
481
509
  platform=platform,
482
510
  source_platform=source_platform,
483
511
  tool_platform=tool_platform,
@@ -602,6 +630,7 @@ class AgentGuardClient:
602
630
 
603
631
  merged_policy_context = self._merge_policy_context(
604
632
  policy_context,
633
+ agent_id=agent_id,
605
634
  platform=effective_platform,
606
635
  source_platform=source_platform,
607
636
  source_agent_id=source_agent_id,
@@ -651,7 +680,33 @@ class AgentGuardClient:
651
680
  is_agent: bool = True,
652
681
  ) -> Dict[str, Any]:
653
682
  path = f"/trust/score/{agent_id}?is_agent={'true' if is_agent else 'false'}"
654
- return self._request("GET", path, tenant_id=tenant_id)
683
+ return self._protected_request("GET", path, tenant_id=tenant_id)
684
+
685
+ def get_behavioral_attestation(
686
+ self,
687
+ agent_id: str,
688
+ tenant_id: Optional[Union[str, int]] = None,
689
+ ) -> Dict[str, Any]:
690
+ self._require_nonempty("agent_id", agent_id)
691
+ return self._protected_request("GET", f"/trust/behavior/{agent_id}", tenant_id=tenant_id)
692
+
693
+ def get_behavioral_summary(
694
+ self,
695
+ tenant_id: Optional[Union[str, int]] = None,
696
+ limit: int = 300,
697
+ ) -> Dict[str, Any]:
698
+ bounded_limit = max(1, min(int(limit), 1000))
699
+ return self._protected_request(
700
+ "GET",
701
+ f"/trust/behavior-summary?limit={bounded_limit}",
702
+ tenant_id=tenant_id,
703
+ )
704
+
705
+ def get_threat_signature_status(
706
+ self,
707
+ tenant_id: Optional[Union[str, int]] = None,
708
+ ) -> Dict[str, Any]:
709
+ return self._protected_request("GET", "/security/threat-signatures/status", tenant_id=tenant_id)
655
710
 
656
711
  def report_incident(
657
712
  self,
@@ -672,7 +727,7 @@ class AgentGuardClient:
672
727
  "is_agent": is_agent,
673
728
  "platform": platform or "unknown",
674
729
  }
675
- return self._request("POST", "/trust/report", json_body=payload, tenant_id=tenant_id)
730
+ return self._protected_request("POST", "/trust/report", json_body=payload, tenant_id=tenant_id)
676
731
 
677
732
  def reset_trust_score(
678
733
  self,
@@ -682,7 +737,7 @@ class AgentGuardClient:
682
737
  is_agent: bool = True,
683
738
  service_token: Optional[str] = None,
684
739
  ) -> Dict[str, Any]:
685
- token = service_token or admin_secret or os.getenv("AGENTICDOME_SERVICE_TOKEN") or os.getenv("SERVICE_SECRET")
740
+ token = service_token or admin_secret or self.service_token
686
741
  if not token:
687
742
  raise ValueError("reset_trust_score requires service_token or AGENTICDOME_SERVICE_TOKEN")
688
743
  path = f"/trust/reset/{agent_id}?is_agent={'true' if is_agent else 'false'}"
@@ -742,6 +797,16 @@ class AgentGuardClient:
742
797
  block_on_sensitive_output: Optional[bool] = None,
743
798
  trusted_destination_domains: Optional[List[str]] = None,
744
799
  allowed_destination_domains: Optional[List[str]] = None,
800
+ user_id: Optional[str] = None,
801
+ actor_chain: Optional[List[Dict[str, Any]]] = None,
802
+ scopes: Optional[List[str]] = None,
803
+ permissions: Optional[List[str]] = None,
804
+ parent_jti: Optional[str] = None,
805
+ root_jti: Optional[str] = None,
806
+ policy_id: Optional[str] = None,
807
+ policy_version: Optional[str] = None,
808
+ policy_hash: Optional[str] = None,
809
+ proof_thumbprint: Optional[str] = None,
745
810
  tenant_id: Optional[Union[str, int]] = None,
746
811
  request_id: Union[str, int] = "1",
747
812
  ) -> Dict[str, Any]:
@@ -779,6 +844,7 @@ class AgentGuardClient:
779
844
 
780
845
  merged_policy_context = self._merge_policy_context(
781
846
  policy_context,
847
+ agent_id=agent_id,
782
848
  platform=platform,
783
849
  source_platform=source_platform,
784
850
  tool_platform=tool_platform,
@@ -798,6 +864,16 @@ class AgentGuardClient:
798
864
  block_on_sensitive_output=block_on_sensitive_output,
799
865
  trusted_destination_domains=trusted_destination_domains,
800
866
  allowed_destination_domains=allowed_destination_domains,
867
+ user_id=user_id,
868
+ actor_chain=actor_chain,
869
+ scopes=scopes,
870
+ permissions=permissions,
871
+ parent_jti=parent_jti,
872
+ root_jti=root_jti,
873
+ policy_id=policy_id,
874
+ policy_version=policy_version,
875
+ policy_hash=policy_hash,
876
+ proof_thumbprint=proof_thumbprint,
801
877
  )
802
878
 
803
879
  arguments = self._drop_none(
@@ -826,6 +902,16 @@ class AgentGuardClient:
826
902
  "block_on_sensitive_output": block_on_sensitive_output,
827
903
  "trusted_destination_domains": trusted_destination_domains,
828
904
  "allowed_destination_domains": allowed_destination_domains,
905
+ "user_id": user_id,
906
+ "actor_chain": actor_chain,
907
+ "scopes": scopes,
908
+ "permissions": permissions,
909
+ "parent_jti": parent_jti,
910
+ "root_jti": root_jti,
911
+ "policy_id": policy_id,
912
+ "policy_version": policy_version,
913
+ "policy_hash": policy_hash,
914
+ "proof_thumbprint": proof_thumbprint,
829
915
  }
830
916
  )
831
917
 
@@ -854,7 +940,12 @@ class AgentGuardClient:
854
940
  agent_id: Optional[str] = None,
855
941
  source_agent_id: Optional[str] = None,
856
942
  platform: Optional[str] = None,
943
+ user_id: Optional[str] = None,
944
+ session_id: Optional[str] = None,
945
+ proof_thumbprint: Optional[str] = None,
946
+ proof_token: Optional[str] = None,
857
947
  require_allowed: bool = True,
948
+ consume: bool = True,
858
949
  tenant_id: Optional[Union[str, int]] = None,
859
950
  ) -> Dict[str, Any]:
860
951
  """
@@ -881,7 +972,12 @@ class AgentGuardClient:
881
972
  "agent_id": agent_id,
882
973
  "source_agent_id": source_agent_id,
883
974
  "platform": platform,
975
+ "user_id": user_id,
976
+ "session_id": session_id,
977
+ "proof_thumbprint": proof_thumbprint,
978
+ "proof_token": proof_token,
884
979
  "require_allowed": require_allowed,
980
+ "consume": consume,
885
981
  }
886
982
  )
887
983
 
@@ -896,7 +992,12 @@ class AgentGuardClient:
896
992
  agent_id: Optional[str] = None,
897
993
  source_agent_id: Optional[str] = None,
898
994
  platform: Optional[str] = None,
995
+ user_id: Optional[str] = None,
996
+ session_id: Optional[str] = None,
997
+ proof_thumbprint: Optional[str] = None,
998
+ proof_token: Optional[str] = None,
899
999
  require_allowed: bool = True,
1000
+ consume: bool = True,
900
1001
  tenant_id: Optional[Union[str, int]] = None,
901
1002
  request_id: Union[str, int] = "1",
902
1003
  ) -> Dict[str, Any]:
@@ -924,7 +1025,12 @@ class AgentGuardClient:
924
1025
  "agent_id": agent_id,
925
1026
  "source_agent_id": source_agent_id,
926
1027
  "platform": platform,
1028
+ "user_id": user_id,
1029
+ "session_id": session_id,
1030
+ "proof_thumbprint": proof_thumbprint,
1031
+ "proof_token": proof_token,
927
1032
  "require_allowed": require_allowed,
1033
+ "consume": consume,
928
1034
  }
929
1035
  )
930
1036
 
@@ -935,6 +1041,44 @@ class AgentGuardClient:
935
1041
  tenant_id=tenant_id,
936
1042
  )
937
1043
 
1044
+ def get_decision_token_status(
1045
+ self,
1046
+ jti: str,
1047
+ *,
1048
+ tenant_id: Optional[Union[str, int]] = None,
1049
+ ) -> Dict[str, Any]:
1050
+ self._require_nonempty("jti", jti)
1051
+ return self._request(
1052
+ "GET",
1053
+ f"/a2a/decision/status/{jti}",
1054
+ tenant_id=tenant_id,
1055
+ )
1056
+
1057
+ def revoke_decision_token(
1058
+ self,
1059
+ *,
1060
+ jti: Optional[str] = None,
1061
+ root_jti: Optional[str] = None,
1062
+ agent_id: Optional[str] = None,
1063
+ user_id: Optional[str] = None,
1064
+ reason: str = "revoked by tenant administrator",
1065
+ tenant_id: Optional[Union[str, int]] = None,
1066
+ ) -> Dict[str, Any]:
1067
+ if not any(self._normalize_optional_string(value) for value in (jti, root_jti, agent_id, user_id)):
1068
+ raise ValueError("revoke_decision_token requires jti, root_jti, agent_id, or user_id")
1069
+ return self._request(
1070
+ "POST",
1071
+ "/a2a/decision/revoke",
1072
+ json_body=self._drop_none({
1073
+ "jti": jti,
1074
+ "root_jti": root_jti,
1075
+ "agent_id": agent_id,
1076
+ "user_id": user_id,
1077
+ "reason": reason,
1078
+ }),
1079
+ tenant_id=tenant_id,
1080
+ )
1081
+
938
1082
  # ------------------------------------------------------------------
939
1083
  # MCP JSON-RPC
940
1084
  # ------------------------------------------------------------------
@@ -1136,7 +1280,7 @@ class AgentGuardClient:
1136
1280
  "attack_profiles": attack_profiles or ["prompt_injection", "pii_leak"],
1137
1281
  "context": context,
1138
1282
  }
1139
- return self._request("POST", "/security/", json_body=payload, tenant_id=tenant_id)
1283
+ return self._protected_request("POST", "/security/", json_body=payload, tenant_id=tenant_id)
1140
1284
 
1141
1285
  # ------------------------------------------------------------------
1142
1286
  # Convenience scenario builders
@@ -0,0 +1,129 @@
1
+ from __future__ import annotations
2
+
3
+ import hashlib
4
+ import json
5
+ from typing import Any
6
+
7
+
8
+ IDENTITY_CONTEXT_VERSION = "agenticdome.identity.v1"
9
+
10
+
11
+ def _text(value: Any) -> str:
12
+ return str(value or "").strip()
13
+
14
+
15
+ def _list(value: Any) -> list[str]:
16
+ if value is None:
17
+ return []
18
+ if isinstance(value, str):
19
+ value = value.replace(",", " ").split()
20
+ if not isinstance(value, (list, tuple, set)):
21
+ value = [value]
22
+ return sorted({_text(item) for item in value if _text(item)})
23
+
24
+
25
+ def _hash(value: Any) -> str:
26
+ raw = json.dumps(value, sort_keys=True, separators=(",", ":"), default=str).encode("utf-8")
27
+ return "sha256:" + hashlib.sha256(raw).hexdigest()
28
+
29
+
30
+ def canonicalize_identity_context(
31
+ policy_context: dict[str, Any] | None,
32
+ *,
33
+ platform: str | None = None,
34
+ target_agent_id: str | None = None,
35
+ ) -> dict[str, Any]:
36
+ context = dict(policy_context or {})
37
+ existing = context.get("agenticdome_identity")
38
+ if isinstance(existing, dict) and existing.get("version") == IDENTITY_CONTEXT_VERSION:
39
+ return existing
40
+
41
+ claims = context.get("verified_identity_claims")
42
+ claims = dict(claims) if isinstance(claims, dict) else {}
43
+ asserted_subject = _text(claims.get("oid") or claims.get("sub") or claims.get("user_id"))
44
+ runtime_subject = _text(context.get("user_id") or context.get("principal_id") or context.get("caller_id"))
45
+ subject_id = runtime_subject or asserted_subject
46
+
47
+ subject = None
48
+ if subject_id:
49
+ subject = {
50
+ "id": subject_id,
51
+ "type": "human" if runtime_subject or claims.get("oid") else "principal",
52
+ "tenant_id": _text(claims.get("tid") or context.get("entra_tenant_id") or context.get("tenant_id")) or None,
53
+ "issuer": _text(claims.get("iss") or context.get("issuer")) or None,
54
+ "provenance": "runtime_context" if runtime_subject else "client_claim_assertion",
55
+ "verified": False,
56
+ "attributes": {
57
+ "asserted_roles": _list(claims.get("roles") or context.get("roles")),
58
+ "asserted_scopes": _list(claims.get("scp") or context.get("scp")),
59
+ },
60
+ }
61
+
62
+ raw_chain = context.get("actor_chain") or context.get("delegation_chain") or []
63
+ if not isinstance(raw_chain, list):
64
+ raw_chain = [raw_chain]
65
+ actors: list[dict[str, Any]] = []
66
+ for item in raw_chain:
67
+ if len(actors) >= 32:
68
+ break
69
+ if isinstance(item, dict):
70
+ actor_id = _text(item.get("id") or item.get("sub") or item.get("agent_id"))
71
+ framework = _text(item.get("framework") or item.get("platform"))
72
+ verified = False
73
+ provenance = "client_runtime_assertion"
74
+ else:
75
+ actor_id = _text(item)
76
+ framework = ""
77
+ verified = False
78
+ provenance = "runtime_context"
79
+ if actor_id and len(actor_id) <= 512 and not any(actor["id"] == actor_id for actor in actors):
80
+ actors.append({
81
+ "id": actor_id,
82
+ "type": "agent",
83
+ "framework": framework or None,
84
+ "verified": verified,
85
+ "provenance": provenance,
86
+ })
87
+
88
+ for actor_id, framework in (
89
+ (context.get("source_agent_id"), context.get("source_platform") or platform),
90
+ (target_agent_id or context.get("target_agent_id") or context.get("agent_id"), context.get("platform") or platform),
91
+ ):
92
+ if len(actors) >= 32:
93
+ break
94
+ value = _text(actor_id)
95
+ if value and not any(actor["id"] == value for actor in actors):
96
+ actors.append({
97
+ "id": value,
98
+ "type": "agent",
99
+ "framework": _text(framework) or None,
100
+ "verified": False,
101
+ "provenance": "request_binding",
102
+ })
103
+
104
+ return {
105
+ "version": IDENTITY_CONTEXT_VERSION,
106
+ "framework": _text(platform or context.get("platform")) or "unknown",
107
+ "subject": subject,
108
+ "actors": actors,
109
+ "provenance": {
110
+ "client_claims_asserted": bool(claims),
111
+ "verified_claims_present": False,
112
+ "native_context_hash": _hash(context),
113
+ },
114
+ }
115
+
116
+
117
+ def enrich_policy_context(
118
+ policy_context: dict[str, Any] | None,
119
+ *,
120
+ platform: str | None = None,
121
+ target_agent_id: str | None = None,
122
+ ) -> dict[str, Any]:
123
+ context = dict(policy_context or {})
124
+ context["agenticdome_identity"] = canonicalize_identity_context(
125
+ context,
126
+ platform=platform,
127
+ target_agent_id=target_agent_id,
128
+ )
129
+ return context
@@ -1111,6 +1111,20 @@ class AgenticDomeLangGraphFirewall:
1111
1111
  ns = _state_ns(state)
1112
1112
  if isinstance(ns.get("policy_context"), dict):
1113
1113
  ctx.update(cast(Dict[str, Any], ns["policy_context"]))
1114
+ lineage = ns.get("lineage_context")
1115
+ if isinstance(lineage, dict):
1116
+ for key in (
1117
+ "user_id",
1118
+ "actor_chain",
1119
+ "root_jti",
1120
+ "parent_jti",
1121
+ "scopes",
1122
+ "policy_id",
1123
+ "policy_version",
1124
+ "policy_hash",
1125
+ ):
1126
+ if lineage.get(key) is not None and key not in ctx:
1127
+ ctx[key] = lineage[key]
1114
1128
 
1115
1129
  ctx.setdefault("source_agent_id", agent_id)
1116
1130
  ctx.setdefault("request_purpose", default_request_purpose)
@@ -1136,6 +1150,23 @@ class AgenticDomeLangGraphFirewall:
1136
1150
 
1137
1151
  return ctx
1138
1152
 
1153
+ def _capture_verified_lineage(self, state: AgentState, verification: Dict[str, Any]) -> None:
1154
+ claims = verification.get("claims") if isinstance(verification.get("claims"), dict) else {}
1155
+ if not claims:
1156
+ return
1157
+ subject = claims.get("subject") if isinstance(claims.get("subject"), dict) else {}
1158
+ policy = claims.get("policy") if isinstance(claims.get("policy"), dict) else {}
1159
+ _state_ns(state)["lineage_context"] = {
1160
+ "user_id": claims.get("user_id") or subject.get("id"),
1161
+ "actor_chain": claims.get("actor_chain") or [],
1162
+ "root_jti": claims.get("root_jti") or claims.get("jti"),
1163
+ "parent_jti": claims.get("jti"),
1164
+ "scopes": claims.get("scopes") or [],
1165
+ "policy_id": policy.get("id"),
1166
+ "policy_version": policy.get("version"),
1167
+ "policy_hash": policy.get("hash"),
1168
+ }
1169
+
1139
1170
  def _extract_explicit_handoff(self, state: AgentState) -> Optional[Dict[str, Any]]:
1140
1171
  ns = _state_ns(state)
1141
1172
  raw = ns.get("handoff") or cast(Dict[str, Any], state).get("handoff")
@@ -1261,6 +1292,7 @@ class AgenticDomeLangGraphFirewall:
1261
1292
  if not valid:
1262
1293
  raise AgenticDomeDenied(f"AgenticDome blocked delegated execution: {_reason(verification)}")
1263
1294
 
1295
+ self._capture_verified_lineage(state, verification)
1264
1296
  self._clear_delegation_state(state)
1265
1297
  return
1266
1298
 
@@ -1287,6 +1319,7 @@ class AgenticDomeLangGraphFirewall:
1287
1319
  )
1288
1320
  if not valid:
1289
1321
  raise AgenticDomeDenied(f"AgenticDome blocked delegated execution: {_reason(verification)}")
1322
+ self._capture_verified_lineage(state, verification)
1290
1323
  return
1291
1324
 
1292
1325
  pending = self.token_store.consume(
@@ -1312,6 +1345,7 @@ class AgenticDomeLangGraphFirewall:
1312
1345
  )
1313
1346
  if not valid:
1314
1347
  raise AgenticDomeDenied(f"AgenticDome blocked delegated execution: {_reason(verification)}")
1348
+ self._capture_verified_lineage(state, verification)
1315
1349
  self._audit("delegated_execution_allowed", agent_id=agent_id, source_agent_id=pending.source_agent_id, tool_name=tool_name)
1316
1350
  return
1317
1351
 
@@ -715,6 +715,9 @@ class AgenticDomeMicrosoftAgentFirewall:
715
715
  "upn",
716
716
  "username",
717
717
  "email",
718
+ "user_id",
719
+ "principal_id",
720
+ "caller_id",
718
721
  "roles",
719
722
  "scp",
720
723
  "azp",
@@ -562,6 +562,7 @@ class AgenticDomeMicrosoftAIFoundryFirewall:
562
562
  for key in (
563
563
  "tenant_id", "entra_tenant_id", "oid", "object_id", "appid", "app_id", "client_id",
564
564
  "upn", "username", "email", "roles", "scp", "azp", "purview_label",
565
+ "user_id", "principal_id", "caller_id",
565
566
  "sensitivity_label", "data_classification", "foundry_project_id", "foundry_agent_id",
566
567
  ):
567
568
  value = self._ctx_attr(ctx, key, default=None)
@@ -0,0 +1,80 @@
1
+ from __future__ import annotations
2
+
3
+ import base64
4
+ import hashlib
5
+ import json
6
+ import time
7
+ import uuid
8
+ from typing import Any
9
+
10
+
11
+ def _crypto():
12
+ try:
13
+ from cryptography.hazmat.primitives import hashes, serialization
14
+ from cryptography.hazmat.primitives.asymmetric import padding, rsa
15
+ except ImportError as exc:
16
+ raise RuntimeError(
17
+ "Proof-of-possession helpers require: pip install 'agenticdome-python-sdk[pop]'"
18
+ ) from exc
19
+ return hashes, serialization, padding, rsa
20
+
21
+
22
+ def _b64u(data: bytes) -> str:
23
+ return base64.urlsafe_b64encode(data).decode("ascii").rstrip("=")
24
+
25
+
26
+ def _public_jwk(private_key) -> dict[str, str]:
27
+ numbers = private_key.public_key().public_numbers()
28
+ return {
29
+ "kty": "RSA",
30
+ "n": _b64u(numbers.n.to_bytes((numbers.n.bit_length() + 7) // 8, "big")),
31
+ "e": _b64u(numbers.e.to_bytes((numbers.e.bit_length() + 7) // 8, "big")),
32
+ }
33
+
34
+
35
+ def jwk_thumbprint(jwk: dict[str, Any]) -> str:
36
+ canonical = json.dumps(
37
+ {key: jwk[key] for key in ("e", "kty", "n")},
38
+ sort_keys=True,
39
+ separators=(",", ":"),
40
+ ).encode("utf-8")
41
+ return _b64u(hashlib.sha256(canonical).digest())
42
+
43
+
44
+ def generate_rsa_proof_key(*, key_size: int = 2048) -> dict[str, Any]:
45
+ _, serialization, _, rsa = _crypto()
46
+ private_key = rsa.generate_private_key(public_exponent=65537, key_size=max(2048, key_size))
47
+ private_pem = private_key.private_bytes(
48
+ encoding=serialization.Encoding.PEM,
49
+ format=serialization.PrivateFormat.PKCS8,
50
+ encryption_algorithm=serialization.NoEncryption(),
51
+ ).decode("ascii")
52
+ jwk = _public_jwk(private_key)
53
+ return {"private_key_pem": private_pem, "public_jwk": jwk, "thumbprint": jwk_thumbprint(jwk)}
54
+
55
+
56
+ def create_dpop_proof(
57
+ private_key_pem: str,
58
+ *,
59
+ access_token: str,
60
+ method: str,
61
+ uri: str,
62
+ proof_jti: str | None = None,
63
+ issued_at: int | None = None,
64
+ ) -> str:
65
+ hashes, serialization, padding, _ = _crypto()
66
+ private_key = serialization.load_pem_private_key(private_key_pem.encode("ascii"), password=None)
67
+ jwk = _public_jwk(private_key)
68
+ header = {"typ": "dpop+jwt", "alg": "RS256", "jwk": jwk}
69
+ payload = {
70
+ "jti": proof_jti or uuid.uuid4().hex,
71
+ "iat": int(issued_at or time.time()),
72
+ "htm": str(method).upper(),
73
+ "htu": str(uri),
74
+ "ath": _b64u(hashlib.sha256(access_token.encode("utf-8")).digest()),
75
+ }
76
+ encoded_header = _b64u(json.dumps(header, sort_keys=True, separators=(",", ":")).encode("utf-8"))
77
+ encoded_payload = _b64u(json.dumps(payload, sort_keys=True, separators=(",", ":")).encode("utf-8"))
78
+ signing_input = f"{encoded_header}.{encoded_payload}".encode("ascii")
79
+ signature = private_key.sign(signing_input, padding.PKCS1v15(), hashes.SHA256())
80
+ return f"{encoded_header}.{encoded_payload}.{_b64u(signature)}"
@@ -1,19 +0,0 @@
1
- agenticdome_python_sdk-1.1.3.dist-info/licenses/LICENSE,sha256=lqAH8G9tU2WPK9fzrnM_QMd4XUrh9fsmPqKE_hniKpM,718
2
- agenticdome_sdk/__init__.py,sha256=87__SX3oTttDLur7z8BhzAe6QMOSK1GXjoaTZRVTbc0,223
3
- agenticdome_sdk/agno.py,sha256=3gbc5URNTAHyNVAaAH882CpQpMecTv0R6S0CNMDOgos,60686
4
- agenticdome_sdk/aws_bedrock.py,sha256=Z1Rcbps7VgvETmq_wrUbIvg6lJxsoe7YJEPZYkBKr80,69498
5
- agenticdome_sdk/client.py,sha256=9OJqaE5OMr7_mcqFI5b_QodQU-ZP9LxgRRoUU38rYW0,43513
6
- agenticdome_sdk/crewai.py,sha256=7o7yapjbGfxfHGrmKtnpERIeJlDKIRgqz2h1WpLQJkQ,52389
7
- agenticdome_sdk/google_adk.py,sha256=U23uSvUxgeQRUX6fGewls0CU0GI8mru67O1mHti7RkA,57175
8
- agenticdome_sdk/langgraph.py,sha256=Eyaq-zcScLVlvT4VBHPN1H_K1An45LI7lKi0YgsXCOs,82660
9
- agenticdome_sdk/llamaindex.py,sha256=uFDzeYNz4Y72W-5XdluhdHvKAc8xkPJRkPaLFvwhlSk,42777
10
- agenticdome_sdk/mcp_host.py,sha256=bEGamFhnUEL-V_qP1FLTqrItpx7p9NQWlJyzUzqQcYw,59484
11
- agenticdome_sdk/microsoft_agent_framework.py,sha256=W0zP49u_jucyMcSsuCM9bfdOnuRclKeu18nakaCfwq0,67064
12
- agenticdome_sdk/microsoft_ai_foundry.py,sha256=aIofnEUKU30P-4vKkWx1YdZZVHQIZECjEmoMLzvrp4g,56751
13
- agenticdome_sdk/openai_agents.py,sha256=bWoJ2hjCyXDWl5Eo4pjeRr_MOQgNOZW7QE9WRDo6oDw,57243
14
- agenticdome_sdk/pydantic.py,sha256=7R6X0JgPIMLcWO682wcpN0X8dSMVEiwvVc4ydUN111s,54882
15
- agenticdome_sdk/scenarios.py,sha256=QROC_JWKwub5AdpP9pLXdJCpotEACkF-qgKAnDAo8XA,7882
16
- agenticdome_python_sdk-1.1.3.dist-info/METADATA,sha256=AIR5JmEYx51U-lYBLub7i6v7JKkwpgwLxjap5wu9294,164205
17
- agenticdome_python_sdk-1.1.3.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
18
- agenticdome_python_sdk-1.1.3.dist-info/top_level.txt,sha256=LZbbjXco5mqDrGwlTJpIKI5Sp6R_njzHHjExxAs9c3s,16
19
- agenticdome_python_sdk-1.1.3.dist-info/RECORD,,