livepilot 1.27.2 → 1.27.3
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 +66 -0
- package/README.md +10 -7
- package/bin/livepilot.js +97 -39
- package/livepilot/.Codex-plugin/plugin.json +1 -1
- package/livepilot/.claude-plugin/plugin.json +1 -1
- package/livepilot/skills/livepilot-core/SKILL.md +33 -1
- package/livepilot/skills/livepilot-core/references/atlas-tool-notes.md +69 -0
- package/livepilot/skills/livepilot-core/references/overview.md +18 -11
- package/livepilot/skills/livepilot-core/references/perception.md +125 -0
- package/livepilot/skills/livepilot-devices/references/device-parameter-units.md +66 -0
- package/livepilot/skills/livepilot-evaluation/references/capability-modes.md +1 -1
- package/livepilot/skills/livepilot-mix-engine/SKILL.md +8 -0
- package/livepilot/skills/livepilot-release/SKILL.md +1 -1
- package/livepilot/skills/livepilot-sample-engine/references/splice-tools-notes.md +56 -0
- package/livepilot/skills/livepilot-wonder/SKILL.md +6 -0
- package/m4l_device/LivePilot_Analyzer.amxd +0 -0
- package/m4l_device/livepilot_bridge.js +1 -1
- package/mcp_server/__init__.py +1 -1
- package/mcp_server/atlas/__init__.py +181 -40
- package/mcp_server/atlas/overlays.py +46 -3
- package/mcp_server/atlas/tools.py +226 -86
- package/mcp_server/audit/checks.py +50 -22
- package/mcp_server/audit/state.py +10 -2
- package/mcp_server/audit/tools.py +27 -6
- package/mcp_server/composer/develop/apply.py +7 -7
- package/mcp_server/composer/fast/apply.py +29 -23
- package/mcp_server/composer/framework/atlas_resolver.py +16 -1
- package/mcp_server/composer/full/apply.py +40 -34
- package/mcp_server/composer/full/engine.py +66 -32
- package/mcp_server/composer/tools.py +4 -3
- package/mcp_server/connection.py +67 -9
- package/mcp_server/creative_constraints/engine.py +10 -2
- package/mcp_server/creative_constraints/tools.py +24 -7
- package/mcp_server/curves.py +30 -7
- package/mcp_server/device_forge/builder.py +40 -11
- package/mcp_server/device_forge/models.py +9 -0
- package/mcp_server/device_forge/tools.py +30 -11
- package/mcp_server/experiment/engine.py +29 -22
- package/mcp_server/experiment/tools.py +15 -5
- package/mcp_server/m4l_bridge.py +69 -7
- package/mcp_server/memory/taste_graph.py +43 -0
- package/mcp_server/memory/technique_store.py +26 -3
- package/mcp_server/memory/tools.py +62 -4
- package/mcp_server/mix_engine/critics.py +187 -30
- package/mcp_server/mix_engine/models.py +21 -1
- package/mcp_server/mix_engine/state_builder.py +87 -8
- package/mcp_server/mix_engine/tools.py +16 -4
- package/mcp_server/performance_engine/tools.py +56 -8
- package/mcp_server/persistence/base_store.py +11 -0
- package/mcp_server/persistence/project_store.py +132 -8
- package/mcp_server/persistence/taste_store.py +90 -7
- package/mcp_server/preview_studio/engine.py +40 -10
- package/mcp_server/preview_studio/models.py +40 -0
- package/mcp_server/preview_studio/tools.py +56 -12
- package/mcp_server/project_brain/arrangement_graph.py +4 -0
- package/mcp_server/project_brain/models.py +2 -0
- package/mcp_server/project_brain/role_graph.py +13 -7
- package/mcp_server/reference_engine/gap_analyzer.py +58 -3
- package/mcp_server/reference_engine/profile_builder.py +47 -4
- package/mcp_server/reference_engine/tools.py +6 -0
- package/mcp_server/runtime/execution_router.py +51 -1
- package/mcp_server/runtime/tools.py +0 -1
- package/mcp_server/sample_engine/sources.py +0 -2
- package/mcp_server/sample_engine/tools.py +19 -38
- package/mcp_server/semantic_moves/mix_compilers.py +276 -51
- package/mcp_server/semantic_moves/performance_compilers.py +51 -17
- package/mcp_server/semantic_moves/resolvers.py +45 -0
- package/mcp_server/semantic_moves/sound_design_compilers.py +14 -6
- package/mcp_server/semantic_moves/tools.py +80 -2
- package/mcp_server/semantic_moves/transition_compilers.py +26 -9
- package/mcp_server/server.py +26 -24
- package/mcp_server/session_continuity/tracker.py +51 -3
- package/mcp_server/song_brain/builder.py +47 -5
- package/mcp_server/song_brain/tools.py +21 -7
- package/mcp_server/sound_design/critics.py +1 -0
- package/mcp_server/splice_client/client.py +117 -33
- package/mcp_server/splice_client/http_bridge.py +15 -3
- package/mcp_server/splice_client/quota.py +28 -0
- package/mcp_server/stuckness_detector/detector.py +8 -5
- package/mcp_server/synthesis_brain/adapters/drift.py +13 -0
- package/mcp_server/synthesis_brain/adapters/meld.py +13 -0
- package/mcp_server/tools/_analyzer_engine/sample.py +36 -10
- package/mcp_server/tools/_perception_engine.py +6 -0
- package/mcp_server/tools/agent_os.py +4 -1
- package/mcp_server/tools/analyzer.py +198 -209
- package/mcp_server/tools/arrangement.py +7 -4
- package/mcp_server/tools/automation.py +24 -4
- package/mcp_server/tools/browser.py +25 -11
- package/mcp_server/tools/clips.py +6 -0
- package/mcp_server/tools/composition.py +33 -2
- package/mcp_server/tools/devices.py +53 -53
- package/mcp_server/tools/generative.py +14 -14
- package/mcp_server/tools/harmony.py +7 -7
- package/mcp_server/tools/mixing.py +4 -4
- package/mcp_server/tools/planner.py +68 -6
- package/mcp_server/tools/research.py +20 -2
- package/mcp_server/tools/theory.py +10 -10
- package/mcp_server/tools/transport.py +7 -2
- package/mcp_server/transition_engine/critics.py +13 -1
- package/mcp_server/user_corpus/tools.py +30 -1
- package/mcp_server/wonder_mode/engine.py +82 -9
- package/mcp_server/wonder_mode/session.py +32 -10
- package/mcp_server/wonder_mode/tools.py +14 -1
- package/package.json +1 -1
- package/remote_script/LivePilot/__init__.py +1 -1
- package/remote_script/LivePilot/arrangement.py +93 -33
- package/remote_script/LivePilot/browser.py +60 -4
- package/remote_script/LivePilot/devices.py +132 -62
- package/remote_script/LivePilot/mixing.py +31 -5
- package/remote_script/LivePilot/server.py +94 -22
- package/remote_script/LivePilot/transport.py +11 -0
- package/requirements.txt +5 -5
- package/server.json +2 -2
|
@@ -17,6 +17,7 @@ resulting in silent playback. The hygiene here fixes both.
|
|
|
17
17
|
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
|
|
20
|
+
import asyncio
|
|
20
21
|
import logging
|
|
21
22
|
import os
|
|
22
23
|
import re
|
|
@@ -86,10 +87,14 @@ _ONESHOT_HINTS = (
|
|
|
86
87
|
"/one_shots/",
|
|
87
88
|
"/one-shots/",
|
|
88
89
|
)
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
)
|
|
90
|
+
# The "loop" word is an unambiguous loop signal.
|
|
91
|
+
_LOOP_TOKEN_RE = re.compile(r"(?:_|\b)loop(?:_|\b)", re.IGNORECASE)
|
|
92
|
+
# A bare 2-3 digit number is an AMBIGUOUS signal — it matches Splice bare-BPM
|
|
93
|
+
# names ("pluck_124_Cmin") but ALSO drum-machine model numbers / indices in
|
|
94
|
+
# one-shot names ("Kick_808", "snare_05", "tom_120").
|
|
95
|
+
_BARE_NUMBER_RE = re.compile(r"(?:_|\b)(\d{2,3})(?:_|bpm|\b)", re.IGNORECASE)
|
|
96
|
+
# Drum-machine model numbers are gear identifiers, NEVER tempos.
|
|
97
|
+
_DRUM_MACHINE_MODELS = frozenset({808, 909, 707, 606, 505, 727, 626, 303, 333, 555})
|
|
93
98
|
|
|
94
99
|
|
|
95
100
|
def _is_warped_loop(file_path: str) -> bool:
|
|
@@ -113,16 +118,34 @@ def _is_warped_loop(file_path: str) -> bool:
|
|
|
113
118
|
return False
|
|
114
119
|
|
|
115
120
|
stem = os.path.splitext(os.path.basename(file_path))[0]
|
|
121
|
+
|
|
122
|
+
# Explicit, unambiguous loop signals win first — genuine drum/melodic loops
|
|
123
|
+
# almost always carry one of these (a "125bpm" literal, a "loop" token, or
|
|
124
|
+
# a loops folder), so honoring them keeps the 2026-05-01 broadening intact.
|
|
116
125
|
if _BPM_IN_FILENAME_RE.search(stem):
|
|
117
126
|
return True
|
|
118
|
-
if
|
|
127
|
+
if _LOOP_TOKEN_RE.search(stem):
|
|
119
128
|
return True
|
|
120
129
|
# Append trailing slash so `/loops/` and `/drum_loops/` match the
|
|
121
130
|
# last directory component cleanly (os.path.dirname strips trailing /).
|
|
122
131
|
parent = os.path.dirname(file_path).lower() + "/"
|
|
123
132
|
if any(seg in parent for seg in _LOOP_PATH_HINTS):
|
|
124
133
|
return True
|
|
125
|
-
|
|
134
|
+
|
|
135
|
+
# Only a bare 2-3 digit number remains. This is where drum ONE-SHOTS were
|
|
136
|
+
# being misclassified as warped loops (Kick_808, snare_05, tom_120), which
|
|
137
|
+
# then skipped the drum-root Transpose (-> plays 2 octaves down), force-
|
|
138
|
+
# looped, and warped them — the documented recurring drum-Simpler bug.
|
|
139
|
+
# A drum-machine model number is never a tempo; a bare number on a
|
|
140
|
+
# drum-material name with no explicit loop signal is a one-shot, not a loop.
|
|
141
|
+
m = _BARE_NUMBER_RE.search(stem)
|
|
142
|
+
if not m:
|
|
143
|
+
return False
|
|
144
|
+
if int(m.group(1)) in _DRUM_MACHINE_MODELS:
|
|
145
|
+
return False
|
|
146
|
+
if _detect_drum_root_note(file_path) is not None:
|
|
147
|
+
return False
|
|
148
|
+
return True
|
|
126
149
|
|
|
127
150
|
|
|
128
151
|
def _filename_stem(file_path: str) -> str:
|
|
@@ -181,8 +204,11 @@ async def _simpler_post_load_hygiene(
|
|
|
181
204
|
|
|
182
205
|
# Step 1: verify device name matches expected file
|
|
183
206
|
try:
|
|
184
|
-
|
|
185
|
-
|
|
207
|
+
# send_command is blocking socket I/O; this is an async tool, so offload
|
|
208
|
+
# to a worker thread to avoid freezing the event loop (and the bridge
|
|
209
|
+
# UDP endpoint + all other concurrent handlers) for the round-trip.
|
|
210
|
+
track_info = await asyncio.to_thread(
|
|
211
|
+
ableton.send_command, "get_track_info", {"track_index": track_index}
|
|
186
212
|
)
|
|
187
213
|
except Exception as exc:
|
|
188
214
|
return {"error": f"Verification read failed: {exc}"}
|
|
@@ -276,7 +302,7 @@ async def _simpler_post_load_hygiene(
|
|
|
276
302
|
)
|
|
277
303
|
|
|
278
304
|
try:
|
|
279
|
-
ableton.send_command
|
|
305
|
+
await asyncio.to_thread(ableton.send_command, "batch_set_parameters", {
|
|
280
306
|
"track_index": track_index,
|
|
281
307
|
"device_index": device_index,
|
|
282
308
|
"parameters": hygiene_params,
|
|
@@ -293,7 +319,7 @@ async def _simpler_post_load_hygiene(
|
|
|
293
319
|
# to Slice/One-Shot explicitly if they want.
|
|
294
320
|
playback_mode_set = False
|
|
295
321
|
try:
|
|
296
|
-
ableton.send_command
|
|
322
|
+
await asyncio.to_thread(ableton.send_command, "set_simpler_playback_mode", {
|
|
297
323
|
"track_index": track_index,
|
|
298
324
|
"device_index": device_index,
|
|
299
325
|
"playback_mode": 0, # 0 = Classic, 1 = One-Shot, 2 = Slice
|
|
@@ -413,6 +413,12 @@ def compare_to_reference(
|
|
|
413
413
|
"stereo_width_mix": stereo_width_mix,
|
|
414
414
|
"stereo_width_ref": stereo_width_ref,
|
|
415
415
|
"band_deltas": band_deltas,
|
|
416
|
+
# Absolute per-band energy balances (NOT deltas). The reference
|
|
417
|
+
# builder needs the reference's OWN band_balance to populate a
|
|
418
|
+
# ReferenceProfile; band_deltas (mix - ref) is the wrong scale for
|
|
419
|
+
# that. Kept alongside band_deltas so existing callers are unaffected.
|
|
420
|
+
"mix_band_balance": dict(mix_bands),
|
|
421
|
+
"reference_band_balance": dict(ref_bands),
|
|
416
422
|
"suggestions": suggestions,
|
|
417
423
|
}
|
|
418
424
|
|
|
@@ -9,6 +9,7 @@ These tools power the Agent OS cyclical loop:
|
|
|
9
9
|
|
|
10
10
|
from __future__ import annotations
|
|
11
11
|
|
|
12
|
+
import asyncio
|
|
12
13
|
import json
|
|
13
14
|
import logging
|
|
14
15
|
from typing import Optional
|
|
@@ -612,7 +613,9 @@ async def iterate_toward_goal(
|
|
|
612
613
|
if move is None:
|
|
613
614
|
branch.status = "failed"
|
|
614
615
|
continue
|
|
615
|
-
session_info =
|
|
616
|
+
session_info = await asyncio.to_thread(
|
|
617
|
+
ableton.send_command, "get_session_info"
|
|
618
|
+
)
|
|
616
619
|
kernel = {"session_info": session_info, "mode": "explore"}
|
|
617
620
|
plan = compiler.compile(move, kernel)
|
|
618
621
|
branch.compiled_plan = plan.to_dict()
|