muse-code-sdk 1.4.12__tar.gz → 1.4.14__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.
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/PKG-INFO +43 -2
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/README.md +41 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/pyproject.toml +2 -2
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/src/muse_code/__init__.py +2 -2
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/src/muse_code/facade/approval.py +5 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/src/muse_code/facade/client.py +14 -4
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/src/muse_code_sdk.egg-info/PKG-INFO +43 -2
- muse_code_sdk-1.4.14/src/muse_code_sdk.egg-info/requires.txt +2 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_facade_approval.py +32 -0
- muse_code_sdk-1.4.12/src/muse_code_sdk.egg-info/requires.txt +0 -2
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/LICENSE +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/setup.cfg +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/src/muse_code/connection/__init__.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/src/muse_code/connection/connection.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/src/muse_code/connection/discovery.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/src/muse_code/connection/spawn.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/src/muse_code/connection/validation.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/src/muse_code/errors.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/src/muse_code/facade/__init__.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/src/muse_code/facade/discarded.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/src/muse_code/facade/gap_fill.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/src/muse_code/facade/host_death.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/src/muse_code/facade/host_start.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/src/muse_code/facade/session.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/src/muse_code/facade/turn_handle.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/src/muse_code/facade/turn_submit.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/src/muse_code/fold/__init__.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/src/muse_code/fold/item_store.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/src/muse_code/fold/session_fold.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/src/muse_code/fold/state_store.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/src/muse_code/pending/__init__.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/src/muse_code/pending/pending_command_set.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/src/muse_code/py.typed +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/src/muse_code/replay.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/src/muse_code/sync_facade.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/src/muse_code_sdk.egg-info/SOURCES.txt +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/src/muse_code_sdk.egg-info/dependency_links.txt +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/src/muse_code_sdk.egg-info/top_level.txt +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_asyncio_cancellation.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_compatibility_row.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_connection.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_connection_error_arms.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_docs_generation.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_external_audience.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_facade_approval_resend.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_facade_gap_fill.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_facade_open_same_chunk.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_facade_persistent_approval.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_facade_required_selection.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_facade_turn.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_facade_user_input_resend.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_host_discovery.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_item_store.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_manifests.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_muse_serve_child.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_pending_command_corpus.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_pending_command_set.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_pending_command_wire_binding.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_permission_state_wire_types.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_public_mirror_text.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_publish_shape.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_recovery_observation.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_session_fold.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_source_closure.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_spawn_handshake.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_spawn_host_lost.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_state_store.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_sync_facade.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_tolerance_corpus.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_transcript_replay.py +0 -0
- {muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/tests/test_typing_gates.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: muse-code-sdk
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.14
|
|
4
4
|
Summary: Muse Code SDK for MSP: asyncio-first facade over the generated wire types (muse-code-msp), with a thin sync wrapper.
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Project-URL: Homepage, https://github.com/meta-models/muse-code-sdk
|
|
@@ -15,7 +15,7 @@ Requires-Python: >=3.10
|
|
|
15
15
|
Description-Content-Type: text/markdown
|
|
16
16
|
License-File: LICENSE
|
|
17
17
|
Requires-Dist: pydantic==2.13.5
|
|
18
|
-
Requires-Dist: muse-code-msp==1.4.
|
|
18
|
+
Requires-Dist: muse-code-msp==1.4.14
|
|
19
19
|
Dynamic: license-file
|
|
20
20
|
|
|
21
21
|
# `muse-code-sdk`
|
|
@@ -84,6 +84,47 @@ async def main() -> None:
|
|
|
84
84
|
asyncio.run(main())
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
+
To run a session and the child agents it starts without approval prompts,
|
|
88
|
+
start it under the built-in `:unrestricted` permission profile. Current
|
|
89
|
+
releases admit every child of such a session without prompts; a child admitted
|
|
90
|
+
with a narrower authority would stay gated at it.
|
|
91
|
+
|
|
92
|
+
That profile is described, verbatim, as "No filesystem sandbox or approval
|
|
93
|
+
prompts; local commands have direct network access; project trust is
|
|
94
|
+
unchanged." It also sets the approval reviewer to none. Use it only for a
|
|
95
|
+
trusted workspace and trusted prompts. Never use it where the prompts or the
|
|
96
|
+
sandbox are what protects you.
|
|
97
|
+
|
|
98
|
+
Start it with that profile, and pass the same profile when you resume it.
|
|
99
|
+
Paste inside `main()` above, indented, before `await client.close()`, with the same client:
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from muse_code import ResumeSessionOptions, StartSessionOptions
|
|
103
|
+
|
|
104
|
+
session = await client.start_session(StartSessionOptions(
|
|
105
|
+
workspace_root="/path/to/repo", # an absolute path
|
|
106
|
+
permission_profile=":unrestricted",
|
|
107
|
+
))
|
|
108
|
+
saved_session_id = session.session_id
|
|
109
|
+
# ... later, in the same client:
|
|
110
|
+
session = await client.resume_session(ResumeSessionOptions(
|
|
111
|
+
session_id=saved_session_id,
|
|
112
|
+
permission_profile=":unrestricted",
|
|
113
|
+
))
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
On start, `require_permission_profile=True` makes the client prove that the
|
|
117
|
+
pick was applied, and raise `PermissionProfileNotApplied` if it cannot (a
|
|
118
|
+
failed `session/read` read-back raises its own error). A host
|
|
119
|
+
that does not report the committed selection fails that proof even when the
|
|
120
|
+
pick was applied (seen with Muse Code 1.4.12). Resume has no
|
|
121
|
+
`require_permission_profile`, so the client never verifies the pick there.
|
|
122
|
+
|
|
123
|
+
`approval_mode` alone is not enough: it changes the session's own approval
|
|
124
|
+
mode, but its child agents are capped by the session's permission profile.
|
|
125
|
+
Under a prompting profile (such as `:ask-me`, whose approval is `on_request`),
|
|
126
|
+
the children still ask.
|
|
127
|
+
|
|
87
128
|
## Documentation
|
|
88
129
|
|
|
89
130
|
- Guides, cookbook recipes, and the protocol reference:
|
|
@@ -64,6 +64,47 @@ async def main() -> None:
|
|
|
64
64
|
asyncio.run(main())
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
+
To run a session and the child agents it starts without approval prompts,
|
|
68
|
+
start it under the built-in `:unrestricted` permission profile. Current
|
|
69
|
+
releases admit every child of such a session without prompts; a child admitted
|
|
70
|
+
with a narrower authority would stay gated at it.
|
|
71
|
+
|
|
72
|
+
That profile is described, verbatim, as "No filesystem sandbox or approval
|
|
73
|
+
prompts; local commands have direct network access; project trust is
|
|
74
|
+
unchanged." It also sets the approval reviewer to none. Use it only for a
|
|
75
|
+
trusted workspace and trusted prompts. Never use it where the prompts or the
|
|
76
|
+
sandbox are what protects you.
|
|
77
|
+
|
|
78
|
+
Start it with that profile, and pass the same profile when you resume it.
|
|
79
|
+
Paste inside `main()` above, indented, before `await client.close()`, with the same client:
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
from muse_code import ResumeSessionOptions, StartSessionOptions
|
|
83
|
+
|
|
84
|
+
session = await client.start_session(StartSessionOptions(
|
|
85
|
+
workspace_root="/path/to/repo", # an absolute path
|
|
86
|
+
permission_profile=":unrestricted",
|
|
87
|
+
))
|
|
88
|
+
saved_session_id = session.session_id
|
|
89
|
+
# ... later, in the same client:
|
|
90
|
+
session = await client.resume_session(ResumeSessionOptions(
|
|
91
|
+
session_id=saved_session_id,
|
|
92
|
+
permission_profile=":unrestricted",
|
|
93
|
+
))
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
On start, `require_permission_profile=True` makes the client prove that the
|
|
97
|
+
pick was applied, and raise `PermissionProfileNotApplied` if it cannot (a
|
|
98
|
+
failed `session/read` read-back raises its own error). A host
|
|
99
|
+
that does not report the committed selection fails that proof even when the
|
|
100
|
+
pick was applied (seen with Muse Code 1.4.12). Resume has no
|
|
101
|
+
`require_permission_profile`, so the client never verifies the pick there.
|
|
102
|
+
|
|
103
|
+
`approval_mode` alone is not enough: it changes the session's own approval
|
|
104
|
+
mode, but its child agents are capped by the session's permission profile.
|
|
105
|
+
Under a prompting profile (such as `:ask-me`, whose approval is `on_request`),
|
|
106
|
+
the children still ask.
|
|
107
|
+
|
|
67
108
|
## Documentation
|
|
68
109
|
|
|
69
110
|
- Guides, cookbook recipes, and the protocol reference:
|
|
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
|
|
|
5
5
|
|
|
6
6
|
[project]
|
|
7
7
|
name = "muse-code-sdk"
|
|
8
|
-
version = "1.4.
|
|
8
|
+
version = "1.4.14"
|
|
9
9
|
description = "Muse Code SDK for MSP: asyncio-first facade over the generated wire types (muse-code-msp), with a thin sync wrapper."
|
|
10
10
|
readme = "README.md"
|
|
11
11
|
requires-python = ">=3.10"
|
|
@@ -18,7 +18,7 @@ license-files = ["LICENSE"]
|
|
|
18
18
|
# `pip install muse-code-sdk` must import, and the release bump moves this
|
|
19
19
|
# package's version and its muse-code-msp pin together; pydantic bumps stay
|
|
20
20
|
# reviewed PRs (test_publish_shape pins the pairing).
|
|
21
|
-
dependencies = ["pydantic==2.13.5", "muse-code-msp==1.4.
|
|
21
|
+
dependencies = ["pydantic==2.13.5", "muse-code-msp==1.4.14"]
|
|
22
22
|
classifiers = [
|
|
23
23
|
# Alpha states the withheld promise: publication is permitted, but the
|
|
24
24
|
# stability promise and conformance claim stay withheld — experimental
|
|
@@ -80,7 +80,7 @@ __all__ = [
|
|
|
80
80
|
]
|
|
81
81
|
|
|
82
82
|
EXPECTED_SCHEMA_FINGERPRINT: Final[str] = (
|
|
83
|
-
"sha256:
|
|
83
|
+
"sha256:c94c3d1f2f51e6424074b9ec43eac3eedcf532d3dcd77351ec1383a87d3049c6"
|
|
84
84
|
)
|
|
85
85
|
"""The stable schema-bundle fingerprint this SDK was built against.
|
|
86
86
|
|
|
@@ -92,7 +92,7 @@ Python SDK reds this lane instead of drifting silently.
|
|
|
92
92
|
# The lockstep rule: the release train bumps pyproject.toml, the
|
|
93
93
|
# distribution-metadata authority; this constant is aligned at publication
|
|
94
94
|
# time.
|
|
95
|
-
__version__: Final[str] = "1.4.
|
|
95
|
+
__version__: Final[str] = "1.4.14"
|
|
96
96
|
|
|
97
97
|
# The facade is imported last so the constants above are already bound: the
|
|
98
98
|
# spawn path reads ``EXPECTED_SCHEMA_FINGERPRINT`` (lazily, at initialize
|
|
@@ -66,6 +66,7 @@ _REFRESH_FROM_REQUEST = frozenset(
|
|
|
66
66
|
"judgeEscalated",
|
|
67
67
|
"protectedWrite",
|
|
68
68
|
"rawArgs",
|
|
69
|
+
"reviewerReason",
|
|
69
70
|
"taskId",
|
|
70
71
|
"toolCallId",
|
|
71
72
|
"toolName",
|
|
@@ -302,6 +303,10 @@ class ApprovalRouter:
|
|
|
302
303
|
# the retained request across stages.
|
|
303
304
|
if "cuaCardFacts" in requested:
|
|
304
305
|
refreshed["cuaCardFacts"] = requested["cuaCardFacts"]
|
|
306
|
+
# The escalation reason belongs to the call, so it stays with the
|
|
307
|
+
# retained request across stages.
|
|
308
|
+
if "reviewerReason" in requested:
|
|
309
|
+
refreshed["reviewerReason"] = requested["reviewerReason"]
|
|
305
310
|
acked = self._in_flight.get(requested["approvalId"])
|
|
306
311
|
if acked is not None:
|
|
307
312
|
return self._after_ack(acked, refreshed)
|
|
@@ -80,7 +80,8 @@ class StartSessionOptions:
|
|
|
80
80
|
"""Caller-facing options for ``session/start``.
|
|
81
81
|
|
|
82
82
|
Composed from the generated ``SessionStartParams``. ``config`` is excluded as well as ``commandId`` until the facade
|
|
83
|
-
implements the required ``sessionMcp`` grant check and forwarding
|
|
83
|
+
implements the required ``sessionMcp`` grant check and forwarding; ``previousSessionId`` is excluded because the
|
|
84
|
+
facade starts root sessions, and ``spawnedBy`` because the facade does not expose a spawner yet.
|
|
84
85
|
|
|
85
86
|
Attributes:
|
|
86
87
|
approval_mode: The approval enforcement mode to start under; omitted
|
|
@@ -139,6 +140,9 @@ class ResumeSessionOptions:
|
|
|
139
140
|
wire's ``permissionProfile`` member: the host restores the
|
|
140
141
|
retained authority first, then applies the pick. Omitted means
|
|
141
142
|
no override.
|
|
143
|
+
model_id: The model override forwarded as the wire's ``modelId``
|
|
144
|
+
member: the host applies it after the warm pick, before
|
|
145
|
+
enrichments. Omitted means no override.
|
|
142
146
|
recovery_mode: Optional recovery selection (wire ``recoveryMode``);
|
|
143
147
|
omitted means no selection is sent.
|
|
144
148
|
on_approval: Answers this session's approvals from its first frame,
|
|
@@ -158,6 +162,7 @@ class ResumeSessionOptions:
|
|
|
158
162
|
exclude_items: bool | None = None
|
|
159
163
|
history: Mapping[str, Any] | None = None
|
|
160
164
|
permission_profile: str | None = None
|
|
165
|
+
model_id: str | None = None
|
|
161
166
|
recovery_mode: RecoveryMode | None = None
|
|
162
167
|
on_approval: ApprovalHandler | None = None
|
|
163
168
|
on_approval_error: ApprovalFailureHandler | None = None
|
|
@@ -168,12 +173,15 @@ class ResumeSessionOptions:
|
|
|
168
173
|
# generated params but not to the options dataclass reds THIS import (and thus
|
|
169
174
|
# every test), so a regenerated member cannot silently fail to reach the wire.
|
|
170
175
|
# The excluded members are the ones the facade owns rather than forwards:
|
|
171
|
-
# `commandId` (the connection is the single minter)
|
|
172
|
-
# (temporarily withheld until capability-checked forwarding lands)
|
|
176
|
+
# `commandId` (the connection is the single minter), `config`
|
|
177
|
+
# (temporarily withheld until capability-checked forwarding lands) and
|
|
178
|
+
# `previousSessionId` (the facade starts root sessions; the predecessor link
|
|
179
|
+
# belongs to a client that switches sessions) and `spawnedBy` (the facade
|
|
180
|
+
# does not expose a spawner yet). The owned
|
|
173
181
|
# members are options-only posture the wire never carries (client-local
|
|
174
182
|
# `requirePermissionProfile`, the required-selection check): subtracted from
|
|
175
183
|
# the options side, so a regen that adds a same-named wire member reds here.
|
|
176
|
-
_START_EXCLUDED = {"commandId", "config"}
|
|
184
|
+
_START_EXCLUDED = {"commandId", "config", "previousSessionId", "spawnedBy"}
|
|
177
185
|
_START_OWNED = {"requirePermissionProfile"}
|
|
178
186
|
assert (
|
|
179
187
|
{_camel(f.name) for f in fields(StartSessionOptions)} - _START_OWNED
|
|
@@ -521,6 +529,8 @@ class MuseClient(Generic[_I]):
|
|
|
521
529
|
params["excludeItems"] = options.exclude_items
|
|
522
530
|
if options.history is not None:
|
|
523
531
|
params["history"] = options.history
|
|
532
|
+
if options.model_id is not None:
|
|
533
|
+
params["modelId"] = options.model_id
|
|
524
534
|
if options.recovery_mode is not None:
|
|
525
535
|
params["recoveryMode"] = options.recovery_mode
|
|
526
536
|
if options.permission_profile is not None:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: muse-code-sdk
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.14
|
|
4
4
|
Summary: Muse Code SDK for MSP: asyncio-first facade over the generated wire types (muse-code-msp), with a thin sync wrapper.
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Project-URL: Homepage, https://github.com/meta-models/muse-code-sdk
|
|
@@ -15,7 +15,7 @@ Requires-Python: >=3.10
|
|
|
15
15
|
Description-Content-Type: text/markdown
|
|
16
16
|
License-File: LICENSE
|
|
17
17
|
Requires-Dist: pydantic==2.13.5
|
|
18
|
-
Requires-Dist: muse-code-msp==1.4.
|
|
18
|
+
Requires-Dist: muse-code-msp==1.4.14
|
|
19
19
|
Dynamic: license-file
|
|
20
20
|
|
|
21
21
|
# `muse-code-sdk`
|
|
@@ -84,6 +84,47 @@ async def main() -> None:
|
|
|
84
84
|
asyncio.run(main())
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
+
To run a session and the child agents it starts without approval prompts,
|
|
88
|
+
start it under the built-in `:unrestricted` permission profile. Current
|
|
89
|
+
releases admit every child of such a session without prompts; a child admitted
|
|
90
|
+
with a narrower authority would stay gated at it.
|
|
91
|
+
|
|
92
|
+
That profile is described, verbatim, as "No filesystem sandbox or approval
|
|
93
|
+
prompts; local commands have direct network access; project trust is
|
|
94
|
+
unchanged." It also sets the approval reviewer to none. Use it only for a
|
|
95
|
+
trusted workspace and trusted prompts. Never use it where the prompts or the
|
|
96
|
+
sandbox are what protects you.
|
|
97
|
+
|
|
98
|
+
Start it with that profile, and pass the same profile when you resume it.
|
|
99
|
+
Paste inside `main()` above, indented, before `await client.close()`, with the same client:
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from muse_code import ResumeSessionOptions, StartSessionOptions
|
|
103
|
+
|
|
104
|
+
session = await client.start_session(StartSessionOptions(
|
|
105
|
+
workspace_root="/path/to/repo", # an absolute path
|
|
106
|
+
permission_profile=":unrestricted",
|
|
107
|
+
))
|
|
108
|
+
saved_session_id = session.session_id
|
|
109
|
+
# ... later, in the same client:
|
|
110
|
+
session = await client.resume_session(ResumeSessionOptions(
|
|
111
|
+
session_id=saved_session_id,
|
|
112
|
+
permission_profile=":unrestricted",
|
|
113
|
+
))
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
On start, `require_permission_profile=True` makes the client prove that the
|
|
117
|
+
pick was applied, and raise `PermissionProfileNotApplied` if it cannot (a
|
|
118
|
+
failed `session/read` read-back raises its own error). A host
|
|
119
|
+
that does not report the committed selection fails that proof even when the
|
|
120
|
+
pick was applied (seen with Muse Code 1.4.12). Resume has no
|
|
121
|
+
`require_permission_profile`, so the client never verifies the pick there.
|
|
122
|
+
|
|
123
|
+
`approval_mode` alone is not enough: it changes the session's own approval
|
|
124
|
+
mode, but its child agents are capped by the session's permission profile.
|
|
125
|
+
Under a prompting profile (such as `:ask-me`, whose approval is `on_request`),
|
|
126
|
+
the children still ask.
|
|
127
|
+
|
|
87
128
|
## Documentation
|
|
88
129
|
|
|
89
130
|
- Guides, cookbook recipes, and the protocol reference:
|
|
@@ -734,6 +734,38 @@ async def test_a_stage_advance_keeps_the_requests_cua_card_facts(facts: Any) ->
|
|
|
734
734
|
await settled_io(updated.io)
|
|
735
735
|
|
|
736
736
|
|
|
737
|
+
@pytest.mark.asyncio
|
|
738
|
+
@pytest.mark.parametrize("reason", ["pipes a downloaded script into sh", None])
|
|
739
|
+
async def test_a_stage_advance_keeps_the_requests_reviewer_reason(reason: Any) -> None:
|
|
740
|
+
# `reviewerReason` belongs to the call and `approval/updated` doesn't
|
|
741
|
+
# carry it, so the refreshed stage-2 request keeps the original request's
|
|
742
|
+
# reason, and a request without one stays without the key.
|
|
743
|
+
transport, session, minted = wired()
|
|
744
|
+
seen: List[Params] = []
|
|
745
|
+
|
|
746
|
+
def handler(request: Any) -> ApprovalDecisionInput:
|
|
747
|
+
seen.append(dict(request))
|
|
748
|
+
return ApprovalDecisionInput(choice_id="allow_once")
|
|
749
|
+
|
|
750
|
+
session.on_approval(handler)
|
|
751
|
+
overrides: Params = {} if reason is None else {"reviewerReason": reason}
|
|
752
|
+
first = session.apply(approval_requested(**overrides))
|
|
753
|
+
await wait_for_writes(transport, 1)
|
|
754
|
+
answer(transport, 0, {**decide_result("mint-0"), "terminal": False})
|
|
755
|
+
await settled_io(first.io)
|
|
756
|
+
|
|
757
|
+
updated = session.apply(stage_resolved(2, CHOICES))
|
|
758
|
+
await wait_for_writes(transport, 2)
|
|
759
|
+
assert minted == ["mint-0", "mint-1"]
|
|
760
|
+
assert len(seen) == 2
|
|
761
|
+
if reason is None:
|
|
762
|
+
assert "reviewerReason" not in seen[1]
|
|
763
|
+
else:
|
|
764
|
+
assert seen[1]["reviewerReason"] == reason
|
|
765
|
+
answer(transport, 1, decide_result("mint-1"))
|
|
766
|
+
await settled_io(updated.io)
|
|
767
|
+
|
|
768
|
+
|
|
737
769
|
@pytest.mark.asyncio
|
|
738
770
|
async def test_an_approval_updated_naming_the_decided_stage_asks_nothing() -> None:
|
|
739
771
|
# The per-stage latch: an update that still names the stage this client
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{muse_code_sdk-1.4.12 → muse_code_sdk-1.4.14}/src/muse_code_sdk.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|