From b98d3478e6aaa1ff4d0c91b245b7e3ef28252a2e Mon Sep 17 00:00:00 2001 From: Zach Guo Date: Wed, 12 Aug 2026 15:21:20 +0800 Subject: [PATCH] feat(music): prefer vocal tracks, widen the pick's turn budget [spec 03-01] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pick instruction now asks for a song with vocals by default — instrumental-only tracks (light/background music, lofi, piano versions) only when the listener explicitly asks. A real pick under this guidance can spend 5 searches before submitting, so the default turn budget goes from 6 to 8 to keep headroom. Co-Authored-By: Claude Fable 5 --- src/music-programmer.ts | 7 ++++--- src/prompts.ts | 3 +++ test/music-programmer.test.ts | 4 +++- test/prompts.test.ts | 1 + 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/music-programmer.ts b/src/music-programmer.ts index 2933d9a..bd00113 100644 --- a/src/music-programmer.ts +++ b/src/music-programmer.ts @@ -9,9 +9,10 @@ import type { AudioClip, Harness, MusicContext, MusicProvider, TrackCandidate, T import { musicTools, type StreamProbe } from './music-tools.ts' import { FIND_MUSIC_INSTRUCTION, MUSIC_CONTEXT_HEADER } from './prompts.ts' -// Enough turns for search -> (maybe refine) -> judge -> submit, and a couple of -// pick-agains if a ref will not resolve. -const DEFAULT_MAX_TURNS = 6 +// Enough turns for several searches -> judge -> submit, and a couple of +// pick-agains if a ref will not resolve: a real pick can spend 5 searches +// before submitting, so the budget leaves headroom beyond that. +const DEFAULT_MAX_TURNS = 8 // Context insertion (spec 03-01 §2.5), the one place a MusicContext becomes // prompt text: the stable persona goes to the system prompt so repeated calls hit diff --git a/src/prompts.ts b/src/prompts.ts index db3722e..aa05a07 100644 --- a/src/prompts.ts +++ b/src/prompts.ts @@ -140,6 +140,9 @@ reason. Guidance: - Prefer official audio / studio versions; avoid hour-long loops, low-quality re-uploads, and live or cover versions unless they clearly fit the moment. +- Pick a song with vocals — someone singing. Avoid instrumental-only tracks + (light/background music, lofi beats, piano versions) unless the listener + explicitly asked for instrumental. - Match the listener's taste and language as expressed by the persona. - Do not repeat something already noted as recently played. - If your pick fails to resolve, pick another candidate and submit again. diff --git a/test/music-programmer.test.ts b/test/music-programmer.test.ts index b97a751..5eb5da5 100644 --- a/test/music-programmer.test.ts +++ b/test/music-programmer.test.ts @@ -74,7 +74,9 @@ describe('MusicProgrammer.nextTrack', () => { expect(task.systemPrompt).toBe(ctx.persona) expect(task.prompt).toContain('FIND-MUSIC-INSTRUCTION') expect(task.prompt).toContain(ctx.situation) - expect(task.maxTurns).toBeGreaterThan(1) // room for search -> judge -> submit + // Room for several searches -> judge -> submit: a real pick can spend 5 + // searches before submitting, so the default must leave headroom. + expect(task.maxTurns).toBeGreaterThanOrEqual(8) }) it('exposes exactly the two music tools and nothing else', async () => { diff --git a/test/prompts.test.ts b/test/prompts.test.ts index 11c3560..e9028e0 100644 --- a/test/prompts.test.ts +++ b/test/prompts.test.ts @@ -62,6 +62,7 @@ describe('music prompts', () => { expect(FIND_MUSIC_INSTRUCTION).toContain('search_music') expect(FIND_MUSIC_INSTRUCTION).toContain('submit_pick') expect(FIND_MUSIC_INSTRUCTION).toContain('announce') + expect(FIND_MUSIC_INSTRUCTION).toContain('vocals') }) it('renders the recent turns and the music-break intent', () => {