livepilot 1.23.0 → 1.23.2
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 +17 -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/overlays.py +39 -18
- package/package.json +1 -1
- package/remote_script/LivePilot/__init__.py +1 -1
- package/server.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v1.23.2 — 2026-04-25
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- M4L bridge `.amxd` ping version now matches the release version. v1.23.1 shipped with the frozen `LivePilot_Analyzer.amxd` still embedding `"version": "1.23.0"` (the m4l_device files weren't bumped during the v1.23.1 patch), which tripped the `amxd-freeze-drift` CI guard introduced after past releases lost to the same drift. In-place binary patch at offsets 32653 + 6691677 (same byte count, file size unchanged at 6,754,576 bytes), plus source bumps in `livepilot_bridge.js` (`var VERSION`) and `LivePilot_Analyzer.maxpat` (UI label) so the next freeze starts in sync.
|
|
7
|
+
|
|
8
|
+
### Notes
|
|
9
|
+
- Bridge functionality is unchanged from v1.23.1. This is a metadata-only patch: end users who looked at the bridge UI in v1.23.1 saw "1.23.0" — that's now corrected.
|
|
10
|
+
- All distribution channels (npm, GitHub release MCPB, marketplace mirror) are re-published from this commit.
|
|
11
|
+
|
|
12
|
+
## v1.23.1 — 2026-04-25
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
- `extension_atlas_search` multi-word queries returned 0 hits because the search did literal-substring matching. `"sophie ponyboy"` failed to match `"SOPHIE — Ponyboy kick"` because of the em-dash separator. Now: query is tokenized on whitespace, each token must match somewhere (AND semantics), per-token scores sum for ranking. Single-token queries collapse to the original behavior — fully backwards-compatible.
|
|
16
|
+
|
|
17
|
+
### Tests
|
|
18
|
+
- 3 new tests covering multi-token AND, em-dash separator handling, per-token score aggregation.
|
|
19
|
+
|
|
3
20
|
## v1.23.0 — 2026-04-25
|
|
4
21
|
|
|
5
22
|
### Added
|
|
Binary file
|
|
@@ -34,7 +34,7 @@ outlets = 2; // 0: to udpsend (responses), 1: to buffer~/status
|
|
|
34
34
|
// Single source of truth for the bridge version — bumped alongside the
|
|
35
35
|
// rest of the release manifest. Surfaced in the UI via messnamed("livepilot_version", ...)
|
|
36
36
|
// so the frozen .amxd visibly reports which build it was last exported from.
|
|
37
|
-
var VERSION = "1.23.
|
|
37
|
+
var VERSION = "1.23.2";
|
|
38
38
|
|
|
39
39
|
// ── State ──────────────────────────────────────────────────────────────────
|
|
40
40
|
|
package/mcp_server/__init__.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""LivePilot MCP Server — bridges MCP protocol to Ableton Live."""
|
|
2
|
-
__version__ = "1.23.
|
|
2
|
+
__version__ = "1.23.2"
|
|
@@ -91,14 +91,20 @@ class OverlayIndex:
|
|
|
91
91
|
def search(self, query: str, namespace: Optional[str] = None,
|
|
92
92
|
entity_type: Optional[str] = None,
|
|
93
93
|
limit: int = 10) -> list[OverlayEntry]:
|
|
94
|
-
"""Weighted substring search.
|
|
94
|
+
"""Weighted substring search with whitespace-tokenized AND semantics.
|
|
95
95
|
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
The query is split on whitespace into tokens. Each token is scored
|
|
97
|
+
against each entry independently:
|
|
98
|
+
+1000 if token == entity_id (case-insensitive exact match)
|
|
98
99
|
+100 per substring hit in name
|
|
99
100
|
+50 per substring hit in tag or artist
|
|
100
101
|
+10 per substring hit in description
|
|
101
102
|
|
|
103
|
+
An entry matches only if EVERY token scores > 0 somewhere (AND
|
|
104
|
+
semantics — prevents 'sophie ponyboy' from matching unrelated
|
|
105
|
+
entries that contain only one of the two words). The entry's
|
|
106
|
+
final score is the sum across all tokens.
|
|
107
|
+
|
|
102
108
|
Sorts by descending score, then by entity_id for stable ties.
|
|
103
109
|
Filters by namespace and/or entity_type if provided.
|
|
104
110
|
Empty query returns empty list.
|
|
@@ -106,6 +112,9 @@ class OverlayIndex:
|
|
|
106
112
|
q = (query or "").strip().lower()
|
|
107
113
|
if not q:
|
|
108
114
|
return []
|
|
115
|
+
tokens = q.split()
|
|
116
|
+
if not tokens:
|
|
117
|
+
return []
|
|
109
118
|
|
|
110
119
|
scored: list[tuple[int, str, OverlayEntry]] = []
|
|
111
120
|
for entry in self._entries.values():
|
|
@@ -113,21 +122,33 @@ class OverlayIndex:
|
|
|
113
122
|
continue
|
|
114
123
|
if entity_type is not None and entry.entity_type != entity_type:
|
|
115
124
|
continue
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
for
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
for
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
125
|
+
|
|
126
|
+
name_lower = entry.name.lower()
|
|
127
|
+
entity_id_lower = entry.entity_id.lower()
|
|
128
|
+
description_lower = entry.description.lower()
|
|
129
|
+
tags_lower = [str(t).lower() for t in entry.tags]
|
|
130
|
+
artists_lower = [str(a).lower() for a in entry.artists]
|
|
131
|
+
|
|
132
|
+
token_scores = []
|
|
133
|
+
for tok in tokens:
|
|
134
|
+
s = 0
|
|
135
|
+
if entity_id_lower == tok:
|
|
136
|
+
s += 1000
|
|
137
|
+
if tok in name_lower:
|
|
138
|
+
s += 100
|
|
139
|
+
for tag in tags_lower:
|
|
140
|
+
if tok in tag:
|
|
141
|
+
s += 50
|
|
142
|
+
for artist in artists_lower:
|
|
143
|
+
if tok in artist:
|
|
144
|
+
s += 50
|
|
145
|
+
if tok in description_lower:
|
|
146
|
+
s += 10
|
|
147
|
+
token_scores.append(s)
|
|
148
|
+
|
|
149
|
+
# AND semantics — every token must match somewhere
|
|
150
|
+
if all(s > 0 for s in token_scores):
|
|
151
|
+
scored.append((sum(token_scores), entry.entity_id, entry))
|
|
131
152
|
|
|
132
153
|
scored.sort(key=lambda triple: (-triple[0], triple[1]))
|
|
133
154
|
return [entry for (_, _, entry) in scored[:max(0, limit)]]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "livepilot",
|
|
3
|
-
"version": "1.23.
|
|
3
|
+
"version": "1.23.2",
|
|
4
4
|
"mcpName": "io.github.dreamrec/livepilot",
|
|
5
5
|
"description": "Agentic production system for Ableton Live 12 — 433 tools, 53 domains, 44 semantic moves. Device atlas (5264 devices, 120 enriched, 7 indexes), Splice intelligence (gRPC + GraphQL describe-a-sound + preview + collections + presets), 9-band spectral perception auto-loaded via ensure_analyzer_on_master, Creative Director skill, technique memory, 12 creative intelligence engines",
|
|
6
6
|
"author": "Pilot Studio",
|
|
@@ -5,7 +5,7 @@ Entry point for the ControlSurface. Ableton calls create_instance(c_instance)
|
|
|
5
5
|
when this script is selected in Preferences > Link, Tempo & MIDI.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
__version__ = "1.23.
|
|
8
|
+
__version__ = "1.23.2"
|
|
9
9
|
|
|
10
10
|
from _Framework.ControlSurface import ControlSurface
|
|
11
11
|
from . import router
|
package/server.json
CHANGED
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
"url": "https://github.com/dreamrec/LivePilot",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "1.23.
|
|
9
|
+
"version": "1.23.2",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "livepilot",
|
|
14
|
-
"version": "1.23.
|
|
14
|
+
"version": "1.23.1",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
}
|