ms-tau-sdk 2.0.6.dev40__tar.gz → 2.0.7.dev41__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/CHANGELOG.md +34 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/PKG-INFO +12 -10
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/README.md +11 -9
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/pyproject.toml +1 -1
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/__init__.py +2 -2
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/agent_skills/tau_a2a_runtime_adapter/SKILL.md +7 -8
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/agent_skills/tau_project_customization/SKILL.md +42 -34
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/api/a2a.py +20 -48
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/backend/client.py +25 -19
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/backend/local.py +30 -10
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/runtime/manager.py +37 -53
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/runtime/requester.py +220 -120
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/runtime/task_context.py +5 -4
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/tools/mainsequence_mcp.py +34 -63
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/tools/mcp_applications.py +15 -23
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/tools/mcp_connection.py +3 -10
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/.gitignore +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/packages/tau-board/src/ms_tau_board/__init__.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/packages/tau-board/src/ms_tau_board/app.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/packages/tau-board/src/ms_tau_board/cli.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/packages/tau-board/src/ms_tau_board/config.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/packages/tau-board/src/ms_tau_board/env_file.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/packages/tau-board/src/ms_tau_board/logs.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/packages/tau-board/src/ms_tau_board/proxy.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/packages/tau-board/src/ms_tau_board/state.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/packages/tau-board/src/ms_tau_board/static/BULMA-LICENSE.txt +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/packages/tau-board/src/ms_tau_board/static/app.js +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/packages/tau-board/src/ms_tau_board/static/board.css +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/packages/tau-board/src/ms_tau_board/static/bulma.min.css +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/packages/tau-board/src/ms_tau_board/static/index.html +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/agent_skills/tau_local_development/SKILL.md +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/agent_skills/tau_repository_integration/SKILL.md +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/api/__init__.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/api/chat.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/api/conversations.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/api/dependencies.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/api/health.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/api/inspection.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/api/local_chat.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/api/models.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/api/request_identity.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/api/sessions.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/app.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/application.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/backend/__init__.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/backend/assertions.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/backend/auth.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/backend/mcp.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/backend/models.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/backend/routes.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/cli.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/errors.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/logging.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/protocols/__init__.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/protocols/a2a_failure.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/protocols/a2a_message.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/protocols/a2a_roles.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/protocols/assistant_ui.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/protocols/chat_history.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/protocols/strict_json.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/providers/__init__.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/providers/definitions.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/providers/factory.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/providers/tau_compat.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/resources/SYSTEM.md +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/resources/__init__.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/resources/loader.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/resources/prompts/review-code-repository.md +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/runtime/__init__.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/runtime/deployment_health.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/runtime/events.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/runtime/extensions.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/runtime/failures.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/runtime/live_turns.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/runtime/observability.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/runtime/provenance.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/runtime/session.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/runtime/snapshots.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/sessions/__init__.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/sessions/storage.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/settings.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/skills.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/tools/__init__.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/tools/skill_read.py +0 -0
- {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev41}/src/ms_tau_sdk/tools/task_control.py +0 -0
|
@@ -2,6 +2,40 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
- **Breaking: one delegation envelope on every call made for the work
|
|
6
|
+
([#78](https://github.com/mainsequence-sdk/ms-tau-sdk/issues/78), ADR 0021 amendment).** This
|
|
7
|
+
release works only with the matching platform change, deployed in the same cutover; there is no
|
|
8
|
+
deprecation period, and earlier releases, including 2.0.6, stop acting for people once that
|
|
9
|
+
platform is deployed.
|
|
10
|
+
- Every hosted Main Sequence MCP call names the turn's session, and carries the person's
|
|
11
|
+
delegation (`mainsequence.ai/delegation/v1`) while the turn serves a person. The platform's
|
|
12
|
+
per-tool labels (`mainsequence.ai/requires-requester/v1`,
|
|
13
|
+
`mainsequence.ai/requires-caller-session-proof/v1`) are no longer read, and a turn that serves
|
|
14
|
+
nobody keeps its MCP tools: its calls are the Agent's own.
|
|
15
|
+
- Declared application tools run in every turn, with a token for the person the turn serves or
|
|
16
|
+
the Agent's own token when it serves nobody. A refused delegated call is reported and never
|
|
17
|
+
retried as the Agent.
|
|
18
|
+
- The person a turn serves comes only from the platform's answer to the turn start, whoever
|
|
19
|
+
called; dispatch, delivery and Task answers are no longer read for it. Delegated work serves
|
|
20
|
+
the person the platform records for it.
|
|
21
|
+
- `platform_client()` replaces `requester_client()`, with no alias. By default a call carries the
|
|
22
|
+
delegation while the turn serves a person; `delegation="none"` never carries it and
|
|
23
|
+
`delegation="required"` refuses the call before sending when the turn serves nobody. Outside a
|
|
24
|
+
turn no call carries a delegation, and in local mode calls use the signed-in person's own
|
|
25
|
+
credential.
|
|
26
|
+
- Delegated calls use the person's ordinary permissions, including administrative ones; the
|
|
27
|
+
statement people are shown changes accordingly.
|
|
28
|
+
- The SDK no longer hides the withdrawn private Secret entry operations, and the local health
|
|
29
|
+
field `mcp_session_proof_limited_tool_count` is removed.
|
|
30
|
+
|
|
31
|
+
- Documentation now distinguishes requester-bound reads and supported writes from workload grants,
|
|
32
|
+
states the write risk and platform rollout requirements, and includes conversation/Task
|
|
33
|
+
permissions and denial recovery. The Security and access guide keeps its `security-model.md`
|
|
34
|
+
path. Provider selection settings and troubleshooting, the public readiness-hook reference, and
|
|
35
|
+
the exported API compatibility list are complete. This changes documentation only.
|
|
36
|
+
|
|
37
|
+
## 2.0.6 — 2026-10-07
|
|
38
|
+
|
|
5
39
|
- The documentation no longer describes the platform's internal implementation. It no longer names
|
|
6
40
|
the backend framework, its repositories, ADRs, classes or commits, and calls the backend "the
|
|
7
41
|
platform". The archived Astro documents (`docs/history/astro`) and the ADR 56 migration workspace
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: ms-tau-sdk
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.7.dev41
|
|
4
4
|
Summary: Workspace-bound Tau application primitives for Main Sequence projects
|
|
5
5
|
Project-URL: Changelog, https://github.com/mainsequence-sdk/ms-tau-sdk/blob/development/CHANGELOG.md
|
|
6
6
|
Project-URL: Documentation, https://github.com/mainsequence-sdk/ms-tau-sdk/tree/development/docs
|
|
@@ -133,10 +133,11 @@ only an application that declares it, so serve the application `create_app()` re
|
|
|
133
133
|
hosting, requests are handled as before. See
|
|
134
134
|
[request identity](docs/reference/runtime-contract.md#request-identity).
|
|
135
135
|
|
|
136
|
-
An Agent that an Organization admin enabled for it can
|
|
137
|
-
request a turn is serving. Project tools read that person with `current_requester()`
|
|
138
|
-
platform or another platform application
|
|
139
|
-
proof or a token. See
|
|
136
|
+
An Agent that an Organization admin enabled for it can act with the ordinary permissions of the
|
|
137
|
+
person whose request a turn is serving. Project tools read that person with `current_requester()`
|
|
138
|
+
and call the platform or another platform application with `platform_client()`, which carries the
|
|
139
|
+
person's delegation by default while the turn serves one; neither exposes a proof or a token. See
|
|
140
|
+
the [public API](docs/reference/public-api.md#current_requester-and-platform_client).
|
|
140
141
|
|
|
141
142
|
Job-hosted batch execution is an [accepted design](docs/adrs/0015-job-hosted-batch-execution.md)
|
|
142
143
|
with implementation pending. It will run this SDK's configured Tau composition for one assignment
|
|
@@ -287,13 +288,14 @@ are not bundled into the SDK. Main Sequence transport and protocol behavior rema
|
|
|
287
288
|
- explicit, version-matched development skills for repository integration, local debugging,
|
|
288
289
|
project customization, and TAU's A2A host adapter
|
|
289
290
|
|
|
290
|
-
## Security
|
|
291
|
+
## Security and access guide
|
|
291
292
|
|
|
292
|
-
A hosted Agent runs as its own workload, with no access until it is granted
|
|
293
|
-
|
|
294
|
-
|
|
293
|
+
A hosted Agent runs as its own workload, with no access until it is granted. An Organization admin
|
|
294
|
+
can let it act with the ordinary permissions of the person it serves, including administrative
|
|
295
|
+
ones, only during that work and for at most 24 hours. Prompt injection can cause unintended actions within those rights;
|
|
296
|
+
completed changes can outlast that access. Everything its tools read reaches the model, and its
|
|
295
297
|
tools and extensions run with its credentials. The
|
|
296
|
-
[
|
|
298
|
+
[Security and access guide](docs/reference/security-model.md) explains what people who build and use
|
|
297
299
|
Agents need to know.
|
|
298
300
|
|
|
299
301
|
## Deployment boundary
|
|
@@ -100,10 +100,11 @@ only an application that declares it, so serve the application `create_app()` re
|
|
|
100
100
|
hosting, requests are handled as before. See
|
|
101
101
|
[request identity](docs/reference/runtime-contract.md#request-identity).
|
|
102
102
|
|
|
103
|
-
An Agent that an Organization admin enabled for it can
|
|
104
|
-
request a turn is serving. Project tools read that person with `current_requester()`
|
|
105
|
-
platform or another platform application
|
|
106
|
-
proof or a token. See
|
|
103
|
+
An Agent that an Organization admin enabled for it can act with the ordinary permissions of the
|
|
104
|
+
person whose request a turn is serving. Project tools read that person with `current_requester()`
|
|
105
|
+
and call the platform or another platform application with `platform_client()`, which carries the
|
|
106
|
+
person's delegation by default while the turn serves one; neither exposes a proof or a token. See
|
|
107
|
+
the [public API](docs/reference/public-api.md#current_requester-and-platform_client).
|
|
107
108
|
|
|
108
109
|
Job-hosted batch execution is an [accepted design](docs/adrs/0015-job-hosted-batch-execution.md)
|
|
109
110
|
with implementation pending. It will run this SDK's configured Tau composition for one assignment
|
|
@@ -254,13 +255,14 @@ are not bundled into the SDK. Main Sequence transport and protocol behavior rema
|
|
|
254
255
|
- explicit, version-matched development skills for repository integration, local debugging,
|
|
255
256
|
project customization, and TAU's A2A host adapter
|
|
256
257
|
|
|
257
|
-
## Security
|
|
258
|
+
## Security and access guide
|
|
258
259
|
|
|
259
|
-
A hosted Agent runs as its own workload, with no access until it is granted
|
|
260
|
-
|
|
261
|
-
|
|
260
|
+
A hosted Agent runs as its own workload, with no access until it is granted. An Organization admin
|
|
261
|
+
can let it act with the ordinary permissions of the person it serves, including administrative
|
|
262
|
+
ones, only during that work and for at most 24 hours. Prompt injection can cause unintended actions within those rights;
|
|
263
|
+
completed changes can outlast that access. Everything its tools read reaches the model, and its
|
|
262
264
|
tools and extensions run with its credentials. The
|
|
263
|
-
[
|
|
265
|
+
[Security and access guide](docs/reference/security-model.md) explains what people who build and use
|
|
264
266
|
Agents need to know.
|
|
265
267
|
|
|
266
268
|
## Deployment boundary
|
|
@@ -9,7 +9,7 @@ from .runtime.deployment_health import (
|
|
|
9
9
|
RUNTIME_HEALTH_ABI_VERSION,
|
|
10
10
|
register_deployment_readiness_hook,
|
|
11
11
|
)
|
|
12
|
-
from .runtime.requester import current_requester,
|
|
12
|
+
from .runtime.requester import current_requester, platform_client
|
|
13
13
|
from .settings import TauSDKSettings
|
|
14
14
|
|
|
15
15
|
__all__ = [
|
|
@@ -18,6 +18,6 @@ __all__ = [
|
|
|
18
18
|
"__version__",
|
|
19
19
|
"create_app",
|
|
20
20
|
"current_requester",
|
|
21
|
+
"platform_client",
|
|
21
22
|
"register_deployment_readiness_hook",
|
|
22
|
-
"requester_client",
|
|
23
23
|
]
|
|
@@ -23,19 +23,18 @@ The SDK owns:
|
|
|
23
23
|
|
|
24
24
|
- projecting the authenticated Main Sequence MCP catalog into a TAU session;
|
|
25
25
|
- preserving each tool's canonical name and metadata through host normalization;
|
|
26
|
-
- privately attaching
|
|
27
|
-
`mainsequence.ai/
|
|
28
|
-
|
|
29
|
-
which the platform runs for the turn's requester, and refusing that tool before sending it in a
|
|
30
|
-
hosted turn that serves nobody;
|
|
26
|
+
- privately attaching, to every hosted Main Sequence MCP call, the turn's caller-session proof under
|
|
27
|
+
`mainsequence.ai/caller-session-proof/v1`, and, while the turn serves a person, the same proof as
|
|
28
|
+
that person's delegation under `mainsequence.ai/delegation/v1`. No tool metadata decides it;
|
|
31
29
|
- verifying the platform's signed caller or platform assertion on every inbound request of a
|
|
32
30
|
hosted runtime, and admitting a request to a session or its Tasks only for the session's owner,
|
|
33
31
|
an Organization admin, or the workload User of the Agent that delegated to that child session,
|
|
34
32
|
which the platform's own records establish, never the `X-Caller-*` headers;
|
|
35
33
|
- presenting the verified caller assertion of the request that starts a chat or A2A Message turn
|
|
36
|
-
only when it marks that turn active, so that the platform can record the turn's requester
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
only when it marks that turn active, so that the platform can record the turn's requester;
|
|
35
|
+
taking the person the turn serves only from the platform's answer to the turn start; and giving
|
|
36
|
+
extension tools that person and calls for the work through `current_requester()` and
|
|
37
|
+
`platform_client()` without exposing the assertion, the lease proof, or any token;
|
|
39
38
|
- translating inbound A2A requests into the shared TAU runtime; and
|
|
40
39
|
- translating runtime events and results into validated A2A responses.
|
|
41
40
|
|
|
@@ -97,10 +97,11 @@ tools do not grant new platform permissions merely because they run inside TAU.
|
|
|
97
97
|
|
|
98
98
|
## Acting for the person a turn serves
|
|
99
99
|
|
|
100
|
-
An Agent that an Organization admin enabled for it can
|
|
101
|
-
applications
|
|
102
|
-
platform keeps that authority and finds the person in its own records; the runtime
|
|
103
|
-
which of its sessions it is working on. Extension tools use two SDK functions and
|
|
100
|
+
An Agent that an Organization admin enabled for it can call the platform and other platform
|
|
101
|
+
applications with the ordinary permissions of the person whose request a turn is serving: the
|
|
102
|
+
requester. The platform keeps that authority and finds the person in its own records; the runtime
|
|
103
|
+
only proves which of its sessions it is working on. Extension tools use two SDK functions and
|
|
104
|
+
nothing else:
|
|
104
105
|
|
|
105
106
|
```python
|
|
106
107
|
import json
|
|
@@ -108,64 +109,71 @@ import json
|
|
|
108
109
|
from tau_agent.messages import TextContent
|
|
109
110
|
from tau_agent.tools import AgentToolResult
|
|
110
111
|
|
|
111
|
-
from ms_tau_sdk import
|
|
112
|
+
from ms_tau_sdk import platform_client
|
|
112
113
|
|
|
113
114
|
ANALYST_DATA_RELEASE_UID = "..." # the release of the application to ask
|
|
114
115
|
|
|
115
116
|
|
|
116
117
|
async def revenue_by_region(tool_call_id, arguments, signal=None, on_update=None):
|
|
117
|
-
|
|
118
|
-
return AgentToolResult(content=[TextContent(text="Ask me from your own conversation.")])
|
|
118
|
+
# This tool answers each person with their own data, so it needs a person.
|
|
119
119
|
try:
|
|
120
|
-
answer = await
|
|
120
|
+
answer = await platform_client(delegation="required").call_release(
|
|
121
121
|
ANALYST_DATA_RELEASE_UID,
|
|
122
122
|
"POST",
|
|
123
123
|
"/query",
|
|
124
124
|
json={"question": "revenue by region"},
|
|
125
125
|
)
|
|
126
126
|
except PermissionError:
|
|
127
|
-
return AgentToolResult(content=[TextContent(text="
|
|
127
|
+
return AgentToolResult(content=[TextContent(text="Ask me from your own conversation.")])
|
|
128
128
|
return AgentToolResult(content=[TextContent(text=json.dumps(answer.json()["rows"]))])
|
|
129
129
|
```
|
|
130
130
|
|
|
131
|
-
- `current_requester()` returns the turn
|
|
132
|
-
`None`.
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
131
|
+
- `current_requester()` returns the person the turn serves, with `uid` and `team_uids`, or
|
|
132
|
+
`None`. The platform names that person when the turn starts, whoever called; it is `None` when
|
|
133
|
+
the platform names nobody, in local mode, and in code outside a turn. Only it names the
|
|
134
|
+
requester: never take a person's UID from tool arguments, the prompt, history, or a header.
|
|
135
|
+
- `platform_client()` returns a client. `await client.request("GET", "/api/v1/...")` calls a
|
|
136
|
+
platform API path, and `await client.call_release(release_uid, method, path, ...)` calls another
|
|
137
|
+
platform application. Both return an `httpx.Response`.
|
|
138
|
+
- By default (`delegation="auto"`) a call carries the person's delegation while the turn serves a
|
|
139
|
+
person, and is the Agent's own otherwise; the operation or application decides what it may do.
|
|
140
|
+
`delegation="none"` never carries it. `delegation="required"` raises a `PermissionError` before
|
|
141
|
+
sending when the turn serves nobody; use it in a tool that only makes sense for a person.
|
|
142
|
+
- A call the platform refuses because the person's access ended (`code`
|
|
143
|
+
`requester_binding_invalid` or `runtime_lease_*`) raises a `PermissionError`: the turn is over,
|
|
144
|
+
the access was removed, more than 24 hours passed, or the Agent is not enabled. Catch it, say in
|
|
145
|
+
plain words that the request cannot be served, and never retry it as the Agent.
|
|
145
146
|
|
|
146
147
|
Rules for tools that act for the requester:
|
|
147
148
|
|
|
148
149
|
- Never handle proofs or tokens. The SDK attaches the session, the lease proof, and the
|
|
149
150
|
credentials itself. A tool never reads, logs, stores, or forwards them, passes a path rather than
|
|
150
151
|
a URL, and never sets `Authorization` or an `X-MainSequence-*` header.
|
|
151
|
-
-
|
|
152
|
-
|
|
152
|
+
- A delegated call uses the person's ordinary permissions, including administrative ones; any other
|
|
153
|
+
call uses the Agent's own. Each operation decides what it needs. Never infer write permission
|
|
154
|
+
from view access.
|
|
155
|
+
- This needs the platform's matching change, deployed in the same cutover; check the deployed
|
|
156
|
+
platform and the installed SDK before depending on it.
|
|
153
157
|
- Return to the model only business results, such as rows, numbers, and names. Never return the
|
|
154
158
|
response object, its headers, a token, a proof, or a raw error body.
|
|
155
|
-
- Keep nothing for another turn or another person. The
|
|
156
|
-
tool leaves running
|
|
159
|
+
- Keep nothing for another turn or another person. The delegation ends with the turn, and a task
|
|
160
|
+
the tool leaves running acts only as the Agent afterwards.
|
|
157
161
|
- What a tool reads for a person belongs to that person's conversation. Do not write it to shared
|
|
158
162
|
stores, other Agents, or external systems.
|
|
159
163
|
|
|
160
164
|
People who use such an Agent are told:
|
|
161
165
|
|
|
162
|
-
> **This Agent works with your identity
|
|
163
|
-
>
|
|
164
|
-
>
|
|
165
|
-
>
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
166
|
+
> **This Agent works with your identity.** It can read, create, change, run,
|
|
167
|
+
> share or delete only what your permissions allow through supported operations,
|
|
168
|
+
> only while serving your request, and for at most 24 hours after you ask. It
|
|
169
|
+
> uses your ordinary permissions, including administrative permissions, and
|
|
170
|
+
> access is checked on every call. Your Organization's administrator approved it
|
|
171
|
+
> to work this way.
|
|
172
|
+
|
|
173
|
+
The statement describes delegated calls. The Agent's own grants and trusted extension code remain
|
|
174
|
+
separate authority. Prompt injection can cause unintended changes, sharing, or deletion within the
|
|
175
|
+
person's permissions, and completed writes can outlast the delegation. Only Organization admins
|
|
176
|
+
enable this authority.
|
|
169
177
|
|
|
170
178
|
## Validation
|
|
171
179
|
|
|
@@ -20,7 +20,7 @@ from fastapi.responses import JSONResponse, StreamingResponse
|
|
|
20
20
|
from structlog.contextvars import bind_contextvars
|
|
21
21
|
from tau_agent.types import JSONValue
|
|
22
22
|
|
|
23
|
-
from ms_tau_sdk.backend.assertions import CallerAssertion
|
|
23
|
+
from ms_tau_sdk.backend.assertions import CallerAssertion, VerifiedCaller
|
|
24
24
|
from ms_tau_sdk.backend.client import MainSequenceClient
|
|
25
25
|
from ms_tau_sdk.backend.models import (
|
|
26
26
|
AgentTask,
|
|
@@ -63,7 +63,7 @@ from ms_tau_sdk.runtime.provenance import (
|
|
|
63
63
|
TurnProvenance,
|
|
64
64
|
turn_provenance_from_request,
|
|
65
65
|
)
|
|
66
|
-
from ms_tau_sdk.runtime.requester import CallerDelivery
|
|
66
|
+
from ms_tau_sdk.runtime.requester import CallerDelivery
|
|
67
67
|
from ms_tau_sdk.runtime.task_context import (
|
|
68
68
|
TaskExecutionContext,
|
|
69
69
|
active_task_execution,
|
|
@@ -920,22 +920,14 @@ def _presented_assertion(caller_assertion: CallerAssertion | None) -> dict[str,
|
|
|
920
920
|
return {"caller_assertion": token} if token else {}
|
|
921
921
|
|
|
922
922
|
|
|
923
|
-
def
|
|
924
|
-
|
|
925
|
-
caller_assertion: CallerAssertion | None,
|
|
926
|
-
) -> Requester | None:
|
|
927
|
-
"""Return the request's verified caller when the platform recorded that person as requester.
|
|
923
|
+
def _request_caller(caller_assertion: CallerAssertion | None) -> VerifiedCaller | None:
|
|
924
|
+
"""Return the verified caller of a request that runs a Task attempt itself.
|
|
928
925
|
|
|
929
|
-
|
|
930
|
-
|
|
926
|
+
The platform's answer to the attempt's turn start names the person the attempt serves; this
|
|
927
|
+
caller only supplies that person's teams, when it is that person.
|
|
931
928
|
"""
|
|
932
929
|
|
|
933
|
-
if caller_assertion is None
|
|
934
|
-
return None
|
|
935
|
-
caller = caller_assertion.caller
|
|
936
|
-
if task.requester_identity_type != "human" or task.requester_user_uid != caller.uid:
|
|
937
|
-
return None
|
|
938
|
-
return Requester(uid=caller.uid, team_uids=caller.team_uids)
|
|
930
|
+
return caller_assertion.caller if caller_assertion is not None else None
|
|
939
931
|
|
|
940
932
|
|
|
941
933
|
async def _wait_for_task_return_state(
|
|
@@ -1289,7 +1281,7 @@ async def _execute_task(
|
|
|
1289
1281
|
config: TauSDKSettings | None = None,
|
|
1290
1282
|
dispatch_uid: str | None = None,
|
|
1291
1283
|
claim: _ClaimedTask | None = None,
|
|
1292
|
-
|
|
1284
|
+
caller: VerifiedCaller | None = None,
|
|
1293
1285
|
) -> dict[str, Any]:
|
|
1294
1286
|
bind_contextvars(
|
|
1295
1287
|
a2a_task_id=task.task_id,
|
|
@@ -1322,7 +1314,7 @@ async def _execute_task(
|
|
|
1322
1314
|
attempt_uid=claim.attempt_uid,
|
|
1323
1315
|
holder_id=claim.holder_id,
|
|
1324
1316
|
lease_token=claim.lease_token,
|
|
1325
|
-
|
|
1317
|
+
caller=caller,
|
|
1326
1318
|
)
|
|
1327
1319
|
try:
|
|
1328
1320
|
await writer.ensure_not_canceled(force=True)
|
|
@@ -1408,7 +1400,7 @@ async def _schedule_task_accelerator(
|
|
|
1408
1400
|
max_output_bytes: int,
|
|
1409
1401
|
provenance: TurnProvenance,
|
|
1410
1402
|
config: TauSDKSettings,
|
|
1411
|
-
|
|
1403
|
+
caller: VerifiedCaller | None = None,
|
|
1412
1404
|
) -> bool:
|
|
1413
1405
|
"""Best-effort local start after durable creation; dispatch remains recovery owner."""
|
|
1414
1406
|
|
|
@@ -1440,7 +1432,7 @@ async def _schedule_task_accelerator(
|
|
|
1440
1432
|
provenance=provenance,
|
|
1441
1433
|
config=config,
|
|
1442
1434
|
claim=claim,
|
|
1443
|
-
|
|
1435
|
+
caller=caller,
|
|
1444
1436
|
)
|
|
1445
1437
|
try:
|
|
1446
1438
|
_background, scheduled = manager.create_a2a_task_execution(
|
|
@@ -1680,7 +1672,7 @@ async def _stream_task_events(
|
|
|
1680
1672
|
provenance: TurnProvenance,
|
|
1681
1673
|
config: TauSDKSettings | None = None,
|
|
1682
1674
|
history_length: int = DEFAULT_TASK_HISTORY_LENGTH,
|
|
1683
|
-
|
|
1675
|
+
caller: VerifiedCaller | None = None,
|
|
1684
1676
|
) -> AsyncIterator[dict[str, Any]]:
|
|
1685
1677
|
claim = await _claim_backend_task(client, manager, task)
|
|
1686
1678
|
resolved = config or manager.settings
|
|
@@ -1700,7 +1692,7 @@ async def _stream_task_events(
|
|
|
1700
1692
|
attempt_uid=claim.attempt_uid,
|
|
1701
1693
|
holder_id=claim.holder_id,
|
|
1702
1694
|
lease_token=claim.lease_token,
|
|
1703
|
-
|
|
1695
|
+
caller=caller,
|
|
1704
1696
|
)
|
|
1705
1697
|
working = await client.get_task(task.uid)
|
|
1706
1698
|
working = await _task_with_history(client, working, history_length=history_length)
|
|
@@ -1878,7 +1870,7 @@ def _message_stream_response(
|
|
|
1878
1870
|
history_length: int = DEFAULT_TASK_HISTORY_LENGTH,
|
|
1879
1871
|
json_rpc: bool = False,
|
|
1880
1872
|
request_id: object = None,
|
|
1881
|
-
|
|
1873
|
+
caller: VerifiedCaller | None = None,
|
|
1882
1874
|
) -> StreamingResponse:
|
|
1883
1875
|
async def stream() -> AsyncIterator[bytes]:
|
|
1884
1876
|
try:
|
|
@@ -1892,7 +1884,7 @@ def _message_stream_response(
|
|
|
1892
1884
|
provenance=provenance,
|
|
1893
1885
|
config=config,
|
|
1894
1886
|
history_length=history_length,
|
|
1895
|
-
|
|
1887
|
+
caller=caller,
|
|
1896
1888
|
):
|
|
1897
1889
|
yield _sse(
|
|
1898
1890
|
_stream_payload(
|
|
@@ -2149,21 +2141,6 @@ def _durable_task_execution_input(
|
|
|
2149
2141
|
return prompt, contract, provenance
|
|
2150
2142
|
|
|
2151
2143
|
|
|
2152
|
-
def _dispatched_requester(body: dict[str, Any], config: TauSDKSettings) -> Requester | None:
|
|
2153
|
-
"""Return the requester that the platform's verified dispatch or caller delivery names.
|
|
2154
|
-
|
|
2155
|
-
Only a person is a requester: an Agent's workload User never is. A runtime that does not
|
|
2156
|
-
verify the platform's assertion on its internal routes takes no requester from them.
|
|
2157
|
-
"""
|
|
2158
|
-
|
|
2159
|
-
if config.local_mode or config.request_identity_mode != "assertion":
|
|
2160
|
-
return None
|
|
2161
|
-
if body.get("requester_identity_type") != "human":
|
|
2162
|
-
return None
|
|
2163
|
-
uid = canonical_requester_uid(body.get("requester_user_uid"))
|
|
2164
|
-
return Requester(uid=uid) if uid is not None else None
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
2144
|
@router.post("/internal/a2a/task-dispatch", status_code=200)
|
|
2168
2145
|
async def task_dispatch_available(
|
|
2169
2146
|
body: dict[str, Any],
|
|
@@ -2199,7 +2176,6 @@ async def task_dispatch_available(
|
|
|
2199
2176
|
provenance=provenance,
|
|
2200
2177
|
config=config,
|
|
2201
2178
|
claim=claim,
|
|
2202
|
-
requester=_dispatched_requester(body, config),
|
|
2203
2179
|
),
|
|
2204
2180
|
name=f"a2a-task-{task.task_id}",
|
|
2205
2181
|
)
|
|
@@ -2242,7 +2218,6 @@ async def _resume_caller_delivery(
|
|
|
2242
2218
|
async def task_caller_delivery_available(
|
|
2243
2219
|
body: dict[str, Any],
|
|
2244
2220
|
manager: RuntimeManagerDep,
|
|
2245
|
-
config: SettingsDep,
|
|
2246
2221
|
) -> dict[str, Any]:
|
|
2247
2222
|
delivery_uid = str(body.get("delivery_uid") or "").strip()
|
|
2248
2223
|
task_uid = str(body.get("task_uid") or "").strip()
|
|
@@ -2289,10 +2264,7 @@ async def task_caller_delivery_available(
|
|
|
2289
2264
|
task_id=task_id,
|
|
2290
2265
|
task_status=task_status,
|
|
2291
2266
|
caller_agent_session_uid=caller_agent_session_uid,
|
|
2292
|
-
delivery=CallerDelivery(
|
|
2293
|
-
uid=delivery_uid,
|
|
2294
|
-
requester=_dispatched_requester(body, config),
|
|
2295
|
-
),
|
|
2267
|
+
delivery=CallerDelivery(uid=delivery_uid),
|
|
2296
2268
|
),
|
|
2297
2269
|
name=f"a2a-caller-delivery-{delivery_uid}",
|
|
2298
2270
|
)
|
|
@@ -2381,7 +2353,7 @@ async def message_send(
|
|
|
2381
2353
|
max_output_bytes=config.max_turn_output_bytes,
|
|
2382
2354
|
provenance=provenance,
|
|
2383
2355
|
config=config,
|
|
2384
|
-
|
|
2356
|
+
caller=_request_caller(caller_assertion),
|
|
2385
2357
|
)
|
|
2386
2358
|
if return_immediately:
|
|
2387
2359
|
task = await _task_with_history(client, task, history_length=history_length)
|
|
@@ -2416,7 +2388,7 @@ async def message_send(
|
|
|
2416
2388
|
max_output_bytes=config.max_turn_output_bytes,
|
|
2417
2389
|
provenance=provenance,
|
|
2418
2390
|
config=config,
|
|
2419
|
-
|
|
2391
|
+
caller=_request_caller(caller_assertion),
|
|
2420
2392
|
)
|
|
2421
2393
|
if return_immediately:
|
|
2422
2394
|
task = await _task_with_history(client, task, history_length=history_length)
|
|
@@ -2556,7 +2528,7 @@ async def message_stream(
|
|
|
2556
2528
|
provenance=provenance,
|
|
2557
2529
|
config=config,
|
|
2558
2530
|
history_length=history_length,
|
|
2559
|
-
|
|
2531
|
+
caller=_request_caller(caller_assertion),
|
|
2560
2532
|
)
|
|
2561
2533
|
|
|
2562
2534
|
|
|
@@ -2808,7 +2780,7 @@ async def json_rpc(
|
|
|
2808
2780
|
history_length=history_length,
|
|
2809
2781
|
json_rpc=True,
|
|
2810
2782
|
request_id=request_id,
|
|
2811
|
-
|
|
2783
|
+
caller=_request_caller(caller_assertion),
|
|
2812
2784
|
)
|
|
2813
2785
|
elif method in {"GetTask", "tasks/get"}:
|
|
2814
2786
|
result = await get_task(
|
|
@@ -88,8 +88,8 @@ PATH_IDENTIFIER_PATTERN = re.compile(
|
|
|
88
88
|
r"(?<=/)(?:[0-9a-f]{8}-[0-9a-f-]{27,}|[0-9]+)(?=/|$)",
|
|
89
89
|
re.IGNORECASE,
|
|
90
90
|
)
|
|
91
|
-
# A
|
|
92
|
-
#
|
|
91
|
+
# A delegated call names the session the runtime is serving and proves the runtime's lease on it,
|
|
92
|
+
# beside the runtime's own credential. The platform finds the person in its own record of that
|
|
93
93
|
# session's active turn or Task attempt: the call never names a person.
|
|
94
94
|
ACTING_FOR_SESSION_HEADER = "X-MainSequence-Acting-For-Session"
|
|
95
95
|
LEASE_HOLDER_HEADER = "X-MainSequence-Lease-Holder"
|
|
@@ -119,7 +119,7 @@ def _field_error_paths(value: object, *, prefix: str = "") -> list[str]:
|
|
|
119
119
|
|
|
120
120
|
@dataclass(frozen=True, slots=True)
|
|
121
121
|
class LeaseProof:
|
|
122
|
-
"""The session a
|
|
122
|
+
"""The session a delegated call serves, and the runtime's lease on that session."""
|
|
123
123
|
|
|
124
124
|
session_uid: str
|
|
125
125
|
holder_id: str
|
|
@@ -601,14 +601,18 @@ class MainSequenceClient:
|
|
|
601
601
|
self,
|
|
602
602
|
release_uid: str,
|
|
603
603
|
*,
|
|
604
|
-
proof: LeaseProof,
|
|
604
|
+
proof: LeaseProof | None,
|
|
605
605
|
) -> ReleaseRuntimeAccess:
|
|
606
|
-
"""Obtain access to an application release
|
|
606
|
+
"""Obtain access to an application release.
|
|
607
|
+
|
|
608
|
+
With ``proof`` the call carries the delegation of the person the turn serves, and the
|
|
609
|
+
token acts for that person. Without it the token is the runtime's own.
|
|
610
|
+
"""
|
|
607
611
|
|
|
608
612
|
data = await self._request(
|
|
609
613
|
"POST",
|
|
610
614
|
resource_release_runtime_access(release_uid),
|
|
611
|
-
headers=proof.headers(),
|
|
615
|
+
headers=proof.headers() if proof is not None else None,
|
|
612
616
|
)
|
|
613
617
|
try:
|
|
614
618
|
return ReleaseRuntimeAccess.model_validate(data)
|
|
@@ -617,12 +621,12 @@ class MainSequenceClient:
|
|
|
617
621
|
# Raised outside the handler: a validation error repeats its input, which holds the token.
|
|
618
622
|
raise BackendError("Backend release access response is invalid")
|
|
619
623
|
|
|
620
|
-
async def
|
|
624
|
+
async def platform_request(
|
|
621
625
|
self,
|
|
622
626
|
method: str,
|
|
623
627
|
path: str,
|
|
624
628
|
*,
|
|
625
|
-
proof: LeaseProof,
|
|
629
|
+
proof: LeaseProof | None,
|
|
626
630
|
params: Any = None,
|
|
627
631
|
json: Any = None,
|
|
628
632
|
content: bytes | str | None = None,
|
|
@@ -630,11 +634,12 @@ class MainSequenceClient:
|
|
|
630
634
|
files: Any = None,
|
|
631
635
|
headers: Mapping[str, str] | None = None,
|
|
632
636
|
) -> httpx.Response:
|
|
633
|
-
"""Send one
|
|
637
|
+
"""Send one call to a platform path, with the runtime's own credential.
|
|
634
638
|
|
|
635
|
-
``
|
|
636
|
-
|
|
637
|
-
|
|
639
|
+
With ``proof`` the call also carries the delegation of the person the turn serves. ``path``
|
|
640
|
+
is relative to the configured platform base URL, and the call never leaves that origin or
|
|
641
|
+
follows a redirect. The answer is returned on a copy of the request that carries no header,
|
|
642
|
+
so neither the credential nor the lease proof travels with it.
|
|
638
643
|
"""
|
|
639
644
|
|
|
640
645
|
base = httpx.URL(self.settings.backend_url)
|
|
@@ -644,7 +649,8 @@ class MainSequenceClient:
|
|
|
644
649
|
base.host,
|
|
645
650
|
base.port,
|
|
646
651
|
):
|
|
647
|
-
raise ValueError("A
|
|
652
|
+
raise ValueError("A platform call takes a path on the platform's base URL")
|
|
653
|
+
delegation = proof.headers() if proof is not None else {}
|
|
648
654
|
force_auth = False
|
|
649
655
|
operation = _dependency_operation(method, path)
|
|
650
656
|
while True:
|
|
@@ -661,7 +667,7 @@ class MainSequenceClient:
|
|
|
661
667
|
files=files,
|
|
662
668
|
headers={
|
|
663
669
|
**dict(headers or {}),
|
|
664
|
-
**
|
|
670
|
+
**delegation,
|
|
665
671
|
**await self.auth.headers(force=force_auth),
|
|
666
672
|
},
|
|
667
673
|
follow_redirects=False,
|
|
@@ -671,22 +677,22 @@ class MainSequenceClient:
|
|
|
671
677
|
if failure:
|
|
672
678
|
logger.warning(
|
|
673
679
|
"dependency.call.failed",
|
|
674
|
-
message="
|
|
680
|
+
message="Platform call failed",
|
|
675
681
|
dependency_operation=operation,
|
|
676
682
|
target_system="mainsequence_backend",
|
|
677
|
-
requester_bound=
|
|
683
|
+
requester_bound=proof is not None,
|
|
678
684
|
duration_ms=round((time.monotonic() - started_at) * 1000, 3),
|
|
679
685
|
error_type=failure,
|
|
680
686
|
outcome="failed",
|
|
681
687
|
)
|
|
682
688
|
# Raised outside the handler: the error holds the request and its credentials.
|
|
683
|
-
raise BackendError(f"
|
|
689
|
+
raise BackendError(f"Platform call failed: {failure}")
|
|
684
690
|
logger.info(
|
|
685
691
|
"dependency.call.completed",
|
|
686
|
-
message="
|
|
692
|
+
message="Platform call completed",
|
|
687
693
|
dependency_operation=operation,
|
|
688
694
|
target_system="mainsequence_backend",
|
|
689
|
-
requester_bound=
|
|
695
|
+
requester_bound=proof is not None,
|
|
690
696
|
status_code=response.status_code,
|
|
691
697
|
duration_ms=round((time.monotonic() - started_at) * 1000, 3),
|
|
692
698
|
outcome=(
|