livepilot 1.14.1 → 1.16.0
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.
- package/CHANGELOG.md +176 -1
- package/README.md +6 -6
- package/m4l_device/LivePilot_Analyzer.amxd +0 -0
- package/mcp_server/__init__.py +1 -1
- package/mcp_server/atlas/device_atlas.json +91219 -7161
- package/mcp_server/atlas/tools.py +30 -2
- package/mcp_server/runtime/live_version.py +4 -2
- package/mcp_server/runtime/remote_commands.py +5 -0
- package/mcp_server/sample_engine/tools.py +692 -60
- package/mcp_server/splice_client/client.py +511 -65
- package/mcp_server/splice_client/http_bridge.py +361 -0
- package/mcp_server/splice_client/models.py +266 -2
- package/mcp_server/splice_client/quota.py +229 -0
- package/mcp_server/tools/_analyzer_engine/__init__.py +4 -0
- package/mcp_server/tools/_analyzer_engine/sample.py +73 -0
- package/mcp_server/tools/analyzer.py +666 -6
- package/mcp_server/tools/browser.py +164 -13
- package/mcp_server/tools/devices.py +56 -11
- package/mcp_server/tools/mixing.py +64 -15
- package/mcp_server/tools/scales.py +18 -6
- package/mcp_server/tools/tracks.py +92 -4
- package/package.json +2 -2
- package/remote_script/LivePilot/__init__.py +2 -1
- package/remote_script/LivePilot/_clip_helpers.py +86 -0
- package/remote_script/LivePilot/_drum_helpers.py +40 -0
- package/remote_script/LivePilot/_scale_helpers.py +87 -0
- package/remote_script/LivePilot/arrangement.py +44 -15
- package/remote_script/LivePilot/clips.py +182 -2
- package/remote_script/LivePilot/devices.py +82 -2
- package/remote_script/LivePilot/notes.py +17 -2
- package/remote_script/LivePilot/scales.py +31 -16
- package/remote_script/LivePilot/simpler_sample.py +186 -0
- package/server.json +3 -3
|
@@ -150,7 +150,11 @@ def atlas_compare(ctx: Context, device_a: str, device_b: str, role: str = "") ->
|
|
|
150
150
|
|
|
151
151
|
|
|
152
152
|
@mcp.tool()
|
|
153
|
-
def scan_full_library(
|
|
153
|
+
def scan_full_library(
|
|
154
|
+
ctx: Context,
|
|
155
|
+
force: bool = False,
|
|
156
|
+
max_per_category: int = 5000,
|
|
157
|
+
) -> dict:
|
|
154
158
|
"""Scan the full Ableton browser and rebuild the device atlas.
|
|
155
159
|
|
|
156
160
|
Walks every category (instruments, audio_effects, midi_effects, max_for_live,
|
|
@@ -158,6 +162,16 @@ def scan_full_library(ctx: Context, force: bool = False) -> dict:
|
|
|
158
162
|
Results are merged with curated enrichments and saved to device_atlas.json.
|
|
159
163
|
|
|
160
164
|
force: if True, rescan even if atlas already exists (default False)
|
|
165
|
+
max_per_category: ceiling per category (default 5000). The previous
|
|
166
|
+
hardcoded 1000 cap silently truncated large categories — for
|
|
167
|
+
example, the samples category alone has ~22,000 items per the
|
|
168
|
+
browser tree, so the reported count "1000 samples" was wrong by
|
|
169
|
+
a factor of 22 (BUG-2026-04-22 #12). Raise this if your library
|
|
170
|
+
is huge; lower it for fast smoke scans.
|
|
171
|
+
|
|
172
|
+
Returns a stats dict including `truncated_categories` listing any
|
|
173
|
+
category that hit the cap (so callers know the count is a lower
|
|
174
|
+
bound rather than the true total).
|
|
161
175
|
"""
|
|
162
176
|
from .scanner import normalize_scan_results
|
|
163
177
|
from .enrichments import load_enrichments, merge_enrichments
|
|
@@ -183,11 +197,23 @@ def scan_full_library(ctx: Context, force: bool = False) -> dict:
|
|
|
183
197
|
|
|
184
198
|
# Scan browser
|
|
185
199
|
ableton = _get_ableton(ctx)
|
|
186
|
-
raw = ableton.send_command("scan_browser_deep", {"max_per_category":
|
|
200
|
+
raw = ableton.send_command("scan_browser_deep", {"max_per_category": max_per_category})
|
|
187
201
|
|
|
188
202
|
# Normalize
|
|
189
203
|
devices = normalize_scan_results(raw)
|
|
190
204
|
|
|
205
|
+
# Detect truncation: per-category count == cap means we likely hit it.
|
|
206
|
+
truncated_categories = []
|
|
207
|
+
if isinstance(raw, dict):
|
|
208
|
+
per_cat = raw.get("counts") or raw.get("stats") or {}
|
|
209
|
+
if isinstance(per_cat, dict):
|
|
210
|
+
for cat, count in per_cat.items():
|
|
211
|
+
try:
|
|
212
|
+
if int(count) >= max_per_category:
|
|
213
|
+
truncated_categories.append(cat)
|
|
214
|
+
except (TypeError, ValueError):
|
|
215
|
+
continue
|
|
216
|
+
|
|
191
217
|
# Load and merge enrichments
|
|
192
218
|
enrichments = load_enrichments(enrichments_dir)
|
|
193
219
|
devices = merge_enrichments(devices, enrichments)
|
|
@@ -214,6 +240,8 @@ def scan_full_library(ctx: Context, force: bool = False) -> dict:
|
|
|
214
240
|
"live_version": live_version,
|
|
215
241
|
"scanned_at": time.strftime("%Y-%m-%dT%H:%M:%SZ"),
|
|
216
242
|
"stats": stats,
|
|
243
|
+
"max_per_category": max_per_category,
|
|
244
|
+
"truncated_categories": truncated_categories,
|
|
217
245
|
"devices": devices,
|
|
218
246
|
"packs": [],
|
|
219
247
|
}
|
|
@@ -79,8 +79,10 @@ class LiveVersionCapabilities:
|
|
|
79
79
|
|
|
80
80
|
@property
|
|
81
81
|
def capability_tier(self) -> str:
|
|
82
|
-
"""Human-readable tier: core | enhanced_arrangement | full_intelligence."""
|
|
83
|
-
if self._version_tuple >= (12,
|
|
82
|
+
"""Human-readable tier: core | enhanced_arrangement | full_intelligence | collaborative."""
|
|
83
|
+
if self._version_tuple >= (12, 4, 0):
|
|
84
|
+
return "collaborative"
|
|
85
|
+
elif self._version_tuple >= (12, 3, 0):
|
|
84
86
|
return "full_intelligence"
|
|
85
87
|
elif self._version_tuple >= (12, 1, 10):
|
|
86
88
|
return "enhanced_arrangement"
|
|
@@ -48,6 +48,9 @@ REMOTE_COMMANDS: frozenset[str] = frozenset({
|
|
|
48
48
|
"insert_device", # 12.3+ native device insertion
|
|
49
49
|
"insert_rack_chain", # 12.3+ rack chain insertion
|
|
50
50
|
"set_drum_chain_note", # 12.3+ drum chain note assignment
|
|
51
|
+
"set_chain_name", # Rack chain rename (any rack type)
|
|
52
|
+
"fire_test_note", # Temp-clip MIDI trigger for verify_device_health
|
|
53
|
+
"cleanup_test_note", # Scratch-clip teardown paired with fire_test_note
|
|
51
54
|
# rack variations + macro CRUD (Live 11+)
|
|
52
55
|
"get_rack_variations", "store_rack_variation",
|
|
53
56
|
"recall_rack_variation", "delete_rack_variation",
|
|
@@ -117,6 +120,8 @@ REMOTE_COMMANDS: frozenset[str] = frozenset({
|
|
|
117
120
|
"get_appointed_device",
|
|
118
121
|
# ping (built-in)
|
|
119
122
|
"ping",
|
|
123
|
+
# Live 12.4+ native Simpler sample replacement (Collaborative tier)
|
|
124
|
+
"replace_sample_native",
|
|
120
125
|
})
|
|
121
126
|
|
|
122
127
|
# M4L bridge commands — routed through TCP but handled by livepilot_bridge.js
|