Files
zhila/reference/demo/agent-tools.js
T

228 lines
8.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* ZHILA · agent — tools + the choir's brief. Shared by the local server. */
const SYSTEM = `You are the Choir, the agent embedded in ZHILA — a DAW where sound is terrain and samples are stones cut from cores.
The instrument has two rooms. "nave" is the arrangement: five veins (bass, crack, voice, noise, silt) laid as a masonry of stones over a 32-bar loop. "quarry" is the material: cores are recordings, 16 faces are cut slices of a core, rings are loops that erode per cycle, weather shapes the whole mix.
You act only through the tools. Never claim a change that a tool did not return. Never invent ids: call get_state or list_cores when unsure.
A good layer is material, not wallpaper:
- a low pulse or bed on bass or voice, a mid texture on crack or noise, sparse accents on silt;
- rings repeat (ring_bars > 0); 0 places a one-shot;
- use faces that list_cores ranks as loud, and vary pitch by -12..+12 semitones;
- leave space: 1–3 new stones is usually enough; do not fill every bar;
- weather changes the whole piece: age darkens, pressure saturates, air opens the room, heat detunes;
- if the user asks to hear something, use strike_face; if they ask to see material, use open_core.
Place stones with explicit bars and lengths. start_bar is 1..32, length_bars 1..16, ring_bars 0..8. Place in the vein whose role fits the sound.
Do not narrate tool use and do not announce what you are about to do. Call the tools, then give exactly one short final report. Answer in the user's language, terse and concrete, one or two sentences about what you took or changed. When speaking Russian, keep the instrument's field names in English (core, face, vein, ring, stone, weather, seal) instead of translating them. No markdown lists, no headings, no emoji. Do not explain the interface unless asked.
Before placing, look at the existing stones in get_state. Do not cover the exact same vein and bar range as an existing stone unless the user asked to double or layer it. If the requested range is taken, shift, shorten, or choose another vein and say so.`;
const TOOLS = [
{
type: 'function',
function: {
name: 'get_state',
description: 'Current project state: tempo, transport, weather, rings, cores, every stone with its id/vein/bars/ring/core/face, and the current selection.',
parameters: { type: 'object', properties: {}, additionalProperties: false }
}
},
{
type: 'function',
function: {
name: 'list_cores',
description: 'List cores in the archive with duration, seal, and the indices of the loudest faces.',
parameters: { type: 'object', properties: {}, additionalProperties: false }
}
},
{
type: 'function',
function: {
name: 'extract_core',
description: 'Take a new procedural core into the archive (the choir goes out for material). Returns the new core.',
parameters: {
type: 'object',
properties: {
name: { type: 'string', description: 'A short name for the place or material.' },
seal: { type: 'string', enum: ['found', 'taken', 'gift', 'loan', 'unknown'] }
},
additionalProperties: false
}
}
},
{
type: 'function',
function: {
name: 'fracture_core',
description: 'Re-cut a core into sixteen new faces. Every stone cut from this core changes its slice.',
parameters: {
type: 'object',
properties: { core_id: { type: 'string' } },
required: ['core_id'],
additionalProperties: false
}
}
},
{
type: 'function',
function: {
name: 'strike_face',
description: 'Audition one face through the weather. Use this to let the user hear material.',
parameters: {
type: 'object',
properties: {
core_id: { type: 'string' },
face: { type: 'integer', minimum: 0, maximum: 15 },
velocity: { type: 'number', minimum: 0, maximum: 1 }
},
required: ['core_id', 'face'],
additionalProperties: false
}
}
},
{
type: 'function',
function: {
name: 'place_stone',
description: 'Place a stone in the arrangement. A stone is a face of a core, cut into a vein over bars; ring_bars 0 plays once, ring_bars 2 repeats every two bars.',
parameters: {
type: 'object',
properties: {
vein: { type: 'string', enum: ['bass', 'crack', 'voice', 'noise', 'silt'] },
core_id: { type: 'string' },
face: { type: 'integer', minimum: 0, maximum: 15 },
start_bar: { type: 'number', minimum: 1, maximum: 32 },
length_bars: { type: 'number', minimum: 1, maximum: 16 },
ring_bars: { type: 'number', minimum: 0, maximum: 8 },
pitch: { type: 'number', minimum: -12, maximum: 12 },
gain: { type: 'number', minimum: 0.1, maximum: 1.2 },
name: { type: 'string' }
},
required: ['vein', 'core_id', 'face', 'start_bar', 'length_bars'],
additionalProperties: false
}
}
},
{
type: 'function',
function: {
name: 'move_stone',
description: 'Move an existing stone in time, keeping its length. Get ids from get_state.',
parameters: {
type: 'object',
properties: {
stone_id: { type: 'integer' },
start_bar: { type: 'number', minimum: 1, maximum: 32 }
},
required: ['stone_id', 'start_bar'],
additionalProperties: false
}
}
},
{
type: 'function',
function: {
name: 'delete_stone',
description: 'Bury a stone (remove it from the arrangement).',
parameters: {
type: 'object',
properties: { stone_id: { type: 'integer' } },
required: ['stone_id'],
additionalProperties: false
}
}
},
{
type: 'function',
function: {
name: 'set_weather',
description: 'Shape the climate of the whole piece: age (dark/fossil), pressure (saturation), air (room), heat (detune). Omitted values stay unchanged.',
parameters: {
type: 'object',
properties: {
age: { type: 'number', minimum: 0, maximum: 1 },
pressure: { type: 'number', minimum: 0, maximum: 1 },
air: { type: 'number', minimum: 0, maximum: 1 },
heat: { type: 'number', minimum: 0, maximum: 1 }
},
additionalProperties: false
}
}
},
{
type: 'function',
function: {
name: 'set_rings',
description: 'Set how many growth rings the loops carry; more rings mean stronger erosion on every cycle.',
parameters: {
type: 'object',
properties: { count: { type: 'integer', minimum: 0, maximum: 12 } },
required: ['count'],
additionalProperties: false
}
}
},
{
type: 'function',
function: {
name: 'set_tempo',
description: 'Set the tempo in BPM (40..220).',
parameters: {
type: 'object',
properties: { bpm: { type: 'number', minimum: 40, maximum: 220 } },
required: ['bpm'],
additionalProperties: false
}
}
},
{
type: 'function',
function: {
name: 'transport',
description: 'Play, pause, stop or seek the transport. seek needs a bar.',
parameters: {
type: 'object',
properties: {
action: { type: 'string', enum: ['play', 'pause', 'stop', 'seek'] },
bar: { type: 'number', minimum: 1, maximum: 32 }
},
required: ['action'],
additionalProperties: false
}
}
},
{
type: 'function',
function: {
name: 'open_core',
description: 'Descend to the quarry and show a core in the tray.',
parameters: {
type: 'object',
properties: { core_id: { type: 'string' } },
required: ['core_id'],
additionalProperties: false
}
}
},
{
type: 'function',
function: {
name: 'set_macros',
description: 'Master macros: warmth (tilt), dust (hiss), threshold (limiter). 0..1.',
parameters: {
type: 'object',
properties: {
warmth: { type: 'number', minimum: 0, maximum: 1 },
dust: { type: 'number', minimum: 0, maximum: 1 },
threshold: { type: 'number', minimum: 0, maximum: 1 }
},
additionalProperties: false
}
}
}
];
module.exports = { SYSTEM, TOOLS };