fix: rename start_beat to start and end_beat to end in 3 tools.

This commit is contained in:
Xiaohan-Tian
2026-04-05 21:28:19 -07:00
parent ee31ca087e
commit 26b7510178
5 changed files with 105 additions and 105 deletions
+4 -4
View File
@@ -25,9 +25,9 @@ Read existing musical content from the project. The output is in ABC notation. I
Remove notes from a given beat range in the current region. Remove notes from a given beat range in the current region.
## add_notes ## add_notes
Add notes to the current region. Pitches use scientific pitch notation with support for sharps and flats (e.g., `C4`, `F#3`, `Bb2`). **Important**: the `start_beat` parameter is always the **absolute** beat position in the project timeline — not relative to the current region's start. For example, to place a note at beat 6, set `start_beat` to 6 regardless of where the current region begins. Add notes to the current region. Pitches use scientific pitch notation with support for sharps and flats (e.g., `C4`, `F#3`, `Bb2`). **Important**: the `start` parameter is always the **absolute** beat position in the project timeline — not relative to the current region's start. For example, to place a note at beat 6, set `start` to 6 regardless of where the current region begins.
To create a melodic line, use sequential `start_beat` values for each note. To create a chord, give multiple notes the same `start_beat`. To create a melodic line, use sequential `start` values for each note. To create a chord, give multiple notes the same `start`.
# Tool Use Guidelines # Tool Use Guidelines
@@ -80,12 +80,12 @@ You have access to two tools for working with the current music region: **remove
- Check that chord progressions are appropriate for the key signature - Check that chord progressions are appropriate for the key signature
- Confirm note lengths don't extend beyond reasonable musical phrases - Confirm note lengths don't extend beyond reasonable musical phrases
- **Pitch Notation**: Use scientific pitch notation (e.g., C4, A#3, Bb2) and ensure octave numbers are appropriate for the instrument - **Pitch Notation**: Use scientific pitch notation (e.g., C4, A#3, Bb2) and ensure octave numbers are appropriate for the instrument
- **Timing Constraints**: All start_beat and length values must align with the time signature grid - **Timing Constraints**: All start and length values must align with the time signature grid
- When adding chord progressions, first break down the progression into individual notes based on the key signature, then add all the notes. - When adding chord progressions, first break down the progression into individual notes based on the key signature, then add all the notes.
- For example, to create a I-V-vi-IV progression in C major with 4-beat chords: - For example, to create a I-V-vi-IV progression in C major with 4-beat chords:
1. Check the key signature. In C major, the chords are C, G, Am, F. 1. Check the key signature. In C major, the chords are C, G, Am, F.
2. Convert each chord to individual notes: C = C4/E4/G4, G = G3/B3/D4, Am = A3/C4/E4, F = F3/A3/C4. 2. Convert each chord to individual notes: C = C4/E4/G4, G = G3/B3/D4, Am = A3/C4/E4, F = F3/A3/C4.
3. Call `add_notes` with all 12 notes: the C chord notes at `start_beat` 0, the G chord notes at `start_beat` 4, the Am chord notes at `start_beat` 8, and the F chord notes at `start_beat` 12 — each with `length` 4. 3. Call `add_notes` with all 12 notes: the C chord notes at `start` 0, the G chord notes at `start` 4, the Am chord notes at `start` 8, and the F chord notes at `start` 12 — each with `length` 4.
# Workflow Tips # Workflow Tips
+10 -10
View File
@@ -17,7 +17,7 @@ export class AddNotesTool extends BaseTool {
readonly parameters: Record<string, ToolParameter> = { readonly parameters: Record<string, ToolParameter> = {
notes: { notes: {
type: 'array', type: 'array',
description: 'List of notes to add. To create a chord, give multiple notes the same start_beat. To create a melody, use sequential start_beat values.', description: 'List of notes to add. To create a chord, give multiple notes the same start beat. To create a melody, use sequential start values.',
required: true, required: true,
items: { items: {
type: 'object', type: 'object',
@@ -28,9 +28,9 @@ export class AddNotesTool extends BaseTool {
description: 'Pitch in scientific notation: note name, optional accidental (# or b), and octave number. Examples: "C4" (middle C), "F#3" (F-sharp 3rd octave), "Bb2" (B-flat 2nd octave).', description: 'Pitch in scientific notation: note name, optional accidental (# or b), and octave number. Examples: "C4" (middle C), "F#3" (F-sharp 3rd octave), "Bb2" (B-flat 2nd octave).',
required: true required: true
}, },
start_beat: { start: {
type: 'number', type: 'number',
description: 'Absolute beat position on the project timeline where the note starts. This is NOT relative to the region — beat 6 means beat 6 in the project regardless of where the region begins. Fractional values are supported (e.g., 0.5 = half a beat after beat 0).', description: 'Start beat — the absolute beat position on the project timeline where the note begins. This is NOT relative to the region — beat 6 means beat 6 in the project regardless of where the region begins. Fractional values are supported (e.g., 0.5 = half a beat after beat 0).',
required: true required: true
}, },
length: { length: {
@@ -60,7 +60,7 @@ export class AddNotesTool extends BaseTool {
const notes = params.notes as Array<{ const notes = params.notes as Array<{
pitch: string; pitch: string;
start_beat: number; start: number;
length: number; length: number;
velocity?: number; velocity?: number;
}>; }>;
@@ -79,7 +79,7 @@ export class AddNotesTool extends BaseTool {
// Validate and convert notes to creation data // Validate and convert notes to creation data
const noteCreationData: NoteCreationData[] = []; const noteCreationData: NoteCreationData[] = [];
const createdNotes: Array<{ pitch: string; start_beat: number; length: number }> = []; const createdNotes: Array<{ pitch: string; start: number; length: number }> = [];
for (const note of notes) { for (const note of notes) {
try { try {
@@ -92,8 +92,8 @@ export class AddNotesTool extends BaseTool {
} }
// Validate beat positions // Validate beat positions
if (note.start_beat < 0) { if (note.start < 0) {
return this.createErrorResult(`Invalid start_beat ${note.start_beat}. Must be >= 0.`); return this.createErrorResult(`Invalid start ${note.start}. Must be >= 0.`);
} }
if (note.length <= 0) { if (note.length <= 0) {
@@ -102,7 +102,7 @@ export class AddNotesTool extends BaseTool {
// Adjust note position relative to region's start beat // Adjust note position relative to region's start beat
const regionStartBeat = targetRegion.getStartFromBeat(); const regionStartBeat = targetRegion.getStartFromBeat();
const adjustedStartBeat = note.start_beat - regionStartBeat; const adjustedStartBeat = note.start - regionStartBeat;
const adjustedEndBeat = adjustedStartBeat + note.length; const adjustedEndBeat = adjustedStartBeat + note.length;
// Create note creation data // Create note creation data
@@ -116,7 +116,7 @@ export class AddNotesTool extends BaseTool {
createdNotes.push({ createdNotes.push({
pitch: note.pitch, pitch: note.pitch,
start_beat: note.start_beat, start: note.start,
length: note.length length: note.length
}); });
@@ -132,7 +132,7 @@ export class AddNotesTool extends BaseTool {
// Create success message // Create success message
const noteCount = createdNotes.length; const noteCount = createdNotes.length;
const noteList = createdNotes const noteList = createdNotes
.map(note => `${note.pitch} (beat ${note.start_beat}, length ${note.length})`) .map(note => `${note.pitch} (beat ${note.start}, length ${note.length})`)
.join(', '); .join(', ');
return this.createSuccessResult( return this.createSuccessResult(
+5 -5
View File
@@ -20,9 +20,9 @@ export class ReadMusicTool extends BaseTool {
description: 'Which track to read. Pass a specific track ID, or "all" to read every track. If omitted, reads the first available track.', description: 'Which track to read. Pass a specific track ID, or "all" to read every track. If omitted, reads the first available track.',
required: false required: false
}, },
start_beat: { start: {
type: 'number', type: 'number',
description: 'Absolute beat position to start reading from. The actual output will be rounded down to the nearest bar boundary. Defaults to 0.', description: 'Start beat — the absolute beat position to start reading from. The actual output will be rounded down to the nearest bar boundary. Defaults to 0.',
required: false required: false
}, },
length: { length: {
@@ -57,7 +57,7 @@ export class ReadMusicTool extends BaseTool {
this.validateParameters(params); this.validateParameters(params);
const trackId = params.track_id as string | undefined; const trackId = params.track_id as string | undefined;
const startBeat = (params.start_beat as number) || 0; const startBeat = (params.start as number) || 0;
const length = params.length as number | undefined; const length = params.length as number | undefined;
const project = this.getCurrentProject(); const project = this.getCurrentProject();
@@ -67,9 +67,9 @@ export class ReadMusicTool extends BaseTool {
return this.createErrorResult('No tracks found in the project'); return this.createErrorResult('No tracks found in the project');
} }
// Validate start_beat // Validate start
if (startBeat < 0) { if (startBeat < 0) {
return this.createErrorResult(`Invalid start_beat ${startBeat}. Must be >= 0.`); return this.createErrorResult(`Invalid start ${startBeat}. Must be >= 0.`);
} }
// Validate length // Validate length
+8 -8
View File
@@ -14,14 +14,14 @@ export class RemoveNotesTool extends BaseTool {
readonly description = 'Remove all MIDI notes whose start position falls within the specified beat range. Use this to clear a section before rewriting it, or to delete unwanted notes. Beat positions are absolute on the project timeline.'; readonly description = 'Remove all MIDI notes whose start position falls within the specified beat range. Use this to clear a section before rewriting it, or to delete unwanted notes. Beat positions are absolute on the project timeline.';
readonly parameters: Record<string, ToolParameter> = { readonly parameters: Record<string, ToolParameter> = {
start_beat: { start: {
type: 'number', type: 'number',
description: 'Absolute beat position where the removal range begins (inclusive). A note starting at exactly this beat will be removed.', description: 'Start beat — the absolute beat position where the removal range begins (inclusive). A note starting at exactly this beat will be removed.',
required: true required: true
}, },
end_beat: { end: {
type: 'number', type: 'number',
description: 'Absolute beat position where the removal range ends (exclusive). A note starting at exactly this beat will NOT be removed. Must be greater than start_beat.', description: 'End beat — the absolute beat position where the removal range ends (exclusive). A note starting at exactly this beat will NOT be removed. Must be greater than start.',
required: true required: true
}, },
region_id: { region_id: {
@@ -36,17 +36,17 @@ export class RemoveNotesTool extends BaseTool {
// Validate parameters // Validate parameters
this.validateParameters(params); this.validateParameters(params);
const startBeat = params.start_beat as number; const startBeat = params.start as number;
const endBeat = params.end_beat as number; const endBeat = params.end as number;
const regionId = params.region_id as string | undefined; const regionId = params.region_id as string | undefined;
// Validate beat range // Validate beat range
if (startBeat < 0) { if (startBeat < 0) {
return this.createErrorResult(`Invalid start_beat ${startBeat}. Must be >= 0.`); return this.createErrorResult(`Invalid start ${startBeat}. Must be >= 0.`);
} }
if (endBeat <= startBeat) { if (endBeat <= startBeat) {
return this.createErrorResult(`Invalid beat range: end_beat (${endBeat}) must be greater than start_beat (${startBeat}).`); return this.createErrorResult(`Invalid beat range: end (${endBeat}) must be greater than start (${startBeat}).`);
} }
// Find the target region // Find the target region
+6 -6
View File
@@ -268,13 +268,13 @@ export class KGDebugger {
* Usage examples in browser console: * Usage examples in browser console:
* *
* // Single tool call: * // Single tool call:
* await KGStudio.KGDebugger.testToolCall('{"name":"read_music","arguments":{"start_beat":0,"length":8}}') * await KGStudio.KGDebugger.testToolCall('{"name":"read_music","arguments":{"start":0,"length":8}}')
* *
* // Multiple tool calls: * // Multiple tool calls:
* await KGStudio.KGDebugger.testToolCall('[{"name":"remove_notes","arguments":{"start_beat":0,"end_beat":4}},{"name":"add_notes","arguments":{"notes":[{"pitch":"C4","start_beat":0,"length":1}]}}]') * await KGStudio.KGDebugger.testToolCall('[{"name":"remove_notes","arguments":{"start":0,"end_beat":4}},{"name":"add_notes","arguments":{"notes":[{"pitch":"C4","start":0,"length":1}]}}]')
* *
* // Can also pass a JS object directly (no need to stringify): * // Can also pass a JS object directly (no need to stringify):
* await KGStudio.KGDebugger.testToolCall({name:"read_music",arguments:{start_beat:0}}) * await KGStudio.KGDebugger.testToolCall({name:"read_music",arguments:{start:0}})
* *
* @param input - JSON string, object, or array of tool call(s). * @param input - JSON string, object, or array of tool call(s).
* Each tool call should have: { name: string, arguments: object } * Each tool call should have: { name: string, arguments: object }
@@ -352,9 +352,9 @@ export class KGDebugger {
console.log(" - Use browser developer tools for best experience"); console.log(" - Use browser developer tools for best experience");
console.log(""); console.log("");
console.log("💡 testToolCall examples:"); console.log("💡 testToolCall examples:");
console.log(' await KGStudio.KGDebugger.testToolCall(\'{"name":"read_music","arguments":{"start_beat":0,"length":8}}\')'); console.log(' await KGStudio.KGDebugger.testToolCall(\'{"name":"read_music","arguments":{"start":0,"length":8}}\')');
console.log(' await KGStudio.KGDebugger.testToolCall({name:"add_notes",arguments:{notes:[{pitch:"C4",start_beat:0,length:1}]}})'); console.log(' await KGStudio.KGDebugger.testToolCall({name:"add_notes",arguments:{notes:[{pitch:"C4",start:0,length:1}]}})');
console.log(' await KGStudio.KGDebugger.testToolCall([{name:"remove_notes",arguments:{start_beat:0,end_beat:4}},{name:"read_music",arguments:{}}])'); console.log(' await KGStudio.KGDebugger.testToolCall([{name:"remove_notes",arguments:{start:0,end_beat:4}},{name:"read_music",arguments:{}}])');
} }
/** /**