muse-code-sdk 1.3.1__tar.gz → 1.4.2__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.3.1/src/muse_code_sdk.egg-info → muse_code_sdk-1.4.2}/PKG-INFO +1 -1
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/pyproject.toml +1 -1
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/src/muse_code/__init__.py +2 -2
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/src/muse_code/facade/client.py +7 -1
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/src/muse_code/facade/turn_submit.py +7 -1
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2/src/muse_code_sdk.egg-info}/PKG-INFO +1 -1
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/tests/test_publish_shape.py +14 -8
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/tests/test_session_fold.py +41 -7
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/LICENSE +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/README.md +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/setup.cfg +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/src/muse_code/connection/__init__.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/src/muse_code/connection/connection.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/src/muse_code/connection/discovery.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/src/muse_code/connection/spawn.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/src/muse_code/connection/validation.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/src/muse_code/errors.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/src/muse_code/facade/__init__.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/src/muse_code/facade/approval.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/src/muse_code/facade/discarded.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/src/muse_code/facade/gap_fill.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/src/muse_code/facade/host_death.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/src/muse_code/facade/session.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/src/muse_code/facade/turn_handle.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/src/muse_code/fold/__init__.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/src/muse_code/fold/item_store.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/src/muse_code/fold/session_fold.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/src/muse_code/fold/state_store.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/src/muse_code/pending/__init__.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/src/muse_code/pending/pending_command_set.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/src/muse_code/py.typed +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/src/muse_code/replay.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/src/muse_code/sync_facade.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/src/muse_code_sdk.egg-info/SOURCES.txt +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/src/muse_code_sdk.egg-info/dependency_links.txt +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/src/muse_code_sdk.egg-info/requires.txt +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/src/muse_code_sdk.egg-info/top_level.txt +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/tests/test_asyncio_cancellation.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/tests/test_compatibility_row.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/tests/test_connection.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/tests/test_connection_error_arms.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/tests/test_docs_generation.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/tests/test_external_audience.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/tests/test_facade_approval.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/tests/test_facade_gap_fill.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/tests/test_facade_persistent_approval.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/tests/test_facade_turn.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/tests/test_host_discovery.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/tests/test_item_store.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/tests/test_manifests.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/tests/test_muse_serve_child.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/tests/test_pending_command_corpus.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/tests/test_pending_command_set.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/tests/test_pending_command_wire_binding.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/tests/test_source_closure.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/tests/test_spawn_handshake.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/tests/test_state_store.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/tests/test_sync_facade.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/tests/test_tolerance_corpus.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/tests/test_transcript_replay.py +0 -0
- {muse_code_sdk-1.3.1 → muse_code_sdk-1.4.2}/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.
|
|
3
|
+
Version: 1.4.2
|
|
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
|
|
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
|
|
|
5
5
|
|
|
6
6
|
[project]
|
|
7
7
|
name = "muse-code-sdk"
|
|
8
|
-
version = "1.
|
|
8
|
+
version = "1.4.2"
|
|
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"
|
|
@@ -77,7 +77,7 @@ __all__ = [
|
|
|
77
77
|
]
|
|
78
78
|
|
|
79
79
|
EXPECTED_SCHEMA_FINGERPRINT: Final[str] = (
|
|
80
|
-
"sha256:
|
|
80
|
+
"sha256:61afea3112e0906e9dc3a536144278a74cb4b36fc6e20901a91d4432ba3568e2"
|
|
81
81
|
)
|
|
82
82
|
"""The stable schema-bundle fingerprint this SDK was built against.
|
|
83
83
|
|
|
@@ -89,7 +89,7 @@ Python SDK reds this lane instead of drifting silently.
|
|
|
89
89
|
# The lockstep rule: the release train bumps pyproject.toml, the
|
|
90
90
|
# distribution-metadata authority; this constant is aligned at publication
|
|
91
91
|
# time.
|
|
92
|
-
__version__: Final[str] = "1.
|
|
92
|
+
__version__: Final[str] = "1.4.2"
|
|
93
93
|
|
|
94
94
|
# The facade is imported last so the constants above are already bound: the
|
|
95
95
|
# spawn path reads ``EXPECTED_SCHEMA_FINGERPRINT`` (lazily, at initialize
|
|
@@ -23,7 +23,7 @@ from __future__ import annotations
|
|
|
23
23
|
|
|
24
24
|
import asyncio
|
|
25
25
|
from dataclasses import dataclass, fields
|
|
26
|
-
from typing import Any, Awaitable, Generic, Mapping, Sequence, Set, TypeVar
|
|
26
|
+
from typing import Any, Awaitable, Generic, List, Mapping, Sequence, Set, TypeVar
|
|
27
27
|
|
|
28
28
|
from muse_code_msp import (
|
|
29
29
|
ClientCapabilities,
|
|
@@ -77,6 +77,9 @@ class StartSessionOptions:
|
|
|
77
77
|
session_id: A caller-chosen session id; omitted = the host mints one.
|
|
78
78
|
workspace_root: The workspace the session works in; omitted = the
|
|
79
79
|
host decides.
|
|
80
|
+
workspace_roots: The session's initial runtime workspace-root set
|
|
81
|
+
(wire ``workspaceRoots``; first root = the CWD). When
|
|
82
|
+
``workspace_root`` is also given the two must agree.
|
|
80
83
|
model_id: The model to serve the session with; omitted = the
|
|
81
84
|
provider's default.
|
|
82
85
|
"""
|
|
@@ -85,6 +88,7 @@ class StartSessionOptions:
|
|
|
85
88
|
provider_id: str | None = None
|
|
86
89
|
session_id: str | None = None
|
|
87
90
|
workspace_root: str | None = None
|
|
91
|
+
workspace_roots: List[str] | None = None
|
|
88
92
|
model_id: str | None = None
|
|
89
93
|
|
|
90
94
|
|
|
@@ -322,6 +326,8 @@ class MuseClient(Generic[_I]):
|
|
|
322
326
|
params["sessionId"] = options.session_id
|
|
323
327
|
if options.workspace_root is not None:
|
|
324
328
|
params["workspaceRoot"] = options.workspace_root
|
|
329
|
+
if options.workspace_roots is not None:
|
|
330
|
+
params["workspaceRoots"] = options.workspace_roots
|
|
325
331
|
if options.model_id is not None:
|
|
326
332
|
params["modelId"] = options.model_id
|
|
327
333
|
raw = await self._connection.command("session/start", params)
|
|
@@ -51,6 +51,9 @@ class SendUserTurnOptions(Generic[_I]):
|
|
|
51
51
|
if_busy: How to treat a submit while a turn runs (wire ``ifBusy``).
|
|
52
52
|
reasoning_effort: The turn's reasoning effort (wire
|
|
53
53
|
``reasoningEffort``).
|
|
54
|
+
workspace_roots: A sticky replacement of the session's runtime
|
|
55
|
+
workspace-root set for this turn and subsequent turns (wire
|
|
56
|
+
``workspaceRoots``).
|
|
54
57
|
composer_input: What to hand back to the composer if this submit is
|
|
55
58
|
ever retired — the protocol restores the INPUT, not the wire parts.
|
|
56
59
|
Optional: a consumer rendering nothing optimistically has nothing
|
|
@@ -61,6 +64,7 @@ class SendUserTurnOptions(Generic[_I]):
|
|
|
61
64
|
display_text: str | None = None
|
|
62
65
|
if_busy: IfBusy | None = None
|
|
63
66
|
reasoning_effort: ReasoningEffort | None = None
|
|
67
|
+
workspace_roots: List[str] | None = None
|
|
64
68
|
composer_input: _I | None = None
|
|
65
69
|
|
|
66
70
|
|
|
@@ -82,7 +86,7 @@ def _camel(field_name: str) -> str:
|
|
|
82
86
|
# own field, never a wire member, so it is dropped
|
|
83
87
|
# before the compare; `commandId`/`sessionId` are excluded because the
|
|
84
88
|
# connection mints the first and the session owns the second.
|
|
85
|
-
_TURN_WIRE_FIELDS = {"input", "display_text", "if_busy", "reasoning_effort"}
|
|
89
|
+
_TURN_WIRE_FIELDS = {"input", "display_text", "if_busy", "reasoning_effort", "workspace_roots"}
|
|
86
90
|
_TURN_EXCLUDED = {"commandId", "sessionId"}
|
|
87
91
|
assert {
|
|
88
92
|
_camel(f.name) for f in fields(SendUserTurnOptions) if f.name in _TURN_WIRE_FIELDS
|
|
@@ -283,4 +287,6 @@ class TurnSubmitter(Generic[_I]):
|
|
|
283
287
|
params["ifBusy"] = options.if_busy
|
|
284
288
|
if options.reasoning_effort is not None:
|
|
285
289
|
params["reasoningEffort"] = options.reasoning_effort
|
|
290
|
+
if options.workspace_roots is not None:
|
|
291
|
+
params["workspaceRoots"] = options.workspace_roots
|
|
286
292
|
return params
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: muse-code-sdk
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.2
|
|
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
|
|
@@ -103,20 +103,26 @@ def test_the_version_source_is_the_static_manifest_field() -> None:
|
|
|
103
103
|
# eligibility. Publication is permitted at exactly this lockstep
|
|
104
104
|
# version — never a train-external one — so
|
|
105
105
|
# the equality here is what the published wheel's version claims.
|
|
106
|
-
|
|
107
|
-
# 1.3.0 PyPI files were deleted after publication and PyPI
|
|
108
|
-
# reserves deleted filenames forever, so the republish rides 1.3.1
|
|
109
|
-
# while the train stays at 1.3.0. Exactly this pair is allowed;
|
|
110
|
-
# anything else still requires lockstep equality.
|
|
111
|
-
assert (version == _host_version()) or (
|
|
112
|
-
(version, _host_version()) == ("1.3.1", "1.3.0")
|
|
113
|
-
), (
|
|
106
|
+
assert version == _host_version(), (
|
|
114
107
|
f"{distribution}: version {version!r} != the host manifest's "
|
|
115
108
|
f"{_host_version()!r} (the version lockstep rule: only the "
|
|
116
109
|
"release train moves these versions, in one commit)"
|
|
117
110
|
)
|
|
118
111
|
|
|
119
112
|
|
|
113
|
+
def test_the_runtime_version_matches_the_sdk_manifest() -> None:
|
|
114
|
+
import muse_code
|
|
115
|
+
|
|
116
|
+
# `muse_code.__version__` is a hand-kept copy of the manifest field; a
|
|
117
|
+
# release bump that moves one without the other ships a wheel that
|
|
118
|
+
# misreports its own version.
|
|
119
|
+
manifest_version = _pyproject(SDK_DIR)["project"]["version"]
|
|
120
|
+
assert muse_code.__version__ == manifest_version, (
|
|
121
|
+
f"muse_code.__version__ {muse_code.__version__!r} != "
|
|
122
|
+
f"muse-code-sdk manifest version {manifest_version!r}"
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
|
|
120
126
|
def test_the_license_is_mit_with_shipped_text() -> None:
|
|
121
127
|
for package_dir, (distribution, _) in PACKAGES.items():
|
|
122
128
|
project = _pyproject(package_dir)["project"]
|
|
@@ -806,6 +806,25 @@ def test_an_unrecognized_notification_method_folds_without_raising() -> None:
|
|
|
806
806
|
assert fold.active_turn_id == "turn-1", "the rest of the fold is untouched"
|
|
807
807
|
|
|
808
808
|
|
|
809
|
+
def test_a_session_lifecycle_broadcast_keeps_its_pre_enrollment_drop() -> None:
|
|
810
|
+
# The runtime twin of the TypeScript SDK's lifecycle pin: the generated
|
|
811
|
+
# NOTIFICATIONS union carries both lifecycle names, but they are
|
|
812
|
+
# control-plane broadcasts, not view events, and the fold deliberately
|
|
813
|
+
# keeps the pre-enrollment runtime answer (the same sanctioned initial
|
|
814
|
+
# drop the delivery-gap marker had before it became a fold input). This
|
|
815
|
+
# pin is the tripwire the SDK's conscious lifecycle surfacing must
|
|
816
|
+
# replace; it reds if a refactor makes a lifecycle frame seed an item or
|
|
817
|
+
# a state family instead.
|
|
818
|
+
fold = SessionFold()
|
|
819
|
+
fold.apply(turn_started("turn-1", "cmd-1", "v:s:1"))
|
|
820
|
+
for method in ("session/started", "session/closed"):
|
|
821
|
+
outcome = fold.apply({"method": method, "params": {"sessionId": SESSION}})
|
|
822
|
+
assert outcome == IgnoredUnrecognizedMethod(method)
|
|
823
|
+
assert fold.items.size == 0, "a lifecycle broadcast seeds no item"
|
|
824
|
+
assert fold.session_state.families() == [], "and no state family"
|
|
825
|
+
assert fold.active_turn_id == "turn-1", "the rest of the fold is untouched"
|
|
826
|
+
|
|
827
|
+
|
|
809
828
|
def test_a_real_view_gap_frame_moves_the_folds_currency_and_no_store() -> None:
|
|
810
829
|
fold = SessionFold()
|
|
811
830
|
fold.apply(turn_started("turn-1", "cmd-1", "v:s:0"))
|
|
@@ -925,19 +944,34 @@ def test_every_generated_view_notification_is_routed_never_the_default() -> None
|
|
|
925
944
|
# push, not a view-fold input — it reports that the live view stream died,
|
|
926
945
|
# so it carries no cursor and folds into no transcript state. Excluded here
|
|
927
946
|
# like the handshake's `initialized`; the client handles it out of band.
|
|
928
|
-
|
|
929
|
-
|
|
947
|
+
# Deletion completion has no view envelope or fold state.
|
|
948
|
+
non_fold_notifications = {"initialized", "session/viewHealthChanged", "session/deleteCompleted"}
|
|
949
|
+
# Session lifecycle broadcasts (a session was loaded or unloaded on the
|
|
950
|
+
# host) are control-plane notifications, not view events — they carry no
|
|
951
|
+
# view envelope, so they are facade inputs, not fold inputs. Today a
|
|
952
|
+
# lifecycle frame keeps the pre-enrollment runtime answer
|
|
953
|
+
# (``IgnoredUnrecognizedMethod``, pinned by the lifecycle runtime test)
|
|
954
|
+
# until the SDK consciously surfaces the pair.
|
|
955
|
+
session_lifecycle_broadcasts = {"session/started", "session/closed"}
|
|
956
|
+
assert VIEW_EVENT_METHODS == (
|
|
957
|
+
set(NOTIFICATIONS)
|
|
958
|
+
- non_fold_notifications
|
|
959
|
+
- session_lifecycle_broadcasts
|
|
960
|
+
- LIVE_HOST_STATE_PROJECTIONS
|
|
961
|
+
), (
|
|
930
962
|
"a protocol enrollment added or retired a view notification; route it in "
|
|
931
963
|
"SessionFold.apply (exclusions: `initialized`, the command-plane "
|
|
932
|
-
"session/viewHealthChanged push,
|
|
933
|
-
"the governing decision)"
|
|
964
|
+
"session/viewHealthChanged push, the session lifecycle broadcasts, and "
|
|
965
|
+
"the live host-state projections, the governing decision)"
|
|
934
966
|
)
|
|
935
967
|
# The reverse pin (the TS StaleExclusion twin): every excluded projection
|
|
936
968
|
# names a REAL generated notification, so a retired or renamed method
|
|
937
969
|
# cannot rot in the exclusion set as dead vocabulary.
|
|
938
|
-
assert (
|
|
939
|
-
|
|
940
|
-
|
|
970
|
+
assert (
|
|
971
|
+
LIVE_HOST_STATE_PROJECTIONS | non_fold_notifications | session_lifecycle_broadcasts
|
|
972
|
+
) <= set(NOTIFICATIONS), (
|
|
973
|
+
"an excluded method (live host-state projection, lifecycle broadcast, "
|
|
974
|
+
"or non-fold notification) names no generated notification"
|
|
941
975
|
)
|
|
942
976
|
|
|
943
977
|
by_method: dict[str, dict[str, Any]] = {
|
|
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
|
|
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
|