livepilot 1.18.0 → 1.18.1

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 CHANGED
@@ -1,5 +1,124 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.18.1 — Director HIGH-severity patches (April 23 2026)
4
+
5
+ Patch release addressing 4 of the 12 known issues documented in v1.18.0.
6
+ All three HIGH-severity bugs are fixed, plus 6 medium-severity items
7
+ (data cleanups and doc clarifications). All fixes landed with
8
+ regression-guard tests. 2779 project tests pass + 1 xfail (pre-existing).
9
+
10
+ ### High-severity fixes
11
+
12
+ - **#1 `create_experiment` auto-proposal returned single-char move_ids.**
13
+ Python unpacking bug at `mcp_server/experiment/tools.py:267` —
14
+ `[m[0] for m, _ in scored]` indexed the first character of each
15
+ move_id string. Fix: `[move_id for move_id, _ in scored[:limit]]`.
16
+ Pre-fix, calling the director's Flow B with no explicit seeds/move_ids
17
+ would always fail at run_experiment with `"Move t not found"`.
18
+
19
+ - **#2 `propose_composer_branches` ignored concept-packet arrangement
20
+ idioms.** Dub-techno prompts (referencing Basic Channel, Gas, etc.)
21
+ were collapsed to the generic techno template (Intro→Build→Drop→
22
+ Breakdown→Drop 2→Outro with 6 standard layers). Fix: "dub techno"
23
+ is now its own canonical genre in `GENRE_DEFAULTS` and
24
+ `SECTION_TEMPLATES`, with a continuous-evolution scaffold
25
+ (Dawn→Pulse→Chord→Depth→Withdraw→Return, 3-5 layers, energy 0.4).
26
+ Removed the `dub techno → techno` alias that was causing the
27
+ collapse; added `dub-techno` (hyphenated) as an alias to the new
28
+ canonical.
29
+
30
+ - **#3 Director raw-tool-call path bypassed the action ledger.**
31
+ Min-effective doc fix: Phase 6 of `livepilot-creative-director`
32
+ now mandates `add_session_memory(category="move_executed", ...)`
33
+ after raw-tool execution batches, so anti-repetition detection on
34
+ subsequent creative turns isn't blind. Added a state-inference
35
+ fallback table in `anti-repetition-rules.md` for when the ledger
36
+ is still empty (infer recent family from loaded devices, non-default
37
+ mixer state, clip slot contents). Full architectural fix (route all
38
+ Phase 6 execution through `apply_semantic_move`/`commit_experiment`)
39
+ is deferred to v1.19.
40
+
41
+ ### Medium-severity fixes
42
+
43
+ - **#4 Ping Pong Delay ghost packet.** `affordances/devices/ping-pong-delay.yaml`
44
+ previously described a standalone device that doesn't exist in
45
+ Live 12 (`search_browser` returned empty). Rewritten as an explicit
46
+ mode-alias for Echo with `Channel Mode = 1`. `echo.yaml` now prominently
47
+ documents the Channel Mode enum (0=Stereo, 1=Ping Pong, 2=Mid/Side).
48
+
49
+ - **#5 Auto Filter affordance used legacy 20-135 Hz ranges.** Modern
50
+ `AutoFilter2` class (Live 12 default) uses 0-1 normalized for
51
+ Frequency, Resonance, and LFO Amount. Live-verified mapping (raw
52
+ 0.45 → display 448 Hz) is now documented in the YAML. Legacy/modern
53
+ distinction clarified in the notes.
54
+
55
+ - **#9 `propose_composer_branches` silent count degradation.** Explicit
56
+ `count=3` at `freshness<0.7` was silently returning 2 seeds because
57
+ `layer_contrast` was gated behind `freshness>=0.7`. Fix: explicit
58
+ `count>=3` now raises freshness internally to 0.7 to admit all
59
+ strategies. Default `count=2` (no override) still respects the
60
+ freshness gate — preserves the "freshness shapes default strategy
61
+ count" contract and the existing tests that assert it.
62
+
63
+ - **#12 Low-novelty-budget escape hatch for 3-plan diversity rule.**
64
+ `move-family-diversity-rule.md` gained a dedicated section: when
65
+ `novelty_budget < 0.35` (user prompts like "keep the vibe, just
66
+ cleaner"), 1-2 family plans is acceptable and honest. Prevents the
67
+ rule from fighting cleanup requests.
68
+
69
+ ### Bonus fixes
70
+
71
+ - **`batch_set_parameters` schema gotcha documented.** Core SKILL.md
72
+ Rule 15 now shows the correct dict-of-dicts shape:
73
+ `{"ParamName": {"value": v}}`. Live verification surfaced this during
74
+ v1.18.0 pressure testing.
75
+
76
+ - **Convolution Reverb phantom `ir_length` already fixed in v1.18.0
77
+ commit 9** — regression test now guards against reintroduction.
78
+
79
+ ### Tests added
80
+
81
+ - `test_create_experiment_auto_proposal_no_m0_bug` (source-pattern
82
+ regression guard)
83
+ - `test_create_experiment_auto_proposal_functional` (mirror-logic
84
+ integration check)
85
+ - `test_composer_dub_techno_prompt_avoids_drop_scaffold` (no Drop/Drop 2
86
+ on Basic Channel prompts)
87
+ - `test_propose_composer_branches_honors_explicit_count` (count=3
88
+ returns 3 regardless of freshness)
89
+ - `test_medium_freshness_count_3_unlocks_all_strategies` (renamed from
90
+ test encoding the pre-fix bug as desired behavior)
91
+ - `test_medium_freshness_default_count_gives_two` (preserves
92
+ default-count-respects-freshness contract)
93
+ - `test_ping_pong_delay_is_documented_as_echo_mode`
94
+ - `test_auto_filter_ranges_are_normalized_for_modern_class`
95
+ - `test_low_novelty_escape_hatch_documented`
96
+ - `test_batch_set_parameters_schema_documented`
97
+ - `test_director_phase6_records_ledger_marker`
98
+ - `test_anti_repetition_has_state_inference_fallback`
99
+
100
+ ### Still open for v1.18.2 / v1.19
101
+
102
+ 8 items remain from the v1.18.0 Known Issues list:
103
+
104
+ - **#7 Packet `avoid` list runtime enforcement** (currently advisory —
105
+ pre-flight check against tool args needed)
106
+ - **#8 `locked_dimensions` runtime enforcement** (same pattern as #7)
107
+ - **#10 Wonder Mode zero-variant degradation on empty session context**
108
+ - **#11 Evaluation tie-break coarseness** (3-way ties at score 0.6)
109
+ - **Experiment state continuity between branches** (before-snapshot
110
+ drift)
111
+ - **Hybrid-packet compilation algorithm** (union/intersection logic
112
+ for "Basic Channel meets Dilla")
113
+ - **~20 missing genre YAMLs** (downtempo, boom_bap, lo_fi, synthwave,
114
+ techno, etc.) — xfail test tracks this
115
+ - **Full architectural fix for #3** (route director Phase 6 through
116
+ semantic_move commits, replacing the doc-level fix shipped here)
117
+
118
+ These are each scoped for focused follow-up sessions — they need new
119
+ infrastructure or architectural decisions not suitable for a patch
120
+ release.
121
+
3
122
  ## 1.18.0 — Creative Director + concept packets + device affordances (April 23 2026)
4
123
 
5
124
  A structural feature release. Addresses the "agent doesn't variate
@@ -1,2 +1,2 @@
1
1
  """LivePilot MCP Server — bridges MCP protocol to Ableton Live."""
2
- __version__ = "1.18.0"
2
+ __version__ = "1.18.1"
@@ -124,7 +124,18 @@ def propose_composer_branches(
124
124
 
125
125
  intent = parse_prompt(request_text)
126
126
 
127
- # Gate high-novelty strategies on freshness.
127
+ # v1.18.1 #9 fix: explicit count=3 overrides the freshness default.
128
+ # Pre-fix, count=3 at freshness=0.6 silently returned 2 (canonical +
129
+ # energy_shift only; layer_contrast was gated behind freshness>=0.7).
130
+ # Now: caller asking for all 3 strategies gets them by internally
131
+ # raising freshness to 0.7. Count=2 (the default) does NOT raise
132
+ # freshness — the freshness gate still caps at 1 on low-freshness
133
+ # runs, which is the documented "freshness cautiously shapes default
134
+ # strategy count" contract.
135
+ if count >= 3:
136
+ freshness = max(freshness, 0.7)
137
+
138
+ # Gate high-novelty strategies on (possibly-raised) freshness.
128
139
  if freshness < 0.4:
129
140
  strategies = [_STRATEGIES[0]] # canonical only
130
141
  elif freshness < 0.7:
@@ -172,6 +172,19 @@ SECTION_TEMPLATES: dict[str, list[dict]] = {
172
172
  {"name": "Drop 2", "bars": 16, "layers": ["drums", "bass", "lead", "percussion", "vocal", "texture"]},
173
173
  {"name": "Outro", "bars": 8, "layers": ["drums:-6dB", "texture", "pad"]},
174
174
  ],
175
+ # Dub techno — continuous-evolution aesthetic. No Drop structure, no
176
+ # Build/Break cycle. Section names reflect dub-techno arrangement idioms:
177
+ # slow reveal, subtraction before addition, return deeper not louder.
178
+ # Source: concepts/artists/basic-channel.yaml arrangement_idioms +
179
+ # live-verification finding from v1.18.0 CHANGELOG #2. v1.18.1 #2 fix.
180
+ "dub techno": [
181
+ {"name": "Dawn", "bars": 16, "layers": ["texture:-12dB"]},
182
+ {"name": "Pulse", "bars": 16, "layers": ["drums:-6dB", "texture"]},
183
+ {"name": "Chord", "bars": 32, "layers": ["drums", "bass", "pad:-6dB", "texture"]},
184
+ {"name": "Depth", "bars": 32, "layers": ["drums", "bass", "pad", "texture"]},
185
+ {"name": "Withdraw", "bars": 16, "layers": ["pad:-6dB", "texture:-6dB"]},
186
+ {"name": "Return", "bars": 16, "layers": ["texture:-12dB"]},
187
+ ],
175
188
  "house": [
176
189
  {"name": "Intro", "bars": 8, "layers": ["drums:-6dB", "pad"]},
177
190
  {"name": "Verse", "bars": 16, "layers": ["drums", "bass", "pad"]},
@@ -51,6 +51,13 @@ GENRE_DEFAULTS: dict[str, dict] = {
51
51
  "tempo": 128, "keys": ["Am", "Cm"], "energy": 0.7,
52
52
  "layers_min": 5, "layers_max": 7,
53
53
  },
54
+ # Dub techno is its own canonical genre — continuous-evolution aesthetic
55
+ # referencing Basic Channel / Rhythm & Sound / Gas. Previously aliased to
56
+ # "techno" which defaulted to Drop-based scaffolds (v1.18.1 #2 fix).
57
+ "dub techno": {
58
+ "tempo": 125, "keys": ["Am", "Em"], "energy": 0.4,
59
+ "layers_min": 3, "layers_max": 5,
60
+ },
54
61
  "house": {
55
62
  "tempo": 124, "keys": ["Cm", "Fm"], "energy": 0.6,
56
63
  "layers_min": 5, "layers_max": 6,
@@ -93,7 +100,11 @@ _GENRE_ALIASES: dict[str, str] = {
93
100
  "industrial techno": "techno",
94
101
  "minimal techno": "techno",
95
102
  "detroit techno": "techno",
96
- "dub techno": "techno",
103
+ # NOTE: "dub techno" is intentionally NOT aliased to "techno"
104
+ # it's now its own canonical genre with dub-appropriate defaults
105
+ # (see GENRE_DEFAULTS above) and a non-Drop section template (see
106
+ # layer_planner.SECTION_TEMPLATES). v1.18.1 #2 fix.
107
+ "dub-techno": "dub techno",
97
108
  }
98
109
 
99
110
 
@@ -244,18 +244,22 @@ def create_experiment(
244
244
 
245
245
  # ── Mode 2/3: legacy move_ids path ──────────────────────────────────
246
246
  if not move_ids:
247
- # Auto-propose moves from the registry
247
+ # Auto-propose moves from the registry by keyword overlap.
248
+ # v1.18.1 #1 fix: the previous selector indexed the first character
249
+ # of each move_id (a Python unpacking trap — the variable was
250
+ # already the full string, the [0] subscript sliced into it).
251
+ # Result pre-fix: single-char move_ids like 't', 'w', 'm' that
252
+ # failed at run_experiment with "Move t not found". Now the whole
253
+ # move_id string is kept.
248
254
  from ..semantic_moves import registry
249
- from ..semantic_moves.tools import propose_next_best_move
250
- # Use the propose function's logic directly
251
255
  all_moves = list(registry._REGISTRY.values())
252
256
  request_lower = request_text.lower()
253
- scored = []
257
+ request_words = set(request_lower.split())
258
+ scored: list[tuple[str, float]] = []
254
259
  for move in all_moves:
255
260
  score = 0.0
256
261
  move_words = set(move.move_id.replace("_", " ").split())
257
262
  intent_words = set(move.intent.lower().split())
258
- request_words = set(request_lower.split())
259
263
  overlap = request_words & (move_words | intent_words)
260
264
  score += len(overlap) * 0.3
261
265
  for dim in move.targets:
@@ -264,7 +268,7 @@ def create_experiment(
264
268
  if score > 0.1:
265
269
  scored.append((move.move_id, score))
266
270
  scored.sort(key=lambda x: -x[1])
267
- move_ids = [m[0] for m, _ in scored[:limit]] if scored else []
271
+ move_ids = [move_id for move_id, _ in scored[:limit]] if scored else []
268
272
 
269
273
  if not move_ids:
270
274
  return {"error": "No matching semantic moves found for this request"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "livepilot",
3
- "version": "1.18.0",
3
+ "version": "1.18.1",
4
4
  "mcpName": "io.github.dreamrec/livepilot",
5
5
  "description": "Agentic production system for Ableton Live 12 — 427 tools, 52 domains. Device atlas (1305 devices), sample engine (Splice + browser + filesystem), auto-composition, spectral perception, technique memory, creative intelligence (12 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.18.0"
8
+ __version__ = "1.18.1"
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.18.0",
9
+ "version": "1.18.1",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "livepilot",
14
- "version": "1.18.0",
14
+ "version": "1.18.1",
15
15
  "transport": {
16
16
  "type": "stdio"
17
17
  }