muse-code-sdk 1.4.14__tar.gz → 1.4.15__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.14 → muse_code_sdk-1.4.15}/PKG-INFO +41 -13
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/README.md +39 -11
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/pyproject.toml +2 -2
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/src/muse_code/__init__.py +21 -7
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/src/muse_code/connection/discovery.py +5 -4
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/src/muse_code/errors.py +50 -3
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/src/muse_code/facade/__init__.py +6 -2
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/src/muse_code/facade/client.py +223 -25
- muse_code_sdk-1.4.15/src/muse_code/facade/run.py +208 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/src/muse_code/facade/session.py +473 -8
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/src/muse_code/facade/turn_handle.py +126 -10
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/src/muse_code/facade/turn_submit.py +129 -28
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/src/muse_code/fold/session_fold.py +76 -5
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/src/muse_code/sync_facade.py +255 -6
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/src/muse_code_sdk.egg-info/PKG-INFO +41 -13
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/src/muse_code_sdk.egg-info/SOURCES.txt +11 -0
- muse_code_sdk-1.4.15/src/muse_code_sdk.egg-info/requires.txt +2 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_compatibility_row.py +245 -25
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_external_audience.py +23 -0
- muse_code_sdk-1.4.15/tests/test_facade_control_verbs.py +709 -0
- muse_code_sdk-1.4.15/tests/test_facade_raw_command.py +162 -0
- muse_code_sdk-1.4.15/tests/test_facade_run.py +719 -0
- muse_code_sdk-1.4.15/tests/test_facade_session_mcp.py +211 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_facade_turn.py +38 -0
- muse_code_sdk-1.4.15/tests/test_facade_unqueue_retirement.py +238 -0
- muse_code_sdk-1.4.15/tests/test_facade_wire_queries.py +317 -0
- muse_code_sdk-1.4.15/tests/test_fingerprint_vectors.py +86 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_host_discovery.py +98 -1
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_manifests.py +35 -12
- muse_code_sdk-1.4.15/tests/test_msp_py_fingerprint_derivation.py +490 -0
- muse_code_sdk-1.4.15/tests/test_msp_py_host_version_derivation.py +274 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_public_mirror_text.py +4 -1
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_publish_shape.py +1 -1
- muse_code_sdk-1.4.15/tests/test_run_abort_busy_unqueue_real_binary.py +491 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_session_fold.py +155 -3
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_source_closure.py +5 -3
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_sync_facade.py +45 -38
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_typing_gates.py +71 -0
- muse_code_sdk-1.4.14/src/muse_code_sdk.egg-info/requires.txt +0 -2
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/LICENSE +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/setup.cfg +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/src/muse_code/connection/__init__.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/src/muse_code/connection/connection.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/src/muse_code/connection/spawn.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/src/muse_code/connection/validation.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/src/muse_code/facade/approval.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/src/muse_code/facade/discarded.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/src/muse_code/facade/gap_fill.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/src/muse_code/facade/host_death.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/src/muse_code/facade/host_start.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/src/muse_code/fold/__init__.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/src/muse_code/fold/item_store.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/src/muse_code/fold/state_store.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/src/muse_code/pending/__init__.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/src/muse_code/pending/pending_command_set.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/src/muse_code/py.typed +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/src/muse_code/replay.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/src/muse_code_sdk.egg-info/dependency_links.txt +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/src/muse_code_sdk.egg-info/top_level.txt +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_asyncio_cancellation.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_connection.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_connection_error_arms.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_docs_generation.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_facade_approval.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_facade_approval_resend.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_facade_gap_fill.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_facade_open_same_chunk.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_facade_persistent_approval.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_facade_required_selection.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_facade_user_input_resend.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_item_store.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_muse_serve_child.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_pending_command_corpus.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_pending_command_set.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_pending_command_wire_binding.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_permission_state_wire_types.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_recovery_observation.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_spawn_handshake.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_spawn_host_lost.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_state_store.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_tolerance_corpus.py +0 -0
- {muse_code_sdk-1.4.14 → muse_code_sdk-1.4.15}/tests/test_transcript_replay.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.15
|
|
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.15
|
|
19
19
|
Dynamic: license-file
|
|
20
20
|
|
|
21
21
|
# `muse-code-sdk`
|
|
@@ -61,29 +61,57 @@ path passed at spawn time.
|
|
|
61
61
|
```python
|
|
62
62
|
import asyncio
|
|
63
63
|
|
|
64
|
-
from muse_code import
|
|
65
|
-
MuseClient, MuseClientSpawnOptions, SendUserTurnOptions, StartSessionOptions,
|
|
66
|
-
)
|
|
64
|
+
from muse_code import MuseClient, MuseClientSpawnOptions, StartSessionOptions
|
|
67
65
|
|
|
68
66
|
async def main() -> None:
|
|
69
67
|
client = await MuseClient.spawn(MuseClientSpawnOptions(
|
|
70
|
-
muse_bin=
|
|
68
|
+
muse_bin=None, # None finds `muse` on PATH; or pass a path
|
|
71
69
|
args=["serve"],
|
|
72
70
|
client_info={"name": "my-app", "version": "1.0.0"},
|
|
73
71
|
))
|
|
74
72
|
session = await client.start_session(StartSessionOptions(workspace_root="."))
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
composer_input="Summarize this repository.",
|
|
78
|
-
))
|
|
79
|
-
async for item in turn.items():
|
|
80
|
-
print(item)
|
|
81
|
-
await turn.completed
|
|
73
|
+
result = await session.run("Summarize this repository.")
|
|
74
|
+
print(result.final_text)
|
|
82
75
|
await client.close()
|
|
83
76
|
|
|
84
77
|
asyncio.run(main())
|
|
85
78
|
```
|
|
86
79
|
|
|
80
|
+
`session.run` sends one turn and returns when the turn has ended, with the
|
|
81
|
+
outcome, the final answer text, the turn's items, and its token usage. A turn
|
|
82
|
+
that failed or was cancelled still returns; read `result.outcome` to tell. The
|
|
83
|
+
final answer is the last completed agent message that is not commentary. Pass a
|
|
84
|
+
list of input parts instead of a string, and turn options as keywords:
|
|
85
|
+
`await session.run(parts, reasoning_effort="high")`.
|
|
86
|
+
|
|
87
|
+
To stop it, cancel the task that awaits it, for example with
|
|
88
|
+
`asyncio.timeout(60)` on Python 3.11 or newer. A turn still waiting in the
|
|
89
|
+
queue is taken back, and a running turn is cancelled; `run` then waits for
|
|
90
|
+
the turn to end and re-raises `CancelledError`. `SyncSession.run` is the
|
|
91
|
+
blocking version, with no way to cancel.
|
|
92
|
+
|
|
93
|
+
To follow a turn as it runs, send it yourself and read its items (paste
|
|
94
|
+
inside `main()` above, before `await client.close()`; add
|
|
95
|
+
`SendUserTurnOptions` to the import):
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
turn = await session.send_user_turn(SendUserTurnOptions(
|
|
99
|
+
input=[{"type": "text", "text": "Summarize this repository."}],
|
|
100
|
+
composer_input="Summarize this repository.",
|
|
101
|
+
))
|
|
102
|
+
async for item in turn.items():
|
|
103
|
+
print(item)
|
|
104
|
+
await turn.completed
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
To stop a running turn, `await turn.interrupt()` (the stop gesture; pass
|
|
108
|
+
`retract=True` to also take the prompt back) or `await turn.cancel()`. Both are
|
|
109
|
+
requests: the turn is over when `turn.completed` settles. `turn.steer(...)`
|
|
110
|
+
adds input to the running turn, and `turn.unqueue()` takes back a queued one.
|
|
111
|
+
The session itself can `fork`, `compact`, `rename`, and `leave`, and switch its
|
|
112
|
+
model, reasoning effort, or approval mode (`set_model`, `set_reasoning_effort`,
|
|
113
|
+
`set_approval_mode`); `client.list_models()` lists the models it accepts.
|
|
114
|
+
|
|
87
115
|
To run a session and the child agents it starts without approval prompts,
|
|
88
116
|
start it under the built-in `:unrestricted` permission profile. Current
|
|
89
117
|
releases admit every child of such a session without prompts; a child admitted
|
|
@@ -41,29 +41,57 @@ path passed at spawn time.
|
|
|
41
41
|
```python
|
|
42
42
|
import asyncio
|
|
43
43
|
|
|
44
|
-
from muse_code import
|
|
45
|
-
MuseClient, MuseClientSpawnOptions, SendUserTurnOptions, StartSessionOptions,
|
|
46
|
-
)
|
|
44
|
+
from muse_code import MuseClient, MuseClientSpawnOptions, StartSessionOptions
|
|
47
45
|
|
|
48
46
|
async def main() -> None:
|
|
49
47
|
client = await MuseClient.spawn(MuseClientSpawnOptions(
|
|
50
|
-
muse_bin=
|
|
48
|
+
muse_bin=None, # None finds `muse` on PATH; or pass a path
|
|
51
49
|
args=["serve"],
|
|
52
50
|
client_info={"name": "my-app", "version": "1.0.0"},
|
|
53
51
|
))
|
|
54
52
|
session = await client.start_session(StartSessionOptions(workspace_root="."))
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
composer_input="Summarize this repository.",
|
|
58
|
-
))
|
|
59
|
-
async for item in turn.items():
|
|
60
|
-
print(item)
|
|
61
|
-
await turn.completed
|
|
53
|
+
result = await session.run("Summarize this repository.")
|
|
54
|
+
print(result.final_text)
|
|
62
55
|
await client.close()
|
|
63
56
|
|
|
64
57
|
asyncio.run(main())
|
|
65
58
|
```
|
|
66
59
|
|
|
60
|
+
`session.run` sends one turn and returns when the turn has ended, with the
|
|
61
|
+
outcome, the final answer text, the turn's items, and its token usage. A turn
|
|
62
|
+
that failed or was cancelled still returns; read `result.outcome` to tell. The
|
|
63
|
+
final answer is the last completed agent message that is not commentary. Pass a
|
|
64
|
+
list of input parts instead of a string, and turn options as keywords:
|
|
65
|
+
`await session.run(parts, reasoning_effort="high")`.
|
|
66
|
+
|
|
67
|
+
To stop it, cancel the task that awaits it, for example with
|
|
68
|
+
`asyncio.timeout(60)` on Python 3.11 or newer. A turn still waiting in the
|
|
69
|
+
queue is taken back, and a running turn is cancelled; `run` then waits for
|
|
70
|
+
the turn to end and re-raises `CancelledError`. `SyncSession.run` is the
|
|
71
|
+
blocking version, with no way to cancel.
|
|
72
|
+
|
|
73
|
+
To follow a turn as it runs, send it yourself and read its items (paste
|
|
74
|
+
inside `main()` above, before `await client.close()`; add
|
|
75
|
+
`SendUserTurnOptions` to the import):
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
turn = await session.send_user_turn(SendUserTurnOptions(
|
|
79
|
+
input=[{"type": "text", "text": "Summarize this repository."}],
|
|
80
|
+
composer_input="Summarize this repository.",
|
|
81
|
+
))
|
|
82
|
+
async for item in turn.items():
|
|
83
|
+
print(item)
|
|
84
|
+
await turn.completed
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
To stop a running turn, `await turn.interrupt()` (the stop gesture; pass
|
|
88
|
+
`retract=True` to also take the prompt back) or `await turn.cancel()`. Both are
|
|
89
|
+
requests: the turn is over when `turn.completed` settles. `turn.steer(...)`
|
|
90
|
+
adds input to the running turn, and `turn.unqueue()` takes back a queued one.
|
|
91
|
+
The session itself can `fork`, `compact`, `rename`, and `leave`, and switch its
|
|
92
|
+
model, reasoning effort, or approval mode (`set_model`, `set_reasoning_effort`,
|
|
93
|
+
`set_approval_mode`); `client.list_models()` lists the models it accepts.
|
|
94
|
+
|
|
67
95
|
To run a session and the child agents it starts without approval prompts,
|
|
68
96
|
start it under the built-in `:unrestricted` permission profile. Current
|
|
69
97
|
releases admit every child of such a session without prompts; a child admitted
|
|
@@ -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.15"
|
|
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.15"]
|
|
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
|
|
@@ -19,10 +19,15 @@ from __future__ import annotations
|
|
|
19
19
|
|
|
20
20
|
from typing import Final
|
|
21
21
|
|
|
22
|
+
import muse_code_msp
|
|
23
|
+
|
|
22
24
|
from .errors import (
|
|
23
25
|
GapFillFailureReason,
|
|
26
|
+
MuseCapabilityNotGrantedError,
|
|
27
|
+
MuseFacadeOwnedMethodError,
|
|
24
28
|
MuseForeignSessionError,
|
|
25
29
|
MuseGapFillError,
|
|
30
|
+
MuseHostDiscoveryError,
|
|
26
31
|
MuseSessionDiscardedError,
|
|
27
32
|
PermissionProfileNotApplied,
|
|
28
33
|
)
|
|
@@ -42,18 +47,22 @@ __all__ = [
|
|
|
42
47
|
"HostDeathDischarge",
|
|
43
48
|
"HostDeathNotification",
|
|
44
49
|
"ItemStore",
|
|
50
|
+
"MuseCapabilityNotGrantedError",
|
|
45
51
|
"MuseClient",
|
|
46
52
|
"MuseClientOptions",
|
|
47
53
|
"MuseClientSpawnOptions",
|
|
54
|
+
"MuseFacadeOwnedMethodError",
|
|
48
55
|
"MuseForeignSessionError",
|
|
49
56
|
"MuseGapFillError",
|
|
50
57
|
"MuseHostDiedError",
|
|
58
|
+
"MuseHostDiscoveryError",
|
|
51
59
|
"MuseHostStartError",
|
|
52
60
|
"MuseSessionDiscardedError",
|
|
53
61
|
"PendingCommandSet",
|
|
54
62
|
"PendingCommandView",
|
|
55
63
|
"PermissionProfileNotApplied",
|
|
56
64
|
"ResumeSessionOptions",
|
|
65
|
+
"RunResult",
|
|
57
66
|
"SendUserTurnOptions",
|
|
58
67
|
"Session",
|
|
59
68
|
"SessionApplyOutcome",
|
|
@@ -64,6 +73,7 @@ __all__ = [
|
|
|
64
73
|
"SessionGapOverlap",
|
|
65
74
|
"SessionStateStore",
|
|
66
75
|
"StartSessionOptions",
|
|
76
|
+
"SteerTurnOptions",
|
|
67
77
|
"SyncMuseClient",
|
|
68
78
|
"SyncSession",
|
|
69
79
|
"SyncTurn",
|
|
@@ -71,6 +81,7 @@ __all__ = [
|
|
|
71
81
|
"TransportEof",
|
|
72
82
|
"Turn",
|
|
73
83
|
"TurnOutcome",
|
|
84
|
+
"TurnUnqueueOutcome",
|
|
74
85
|
"is_abnormal_host_death",
|
|
75
86
|
"is_launch_failure",
|
|
76
87
|
"load_transcript",
|
|
@@ -79,20 +90,20 @@ __all__ = [
|
|
|
79
90
|
"transcript_dirs",
|
|
80
91
|
]
|
|
81
92
|
|
|
82
|
-
EXPECTED_SCHEMA_FINGERPRINT: Final[str] =
|
|
83
|
-
"sha256:c94c3d1f2f51e6424074b9ec43eac3eedcf532d3dcd77351ec1383a87d3049c6"
|
|
84
|
-
)
|
|
93
|
+
EXPECTED_SCHEMA_FINGERPRINT: Final[str] = muse_code_msp.SCHEMA_FINGERPRINT
|
|
85
94
|
"""The stable schema-bundle fingerprint this SDK was built against.
|
|
86
95
|
|
|
87
|
-
|
|
88
|
-
``
|
|
89
|
-
|
|
96
|
+
No second port and no second copy: this is the generated package's stable
|
|
97
|
+
``SCHEMA_FINGERPRINT``, derived at import from the schema bytes. The
|
|
98
|
+
manifests suite binds it to the value derived from the stable bundle, so a
|
|
99
|
+
drift between the port the package vendors and the shared derivation reds
|
|
100
|
+
that lane instead of passing silently.
|
|
90
101
|
"""
|
|
91
102
|
|
|
92
103
|
# The lockstep rule: the release train bumps pyproject.toml, the
|
|
93
104
|
# distribution-metadata authority; this constant is aligned at publication
|
|
94
105
|
# time.
|
|
95
|
-
__version__: Final[str] = "1.4.
|
|
106
|
+
__version__: Final[str] = "1.4.15"
|
|
96
107
|
|
|
97
108
|
# The facade is imported last so the constants above are already bound: the
|
|
98
109
|
# spawn path reads ``EXPECTED_SCHEMA_FINGERPRINT`` (lazily, at initialize
|
|
@@ -114,6 +125,7 @@ from .facade import ( # noqa: E402
|
|
|
114
125
|
MuseHostStartError,
|
|
115
126
|
PendingCommandView,
|
|
116
127
|
ResumeSessionOptions,
|
|
128
|
+
RunResult,
|
|
117
129
|
SendUserTurnOptions,
|
|
118
130
|
Session,
|
|
119
131
|
SessionApplyOutcome,
|
|
@@ -122,9 +134,11 @@ from .facade import ( # noqa: E402
|
|
|
122
134
|
SessionGapBuffered,
|
|
123
135
|
SessionGapOverlap,
|
|
124
136
|
StartSessionOptions,
|
|
137
|
+
SteerTurnOptions,
|
|
125
138
|
TransportEof,
|
|
126
139
|
Turn,
|
|
127
140
|
TurnOutcome,
|
|
141
|
+
TurnUnqueueOutcome,
|
|
128
142
|
is_abnormal_host_death,
|
|
129
143
|
is_launch_failure,
|
|
130
144
|
read_session_durability,
|
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
The wheel carries no host binary and no code path assumes one. Exactly the
|
|
4
4
|
two ruled tiers, first hit wins: an explicit ``muse_bin`` argument, then a
|
|
5
|
-
``muse`` on ``PATH
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
``muse`` on ``PATH`` (the same two tiers as the TS and Rust SDKs, and what
|
|
6
|
+
``MuseClient.spawn`` applies when ``muse_bin`` is ``None``). The LIBRARY reads
|
|
7
|
+
no other environment variable: ``MUSE_BIN`` is a knob of the
|
|
8
|
+
quickstart/cookbook HARNESSES, which read it themselves and pass the explicit
|
|
9
|
+
parameter down. No discoverable host fails BEFORE any process is
|
|
9
10
|
spawned, with an exact error naming the parameter and the compatibility
|
|
10
11
|
page.
|
|
11
12
|
"""
|
|
@@ -115,6 +115,53 @@ class PermissionProfileNotApplied(Exception):
|
|
|
115
115
|
self.session_id: str = session_id
|
|
116
116
|
|
|
117
117
|
|
|
118
|
+
|
|
119
|
+
class MuseFacadeOwnedMethodError(Exception):
|
|
120
|
+
"""``MuseClient.command`` was asked to send a method whose state the
|
|
121
|
+
facade owns. Sending it raw would bypass that state, so it is refused
|
|
122
|
+
before anything is written; use the facade verb instead.
|
|
123
|
+
|
|
124
|
+
Attributes:
|
|
125
|
+
method: The refused wire method.
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
def __init__(self, method: str) -> None:
|
|
129
|
+
"""Builds the refusal.
|
|
130
|
+
|
|
131
|
+
Args:
|
|
132
|
+
method: The refused wire method.
|
|
133
|
+
"""
|
|
134
|
+
super().__init__(
|
|
135
|
+
f"{method} is sent by the facade itself and cannot go through "
|
|
136
|
+
"MuseClient.command; use the facade verb that owns it"
|
|
137
|
+
)
|
|
138
|
+
self.method: str = method
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class MuseCapabilityNotGrantedError(Exception):
|
|
142
|
+
"""A session open asked for something the host did not grant on this
|
|
143
|
+
connection: today, per-session MCP servers (``config["mcpServers"]``)
|
|
144
|
+
without the ``sessionMcp`` capability. Refused before anything is sent;
|
|
145
|
+
the client stays usable, and an open without that request still goes
|
|
146
|
+
through.
|
|
147
|
+
|
|
148
|
+
Attributes:
|
|
149
|
+
capability: The capability the request needs.
|
|
150
|
+
method: The wire method that was refused.
|
|
151
|
+
"""
|
|
152
|
+
|
|
153
|
+
def __init__(self, capability: str, method: str, reason: str) -> None:
|
|
154
|
+
"""Builds the refusal.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
capability: The capability the request needs.
|
|
158
|
+
method: The wire method that was refused.
|
|
159
|
+
reason: Why the grant is missing.
|
|
160
|
+
"""
|
|
161
|
+
super().__init__(f"{method} was not sent: {reason}")
|
|
162
|
+
self.capability: str = capability
|
|
163
|
+
self.method: str = method
|
|
164
|
+
|
|
118
165
|
ValidationSeam = Literal["initializeResult", "spawnOptions"]
|
|
119
166
|
"""Which validating pydantic seam refused its input.
|
|
120
167
|
|
|
@@ -207,9 +254,9 @@ class MuseHostMismatchError(Exception):
|
|
|
207
254
|
pinned: ``muse_code.EXPECTED_SCHEMA_FINGERPRINT``.
|
|
208
255
|
host_version: ``serverInfo.version`` from the handshake result.
|
|
209
256
|
required_host_version: The generated
|
|
210
|
-
``muse_code_msp.REQUIRED_HOST_VERSION`` —
|
|
211
|
-
|
|
212
|
-
|
|
257
|
+
``muse_code_msp.REQUIRED_HOST_VERSION`` — derived at import
|
|
258
|
+
through the vendored resolver and kept honest by the regen
|
|
259
|
+
gate, never hand-typed.
|
|
213
260
|
Required, not defaulted: the contract names the exact version, so
|
|
214
261
|
a version-less message is not a state this error can carry.
|
|
215
262
|
"""
|
|
@@ -50,8 +50,9 @@ from .session import (
|
|
|
50
50
|
SessionGapOverlap,
|
|
51
51
|
SessionOpening,
|
|
52
52
|
)
|
|
53
|
-
from .
|
|
54
|
-
from .
|
|
53
|
+
from .run import RunResult
|
|
54
|
+
from .turn_handle import FoldedItem, Turn, TurnOutcome, TurnUnqueueOutcome, is_launch_failure
|
|
55
|
+
from .turn_submit import SendUserTurnOptions, SteerTurnOptions
|
|
55
56
|
|
|
56
57
|
__all__ = [
|
|
57
58
|
"AbnormalExit",
|
|
@@ -71,6 +72,7 @@ __all__ = [
|
|
|
71
72
|
"MuseHostStartError",
|
|
72
73
|
"PendingCommandView",
|
|
73
74
|
"ResumeSessionOptions",
|
|
75
|
+
"RunResult",
|
|
74
76
|
"SendUserTurnOptions",
|
|
75
77
|
"Session",
|
|
76
78
|
"SessionApplyOutcome",
|
|
@@ -81,9 +83,11 @@ __all__ = [
|
|
|
81
83
|
"SessionGapOverlap",
|
|
82
84
|
"SessionOpening",
|
|
83
85
|
"StartSessionOptions",
|
|
86
|
+
"SteerTurnOptions",
|
|
84
87
|
"TransportEof",
|
|
85
88
|
"Turn",
|
|
86
89
|
"TurnOutcome",
|
|
90
|
+
"TurnUnqueueOutcome",
|
|
87
91
|
"is_abnormal_host_death",
|
|
88
92
|
"is_launch_failure",
|
|
89
93
|
"read_session_durability",
|