agenticdome-python-sdk 1.2.32__py3-none-any.whl → 1.2.34__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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agenticdome-python-sdk
3
- Version: 1.2.32
3
+ Version: 1.2.34
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,20 +33,20 @@ 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.21,>=1.15.5; extra == "crewai"
36
+ Requires-Dist: crewai<=1.15.22,>=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
40
40
  Requires-Dist: cryptography>=42.0.0; extra == "pop"
41
41
  Provides-Extra: pydanticai
42
- Requires-Dist: pydantic-ai<=2.43.0,>=2.16.0; extra == "pydanticai"
42
+ Requires-Dist: pydantic-ai<=2.51.0,>=2.16.0; extra == "pydanticai"
43
43
  Requires-Dist: anyio>=4.0.0; extra == "pydanticai"
44
44
  Provides-Extra: pydantic
45
- Requires-Dist: pydantic-ai<=2.43.0,>=2.16.0; extra == "pydantic"
45
+ 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
- Requires-Dist: langgraph<=1.2.11,>=1.2.9; extra == "langgraph"
49
- Requires-Dist: langchain-core<=1.6.3,>=1.5.0; extra == "langgraph"
48
+ Requires-Dist: langgraph<=1.2.12,>=1.2.9; extra == "langgraph"
49
+ Requires-Dist: langchain-core<=1.6.5,>=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
@@ -55,51 +55,51 @@ Requires-Dist: autogen-agentchat==0.7.5; extra == "autogen"
55
55
  Provides-Extra: microsoft-autogen
56
56
  Requires-Dist: autogen-agentchat==0.7.5; extra == "microsoft-autogen"
57
57
  Provides-Extra: foundry
58
- Requires-Dist: azure-ai-projects<=2.6.1,>=2.3.0; extra == "foundry"
58
+ Requires-Dist: azure-ai-projects<=2.7.0,>=2.3.0; extra == "foundry"
59
59
  Requires-Dist: azure-identity==1.25.3; extra == "foundry"
60
60
  Provides-Extra: agno
61
- Requires-Dist: agno<=3.0.9,>=2.8.0; extra == "agno"
61
+ Requires-Dist: agno<=3.0.11,>=2.8.0; extra == "agno"
62
62
  Provides-Extra: openai-agents
63
- Requires-Dist: openai-agents<=0.22.2,>=0.18.3; extra == "openai-agents"
63
+ 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.94,>=1.43.54; extra == "bedrock"
67
+ Requires-Dist: boto3<=1.43.103,>=1.43.54; extra == "bedrock"
68
68
  Provides-Extra: aws-bedrock
69
- Requires-Dist: boto3<=1.43.94,>=1.43.54; extra == "aws-bedrock"
69
+ Requires-Dist: boto3<=1.43.103,>=1.43.54; extra == "aws-bedrock"
70
70
  Provides-Extra: llamaindex
71
- Requires-Dist: llama-index<=0.14.24,>=0.14.23; extra == "llamaindex"
71
+ Requires-Dist: llama-index<=0.14.25,>=0.14.23; extra == "llamaindex"
72
72
  Provides-Extra: llama-index
73
- Requires-Dist: llama-index<=0.14.24,>=0.14.23; extra == "llama-index"
73
+ Requires-Dist: llama-index<=0.14.25,>=0.14.23; extra == "llama-index"
74
74
  Provides-Extra: google-adk
75
- Requires-Dist: google-adk<=2.9.0,>=2.5.0; extra == "google-adk"
75
+ Requires-Dist: google-adk<=2.10.0,>=2.5.0; extra == "google-adk"
76
76
  Provides-Extra: adk
77
- Requires-Dist: google-adk<=2.9.0,>=2.5.0; extra == "adk"
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.152,>=0.2.126; extra == "claude"
79
+ Requires-Dist: claude-agent-sdk<=0.2.160,>=0.2.126; extra == "claude"
80
80
  Provides-Extra: claude-agent-sdk
81
- Requires-Dist: claude-agent-sdk<=0.2.152,>=0.2.126; extra == "claude-agent-sdk"
81
+ Requires-Dist: claude-agent-sdk<=0.2.160,>=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.21,>=1.15.5; extra == "all"
85
+ Requires-Dist: crewai<=1.15.22,>=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
- Requires-Dist: pydantic-ai<=2.43.0,>=2.16.0; extra == "all"
88
+ Requires-Dist: pydantic-ai<=2.51.0,>=2.16.0; extra == "all"
89
89
  Requires-Dist: anyio>=4.0.0; extra == "all"
90
- Requires-Dist: langgraph<=1.2.11,>=1.2.9; extra == "all"
91
- Requires-Dist: langchain-core<=1.6.3,>=1.5.0; extra == "all"
90
+ Requires-Dist: langgraph<=1.2.12,>=1.2.9; extra == "all"
91
+ Requires-Dist: langchain-core<=1.6.5,>=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
- Requires-Dist: agno<=3.0.9,>=2.8.0; extra == "all"
95
- Requires-Dist: azure-ai-projects<=2.6.1,>=2.3.0; extra == "all"
94
+ Requires-Dist: agno<=3.0.11,>=2.8.0; extra == "all"
95
+ 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
- Requires-Dist: openai-agents<=0.22.2,>=0.18.3; extra == "all"
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.94,>=1.43.54; extra == "all"
100
- Requires-Dist: llama-index<=0.14.24,>=0.14.23; extra == "all"
101
- Requires-Dist: google-adk<=2.9.0,>=2.5.0; extra == "all"
102
- Requires-Dist: claude-agent-sdk<=0.2.152,>=0.2.126; extra == "all"
99
+ Requires-Dist: boto3<=1.43.103,>=1.43.54; extra == "all"
100
+ Requires-Dist: llama-index<=0.14.25,>=0.14.23; extra == "all"
101
+ Requires-Dist: google-adk<=2.10.0,>=2.5.0; extra == "all"
102
+ Requires-Dist: claude-agent-sdk<=0.2.160,>=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"
@@ -218,7 +218,10 @@ agenticdome openclaw verify --output .agenticdome/verification.json
218
218
  AgenticDome plugin, explicit consent and the exact certified typed hooks.
219
219
  `agenticdome plan` returns source-free, tenant-bound Integration Copilot
220
220
  guidance for review. `openclaw verify` adds workspace-test and assigned-tenant
221
- policy evidence. The
221
+ policy evidence. If the same deployable workload also uses MCP, this command
222
+ includes the MCP transport rehearsal and both `mcp_verification` and
223
+ `openclaw_verification` in one report. Both sections must be ready before the
224
+ report is imported; `mcp verify` alone is not a combined-workload proof. The
222
225
  customer Control Panel separately confirms tenant binding and retained
223
226
  telemetry; neither command silently modifies customer source.
224
227
 
@@ -228,6 +231,17 @@ languages and candidate boundaries can be discovered locally; business
228
231
  purpose, sensitive actions and managed-versus-sovereign deployment remain
229
232
  explicit customer decisions and are not guessed from source code.
230
233
 
234
+ `agenticdome init` creates local configuration without contacting Copilot.
235
+ `inspect` and `plan` send source-free structural metadata to the assigned
236
+ tenant sidecar. A selection spanning several deployable packages is analyzed
237
+ as bounded, sequential workload units; successful units are checkpointed
238
+ locally so a retry does not resubmit them. The report lists analyzed parts
239
+ and any result-list caps. It does not claim that calls or guard placement
240
+ across separate workload units were proven; review those boundaries before
241
+ production. If the selection exceeds the 24-unit safety limit, select the
242
+ application or package that actually executes agent actions. No unexamined
243
+ unit is silently omitted or reported as protected.
244
+
231
245
  Use **Customer Control Panel → Activate Action Firewall → Core Config** to
232
246
  choose the Developer Integration path and import the two evidence files. This
233
247
  path is for SDK, MCP, framework or custom-code integrations; Microsoft
@@ -1,5 +1,5 @@
1
- agenticdome_python_sdk-1.2.32.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
2
- agenticdome_python_sdk-1.2.32.dist-info/licenses/NOTICE,sha256=obvKP6kV1Ny5R8_INFOpf0X5um9U2X43LGwQFobO9kg,550
1
+ agenticdome_python_sdk-1.2.34.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
2
+ agenticdome_python_sdk-1.2.34.dist-info/licenses/NOTICE,sha256=obvKP6kV1Ny5R8_INFOpf0X5um9U2X43LGwQFobO9kg,550
3
3
  agenticdome_sdk/__init__.py,sha256=UY__0ppEM4MlsTQoLh8alZ7AoMjtegGKe4j_Sj7CpNk,903
4
4
  agenticdome_sdk/_framework_firewall.py,sha256=W3gy7WsK50scE7ypJrmVJhHUOBsr0zAWQ85rghqaJk4,31963
5
5
  agenticdome_sdk/_mode.py,sha256=XvOgh5sW-FG8S39V483h3uLiFh8wSt14OmYXz_6eDO8,1283
@@ -7,16 +7,16 @@ agenticdome_sdk/agno.py,sha256=L3yfjTBHW47xzT67a1DsjtwmvrAoYBkbxADpsr85Cp0,60766
7
7
  agenticdome_sdk/attestation.py,sha256=ij4cMff7nzLaIS0W02d2WURFcyKe72bcUlSz-dYkaLE,10310
8
8
  agenticdome_sdk/autogen.py,sha256=KP4qlIcsNXB-4ZT9D7Slc1xWEeWXRIWkc5HGW0U6k2c,29018
9
9
  agenticdome_sdk/aws_bedrock.py,sha256=2zD9j7xi0jna0sMeMf-hKZdc3Y4RPwzj6tMVOUGgIDQ,69581
10
- agenticdome_sdk/catalog_snapshot.json,sha256=Bi7AA6s3h2hk_y1xP6uwV-hdTgtCNXK05MX-2x5-gsw,951
10
+ agenticdome_sdk/catalog_snapshot.json,sha256=aOJMqz8FpPF-q1ynpM2xsEk-O-tMyUCPE5Y51dygtLQ,951
11
11
  agenticdome_sdk/claude.py,sha256=XeY9AUu61SYcJjQVz_AtL_WaN6X4KqP5nprEbbr4Q6A,17456
12
12
  agenticdome_sdk/client.py,sha256=2uVKZR1uXDBIvwOS-lpNPCAXl9K5vroPqsPNNYhBWeg,69473
13
- agenticdome_sdk/connect.py,sha256=yNRh84mqdWr73fXW3S8Zc_lV1QN6gce5T6mZ20cr8ps,16726
14
- agenticdome_sdk/copilot_ir.py,sha256=OMkzkVGSP2pFkxZBjAXNCCRcJk21X0wnllWNhQeErp0,16588
13
+ agenticdome_sdk/connect.py,sha256=MY30wXYA6OaZhs__E67KcFXEy7mZMBxMSV06BnlBjRg,18766
14
+ agenticdome_sdk/copilot_ir.py,sha256=zT13tOX8xu11yrOtIPMRFVud8CQ81Gu3WxsXxyQ4XT0,17928
15
15
  agenticdome_sdk/copilot_ir_collector.cjs,sha256=oxLY8ByONo7Es4YjYiJuRz_A7IKL65Sy486UXnu-4Rs,9681
16
16
  agenticdome_sdk/crewai.py,sha256=sSJQ49O7-8kqOAD2_jrsMtMOmBOcJmFkeOv7S3-ayMs,52490
17
17
  agenticdome_sdk/demo.py,sha256=dyfqt2N_cJoyUWKnjPYuQxuw2hb2DrCNUf1jQKeYYoc,8350
18
18
  agenticdome_sdk/google_adk.py,sha256=2TA-tUhY0lOnkGcs1BN9CUEz67ebVX4HJ7mnNoRPcZs,57258
19
- agenticdome_sdk/hook_catalog.py,sha256=IH8PVvjI393pUXFeVzLaZIibXGDUXW1Ve-IUqrAJY5A,29272
19
+ agenticdome_sdk/hook_catalog.py,sha256=0dfFWNDS0KCeP0IozWZb1NkNBWf1omaO2-yZKNVdTf0,29272
20
20
  agenticdome_sdk/identity.py,sha256=mrymGgZSVsKJ9THRde54qGmMT7j_uZHmPJ-HtWk7PXE,4635
21
21
  agenticdome_sdk/langgraph.py,sha256=FUvF6DSA5aZP3eoBoNeldgGtPrz-dO5xcVmrPPSBEhI,84312
22
22
  agenticdome_sdk/lifecycle.py,sha256=9LvxmUU1LC_tMchb5uVFBnZIkVFUxOv3VH9wG_9gPtA,12855
@@ -27,15 +27,15 @@ agenticdome_sdk/mcp_rehearsal_server.py,sha256=cox4XqUTL8d0gaDzqxDZcEALkaz8otjOj
27
27
  agenticdome_sdk/mcp_verification.py,sha256=VqQS5SpPVFI3G7qCwrT90JmG8vFE6pRJEB7PViHjKqw,14235
28
28
  agenticdome_sdk/microsoft_agent_framework.py,sha256=GfIIuk0n-VhsZaTyoB7P6ilpz9bFLD95TWuX0rFSWeU,67219
29
29
  agenticdome_sdk/microsoft_ai_foundry.py,sha256=YlO968s1dbAYcaEqhqufL92NFR66GuTtngnCv7-1mYc,56911
30
- agenticdome_sdk/onboarding_cli.py,sha256=8ymGtNmllNH6lP87pvxHe2GySlcsHoDoLiispfQ5rDs,95417
30
+ agenticdome_sdk/onboarding_cli.py,sha256=yPPlNRPCjuDNpeJpL-0fJK3RZTOZvII8d-qFHJgTILM,120597
31
31
  agenticdome_sdk/openai_agents.py,sha256=nNM-YcsUDcE23sGv1buLudcYFz0NLju2Mwiw_wrVaJg,57326
32
32
  agenticdome_sdk/outcomes.py,sha256=jadWDzQaZXrHNvpPme8lQY0jihYLCoM3s4CihAq0JRo,2507
33
33
  agenticdome_sdk/proof.py,sha256=ECKc14xSE0V1HHmcpZjfVz8-Q2H_fooah3BfdblFV8M,2878
34
34
  agenticdome_sdk/pydantic.py,sha256=WKb8X0Fgydfid-ep8E-M8Yslz2pWcCP6w7n_aBxt1rI,54961
35
35
  agenticdome_sdk/simulation.py,sha256=UCbZy3u9AzfxQCfY38SCV3CxGxhinV9EA4aHMPlK4mc,8426
36
36
  agenticdome_sdk/smolagents.py,sha256=wjMA1HVAQ-9wRNM38Jr9wlCpKMhF-9vxtTk6R-kwQhs,19094
37
- agenticdome_python_sdk-1.2.32.dist-info/METADATA,sha256=iNu8PnerROIUvox-_F038ah1a1wHBb2OSTUHJE2gZ0A,139108
38
- agenticdome_python_sdk-1.2.32.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
39
- agenticdome_python_sdk-1.2.32.dist-info/entry_points.txt,sha256=cRfCphkr5gLrkGIzXJEtL50HdHLajoZLbZtcMLE8NoY,113
40
- agenticdome_python_sdk-1.2.32.dist-info/top_level.txt,sha256=LZbbjXco5mqDrGwlTJpIKI5Sp6R_njzHHjExxAs9c3s,16
41
- agenticdome_python_sdk-1.2.32.dist-info/RECORD,,
37
+ agenticdome_python_sdk-1.2.34.dist-info/METADATA,sha256=hOOXfVmbkCRG1AKVWBUcSqHa1i6G92XEomK47iBKSiU,140120
38
+ agenticdome_python_sdk-1.2.34.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
39
+ agenticdome_python_sdk-1.2.34.dist-info/entry_points.txt,sha256=cRfCphkr5gLrkGIzXJEtL50HdHLajoZLbZtcMLE8NoY,113
40
+ agenticdome_python_sdk-1.2.34.dist-info/top_level.txt,sha256=LZbbjXco5mqDrGwlTJpIKI5Sp6R_njzHHjExxAs9c3s,16
41
+ agenticdome_python_sdk-1.2.34.dist-info/RECORD,,
@@ -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-09-15",
5
- "python_sdk_version": "1.2.32",
4
+ "verified_at": "2026-09-26",
5
+ "python_sdk_version": "1.2.34",
6
6
  "published_packages": {
7
7
  "agenticdome-python-sdk": {
8
8
  "registry": "pypi",
9
- "version": "1.2.32",
10
- "url": "https://pypi.org/project/agenticdome-python-sdk/1.2.32/"
9
+ "version": "1.2.34",
10
+ "url": "https://pypi.org/project/agenticdome-python-sdk/1.2.34/"
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.4",
25
- "url": "https://www.npmjs.com/package/openclaw/v/2026.9.4"
24
+ "version": "2026.9.6",
25
+ "url": "https://www.npmjs.com/package/openclaw/v/2026.9.6"
26
26
  }
27
27
  }
28
28
  }
@@ -17,9 +17,6 @@ from pathlib import Path
17
17
  from typing import Any, Dict, Optional
18
18
 
19
19
  from .attestation import ensure_attestation_key
20
- from .hook_catalog import CATALOG_SCHEMA, CATALOG_VERIFIED_AT, catalog_digest
21
-
22
-
23
20
  SCOPES = ["onboarding:read", "metadata:write", "evidence:write", "workload:write", "repository:prepare"]
24
21
 
25
22
 
@@ -124,7 +121,10 @@ def _approve_metadata(ir: Dict[str, Any], assume_yes: bool) -> None:
124
121
 
125
122
  def run_connect(root: Path, args: Any) -> Dict[str, Any]:
126
123
  # Import lazily to avoid a module cycle and keep the public client purely orchestration code.
127
- from .onboarding_cli import _installed_sdk_version, inspect_repository
124
+ from .onboarding_cli import (
125
+ _active_copilot_catalog_binding, _copilot_semantic_analysis,
126
+ _ensure_workload_id, _installed_sdk_version, _scope_gap_message, inspect_repository,
127
+ )
128
128
 
129
129
  portal = str(args.portal).rstrip("/")
130
130
  if not portal.startswith("https://") and not getattr(args, "allow_insecure_http", False):
@@ -155,12 +155,23 @@ def run_connect(root: Path, args: Any) -> Dict[str, Any]:
155
155
  if not session.get("runtime") or not session.get("copilot"):
156
156
  raise SystemExit("Authentication succeeded, but no eligible runtime is assigned. The saved portal session can be resumed after an administrator enables an assignment policy.")
157
157
 
158
- report = inspect_repository(root)
158
+ local_workload_id = _ensure_workload_id(root)
159
+ report = inspect_repository(root, remote_analysis=False)
160
+ if report.get("scope", {}).get("complete") is not True:
161
+ raise SystemExit(_scope_gap_message(report))
159
162
  ir = report["copilot_ir"]
160
163
  _approve_metadata(ir, bool(args.yes))
161
164
  private_pem, public_pem = ensure_attestation_key(root / ".agenticdome")
162
165
  del private_pem
163
- workload_uuid = str(uuid.uuid5(uuid.NAMESPACE_URL, session["tenant_id"] + ":" + root.name))
166
+ workload_uuid = str(uuid.uuid5(uuid.NAMESPACE_URL, session["tenant_id"] + ":" + local_workload_id))
167
+ previous_session_path = root / ".agenticdome" / "connect-session.json"
168
+ if previous_session_path.is_file():
169
+ try:
170
+ previous_session = json.loads(previous_session_path.read_text(encoding="utf-8"))
171
+ if previous_session.get("tenant_id") == session["tenant_id"]:
172
+ workload_uuid = str(uuid.UUID(str(previous_session["workload_uuid"])))
173
+ except (OSError, ValueError, KeyError, TypeError, AttributeError, json.JSONDecodeError):
174
+ raise SystemExit("The previous Connect workload identity is unreadable. Restore its connect-session.json before retrying to avoid creating a duplicate workload.")
164
175
  frameworks = [item["key"] for item in report.get("frameworks", [])]
165
176
  _request(portal + "/api/agentguard/connect/workloads", {
166
177
  "session_uuid": session["session_uuid"], "workload_uuid": workload_uuid,
@@ -171,38 +182,51 @@ def run_connect(root: Path, args: Any) -> Dict[str, Any]:
171
182
 
172
183
  runtime_base = str(session["runtime"]["api_base"]).rstrip("/")
173
184
  copilot_key = str(session["copilot"]["api_key"])
174
- ir_digest = hashlib.sha256(json.dumps(ir, sort_keys=True, separators=(",", ":")).encode("utf-8")).hexdigest()
175
- plan = _request(runtime_base + "/integration-copilot/v1/analyze", {
176
- "schema": "agenticdome.copilot-request.v1", "ir": ir,
177
- "catalog_binding": {"schema": CATALOG_SCHEMA, "catalog_digest": catalog_digest(), "verified_at": CATALOG_VERIFIED_AT},
178
- }, headers={"X-API-Key": copilot_key, "X-Tenant-Id": session["tenant_id"], "Idempotency-Key": hashlib.sha256((session["tenant_id"] + ir_digest + catalog_digest()).encode()).hexdigest()})
179
- if plan.get("schema") != "agenticdome.copilot-plan.v1" or plan.get("tenant_id") != session["tenant_id"]:
180
- raise SystemExit("The assigned private Copilot returned an invalid tenant-bound plan.")
181
- semantic = plan.get("semantic_analysis") or {}
182
- if semantic.get("ir_sha256") != ir_digest:
183
- raise SystemExit("The private Copilot plan was not bound to the submitted metadata.")
184
- _request(portal + "/api/agentguard/connect/sessions/" + session["session_uuid"] + "/metadata", {"ir": ir, "signed_plan": plan}, session["access_token"])
185
-
185
+ from .onboarding_cli import _ir_sha256
186
+ ir_digest = _ir_sha256(ir)
186
187
  state_dir = root / ".agenticdome"
187
188
  state_dir.mkdir(parents=True, exist_ok=True)
188
- cache = {"schema": "agenticdome.copilot-cache.v1", "source_upload": False, "tenant_id": session["tenant_id"], "api_base": runtime_base, "semantic_analysis": semantic, "catalog_binding": plan.get("catalog_binding")}
189
- (state_dir / "copilot-analysis.json").write_text(json.dumps(cache, indent=2, sort_keys=True) + "\n", encoding="utf-8")
190
189
  config_path = state_dir / "config.json"
191
190
  if not config_path.exists():
192
191
  config_path.write_text(json.dumps({
193
- "schema": "agenticdome.project-config.v1", "frameworks": frameworks or ["custom-python"],
192
+ "schema": "agenticdome.project-config.v1", "workload_id": local_workload_id,
193
+ "frameworks": frameworks or ["custom-python"],
194
194
  "execution_broker_mode": "policy",
195
195
  "business_purpose": "REVIEW_REQUIRED_NOT_INVENTED", "sensitive_tools": [],
196
196
  "deployment": {"preference": "managed", "region": session["runtime"].get("region") or "auto"},
197
197
  "source_upload": False,
198
198
  }, indent=2, sort_keys=True) + "\n", encoding="utf-8")
199
- resumable = {"schema": "agenticdome.connect-state.v1", "portal": portal, "tenant_id": session["tenant_id"], "session_uuid": session["session_uuid"], "workload_uuid": workload_uuid, "token_expires_at": session["expires_at"], "access_token": session["access_token"]}
200
- state_path = state_dir / "connect-session.json"
201
- state_path.write_text(json.dumps(resumable, indent=2, sort_keys=True) + "\n", encoding="utf-8")
202
- os.chmod(state_path, 0o600)
203
199
  previous = {name: os.environ.get(name) for name in ("AGENTICDOME_API_BASE", "AGENTICDOME_COPILOT_API_KEY", "AGENTICDOME_TENANT_ID")}
204
200
  os.environ.update({"AGENTICDOME_API_BASE": runtime_base, "AGENTICDOME_COPILOT_API_KEY": copilot_key, "AGENTICDOME_TENANT_ID": session["tenant_id"]})
205
201
  try:
202
+ semantic = _copilot_semantic_analysis(root, ir, required=True)
203
+ binding = _active_copilot_catalog_binding(root)
204
+ if semantic.get("ir_sha256") != ir_digest or not binding:
205
+ raise SystemExit("The private Copilot result was not bound to this workload and the installed SDK catalog.")
206
+ # The portal stores a compact inventory, never the potentially large
207
+ # per-function graph. Every selected part was analyzed at the sidecar.
208
+ portal_ir = {
209
+ "schema": "agenticdome.copilot-ir.v1", "source_upload": False,
210
+ "metadata_kind": "bounded_workload_summary", "selected_ir_sha256": ir_digest,
211
+ "files": [], "functions": [],
212
+ "features": {"functions": len(ir.get("functions", []))},
213
+ "scope": {
214
+ "complete": True, "fingerprint": ir.get("scope", {}).get("fingerprint"),
215
+ "eligible_files_scanned": ir.get("scope", {}).get("eligible_files_scanned", 0),
216
+ },
217
+ "workload_coverage": {
218
+ "selected_parts": semantic.get("workload_coverage", {}).get("selected_parts", 1),
219
+ "analyzed_parts": semantic.get("workload_coverage", {}).get("analyzed_parts", 1),
220
+ "cross_part_flow_proven": semantic.get("workload_coverage", {}).get("cross_part_flow_proven", True),
221
+ },
222
+ }
223
+ plan = {
224
+ "schema": "agenticdome.copilot-plan.v1", "tenant_id": session["tenant_id"],
225
+ "semantic_analysis": semantic, "catalog_binding": binding,
226
+ "aggregation": {"kind": "sdk_local_bounded_parts", "signature_scope": "individual_sidecar_parts_only"},
227
+ }
228
+ _request(portal + "/api/agentguard/connect/sessions/" + session["session_uuid"] + "/metadata", {"ir": portal_ir, "signed_plan": plan}, session["access_token"])
229
+
206
230
  from .onboarding_cli import create_scaffold
207
231
  patch_path = create_scaffold(root)
208
232
  finally:
@@ -211,6 +235,11 @@ def run_connect(root: Path, args: Any) -> Dict[str, Any]:
211
235
  os.environ.pop(name, None)
212
236
  else:
213
237
  os.environ[name] = value
238
+
239
+ resumable = {"schema": "agenticdome.connect-state.v1", "portal": portal, "tenant_id": session["tenant_id"], "session_uuid": session["session_uuid"], "workload_uuid": workload_uuid, "token_expires_at": session["expires_at"], "access_token": session["access_token"]}
240
+ state_path = state_dir / "connect-session.json"
241
+ state_path.write_text(json.dumps(resumable, indent=2, sort_keys=True) + "\n", encoding="utf-8")
242
+ os.chmod(state_path, 0o600)
214
243
  pull_request = None
215
244
  if args.open_pr:
216
245
  if not args.repository_connection:
@@ -222,6 +251,15 @@ def run_connect(root: Path, args: Any) -> Dict[str, Any]:
222
251
  "next_action": "Ask AgenticDome to confirm policy-aware sidecar readiness before live verification.",
223
252
  })
224
253
  broker_setup["sdk_mode"] = effective_config.get("execution_broker_mode", "existing_sdk_or_environment_default")
254
+ cross_part_review_required = semantic.get("workload_coverage", {}).get("cross_part_flow_proven") is False
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."
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."
259
+ ) if cross_part_review_required else (
260
+ "Review the generated pull request and run agenticdome verify."
261
+ if args.open_pr else "Review the generated patch, apply it on a branch, then run agenticdome verify."
262
+ )
225
263
  return {
226
264
  "status": "changeset_ready", "source_upload": False, "tenant_id": session["tenant_id"],
227
265
  "session_uuid": session["session_uuid"], "workload_uuid": workload_uuid,
@@ -229,9 +267,10 @@ def run_connect(root: Path, args: Any) -> Dict[str, Any]:
229
267
  "execution_broker": broker_setup,
230
268
  "attachment_points": len(semantic.get("attachment_points") or []),
231
269
  "bypass_risks": len(semantic.get("bypass_risks") or []),
270
+ "cross_part_review_required": cross_part_review_required,
232
271
  "patch": str(patch_path.relative_to(root)),
233
272
  "pull_request": pull_request,
234
- "next_action": "Review the generated pull request and run agenticdome verify." if pull_request else "Review the generated patch, apply it on a branch, then run agenticdome verify.",
273
+ "next_action": next_action,
235
274
  "sdk_version": _installed_sdk_version(),
236
275
  }
237
276
 
@@ -18,7 +18,9 @@ from typing import Any, Dict, List, Sequence, Tuple
18
18
 
19
19
 
20
20
  IR_SCHEMA = "agenticdome.copilot-ir.v1"
21
- MAX_IR_FILES = 1_000
21
+ MAX_IR_FILES = 5_000
22
+ MAX_IR_FUNCTIONS = 20_000
23
+ TYPESCRIPT_BATCH_FILES = 200
22
24
 
23
25
 
24
26
  def _relative(path: Path, root: Path) -> str:
@@ -280,7 +282,7 @@ def _collect_python(root: Path, paths: Sequence[Path]) -> Tuple[List[Dict[str, A
280
282
  parsed = 0
281
283
  parse_errors = 0
282
284
  features = {"functions": 0, "calls": 0, "returns": 0, "raises": 0}
283
- for path in paths[:MAX_IR_FILES]:
285
+ for path in paths:
284
286
  try:
285
287
  tree = ast.parse(path.read_text(encoding="utf-8", errors="ignore"), filename=path.name)
286
288
  except (OSError, SyntaxError, ValueError):
@@ -309,29 +311,38 @@ def _collect_typescript(root: Path, paths: Sequence[Path]) -> Tuple[List[Dict[st
309
311
  helper = Path(__file__).with_name("copilot_ir_collector.cjs")
310
312
  if not node or not helper.exists():
311
313
  return _typescript_fallback(root, paths, "Node.js or the packaged IR collector is unavailable.")
312
- try:
313
- completed = subprocess.run(
314
- [node, str(helper)],
315
- input=json.dumps({"root": str(root), "files": [str(path) for path in paths[:MAX_IR_FILES]]}),
316
- text=True,
317
- stdout=subprocess.PIPE,
318
- stderr=subprocess.DEVNULL,
319
- check=False,
320
- timeout=20,
321
- cwd=root,
322
- )
323
- result = json.loads(completed.stdout or "{}") if completed.returncode == 0 else {}
324
- except (OSError, subprocess.TimeoutExpired, json.JSONDecodeError):
325
- result = {}
326
- if not isinstance(result, dict) or not result.get("available"):
327
- return _typescript_fallback(root, paths, str(result.get("reason", "The TypeScript compiler is unavailable."))[:160] if isinstance(result, dict) else "The TypeScript compiler is unavailable.")
328
- functions = result.get("functions") if isinstance(result.get("functions"), list) else []
329
- return [item for item in functions if isinstance(item, dict)], {
314
+ functions: List[Dict[str, Any]] = []
315
+ files_parsed = 0
316
+ parse_errors = 0
317
+ compiler_version = ""
318
+ for offset in range(0, len(paths), TYPESCRIPT_BATCH_FILES):
319
+ batch = paths[offset:offset + TYPESCRIPT_BATCH_FILES]
320
+ try:
321
+ completed = subprocess.run(
322
+ [node, str(helper)],
323
+ input=json.dumps({"root": str(root), "files": [str(path) for path in batch]}),
324
+ text=True,
325
+ stdout=subprocess.PIPE,
326
+ stderr=subprocess.DEVNULL,
327
+ check=False,
328
+ timeout=30,
329
+ cwd=root,
330
+ )
331
+ result = json.loads(completed.stdout or "{}") if completed.returncode == 0 else {}
332
+ except (OSError, subprocess.TimeoutExpired, json.JSONDecodeError):
333
+ result = {}
334
+ if not isinstance(result, dict) or not result.get("available"):
335
+ return _typescript_fallback(root, paths, str(result.get("reason", "The TypeScript compiler is unavailable."))[:160] if isinstance(result, dict) else "The TypeScript compiler is unavailable.")
336
+ functions.extend(item for item in result.get("functions", []) if isinstance(item, dict))
337
+ files_parsed += max(0, int(result.get("files_parsed", 0)))
338
+ parse_errors += max(0, int(result.get("parse_errors", 0)))
339
+ compiler_version = str(result.get("typescript_version", ""))[:40]
340
+ return functions, {
330
341
  "engine": "typescript-compiler-api",
331
342
  "available": True,
332
- "files_parsed": max(0, int(result.get("files_parsed", 0))),
333
- "parse_errors": max(0, int(result.get("parse_errors", 0))),
334
- "typescript_version": str(result.get("typescript_version", ""))[:40],
343
+ "files_parsed": files_parsed,
344
+ "parse_errors": parse_errors,
345
+ "typescript_version": compiler_version,
335
346
  "claim": "Generic compiler AST structure collection; private reasoning is performed by the assigned Copilot service",
336
347
  }
337
348
 
@@ -339,11 +350,13 @@ def _collect_typescript(root: Path, paths: Sequence[Path]) -> Tuple[List[Dict[st
339
350
  def _typescript_fallback(root: Path, paths: Sequence[Path], reason: str) -> Tuple[List[Dict[str, Any]], Dict[str, Any]]:
340
351
  functions: List[Dict[str, Any]] = []
341
352
  parsed = 0
353
+ read_errors = 0
342
354
  call_pattern = re.compile(r"\b([A-Za-z_$][\w$]*(?:\s*\.\s*[A-Za-z_$][\w$]*)*)\s*\(")
343
- for path in paths[:MAX_IR_FILES]:
355
+ for path in paths:
344
356
  try:
345
357
  lines = path.read_text(encoding="utf-8", errors="ignore").splitlines()
346
358
  except OSError:
359
+ read_errors += 1
347
360
  continue
348
361
  events = []
349
362
  for line_number, line in enumerate(lines, start=1):
@@ -357,7 +370,7 @@ def _typescript_fallback(root: Path, paths: Sequence[Path], reason: str) -> Tupl
357
370
  "engine": "typescript-structural-fallback",
358
371
  "available": False,
359
372
  "files_parsed": parsed,
360
- "parse_errors": 0,
373
+ "parse_errors": read_errors,
361
374
  "reason": reason,
362
375
  "claim": "Generic structural collection only; install TypeScript for compiler AST evidence",
363
376
  }
@@ -365,16 +378,30 @@ def _typescript_fallback(root: Path, paths: Sequence[Path], reason: str) -> Tupl
365
378
 
366
379
  def collect_repository_ir(root: Path, paths: Sequence[Path]) -> Dict[str, Any]:
367
380
  """Collect bounded metadata for private reasoning without emitting source."""
368
- python_paths = [path for path in paths if path.suffix.lower() in {".py", ".pyi"}]
369
- typescript_paths = [path for path in paths if path.suffix.lower() in {".js", ".jsx", ".ts", ".tsx"}]
381
+ selected = paths[:MAX_IR_FILES]
382
+ python_paths = [path for path in selected if path.suffix.lower() in {".py", ".pyi"}]
383
+ typescript_paths = [path for path in selected if path.suffix.lower() in {".js", ".jsx", ".ts", ".tsx"}]
370
384
  python_functions, python_engine = _collect_python(root, python_paths)
371
385
  typescript_functions, typescript_engine = _collect_typescript(root, typescript_paths)
386
+ functions = python_functions + typescript_functions
387
+ collection_errors = int(python_engine.get("parse_errors", 0)) + int(typescript_engine.get("parse_errors", 0))
388
+ files_parsed = int(python_engine.get("files_parsed", 0)) + int(typescript_engine.get("files_parsed", 0))
389
+ complete = (len(paths) <= MAX_IR_FILES and len(functions) <= MAX_IR_FUNCTIONS
390
+ and collection_errors == 0 and files_parsed == len(paths))
372
391
  return {
373
392
  "schema": IR_SCHEMA,
374
393
  "source_upload": False,
375
394
  "collector_mode": "generic_ast_metadata_only",
376
395
  "engines": {"python": python_engine, "typescript": typescript_engine},
377
- "functions": (python_functions + typescript_functions)[:20_000],
396
+ "functions": functions[:MAX_IR_FUNCTIONS],
397
+ "coverage": {
398
+ "candidate_source_files": len(paths),
399
+ "files_selected": len(selected),
400
+ "symbols_found": len(functions),
401
+ "complete": complete,
402
+ "limit_reason": "file_limit" if len(paths) > MAX_IR_FILES else "symbol_limit" if len(functions) > MAX_IR_FUNCTIONS
403
+ else "parse_or_read_error" if collection_errors or files_parsed != len(paths) else None,
404
+ },
378
405
  "privacy": {
379
406
  "source_text": False,
380
407
  "string_literals": False,