managed-deepagents 0.6.2.dev25__py3-none-win_amd64.whl → 0.6.2.dev29__py3-none-win_amd64.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.
- managed_deepagents/__init__.py +2 -0
- managed_deepagents/_agent_auth.py +68 -3
- managed_deepagents/_agent_auth_http.py +4 -0
- managed_deepagents/_binaries/mda.exe +0 -0
- managed_deepagents/_connections.py +34 -5
- {managed_deepagents-0.6.2.dev25.dist-info → managed_deepagents-0.6.2.dev29.dist-info}/METADATA +3 -3
- {managed_deepagents-0.6.2.dev25.dist-info → managed_deepagents-0.6.2.dev29.dist-info}/RECORD +11 -11
- {managed_deepagents-0.6.2.dev25.dist-info → managed_deepagents-0.6.2.dev29.dist-info}/WHEEL +0 -0
- {managed_deepagents-0.6.2.dev25.dist-info → managed_deepagents-0.6.2.dev29.dist-info}/entry_points.txt +0 -0
- {managed_deepagents-0.6.2.dev25.dist-info → managed_deepagents-0.6.2.dev29.dist-info}/licenses/LICENSE +0 -0
- {managed_deepagents-0.6.2.dev25.dist-info → managed_deepagents-0.6.2.dev29.dist-info}/top_level.txt +0 -0
managed_deepagents/__init__.py
CHANGED
|
@@ -19,6 +19,7 @@ from managed_deepagents._connections import (
|
|
|
19
19
|
ConnectionNotFoundError,
|
|
20
20
|
CredentialAuthorizationRequiredError,
|
|
21
21
|
CredentialStoreError,
|
|
22
|
+
InvalidAgentAuthEndpointError,
|
|
22
23
|
connections,
|
|
23
24
|
)
|
|
24
25
|
from managed_deepagents._managed_tools import (
|
|
@@ -41,6 +42,7 @@ __all__ = [
|
|
|
41
42
|
"CredentialAuthorizationRequiredError",
|
|
42
43
|
"CredentialStoreError",
|
|
43
44
|
"DeepAgentDefinition",
|
|
45
|
+
"InvalidAgentAuthEndpointError",
|
|
44
46
|
"ManagedDeepAgentRuntime",
|
|
45
47
|
"ManagedServerInfo",
|
|
46
48
|
"MemoryDefinition",
|
|
@@ -46,6 +46,8 @@ class AgentAuthContext:
|
|
|
46
46
|
principal_id: str
|
|
47
47
|
api_key: str | None = None
|
|
48
48
|
workspace_id: str | None = None
|
|
49
|
+
#: Agent Builder service JWT for workspace-owned credential material.
|
|
50
|
+
service_key: str | None = None
|
|
49
51
|
|
|
50
52
|
|
|
51
53
|
class PendingAuthorization(TypedDict):
|
|
@@ -141,7 +143,7 @@ class AgentAuth:
|
|
|
141
143
|
connection_id = (
|
|
142
144
|
item.get("id") or item.get("connection_id") or item.get("credential_id")
|
|
143
145
|
)
|
|
144
|
-
kind = item
|
|
146
|
+
kind = _connection_credential_kind(item)
|
|
145
147
|
owner_policy = item.get("owner_policy")
|
|
146
148
|
if not isinstance(connection_id, str) or not connection_id:
|
|
147
149
|
raise CredentialStoreError("Agent Auth connection row missing id or kind")
|
|
@@ -160,18 +162,62 @@ class AgentAuth:
|
|
|
160
162
|
|
|
161
163
|
def find_workspace_credential_id(self, slug: str) -> str | None:
|
|
162
164
|
"""Workspace credential id for an agent-owned opaque secret grant."""
|
|
165
|
+
connection = self.find_workspace_connection(slug)
|
|
166
|
+
if connection is None:
|
|
167
|
+
return None
|
|
168
|
+
return self.find_secret_credential_id(connection, slug)
|
|
169
|
+
|
|
170
|
+
def find_secret_credential_id(self, connection: WorkspaceConnection, slug: str) -> str | None:
|
|
171
|
+
"""Resolve the credential id for a secret connection row.
|
|
172
|
+
|
|
173
|
+
With an Agent Builder service key, prefer GET-for-owner / workspace list.
|
|
174
|
+
Personal API keys may only list agent-owned credentials.
|
|
175
|
+
"""
|
|
176
|
+
if connection.kind != "secret":
|
|
177
|
+
return None
|
|
163
178
|
workspace_id = (self.context.workspace_id or "").strip()
|
|
164
179
|
if not workspace_id:
|
|
165
180
|
raise CredentialStoreError(
|
|
166
181
|
"connections are not configured: LANGSMITH_WORKSPACE_ID is not set"
|
|
167
182
|
)
|
|
183
|
+
if (self.context.service_key or "").strip():
|
|
184
|
+
from_owner = self._credential_id_for_owner(
|
|
185
|
+
connection.connection_id, "workspace", workspace_id
|
|
186
|
+
)
|
|
187
|
+
if from_owner is not None:
|
|
188
|
+
return from_owner
|
|
189
|
+
return self.find_credential_id(
|
|
190
|
+
owner_type="workspace",
|
|
191
|
+
owner_id=workspace_id,
|
|
192
|
+
kind="secret",
|
|
193
|
+
slug=slug,
|
|
194
|
+
)
|
|
168
195
|
return self.find_credential_id(
|
|
169
|
-
owner_type="
|
|
170
|
-
owner_id=
|
|
196
|
+
owner_type="agent",
|
|
197
|
+
owner_id=self.context.agent_id,
|
|
171
198
|
kind="secret",
|
|
172
199
|
slug=slug,
|
|
173
200
|
)
|
|
174
201
|
|
|
202
|
+
def _credential_id_for_owner(
|
|
203
|
+
self, connection_id: str, owner_type: str, owner_id: str
|
|
204
|
+
) -> str | None:
|
|
205
|
+
query = urllib.parse.urlencode(
|
|
206
|
+
{
|
|
207
|
+
"credential_owner_type": owner_type,
|
|
208
|
+
"credential_owner_id": owner_id,
|
|
209
|
+
}
|
|
210
|
+
)
|
|
211
|
+
status, body = self._request(
|
|
212
|
+
"GET",
|
|
213
|
+
f"/v1/agent-auth/connections/{_path_segment(connection_id)}?{query}",
|
|
214
|
+
)
|
|
215
|
+
if status == _HTTP_NOT_FOUND:
|
|
216
|
+
return None
|
|
217
|
+
if status >= _HTTP_BAD_REQUEST:
|
|
218
|
+
raise CredentialStoreError("Agent Auth get connection for owner failed", status)
|
|
219
|
+
return _connection_credential_id(body)
|
|
220
|
+
|
|
175
221
|
def read_user_secret(self, slug: str) -> str | None:
|
|
176
222
|
"""Read a caller-owned opaque secret grant for a workspace connection slug."""
|
|
177
223
|
credential_id = self.find_credential_id(
|
|
@@ -344,6 +390,7 @@ class AgentAuth:
|
|
|
344
390
|
return agent_auth_headers(
|
|
345
391
|
api_key=self.context.api_key,
|
|
346
392
|
workspace_id=self.context.workspace_id,
|
|
393
|
+
service_key=self.context.service_key,
|
|
347
394
|
)
|
|
348
395
|
|
|
349
396
|
|
|
@@ -351,6 +398,24 @@ def _path_segment(value: str) -> str:
|
|
|
351
398
|
return urllib.parse.quote(value, safe="")
|
|
352
399
|
|
|
353
400
|
|
|
401
|
+
def _connection_credential_kind(item: Mapping[str, object]) -> str:
|
|
402
|
+
credential = item.get("credential")
|
|
403
|
+
if isinstance(credential, Mapping):
|
|
404
|
+
kind = credential.get("kind")
|
|
405
|
+
if isinstance(kind, str) and kind:
|
|
406
|
+
return kind
|
|
407
|
+
kind = item.get("kind")
|
|
408
|
+
return kind if isinstance(kind, str) else ""
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
def _connection_credential_id(body: Mapping[str, object]) -> str | None:
|
|
412
|
+
credential = body.get("credential")
|
|
413
|
+
if not isinstance(credential, Mapping):
|
|
414
|
+
return None
|
|
415
|
+
credential_id = credential.get("credential_id")
|
|
416
|
+
return credential_id if isinstance(credential_id, str) and credential_id else None
|
|
417
|
+
|
|
418
|
+
|
|
354
419
|
def _is_authorization_required(status: int, body: dict[str, object]) -> bool:
|
|
355
420
|
"""Agent Auth answers 409 when a stored grant has lapsed and needs re-auth."""
|
|
356
421
|
if status != _HTTP_CONFLICT:
|
|
@@ -70,12 +70,16 @@ def agent_auth_headers(
|
|
|
70
70
|
*,
|
|
71
71
|
api_key: str | None = None,
|
|
72
72
|
workspace_id: str | None = None,
|
|
73
|
+
service_key: str | None = None,
|
|
73
74
|
) -> dict[str, str]:
|
|
74
75
|
headers = {
|
|
75
76
|
"accept": "application/json",
|
|
76
77
|
"content-type": "application/json",
|
|
77
78
|
"x-langsmith-product": "mda",
|
|
78
79
|
}
|
|
80
|
+
resolved_service_key = (service_key or "").strip()
|
|
81
|
+
if resolved_service_key:
|
|
82
|
+
headers["x-service-key"] = resolved_service_key
|
|
79
83
|
resolved_api_key = (api_key or "").strip()
|
|
80
84
|
if resolved_api_key:
|
|
81
85
|
headers["x-api-key"] = resolved_api_key
|
|
Binary file
|
|
@@ -47,6 +47,7 @@ __all__ = [
|
|
|
47
47
|
"ConnectionRequest",
|
|
48
48
|
"CredentialAuthorizationRequiredError",
|
|
49
49
|
"CredentialStoreError",
|
|
50
|
+
"InvalidAgentAuthEndpointError",
|
|
50
51
|
"agent_connection_env_key",
|
|
51
52
|
"connections",
|
|
52
53
|
"is_connection_reference",
|
|
@@ -132,6 +133,15 @@ _API_KEY_ENV = "LANGSMITH_API_KEY"
|
|
|
132
133
|
_WORKSPACE_ID_ENV = "LANGSMITH_WORKSPACE_ID"
|
|
133
134
|
|
|
134
135
|
|
|
136
|
+
class InvalidAgentAuthEndpointError(CredentialStoreError):
|
|
137
|
+
"""``LANGSMITH_ENDPOINT`` is not a usable Agent Auth origin."""
|
|
138
|
+
|
|
139
|
+
def __init__(self) -> None:
|
|
140
|
+
super().__init__(
|
|
141
|
+
f"LangSmith Agent Auth endpoint is not a valid URL (set {PLATFORM_API_URL_ENV})"
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
|
|
135
145
|
class ConnectionHttpResponse(TypedDict):
|
|
136
146
|
status: int
|
|
137
147
|
body: bytes
|
|
@@ -147,6 +157,7 @@ class _AgentAuthConfig:
|
|
|
147
157
|
api_key: str
|
|
148
158
|
deployment_id: str | None
|
|
149
159
|
workspace_id: str
|
|
160
|
+
service_key: str | None = None
|
|
150
161
|
|
|
151
162
|
|
|
152
163
|
class AgentAuthConnectionStore:
|
|
@@ -177,6 +188,7 @@ class AgentAuthConnectionStore:
|
|
|
177
188
|
principal_id=owner_id,
|
|
178
189
|
api_key=config.api_key,
|
|
179
190
|
workspace_id=config.workspace_id,
|
|
191
|
+
service_key=config.service_key,
|
|
180
192
|
),
|
|
181
193
|
request=self._bind_request(config),
|
|
182
194
|
timeout=self._timeout,
|
|
@@ -200,7 +212,11 @@ class AgentAuthConnectionStore:
|
|
|
200
212
|
) -> tuple[int, dict[str, object]]:
|
|
201
213
|
del method, body
|
|
202
214
|
url = f"{config.base_url}{path}"
|
|
203
|
-
headers = agent_auth_headers(
|
|
215
|
+
headers = agent_auth_headers(
|
|
216
|
+
api_key=config.api_key,
|
|
217
|
+
workspace_id=config.workspace_id,
|
|
218
|
+
service_key=config.service_key,
|
|
219
|
+
)
|
|
204
220
|
response = http_get(url, headers, timeout)
|
|
205
221
|
status = response.get("status")
|
|
206
222
|
raw_body = response.get("body", b"")
|
|
@@ -260,7 +276,7 @@ def _lookup_agent_connection_material(
|
|
|
260
276
|
row: WorkspaceConnection,
|
|
261
277
|
) -> str | None:
|
|
262
278
|
if row.kind == "secret":
|
|
263
|
-
credential_id = client.
|
|
279
|
+
credential_id = client.find_secret_credential_id(row, slug)
|
|
264
280
|
if credential_id is None:
|
|
265
281
|
return None
|
|
266
282
|
return client.read_secret(credential_id)
|
|
@@ -413,6 +429,7 @@ def resolve_agent_auth_context(
|
|
|
413
429
|
principal_id=resolve_owner_id({"type": "user"}, identity, config.deployment_id),
|
|
414
430
|
api_key=config.api_key,
|
|
415
431
|
workspace_id=config.workspace_id,
|
|
432
|
+
service_key=config.service_key,
|
|
416
433
|
)
|
|
417
434
|
|
|
418
435
|
|
|
@@ -426,22 +443,34 @@ def _resolve_agent_auth_config(env: Mapping[str, str] | None) -> _AgentAuthConfi
|
|
|
426
443
|
raise CredentialStoreError(
|
|
427
444
|
f"connections are not configured: {_WORKSPACE_ID_ENV} is not set"
|
|
428
445
|
)
|
|
446
|
+
service_key = (resolved.get("MDA_AGENT_AUTH_SERVICE_KEY") or "").strip() or None
|
|
429
447
|
return _AgentAuthConfig(
|
|
430
448
|
base_url=resolve_agent_auth_base_url(resolved),
|
|
431
449
|
api_key=api_key,
|
|
432
450
|
deployment_id=(resolved.get(DEPLOYMENT_ID_ENV) or "").strip() or None,
|
|
433
451
|
workspace_id=workspace_id,
|
|
452
|
+
service_key=service_key,
|
|
434
453
|
)
|
|
435
454
|
|
|
436
455
|
|
|
437
456
|
def resolve_agent_auth_base_url(env: Mapping[str, str] | None = None) -> str:
|
|
457
|
+
"""Origin for Agent Auth HTTP calls from ``LANGSMITH_ENDPOINT``.
|
|
458
|
+
|
|
459
|
+
Cloud SaaS revisions omit that reserved name and inject
|
|
460
|
+
``LANGCHAIN_ENDPOINT`` instead; read it as the same setting so we do not
|
|
461
|
+
default to production.
|
|
462
|
+
"""
|
|
438
463
|
resolved = os.environ if env is None else env
|
|
439
|
-
raw = (
|
|
464
|
+
raw = (
|
|
465
|
+
(resolved.get(PLATFORM_API_URL_ENV) or "").strip()
|
|
466
|
+
or (resolved.get("LANGCHAIN_ENDPOINT") or "").strip()
|
|
467
|
+
or _DEFAULT_LANGSMITH_ENDPOINT
|
|
468
|
+
)
|
|
440
469
|
try:
|
|
441
470
|
parsed = urllib.parse.urlsplit(raw.rstrip("/"))
|
|
442
471
|
_ = parsed.port
|
|
443
472
|
except ValueError:
|
|
444
|
-
raise
|
|
473
|
+
raise InvalidAgentAuthEndpointError from None
|
|
445
474
|
if (
|
|
446
475
|
parsed.scheme not in {"http", "https"}
|
|
447
476
|
or not parsed.hostname
|
|
@@ -451,7 +480,7 @@ def resolve_agent_auth_base_url(env: Mapping[str, str] | None = None) -> str:
|
|
|
451
480
|
or parsed.query
|
|
452
481
|
or parsed.fragment
|
|
453
482
|
):
|
|
454
|
-
raise
|
|
483
|
+
raise InvalidAgentAuthEndpointError
|
|
455
484
|
return f"{parsed.scheme}://{parsed.netloc}"
|
|
456
485
|
|
|
457
486
|
|
{managed_deepagents-0.6.2.dev25.dist-info → managed_deepagents-0.6.2.dev29.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: managed-deepagents
|
|
3
|
-
Version: 0.6.2.
|
|
3
|
+
Version: 0.6.2.dev29
|
|
4
4
|
Summary: Managed Deep Agents — the define_deep_agent authoring interface plus the CLI that compiles and deploys a code-first Deep Agent repository to a managed LangGraph runtime.
|
|
5
5
|
Author: LangChain
|
|
6
6
|
License: MIT
|
|
@@ -282,8 +282,8 @@ when a grant is missing. `mda dev` has no deployment to hold user grants, so
|
|
|
282
282
|
a user-owned connection fails there with an actionable error; deploy the agent
|
|
283
283
|
to exercise one.
|
|
284
284
|
|
|
285
|
-
Provision workspace connections with `mda
|
|
286
|
-
`mda
|
|
285
|
+
Provision workspace connections with `mda connections create` before deploy.
|
|
286
|
+
`mda connections check` verifies manifest slugs exist in the workspace.
|
|
287
287
|
|
|
288
288
|
Use `include_tools` or `exclude_tools` inside a server config to select a
|
|
289
289
|
subset. Tool names are raw MCP tool names before the managed `{server}__` prefix
|
{managed_deepagents-0.6.2.dev25.dist-info → managed_deepagents-0.6.2.dev29.dist-info}/RECORD
RENAMED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
managed_deepagents/__init__.py,sha256=
|
|
1
|
+
managed_deepagents/__init__.py,sha256=RezkpgYxCcywj6_W7Nk3PN9TMBfYyFgIatxGrIeY8V4,1862
|
|
2
2
|
managed_deepagents/__main__.py,sha256=GcjmqN0Ea5v8OHKMxYToasm3eCX_doSLOlpEzAi1tAw,67
|
|
3
|
-
managed_deepagents/_agent_auth.py,sha256=
|
|
4
|
-
managed_deepagents/_agent_auth_http.py,sha256=
|
|
3
|
+
managed_deepagents/_agent_auth.py,sha256=3rA39j_3PFROrtsIr5OHkAO_FgAHfASM-ee0vGhPGu8,16650
|
|
4
|
+
managed_deepagents/_agent_auth_http.py,sha256=DtspEFmWHTtpp3uqELw1-wuHiLbAx_ers9JW18J3Coc,3924
|
|
5
5
|
managed_deepagents/_channel.py,sha256=-Og7QOM1yvV-yeTDOfv2CxXpR2HLY4xdX1bLrIsPi5k,5272
|
|
6
6
|
managed_deepagents/_cli.py,sha256=jVaw2i1ysdRoWziMdPFmRXtKry_baYGRspyzyIeGWoU,1688
|
|
7
|
-
managed_deepagents/_connections.py,sha256=
|
|
7
|
+
managed_deepagents/_connections.py,sha256=N6luj1YMpBPjpH-WnGc6AIGNTE9DnZoBWAlWcFRSo2I,16518
|
|
8
8
|
managed_deepagents/_connector.py,sha256=Syp0SRs1oFCUUltIUmZbSNi1Ys_PxObVdiAi-I9GBzs,8040
|
|
9
9
|
managed_deepagents/_cors.py,sha256=V96RPrqewdRWG5RpEMEBnPuRq9_zF8nf4vf99k5dkuI,7597
|
|
10
10
|
managed_deepagents/_credential_gate.py,sha256=WlryhbWHtg1FN5IdadiOvgT3JX3G78DtWVGW0wLWvz4,12252
|
|
@@ -28,7 +28,7 @@ managed_deepagents/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
|
28
28
|
managed_deepagents/runtime.py,sha256=B4iKTJZD0zXx_MZ09pqQFOkVo07tqJDT3qvOBr-0iOk,65782
|
|
29
29
|
managed_deepagents/sandbox.py,sha256=xlpcWa6CoVX6GKip2nK-0Lw-HBCoFGFYm0r4x9eYwcY,2530
|
|
30
30
|
managed_deepagents/schedules.py,sha256=MtTQN4tlm1NizFDCjZZv_huGfbQx-dj9WP1dIBybCug,5237
|
|
31
|
-
managed_deepagents/_binaries/mda.exe,sha256=
|
|
31
|
+
managed_deepagents/_binaries/mda.exe,sha256=2tNegm-g-AkSnDb_mHCMIVwJNX47E6AXbRfpM74WQag,3858432
|
|
32
32
|
managed_deepagents/_channels/__init__.py,sha256=Z6eXmzaLxG09DSyJoY_CX34axcsBo9gSJ0G7pRm2D6M,1216
|
|
33
33
|
managed_deepagents/_channels/assistant_text.py,sha256=f-Z3J3PlQFXZHztgBxlRoqB2LigU1Hj1YpwoXBMTR18,2171
|
|
34
34
|
managed_deepagents/_channels/binding.py,sha256=6vAKbWpg-eyLErJ0SsozH4mZc50hA1NhquM63mVmWDQ,3423
|
|
@@ -68,9 +68,9 @@ managed_deepagents/identity/__init__.py,sha256=Slm-oEqKxbaZEQsMqHfD3LbG5M4vH2lKU
|
|
|
68
68
|
managed_deepagents/identity/claims.py,sha256=prby7r_8Lww3MmoBm8PX6PsSGE3GwSHkr8mVIz_08nU,1180
|
|
69
69
|
managed_deepagents/identity/options.py,sha256=x_yMbXEFR7zXyehEjDHG2qjAlukXjrRBcQLcM6IndLM,2550
|
|
70
70
|
managed_deepagents/identity/supabase.py,sha256=8uobl3WCrQL_ieSXG8KTLf1th7Qjim9liZT50HeaJE0,6026
|
|
71
|
-
managed_deepagents-0.6.2.
|
|
72
|
-
managed_deepagents-0.6.2.
|
|
73
|
-
managed_deepagents-0.6.2.
|
|
74
|
-
managed_deepagents-0.6.2.
|
|
75
|
-
managed_deepagents-0.6.2.
|
|
76
|
-
managed_deepagents-0.6.2.
|
|
71
|
+
managed_deepagents-0.6.2.dev29.dist-info/licenses/LICENSE,sha256=WnPZQQ608ojZUkXl7BW6VbKloIAibZiGm1K6cjeZOL8,1066
|
|
72
|
+
managed_deepagents-0.6.2.dev29.dist-info/METADATA,sha256=XkIgC0l4YyYRSgaLIuI97rr2Li4jElapfveTwg_EiZ4,13582
|
|
73
|
+
managed_deepagents-0.6.2.dev29.dist-info/WHEEL,sha256=3I5VVWZdsFlU417aCS2bMRuerS8wsfvBq99MyatBV3A,97
|
|
74
|
+
managed_deepagents-0.6.2.dev29.dist-info/entry_points.txt,sha256=ziZqkKuaDO3qHCjKmBhrx9cm3ok8bZ9xcEDpUTj4unM,53
|
|
75
|
+
managed_deepagents-0.6.2.dev29.dist-info/top_level.txt,sha256=fdBo4O0Hlol_w022tTLB5ftZpamb4yJoQ3MUvjgTGfA,19
|
|
76
|
+
managed_deepagents-0.6.2.dev29.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{managed_deepagents-0.6.2.dev25.dist-info → managed_deepagents-0.6.2.dev29.dist-info}/top_level.txt
RENAMED
|
File without changes
|