managed-deepagents 0.6.2.dev48__py3-none-win_amd64.whl → 0.6.2.dev49__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/_agent_auth.py +8 -81
- managed_deepagents/_binaries/mda.exe +0 -0
- managed_deepagents/_connections.py +37 -128
- managed_deepagents/_identity_auth.py +1 -16
- managed_deepagents/_identity_runtime.py +0 -6
- managed_deepagents/_ingress.py +0 -2
- managed_deepagents/_validated_token.py +0 -2
- managed_deepagents/identity/__init__.py +0 -4
- {managed_deepagents-0.6.2.dev48.dist-info → managed_deepagents-0.6.2.dev49.dist-info}/METADATA +7 -10
- {managed_deepagents-0.6.2.dev48.dist-info → managed_deepagents-0.6.2.dev49.dist-info}/RECORD +14 -14
- {managed_deepagents-0.6.2.dev48.dist-info → managed_deepagents-0.6.2.dev49.dist-info}/WHEEL +0 -0
- {managed_deepagents-0.6.2.dev48.dist-info → managed_deepagents-0.6.2.dev49.dist-info}/entry_points.txt +0 -0
- {managed_deepagents-0.6.2.dev48.dist-info → managed_deepagents-0.6.2.dev49.dist-info}/licenses/LICENSE +0 -0
- {managed_deepagents-0.6.2.dev48.dist-info → managed_deepagents-0.6.2.dev49.dist-info}/top_level.txt +0 -0
|
@@ -34,48 +34,21 @@ __all__ = [
|
|
|
34
34
|
"AgentAuthUnknownProviderError",
|
|
35
35
|
"CredentialAuthorizationRequiredError",
|
|
36
36
|
"PendingAuthorization",
|
|
37
|
-
"ResolvePrincipalIdentity",
|
|
38
37
|
"WorkspaceConnection",
|
|
39
|
-
"clear_principal_resolve_cache_for_tests",
|
|
40
38
|
]
|
|
41
39
|
|
|
42
40
|
|
|
43
41
|
@dataclass(frozen=True)
|
|
44
42
|
class AgentAuthContext:
|
|
45
43
|
base_url: str
|
|
44
|
+
#: Deployment id, passed to oauth-authorization-sessions as ``agent_id``.
|
|
45
|
+
agent_id: str
|
|
46
46
|
#: Authenticated caller, used as ``owner_id`` for user credentials.
|
|
47
47
|
principal_id: str
|
|
48
|
-
#: Deployment id when present. Required for agent-owned lookups; optional for user OAuth.
|
|
49
|
-
agent_id: str | None = None
|
|
50
48
|
api_key: str | None = None
|
|
51
49
|
workspace_id: str | None = None
|
|
52
50
|
|
|
53
51
|
|
|
54
|
-
class ResolvePrincipalIdentity(TypedDict):
|
|
55
|
-
provider: str
|
|
56
|
-
issuer: str
|
|
57
|
-
subject: str
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
_principal_resolve_cache: dict[str, str] = {}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
def clear_principal_resolve_cache_for_tests() -> None:
|
|
64
|
-
"""Drop cached principal resolutions. Test-only."""
|
|
65
|
-
_principal_resolve_cache.clear()
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
def _principal_resolve_cache_key(
|
|
69
|
-
context: AgentAuthContext, identity: ResolvePrincipalIdentity
|
|
70
|
-
) -> str:
|
|
71
|
-
origin = context.base_url.rstrip("/")
|
|
72
|
-
workspace = (context.workspace_id or "").strip()
|
|
73
|
-
return (
|
|
74
|
-
f"{origin}\0{workspace}\0"
|
|
75
|
-
f"{identity['provider']}\0{identity['issuer']}\0{identity['subject']}"
|
|
76
|
-
)
|
|
77
|
-
|
|
78
|
-
|
|
79
52
|
class PendingAuthorization(TypedDict):
|
|
80
53
|
"""One connection slug the caller has not granted, with its connect URL."""
|
|
81
54
|
|
|
@@ -142,49 +115,6 @@ class AgentAuth:
|
|
|
142
115
|
self._timeout = timeout
|
|
143
116
|
self._request: AgentAuthRequest = request if request is not None else self._urlopen_json
|
|
144
117
|
|
|
145
|
-
def resolve_principal(self, identity: ResolvePrincipalIdentity) -> str:
|
|
146
|
-
"""Resolve a verified external identity to an Agent Auth principal UUID."""
|
|
147
|
-
provider = identity["provider"].strip()
|
|
148
|
-
issuer = identity["issuer"].strip()
|
|
149
|
-
subject = identity["subject"].strip()
|
|
150
|
-
if not provider or not issuer or not subject:
|
|
151
|
-
raise CredentialStoreError(
|
|
152
|
-
"Agent Auth principal resolve requires provider, issuer, and subject"
|
|
153
|
-
)
|
|
154
|
-
key = _principal_resolve_cache_key(
|
|
155
|
-
self.context, {"provider": provider, "issuer": issuer, "subject": subject}
|
|
156
|
-
)
|
|
157
|
-
cached = _principal_resolve_cache.get(key)
|
|
158
|
-
if cached is not None:
|
|
159
|
-
return cached
|
|
160
|
-
principal_id = self._resolve_principal_uncached(
|
|
161
|
-
{"provider": provider, "issuer": issuer, "subject": subject}
|
|
162
|
-
)
|
|
163
|
-
_principal_resolve_cache[key] = principal_id
|
|
164
|
-
return principal_id
|
|
165
|
-
|
|
166
|
-
def _resolve_principal_uncached(self, identity: ResolvePrincipalIdentity) -> str:
|
|
167
|
-
status, body = self._request(
|
|
168
|
-
"POST",
|
|
169
|
-
"/v1/agent-auth/principals",
|
|
170
|
-
body={
|
|
171
|
-
"provider": identity["provider"],
|
|
172
|
-
"issuer": identity["issuer"],
|
|
173
|
-
"subject": identity["subject"],
|
|
174
|
-
},
|
|
175
|
-
)
|
|
176
|
-
if status >= _HTTP_BAD_REQUEST:
|
|
177
|
-
raise CredentialStoreError("Agent Auth resolve principal failed", status, body)
|
|
178
|
-
principal = body.get("principal")
|
|
179
|
-
principal_id = ""
|
|
180
|
-
if isinstance(principal, Mapping):
|
|
181
|
-
raw = principal.get("id")
|
|
182
|
-
if isinstance(raw, str):
|
|
183
|
-
principal_id = raw.strip()
|
|
184
|
-
if not principal_id:
|
|
185
|
-
raise CredentialStoreError("Agent Auth resolve principal returned no principal id")
|
|
186
|
-
return principal_id
|
|
187
|
-
|
|
188
118
|
def find_workspace_connection(self, slug: str) -> WorkspaceConnection | None:
|
|
189
119
|
"""List workspace connections and return the row for ``slug``, if any."""
|
|
190
120
|
if not (self.context.workspace_id or "").strip():
|
|
@@ -245,17 +175,14 @@ class AgentAuth:
|
|
|
245
175
|
"""
|
|
246
176
|
if connection.kind != "secret":
|
|
247
177
|
return None
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
"connections are not configured: LANGSMITH_HOST_PROJECT_ID is not set"
|
|
252
|
-
)
|
|
253
|
-
from_agent = self._credential_id_for_owner(connection.connection_id, "agent", agent_id)
|
|
178
|
+
from_agent = self._credential_id_for_owner(
|
|
179
|
+
connection.connection_id, "agent", self.context.agent_id
|
|
180
|
+
)
|
|
254
181
|
if from_agent is not None:
|
|
255
182
|
return from_agent
|
|
256
183
|
return self.find_credential_id(
|
|
257
184
|
owner_type="agent",
|
|
258
|
-
owner_id=agent_id,
|
|
185
|
+
owner_id=self.context.agent_id,
|
|
259
186
|
kind="secret",
|
|
260
187
|
slug=slug,
|
|
261
188
|
)
|
|
@@ -350,8 +277,8 @@ class AgentAuth:
|
|
|
350
277
|
"/v1/agent-auth/oauth-authorization-sessions",
|
|
351
278
|
body={
|
|
352
279
|
"connection_id": connection.connection_id,
|
|
353
|
-
"
|
|
354
|
-
"
|
|
280
|
+
"principal_id": self.context.principal_id,
|
|
281
|
+
"agent_id": self.context.agent_id,
|
|
355
282
|
},
|
|
356
283
|
)
|
|
357
284
|
if status >= _HTTP_BAD_REQUEST:
|
|
Binary file
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
``{ type: "agent" }`` resolves material owned by the current deployment.
|
|
4
4
|
``{ type: "user" }`` resolves per-caller grants (OAuth or opaque). Resolution
|
|
5
|
-
reads Agent Auth on every await and never caches
|
|
5
|
+
reads Agent Auth on every await and never caches.
|
|
6
6
|
|
|
7
7
|
``mda dev`` substitutes local values for agent opaque secrets via ``MDA_DEV_*``.
|
|
8
|
-
User-owned connections
|
|
9
|
-
|
|
8
|
+
User-owned connections need a deployment; opaque user grants use the same
|
|
9
|
+
pre-run gate as OAuth.
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
12
|
from __future__ import annotations
|
|
@@ -24,9 +24,7 @@ from managed_deepagents._agent_auth import (
|
|
|
24
24
|
AgentAuth,
|
|
25
25
|
AgentAuthContext,
|
|
26
26
|
CredentialAuthorizationRequiredError,
|
|
27
|
-
ResolvePrincipalIdentity,
|
|
28
27
|
WorkspaceConnection,
|
|
29
|
-
clear_principal_resolve_cache_for_tests,
|
|
30
28
|
)
|
|
31
29
|
from managed_deepagents._agent_auth_http import (
|
|
32
30
|
AGENT_AUTH_TIMEOUT_SECONDS,
|
|
@@ -51,12 +49,10 @@ __all__ = [
|
|
|
51
49
|
"CredentialStoreError",
|
|
52
50
|
"InvalidAgentAuthEndpointError",
|
|
53
51
|
"agent_connection_env_key",
|
|
54
|
-
"clear_principal_resolve_cache_for_tests",
|
|
55
52
|
"connections",
|
|
56
53
|
"is_connection_reference",
|
|
57
54
|
"resolve_agent_auth_base_url",
|
|
58
55
|
"resolve_agent_auth_context",
|
|
59
|
-
"resolve_credential_principal_id",
|
|
60
56
|
"resolve_owner_id",
|
|
61
57
|
]
|
|
62
58
|
|
|
@@ -112,7 +108,19 @@ class ConnectionNotFoundError(LookupError):
|
|
|
112
108
|
_SLUG_PATTERN = re.compile(r"[a-z0-9]+(?:-[a-z0-9]+)*")
|
|
113
109
|
_MAX_SLUG_LENGTH = 64
|
|
114
110
|
_DEV_CREDENTIAL_PREFIX = "MDA_DEV_"
|
|
115
|
-
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _local_user_connection_unsupported(slug: str | None = None) -> str:
|
|
114
|
+
local_hint = (
|
|
115
|
+
f"set {agent_connection_env_key(slug)}"
|
|
116
|
+
if slug
|
|
117
|
+
else "set the corresponding MDA_DEV_<slug> variable"
|
|
118
|
+
)
|
|
119
|
+
return (
|
|
120
|
+
"user-owned connections need a deployment, so they do not resolve in `mda dev`: "
|
|
121
|
+
"deploy with `mda deploy` to exercise this connection, or declare it as "
|
|
122
|
+
f'{{"type": "agent"}} and {local_hint} for local runs'
|
|
123
|
+
)
|
|
116
124
|
|
|
117
125
|
|
|
118
126
|
#: Env var naming the LangSmith platform API that serves Agent Auth.
|
|
@@ -123,8 +131,6 @@ _DEFAULT_LANGSMITH_ENDPOINT = "https://api.smith.langchain.com"
|
|
|
123
131
|
DEPLOYMENT_ID_ENV = "LANGSMITH_HOST_PROJECT_ID"
|
|
124
132
|
_API_KEY_ENV = "LANGSMITH_API_KEY"
|
|
125
133
|
_WORKSPACE_ID_ENV = "LANGSMITH_WORKSPACE_ID"
|
|
126
|
-
_LOCAL_DEV_USER = "mda:local-dev"
|
|
127
|
-
_LOCAL_DEV_PRINCIPAL_ENV = "MDA_AGENT_AUTH_PRINCIPAL_ID"
|
|
128
134
|
|
|
129
135
|
|
|
130
136
|
class InvalidAgentAuthEndpointError(CredentialStoreError):
|
|
@@ -151,7 +157,6 @@ class _AgentAuthConfig:
|
|
|
151
157
|
api_key: str
|
|
152
158
|
deployment_id: str | None
|
|
153
159
|
workspace_id: str
|
|
154
|
-
local_dev_principal_id: str | None
|
|
155
160
|
|
|
156
161
|
|
|
157
162
|
class AgentAuthConnectionStore:
|
|
@@ -171,29 +176,15 @@ class AgentAuthConnectionStore:
|
|
|
171
176
|
async def fetch(self, request: ConnectionRequest) -> str | None:
|
|
172
177
|
owner = request["owner"]
|
|
173
178
|
resolved = os.environ if self._env is None else self._env
|
|
174
|
-
if resolved.get("MDA_LOCAL_DEV") == "1"
|
|
175
|
-
return
|
|
179
|
+
if resolved.get("MDA_LOCAL_DEV") == "1":
|
|
180
|
+
return _fetch_local_dev_connection(resolved, request["slug"], owner)
|
|
176
181
|
config = _resolve_agent_auth_config(self._env)
|
|
177
|
-
|
|
178
|
-
raise CredentialStoreError(
|
|
179
|
-
f"connections are not configured: {DEPLOYMENT_ID_ENV} is not set"
|
|
180
|
-
)
|
|
181
|
-
# Source-identity match still uses JWT sub / channel actor.
|
|
182
|
-
resolve_owner_id(owner, request["identity"], config.deployment_id)
|
|
183
|
-
if owner["type"] == "user":
|
|
184
|
-
principal_id = resolve_credential_principal_id(
|
|
185
|
-
request["identity"],
|
|
186
|
-
config,
|
|
187
|
-
request_fn=self._bind_request(config),
|
|
188
|
-
timeout=self._timeout,
|
|
189
|
-
)
|
|
190
|
-
else:
|
|
191
|
-
principal_id = resolve_owner_id(owner, request["identity"], config.deployment_id)
|
|
182
|
+
owner_id = resolve_owner_id(owner, request["identity"], config.deployment_id)
|
|
192
183
|
client = AgentAuth(
|
|
193
184
|
AgentAuthContext(
|
|
194
185
|
base_url=config.base_url,
|
|
195
|
-
agent_id=config.deployment_id,
|
|
196
|
-
principal_id=
|
|
186
|
+
agent_id=config.deployment_id or owner_id,
|
|
187
|
+
principal_id=owner_id,
|
|
197
188
|
api_key=config.api_key,
|
|
198
189
|
workspace_id=config.workspace_id,
|
|
199
190
|
),
|
|
@@ -217,14 +208,12 @@ class AgentAuthConnectionStore:
|
|
|
217
208
|
*,
|
|
218
209
|
body: dict[str, object] | None = None,
|
|
219
210
|
) -> tuple[int, dict[str, object]]:
|
|
211
|
+
del method, body
|
|
220
212
|
url = f"{config.base_url}{path}"
|
|
221
213
|
headers = agent_auth_headers(
|
|
222
214
|
api_key=config.api_key,
|
|
223
215
|
workspace_id=config.workspace_id,
|
|
224
216
|
)
|
|
225
|
-
# Test injects only support GET-shaped responses; path still distinguishes
|
|
226
|
-
# principals vs connections for mock routers.
|
|
227
|
-
del method, body
|
|
228
217
|
response = http_get(url, headers, timeout)
|
|
229
218
|
status = response.get("status")
|
|
230
219
|
raw_body = response.get("body", b"")
|
|
@@ -238,7 +227,13 @@ class AgentAuthConnectionStore:
|
|
|
238
227
|
return request
|
|
239
228
|
|
|
240
229
|
|
|
241
|
-
def
|
|
230
|
+
def _fetch_local_dev_connection(
|
|
231
|
+
resolved: Mapping[str, str],
|
|
232
|
+
slug: str,
|
|
233
|
+
owner: ConnectionOwner,
|
|
234
|
+
) -> str:
|
|
235
|
+
if owner["type"] == "user":
|
|
236
|
+
raise CredentialStoreError(_local_user_connection_unsupported(slug))
|
|
242
237
|
value = resolved.get(agent_connection_env_key(slug))
|
|
243
238
|
if value is not None and value.strip():
|
|
244
239
|
return value
|
|
@@ -415,105 +410,24 @@ def resolve_owner_id(
|
|
|
415
410
|
def resolve_agent_auth_context(
|
|
416
411
|
identity: RuntimeIdentity | None,
|
|
417
412
|
env: Mapping[str, str] | None = None,
|
|
418
|
-
*,
|
|
419
|
-
request_fn: Callable[..., tuple[int, dict[str, object]]] | None = None,
|
|
420
|
-
timeout: float = AGENT_AUTH_TIMEOUT_SECONDS,
|
|
421
413
|
) -> AgentAuthContext:
|
|
414
|
+
resolved = os.environ if env is None else env
|
|
415
|
+
if resolved.get("MDA_LOCAL_DEV") == "1":
|
|
416
|
+
raise CredentialStoreError(_local_user_connection_unsupported())
|
|
422
417
|
config = _resolve_agent_auth_config(env)
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
418
|
+
if not config.deployment_id:
|
|
419
|
+
raise CredentialStoreError(
|
|
420
|
+
f"connections are not configured: {DEPLOYMENT_ID_ENV} is not set"
|
|
421
|
+
)
|
|
426
422
|
return AgentAuthContext(
|
|
427
423
|
base_url=config.base_url,
|
|
428
424
|
agent_id=config.deployment_id,
|
|
429
|
-
principal_id=
|
|
425
|
+
principal_id=resolve_owner_id({"type": "user"}, identity, config.deployment_id),
|
|
430
426
|
api_key=config.api_key,
|
|
431
427
|
workspace_id=config.workspace_id,
|
|
432
428
|
)
|
|
433
429
|
|
|
434
430
|
|
|
435
|
-
def resolve_credential_principal_id(
|
|
436
|
-
identity: RuntimeIdentity | None,
|
|
437
|
-
config: _AgentAuthConfig,
|
|
438
|
-
*,
|
|
439
|
-
request_fn: Callable[..., tuple[int, dict[str, object]]] | None = None,
|
|
440
|
-
timeout: float = AGENT_AUTH_TIMEOUT_SECONDS,
|
|
441
|
-
) -> str:
|
|
442
|
-
"""Map a runtime identity to the Agent Auth principal used for user grants."""
|
|
443
|
-
if identity is None:
|
|
444
|
-
raise CredentialStoreError("user connections require an authenticated user principal")
|
|
445
|
-
user = identity.get("user") or {}
|
|
446
|
-
user_id = user.get("id") if isinstance(user, Mapping) else None
|
|
447
|
-
if not isinstance(user_id, str) or not user_id.strip():
|
|
448
|
-
raise CredentialStoreError("user connections require an authenticated user principal")
|
|
449
|
-
kind = user.get("kind") if isinstance(user, Mapping) else None
|
|
450
|
-
if kind == "service":
|
|
451
|
-
if (
|
|
452
|
-
user_id.strip() == _LOCAL_DEV_USER
|
|
453
|
-
and config.local_dev_principal_id is not None
|
|
454
|
-
):
|
|
455
|
-
return config.local_dev_principal_id
|
|
456
|
-
raise CredentialStoreError(
|
|
457
|
-
"user-owned connections require a person principal; "
|
|
458
|
-
"Studio and other service callers cannot own OAuth grants"
|
|
459
|
-
)
|
|
460
|
-
stamped = identity.get("agent_auth_principal_id")
|
|
461
|
-
if isinstance(stamped, str) and stamped.strip():
|
|
462
|
-
return stamped.strip()
|
|
463
|
-
|
|
464
|
-
subject = user_id.strip()
|
|
465
|
-
external = _external_identity_for_resolve(identity, config.workspace_id)
|
|
466
|
-
if external is None:
|
|
467
|
-
raise CredentialStoreError(
|
|
468
|
-
"user-owned connections need a resolvable identity "
|
|
469
|
-
"(validated-token issuer/subject, channel identity_context, or trusted backend)"
|
|
470
|
-
)
|
|
471
|
-
bootstrap = AgentAuth(
|
|
472
|
-
AgentAuthContext(
|
|
473
|
-
base_url=config.base_url,
|
|
474
|
-
principal_id=subject,
|
|
475
|
-
api_key=config.api_key,
|
|
476
|
-
workspace_id=config.workspace_id,
|
|
477
|
-
agent_id=config.deployment_id,
|
|
478
|
-
),
|
|
479
|
-
request=request_fn,
|
|
480
|
-
timeout=timeout,
|
|
481
|
-
)
|
|
482
|
-
return bootstrap.resolve_principal(external)
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
def _external_identity_for_resolve(
|
|
486
|
-
identity: RuntimeIdentity,
|
|
487
|
-
workspace_id: str | None,
|
|
488
|
-
) -> ResolvePrincipalIdentity | None:
|
|
489
|
-
user = identity.get("user") or {}
|
|
490
|
-
subject = user.get("id") if isinstance(user, Mapping) else None
|
|
491
|
-
if not isinstance(subject, str) or not subject.strip():
|
|
492
|
-
return None
|
|
493
|
-
subject = subject.strip()
|
|
494
|
-
provider = identity.get("identity_provider")
|
|
495
|
-
claims = identity.get("claims")
|
|
496
|
-
issuer = None
|
|
497
|
-
if isinstance(claims, Mapping):
|
|
498
|
-
raw_iss = claims.get("iss")
|
|
499
|
-
if isinstance(raw_iss, str) and raw_iss.strip():
|
|
500
|
-
issuer = raw_iss.strip()
|
|
501
|
-
if isinstance(provider, str) and provider.strip() and issuer:
|
|
502
|
-
return {
|
|
503
|
-
"provider": provider.strip(),
|
|
504
|
-
"issuer": issuer,
|
|
505
|
-
"subject": subject,
|
|
506
|
-
}
|
|
507
|
-
workspace = (workspace_id or "").strip()
|
|
508
|
-
if not workspace:
|
|
509
|
-
return None
|
|
510
|
-
return {
|
|
511
|
-
"provider": _TRUSTED_BACKEND_PROVIDER,
|
|
512
|
-
"issuer": workspace,
|
|
513
|
-
"subject": subject,
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
|
|
517
431
|
def _resolve_agent_auth_config(env: Mapping[str, str] | None) -> _AgentAuthConfig:
|
|
518
432
|
resolved = os.environ if env is None else env
|
|
519
433
|
api_key = (resolved.get(_API_KEY_ENV) or "").strip()
|
|
@@ -529,11 +443,6 @@ def _resolve_agent_auth_config(env: Mapping[str, str] | None) -> _AgentAuthConfi
|
|
|
529
443
|
api_key=api_key,
|
|
530
444
|
deployment_id=(resolved.get(DEPLOYMENT_ID_ENV) or "").strip() or None,
|
|
531
445
|
workspace_id=workspace_id,
|
|
532
|
-
local_dev_principal_id=(
|
|
533
|
-
(resolved.get(_LOCAL_DEV_PRINCIPAL_ENV) or "").strip() or None
|
|
534
|
-
if resolved.get("MDA_LOCAL_DEV") == "1"
|
|
535
|
-
else None
|
|
536
|
-
),
|
|
537
446
|
)
|
|
538
447
|
|
|
539
448
|
|
|
@@ -58,10 +58,6 @@ class ManagedUser(ManagedUserRequired, total=False):
|
|
|
58
58
|
mda_source_provider: str
|
|
59
59
|
mda_source_thread_id: str
|
|
60
60
|
mda_user_kind: Literal["user", "service"]
|
|
61
|
-
#: Validated-token provider id for Agent Auth principal resolve.
|
|
62
|
-
mda_identity_provider: str
|
|
63
|
-
#: Agent Auth principal UUID when Trigger ``identity_context`` already resolved one.
|
|
64
|
-
mda_agent_auth_principal_id: str
|
|
65
61
|
|
|
66
62
|
|
|
67
63
|
if TYPE_CHECKING:
|
|
@@ -92,8 +88,6 @@ INGRESS_SECRET_HEADER = "x-mda-ingress-secret" # noqa: S105 - header name, not
|
|
|
92
88
|
#: Internal handoff headers — accepted after a server API key or legacy ingress secret validates.
|
|
93
89
|
SOURCE_PROVIDER_HEADER = "x-mda-source-provider"
|
|
94
90
|
SOURCE_THREAD_HEADER = "x-mda-source-thread-id"
|
|
95
|
-
#: Trigger loopback stamp for a verified identity_context principal UUID.
|
|
96
|
-
AGENT_AUTH_PRINCIPAL_HEADER = "x-mda-agent-auth-principal-id"
|
|
97
91
|
|
|
98
92
|
#: Deployment env var carrying the shared secret the trusted backend presents.
|
|
99
93
|
INGRESS_SECRET_ENV = "MDA_INGRESS_SECRET" # noqa: S105 - env var name, not a secret
|
|
@@ -483,9 +477,6 @@ def _trusted_headers_user(headers: Mapping[str, object]) -> ManagedUser:
|
|
|
483
477
|
if source_provider is not None and source_thread is not None:
|
|
484
478
|
user["mda_source_provider"] = str(source_provider)
|
|
485
479
|
user["mda_source_thread_id"] = str(source_thread)
|
|
486
|
-
principal = str(headers.get(AGENT_AUTH_PRINCIPAL_HEADER) or "").strip()
|
|
487
|
-
if principal:
|
|
488
|
-
user["mda_agent_auth_principal_id"] = principal
|
|
489
480
|
return user
|
|
490
481
|
|
|
491
482
|
|
|
@@ -506,13 +497,7 @@ def _has_valid_handoff_secret(headers: Mapping[str, object]) -> bool:
|
|
|
506
497
|
|
|
507
498
|
def _has_handoff_headers(headers: Mapping[str, object]) -> bool:
|
|
508
499
|
return any(
|
|
509
|
-
header in headers
|
|
510
|
-
for header in (
|
|
511
|
-
USER_HEADER,
|
|
512
|
-
SOURCE_PROVIDER_HEADER,
|
|
513
|
-
SOURCE_THREAD_HEADER,
|
|
514
|
-
AGENT_AUTH_PRINCIPAL_HEADER,
|
|
515
|
-
)
|
|
500
|
+
header in headers for header in (USER_HEADER, SOURCE_PROVIDER_HEADER, SOURCE_THREAD_HEADER)
|
|
516
501
|
)
|
|
517
502
|
|
|
518
503
|
|
|
@@ -455,12 +455,6 @@ def build_runtime_identity(configurable: Mapping[str, object] | None) -> Runtime
|
|
|
455
455
|
claims = _field(user, "mda_claims")
|
|
456
456
|
if isinstance(claims, Mapping):
|
|
457
457
|
identity["claims"] = dict(cast("Mapping[str, object]", claims))
|
|
458
|
-
identity_provider = _field(user, "mda_identity_provider")
|
|
459
|
-
if isinstance(identity_provider, str) and identity_provider.strip():
|
|
460
|
-
identity["identity_provider"] = identity_provider.strip()
|
|
461
|
-
agent_auth_principal_id = _field(user, "mda_agent_auth_principal_id")
|
|
462
|
-
if isinstance(agent_auth_principal_id, str) and agent_auth_principal_id.strip():
|
|
463
|
-
identity["agent_auth_principal_id"] = agent_auth_principal_id.strip()
|
|
464
458
|
# Immutable: tools/middleware get a read-only view they cannot tamper with.
|
|
465
459
|
return cast("RuntimeIdentity", _freeze(identity))
|
|
466
460
|
|
managed_deepagents/_ingress.py
CHANGED
|
@@ -19,7 +19,6 @@ from managed_deepagents._channels.assistant_text import extract_assistant_text
|
|
|
19
19
|
from managed_deepagents._channels.binding import CHANNEL_BINDING_KEY, ChannelBinding
|
|
20
20
|
from managed_deepagents._channels.types import ChannelError
|
|
21
21
|
from managed_deepagents._identity_auth import (
|
|
22
|
-
AGENT_AUTH_PRINCIPAL_HEADER,
|
|
23
22
|
HANDOFF_SECRET_ENV,
|
|
24
23
|
HANDOFF_SECRET_HEADER,
|
|
25
24
|
INGRESS_SECRET_ENV,
|
|
@@ -356,7 +355,6 @@ def _create_trigger_ingress_loopback_client(
|
|
|
356
355
|
)
|
|
357
356
|
headers = {
|
|
358
357
|
USER_HEADER: user_id,
|
|
359
|
-
AGENT_AUTH_PRINCIPAL_HEADER: user_id,
|
|
360
358
|
SOURCE_PROVIDER_HEADER: source["provider"],
|
|
361
359
|
SOURCE_THREAD_HEADER: source["thread_key"],
|
|
362
360
|
}
|
|
@@ -263,8 +263,6 @@ def claims_to_user(provider: ValidatedTokenProvider, claims: Mapping[str, object
|
|
|
263
263
|
"permissions": [],
|
|
264
264
|
"mda_user_id": str(caller),
|
|
265
265
|
"mda_claims": dict(claims),
|
|
266
|
-
# Provider id drives Agent Auth POST /principals (provider, issuer, subject).
|
|
267
|
-
"mda_identity_provider": (provider.get("id") or "").strip() or "oidc",
|
|
268
266
|
}
|
|
269
267
|
groups = normalize_groups(claims.get(claim_map["groups"])) if claim_map.get("groups") else []
|
|
270
268
|
if groups:
|
|
@@ -177,10 +177,6 @@ class RuntimeIdentity(RuntimeIdentityRequired, total=False):
|
|
|
177
177
|
#: tools and middleware.
|
|
178
178
|
groups: tuple[str, ...]
|
|
179
179
|
claims: JsonObject
|
|
180
|
-
#: Validated-token provider id for Agent Auth principal resolve.
|
|
181
|
-
identity_provider: str
|
|
182
|
-
#: Agent Auth principal UUID when channel ingress already resolved one.
|
|
183
|
-
agent_auth_principal_id: str
|
|
184
180
|
|
|
185
181
|
|
|
186
182
|
class PrincipalRequired(TypedDict):
|
{managed_deepagents-0.6.2.dev48.dist-info → managed_deepagents-0.6.2.dev49.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.dev49
|
|
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
|
|
@@ -277,19 +277,16 @@ connector = connectors.mcp(
|
|
|
277
277
|
For this example, set `MDA_DEV_DOCS_TOKEN`.
|
|
278
278
|
|
|
279
279
|
A user-owned connection — `connections.get(slug, {"type": "user"})` — resolves
|
|
280
|
-
per caller (OAuth or opaque). The
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
connection rows exist — use a person principal (for example a Supabase JWT),
|
|
285
|
-
not Studio’s synthetic service user. OAuth completes on LangSmith’s platform
|
|
286
|
-
callback URL; the local UI must surface `credential_authorization_required`
|
|
287
|
-
and resume after the user connects.
|
|
280
|
+
per caller (OAuth or opaque). The pre-run credential gate interrupts the run
|
|
281
|
+
when a grant is missing. `mda dev` has no deployment to hold user grants, so
|
|
282
|
+
a user-owned connection fails there with an actionable error; deploy the agent
|
|
283
|
+
to exercise one.
|
|
288
284
|
|
|
289
285
|
Deploy the project first, then provision its connections with
|
|
290
286
|
`mda connections create`. Agent-owned opaque secrets are scoped to that
|
|
291
287
|
deployment, so the command refuses to create one before `mda deploy`.
|
|
292
|
-
`mda
|
|
288
|
+
`mda deploy` fails when a slug a project declares is missing from the
|
|
289
|
+
workspace.
|
|
293
290
|
|
|
294
291
|
Use `include_tools` or `exclude_tools` inside a server config to select a
|
|
295
292
|
subset. Tool names are raw MCP tool names before the managed `{server}__` prefix
|
{managed_deepagents-0.6.2.dev48.dist-info → managed_deepagents-0.6.2.dev49.dist-info}/RECORD
RENAMED
|
@@ -1,26 +1,26 @@
|
|
|
1
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=
|
|
3
|
+
managed_deepagents/_agent_auth.py,sha256=bOxTT1ZX9BZZyvgIaxd9SZycbEaQl-HuCrPieCAv6G0,17258
|
|
4
4
|
managed_deepagents/_agent_auth_http.py,sha256=aCYn7Rrtw3cnK3r4ir4JWxwzFkb7cF7nBgPpNdydxDw,5108
|
|
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=VwVBwM4T0rp1MgYu9D8QjGj1ireYeEuP3VIAFN5urFY,16246
|
|
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=SNxXunqmHgjBsZpiZu8yp49YkRIO0amkl0-7GHLGnIg,12280
|
|
11
11
|
managed_deepagents/_eval_filesystem.py,sha256=1nuD0yn3gh19JrWNocWyPFyeJW42E7Gse3XRWCUSTAA,1399
|
|
12
12
|
managed_deepagents/_extension.py,sha256=x2H1S8inkvTZQ_dr7kq0M8o8rre1FjzCDvMzItw4iyk,5318
|
|
13
|
-
managed_deepagents/_identity_auth.py,sha256=
|
|
13
|
+
managed_deepagents/_identity_auth.py,sha256=l0t0Xx-J1-z_Zw4K5D-B2yV6lNdeJgOw7UvxODxUxZQ,32798
|
|
14
14
|
managed_deepagents/_identity_http.py,sha256=aVQfZr7UKQoXF1Dry3p9fzXIj1882sEa668rvhn37i0,16029
|
|
15
15
|
managed_deepagents/_identity_links.py,sha256=Z1H2Seo2KaI-vcdU3_PGM-F06wOz0IQqUP-28wqiQsA,9172
|
|
16
|
-
managed_deepagents/_identity_runtime.py,sha256=
|
|
17
|
-
managed_deepagents/_ingress.py,sha256=
|
|
16
|
+
managed_deepagents/_identity_runtime.py,sha256=vsshj0TNWd-rXUhVsPAqXIkANunQT7jI94CWgzq-1cY,24409
|
|
17
|
+
managed_deepagents/_ingress.py,sha256=iqsGm2jZKKn0FqjNn2nJAlR7d-IqCpVKWo6NbMEhjxw,12323
|
|
18
18
|
managed_deepagents/_log.py,sha256=oYwOO0ZL4-INkge9YJvtLuCxL9zAtgjSPIggVbkcyc8,2932
|
|
19
19
|
managed_deepagents/_loopback.py,sha256=hQ1oNi77XpdUjzZURSBRoMvJ1mGCs-STobfBftGmXuE,2409
|
|
20
20
|
managed_deepagents/_managed_middleware.py,sha256=cfInVHTVjWoy_DBoFlnslfrDf2_n6llGnTGasta4AIo,10295
|
|
21
21
|
managed_deepagents/_managed_tools.py,sha256=KsFDULbv5fv0RY3Nj0zbv6z0Y80_o5YazhqeiQ9PnPk,9105
|
|
22
22
|
managed_deepagents/_memory_instructions.py,sha256=lyxKfNuXrWih574gmy3NHhIq_hIpJIM5zl3P8V69mUs,6678
|
|
23
|
-
managed_deepagents/_validated_token.py,sha256=
|
|
23
|
+
managed_deepagents/_validated_token.py,sha256=BY-66bgAOxhhRS3tfkDWVVU2l9HFHAuYXXCKV1pZ-nE,17232
|
|
24
24
|
managed_deepagents/define_deep_agent.py,sha256=17VfiiBINyhlqlATHrlJRPihKVlBsDGDP8K4-fxjxU8,5611
|
|
25
25
|
managed_deepagents/define_memory.py,sha256=n7Ya20dWGvwbZOkPIXoa68nTnJie8tpKEkRwfJQt_fU,5036
|
|
26
26
|
managed_deepagents/namespaces.py,sha256=GS76G19-V5Svfpbca-9xhQfJ6vel52jcJyfj6loLt_Y,4199
|
|
@@ -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=si-RbXt5o5HhOiAutrI8z5I4zerLvIo8iF1pKuJ1D8s,3904512
|
|
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
|
|
@@ -65,13 +65,13 @@ managed_deepagents/_memory/mounts.py,sha256=b2KtaTX3apTkmoqQxG2ENtkO86avSt1Nvrv3
|
|
|
65
65
|
managed_deepagents/_memory/paths.py,sha256=gHI-9KyawUv1ftX1K0kjaBbM4IYLeP7S-_WCaS2gVBM,353
|
|
66
66
|
managed_deepagents/_memory/slices.py,sha256=ljL78ECmDZ27xc3ajzkLliOfUln_bNr-d1ycC1wlS38,3559
|
|
67
67
|
managed_deepagents/_memory/types.py,sha256=scSk6mH0k2OC59wzUCa67szvXylSjWDrfzWWRIU9tZA,4336
|
|
68
|
-
managed_deepagents/identity/__init__.py,sha256=
|
|
68
|
+
managed_deepagents/identity/__init__.py,sha256=Slm-oEqKxbaZEQsMqHfD3LbG5M4vH2lKUmralVPB_Zs,16137
|
|
69
69
|
managed_deepagents/identity/claims.py,sha256=prby7r_8Lww3MmoBm8PX6PsSGE3GwSHkr8mVIz_08nU,1180
|
|
70
70
|
managed_deepagents/identity/options.py,sha256=x_yMbXEFR7zXyehEjDHG2qjAlukXjrRBcQLcM6IndLM,2550
|
|
71
71
|
managed_deepagents/identity/supabase.py,sha256=8uobl3WCrQL_ieSXG8KTLf1th7Qjim9liZT50HeaJE0,6026
|
|
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.
|
|
77
|
-
managed_deepagents-0.6.2.
|
|
72
|
+
managed_deepagents-0.6.2.dev49.dist-info/licenses/LICENSE,sha256=WnPZQQ608ojZUkXl7BW6VbKloIAibZiGm1K6cjeZOL8,1066
|
|
73
|
+
managed_deepagents-0.6.2.dev49.dist-info/METADATA,sha256=7QuGJwj6TqzMO7JMsCPCm51hE7Bmk-H0hvKWNGH4ZHU,13718
|
|
74
|
+
managed_deepagents-0.6.2.dev49.dist-info/WHEEL,sha256=3I5VVWZdsFlU417aCS2bMRuerS8wsfvBq99MyatBV3A,97
|
|
75
|
+
managed_deepagents-0.6.2.dev49.dist-info/entry_points.txt,sha256=ziZqkKuaDO3qHCjKmBhrx9cm3ok8bZ9xcEDpUTj4unM,53
|
|
76
|
+
managed_deepagents-0.6.2.dev49.dist-info/top_level.txt,sha256=fdBo4O0Hlol_w022tTLB5ftZpamb4yJoQ3MUvjgTGfA,19
|
|
77
|
+
managed_deepagents-0.6.2.dev49.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{managed_deepagents-0.6.2.dev48.dist-info → managed_deepagents-0.6.2.dev49.dist-info}/top_level.txt
RENAMED
|
File without changes
|