@kernel.chat/kbot 3.97.1 → 3.98.0
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/README.md +1 -1
- package/dist/agent.js +21 -0
- package/dist/cli.js +119 -0
- package/dist/teacher-logger.d.ts +71 -0
- package/dist/teacher-logger.js +162 -0
- package/dist/tools/ableton.js +176 -42
- package/dist/tools/estimation.d.ts +2 -0
- package/dist/tools/estimation.js +21 -0
- package/dist/tools/idempotency-check.d.ts +2 -0
- package/dist/tools/idempotency-check.js +31 -0
- package/dist/tools/idempotency-checker.d.ts +2 -0
- package/dist/tools/idempotency-checker.js +23 -0
- package/dist/tools/image-variation.d.ts +2 -0
- package/dist/tools/image-variation.js +31 -0
- package/dist/tools/index.js +1 -0
- package/dist/tools/one-prompt-producer.d.ts +2 -0
- package/dist/tools/one-prompt-producer.js +723 -0
- package/dist/tools/schedule-persistence.d.ts +2 -0
- package/dist/tools/schedule-persistence.js +19 -0
- package/dist/tools/sound-designer.js +278 -3
- package/dist/train-agent-trace.d.ts +29 -0
- package/dist/train-agent-trace.js +141 -0
- package/dist/train-curate.d.ts +25 -0
- package/dist/train-curate.js +354 -0
- package/dist/train-cycle.d.ts +22 -0
- package/dist/train-cycle.js +230 -0
- package/dist/train-grpo.d.ts +68 -0
- package/dist/train-grpo.js +206 -0
- package/dist/train-merge.d.ts +26 -0
- package/dist/train-merge.js +148 -0
- package/dist/train-self.d.ts +38 -0
- package/dist/train-self.js +232 -0
- package/package.json +1 -1
package/dist/tools/ableton.js
CHANGED
|
@@ -11,10 +11,12 @@
|
|
|
11
11
|
// ableton_mixer — snapshot levels, batch set, sends
|
|
12
12
|
// ableton_create_progression — chord progressions → MIDI in clips
|
|
13
13
|
// ableton_session_info — full session state snapshot
|
|
14
|
+
// ableton_audio_analysis — real-time audio level meters (track + master RMS)
|
|
14
15
|
// ableton_knowledge — deep Ableton knowledge base queries (registered in ableton-knowledge.ts)
|
|
15
16
|
//
|
|
16
17
|
// Requires: AbletonOSC loaded in Ableton Live (Preferences → Link/Tempo/MIDI → Control Surface)
|
|
17
18
|
import { registerTool } from './index.js';
|
|
19
|
+
import { execSync } from 'node:child_process';
|
|
18
20
|
import { ensureAbleton, formatAbletonError } from '../integrations/ableton-osc.js';
|
|
19
21
|
import { parseProgression, voiceChord, arpeggiate, NAMED_PROGRESSIONS, RHYTHM_PATTERNS, GENRE_DRUM_PATTERNS, noteNameToMidi, midiToNoteName, } from './music-theory.js';
|
|
20
22
|
// ── Helpers ─────────────────────────────────────────────────────────────────
|
|
@@ -769,52 +771,89 @@ export function registerAbletonTools() {
|
|
|
769
771
|
// ─── 10. Load Plugin ──────────────────────────────────────────────────
|
|
770
772
|
registerTool({
|
|
771
773
|
name: 'ableton_load_plugin',
|
|
772
|
-
description: 'Load any instrument or plugin onto a track by name — native (Operator, Wavetable, Drift) or third-party VST/AU (Serum 2, Vital, Kontakt).
|
|
774
|
+
description: 'Load any instrument or plugin onto a track by name — native (Operator, Wavetable, Drift) or third-party VST/AU (Serum 2, Vital, Kontakt). Tries OSC first, then falls back to AppleScript browser automation on macOS.',
|
|
773
775
|
parameters: {
|
|
774
776
|
track: { type: 'number', description: 'Track number (1-based)', required: true },
|
|
775
777
|
plugin: { type: 'string', description: 'Plugin name to search for (e.g. "Serum 2", "Operator", "Wavetable")', required: true },
|
|
776
778
|
manufacturer: { type: 'string', description: 'Manufacturer name for VST/AU (e.g. "Xfer Records", "Native Instruments"). Optional — helps narrow search.' },
|
|
779
|
+
skip_results: { type: 'number', description: 'Number of Down arrow presses before selecting (to skip past FX/presets). Default: 1' },
|
|
777
780
|
},
|
|
778
781
|
tier: 'free',
|
|
779
|
-
timeout:
|
|
782
|
+
timeout: 20_000,
|
|
780
783
|
async execute(args) {
|
|
781
784
|
const t = userTrack(args.track);
|
|
782
785
|
const plugin = String(args.plugin);
|
|
783
786
|
const manufacturer = args.manufacturer ? String(args.manufacturer) : '';
|
|
787
|
+
const skipResults = Number(args.skip_results) || 1;
|
|
788
|
+
// ── Attempt 1: OSC (fast, reliable for native instruments) ──
|
|
784
789
|
try {
|
|
785
790
|
const osc = await ensureAbleton();
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
// Try load_plugin first — _deep_plugin_search correctly handles native
|
|
795
|
-
// instruments by returning the first loadable child of matching browser folders.
|
|
796
|
-
// This works for both native (Drum Rack, Operator, Wavetable) and third-party plugins.
|
|
797
|
-
let result = await osc.query('/live/kbot/load_plugin', t, plugin, '');
|
|
798
|
-
let status = extractArgs(result);
|
|
799
|
-
if (status[0] === 'ok') {
|
|
800
|
-
return `Loaded **${status[1]}** on track ${args.track}`;
|
|
801
|
-
}
|
|
802
|
-
// Fallback: try load_device (uses _search_tree, less reliable for native instruments)
|
|
803
|
-
result = await osc.query('/live/kbot/load_device', t, plugin);
|
|
804
|
-
status = extractArgs(result);
|
|
805
|
-
if (status[0] === 'ok') {
|
|
806
|
-
return `Loaded **${status[1]}** on track ${args.track}`;
|
|
791
|
+
// Select the target track first so the plugin loads there
|
|
792
|
+
osc.send('/live/song/set/current_track', t);
|
|
793
|
+
await new Promise(r => setTimeout(r, 200));
|
|
794
|
+
// Try native load_device endpoint (works for Ableton built-in instruments)
|
|
795
|
+
const nativeResult = await osc.query('/live/track/load/device', t, plugin);
|
|
796
|
+
const nativeStatus = extractArgs(nativeResult);
|
|
797
|
+
if (nativeStatus.length > 0 && String(nativeStatus[0]) !== 'error') {
|
|
798
|
+
return `Loaded **${plugin}** on track ${args.track} (via OSC)`;
|
|
807
799
|
}
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
800
|
+
}
|
|
801
|
+
catch {
|
|
802
|
+
// OSC failed — fall through to AppleScript
|
|
803
|
+
}
|
|
804
|
+
// ── Attempt 2: AppleScript browser automation (macOS only) ──
|
|
805
|
+
// Uses Ableton's built-in browser search: Cmd+F → type name → arrow down → Return
|
|
806
|
+
// Proven approach from ZENOLOGY loading session
|
|
807
|
+
if (process.platform !== 'darwin') {
|
|
808
|
+
return `Plugin "${plugin}" could not be loaded via OSC. AppleScript fallback is macOS-only.`;
|
|
809
|
+
}
|
|
810
|
+
try {
|
|
811
|
+
const searchTerm = manufacturer ? `${manufacturer} ${plugin}` : plugin;
|
|
812
|
+
// Build AppleScript: activate Ableton, open browser search, type plugin name, select, load
|
|
813
|
+
const downArrows = Array(skipResults).fill('key code 125').join('\ndelay 0.3\n'); // 125 = Down arrow
|
|
814
|
+
const script = `
|
|
815
|
+
tell application "Ableton Live 12"
|
|
816
|
+
activate
|
|
817
|
+
end tell
|
|
818
|
+
delay 0.5
|
|
819
|
+
tell application "System Events"
|
|
820
|
+
tell process "Ableton Live 12"
|
|
821
|
+
-- Open browser search: Cmd+F (View > Search in Browser)
|
|
822
|
+
keystroke "f" using command down
|
|
823
|
+
delay 0.8
|
|
824
|
+
-- Clear any existing search text and type plugin name
|
|
825
|
+
keystroke "a" using command down
|
|
826
|
+
delay 0.1
|
|
827
|
+
keystroke "${searchTerm.replace(/"/g, '\\"')}"
|
|
828
|
+
delay 1.0
|
|
829
|
+
-- Navigate down to the result (skip past categories/folders)
|
|
830
|
+
${downArrows}
|
|
831
|
+
delay 0.3
|
|
832
|
+
-- Press Return to load the selected item onto the current track
|
|
833
|
+
key code 36
|
|
834
|
+
delay 0.5
|
|
835
|
+
end tell
|
|
836
|
+
end tell
|
|
837
|
+
return "ok"
|
|
838
|
+
`;
|
|
839
|
+
const lines = script.split('\n').filter(l => l.trim());
|
|
840
|
+
const escapedArgs = lines.map(l => `-e '${l.replace(/'/g, "'\\''")}'`).join(' ');
|
|
841
|
+
const result = execSync(`osascript ${escapedArgs}`, {
|
|
842
|
+
encoding: 'utf-8',
|
|
843
|
+
timeout: 15_000,
|
|
844
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
845
|
+
}).trim();
|
|
846
|
+
if (result === 'ok') {
|
|
847
|
+
return `Loaded **${plugin}** on track ${args.track} (via AppleScript browser search)`;
|
|
813
848
|
}
|
|
814
|
-
return `
|
|
849
|
+
return `AppleScript returned unexpected result: ${result}`;
|
|
815
850
|
}
|
|
816
851
|
catch (err) {
|
|
817
|
-
|
|
852
|
+
const msg = err.message;
|
|
853
|
+
if (msg.includes('not allowed') || msg.includes('assistive')) {
|
|
854
|
+
return `AppleScript failed — Accessibility permission required.\n\nGrant permission in System Settings > Privacy & Security > Accessibility for your terminal app.`;
|
|
855
|
+
}
|
|
856
|
+
return `Failed to load "${plugin}": OSC endpoint not available, AppleScript fallback failed.\n\nError: ${msg}`;
|
|
818
857
|
}
|
|
819
858
|
},
|
|
820
859
|
});
|
|
@@ -964,21 +1003,19 @@ export function registerAbletonTools() {
|
|
|
964
1003
|
if (args.name) {
|
|
965
1004
|
osc.send('/live/track/set/name', newTrackIdx, String(args.name));
|
|
966
1005
|
}
|
|
967
|
-
// Load instrument if specified —
|
|
1006
|
+
// Load instrument if specified — try native OSC first, then load_plugin tool handles fallbacks
|
|
968
1007
|
if (args.instrument) {
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
const result = await osc.query('/live/kbot/load_plugin', newTrackIdx, String(args.instrument), '');
|
|
976
|
-
const status = extractArgs(result);
|
|
977
|
-
if (status[0] !== 'ok') {
|
|
978
|
-
// Fallback to load_device
|
|
979
|
-
await osc.query('/live/kbot/load_device', newTrackIdx, String(args.instrument));
|
|
1008
|
+
try {
|
|
1009
|
+
const loadResult = await osc.query('/live/track/load/device', newTrackIdx, String(args.instrument));
|
|
1010
|
+
const loadStatus = extractArgs(loadResult);
|
|
1011
|
+
if (loadStatus.length === 0 || String(loadStatus[0]) === 'error') {
|
|
1012
|
+
// Native load failed — OSC doesn't have this device. The user can use
|
|
1013
|
+
// ableton_load_plugin separately which has AppleScript fallback.
|
|
980
1014
|
}
|
|
981
1015
|
}
|
|
1016
|
+
catch {
|
|
1017
|
+
// Timeout or connection error — device may still have loaded, continue
|
|
1018
|
+
}
|
|
982
1019
|
}
|
|
983
1020
|
return `Created ${trackType} track **${args.name || 'Track ' + (newTrackIdx + 1)}**${args.instrument ? ' with ' + args.instrument : ''} (track ${newTrackIdx + 1})`;
|
|
984
1021
|
}
|
|
@@ -1035,5 +1072,102 @@ export function registerAbletonTools() {
|
|
|
1035
1072
|
}
|
|
1036
1073
|
},
|
|
1037
1074
|
});
|
|
1075
|
+
// ─── 15. Audio Analysis ──────────────────────────────────────────────
|
|
1076
|
+
registerTool({
|
|
1077
|
+
name: 'ableton_audio_analysis',
|
|
1078
|
+
description: 'Get real-time audio level meters from Ableton Live — track output levels (L/R RMS), master output, and peak detection. Use this to hear what is playing, check if a track has signal, or monitor the mix.',
|
|
1079
|
+
parameters: {
|
|
1080
|
+
track: { type: 'number', description: 'Track number to analyze (1-based). Omit to get master output only.' },
|
|
1081
|
+
all_tracks: { type: 'boolean', description: 'If true, read levels for all tracks plus master. Default: false' },
|
|
1082
|
+
},
|
|
1083
|
+
tier: 'free',
|
|
1084
|
+
timeout: 10_000,
|
|
1085
|
+
async execute(args) {
|
|
1086
|
+
try {
|
|
1087
|
+
const osc = await ensureAbleton();
|
|
1088
|
+
const lines = ['## Audio Levels', ''];
|
|
1089
|
+
// Helper to read a meter value with error handling
|
|
1090
|
+
async function readMeter(address, ...oscArgs) {
|
|
1091
|
+
try {
|
|
1092
|
+
const result = await osc.query(address, ...oscArgs);
|
|
1093
|
+
const vals = extractArgs(result);
|
|
1094
|
+
// Meter values are typically floats 0.0 - 1.0 (or higher for clipping)
|
|
1095
|
+
return typeof vals[vals.length - 1] === 'number' ? vals[vals.length - 1] : 0;
|
|
1096
|
+
}
|
|
1097
|
+
catch {
|
|
1098
|
+
return -1; // timeout = no response
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
// Meter bar visualization
|
|
1102
|
+
function meterBar(level) {
|
|
1103
|
+
if (level < 0)
|
|
1104
|
+
return '[-no signal-]';
|
|
1105
|
+
const db = level > 0 ? 20 * Math.log10(level) : -Infinity;
|
|
1106
|
+
const dbStr = db === -Infinity ? '-inf' : db.toFixed(1);
|
|
1107
|
+
const barLen = Math.min(20, Math.max(0, Math.round(level * 20)));
|
|
1108
|
+
const bar = '\u2588'.repeat(barLen) + '\u2591'.repeat(20 - barLen);
|
|
1109
|
+
return `[${bar}] ${dbStr} dB`;
|
|
1110
|
+
}
|
|
1111
|
+
if (args.all_tracks) {
|
|
1112
|
+
// Read all track levels
|
|
1113
|
+
const countResult = await osc.query('/live/song/get/num_tracks');
|
|
1114
|
+
const numTracks = Number(extractArgs(countResult)[0]) || 0;
|
|
1115
|
+
for (let t = 0; t < numTracks - 1; t++) { // -1 to skip master return
|
|
1116
|
+
const nameResult = await osc.query('/live/track/get/name', t);
|
|
1117
|
+
const name = extractArgs(nameResult)[1] || `Track ${t + 1}`;
|
|
1118
|
+
const left = await readMeter('/live/track/get/output_meter_left', t);
|
|
1119
|
+
const right = await readMeter('/live/track/get/output_meter_right', t);
|
|
1120
|
+
const avg = left >= 0 && right >= 0 ? (left + right) / 2 : Math.max(left, right);
|
|
1121
|
+
lines.push(`**${displayTrack(t)}. ${name}**: ${meterBar(avg)}`);
|
|
1122
|
+
if (left >= 0 && right >= 0 && Math.abs(left - right) > 0.05) {
|
|
1123
|
+
lines.push(` L: ${meterBar(left)} | R: ${meterBar(right)}`);
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
lines.push('');
|
|
1127
|
+
}
|
|
1128
|
+
else if (args.track) {
|
|
1129
|
+
// Read specific track
|
|
1130
|
+
const t = userTrack(args.track);
|
|
1131
|
+
const nameResult = await osc.query('/live/track/get/name', t);
|
|
1132
|
+
const name = extractArgs(nameResult)[1] || `Track ${args.track}`;
|
|
1133
|
+
const left = await readMeter('/live/track/get/output_meter_left', t);
|
|
1134
|
+
const right = await readMeter('/live/track/get/output_meter_right', t);
|
|
1135
|
+
lines.push(`**Track ${args.track} (${name})**`);
|
|
1136
|
+
lines.push(` Left: ${meterBar(left)}`);
|
|
1137
|
+
lines.push(` Right: ${meterBar(right)}`);
|
|
1138
|
+
// Check if signal is present
|
|
1139
|
+
const avg = left >= 0 && right >= 0 ? (left + right) / 2 : Math.max(left, right);
|
|
1140
|
+
if (avg <= 0) {
|
|
1141
|
+
lines.push('');
|
|
1142
|
+
lines.push('No signal detected. Check: is the track armed? Is transport playing? Does the track have clips?');
|
|
1143
|
+
}
|
|
1144
|
+
else if (avg > 1.0) {
|
|
1145
|
+
lines.push('');
|
|
1146
|
+
lines.push('**Warning**: Signal is clipping! Reduce track volume.');
|
|
1147
|
+
}
|
|
1148
|
+
lines.push('');
|
|
1149
|
+
}
|
|
1150
|
+
// Always show master output
|
|
1151
|
+
const masterLeft = await readMeter('/live/master/get/output_meter_left');
|
|
1152
|
+
const masterRight = await readMeter('/live/master/get/output_meter_right');
|
|
1153
|
+
lines.push('**Master Output**');
|
|
1154
|
+
lines.push(` Left: ${meterBar(masterLeft)}`);
|
|
1155
|
+
lines.push(` Right: ${meterBar(masterRight)}`);
|
|
1156
|
+
const masterAvg = masterLeft >= 0 && masterRight >= 0 ? (masterLeft + masterRight) / 2 : Math.max(masterLeft, masterRight);
|
|
1157
|
+
if (masterAvg <= 0) {
|
|
1158
|
+
lines.push('');
|
|
1159
|
+
lines.push('No audio on master output. Is transport playing?');
|
|
1160
|
+
}
|
|
1161
|
+
else if (masterAvg > 0.9) {
|
|
1162
|
+
lines.push('');
|
|
1163
|
+
lines.push('**Loud!** Master is near clipping. Consider reducing levels.');
|
|
1164
|
+
}
|
|
1165
|
+
return lines.join('\n');
|
|
1166
|
+
}
|
|
1167
|
+
catch (err) {
|
|
1168
|
+
return `Ableton connection failed: ${err.message}\n\n${formatAbletonError()}`;
|
|
1169
|
+
}
|
|
1170
|
+
},
|
|
1171
|
+
});
|
|
1038
1172
|
}
|
|
1039
1173
|
//# sourceMappingURL=ableton.js.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// kbot Estimation Tools — Project planning and resource allocation
|
|
2
|
+
import { registerTool } from './index.js';
|
|
3
|
+
export function registerEstimationTools() {
|
|
4
|
+
registerTool({
|
|
5
|
+
name: 'estimate_task',
|
|
6
|
+
description: 'Estimate the time or resources needed for a task. Provide as much detail as possible for a more accurate estimate.',
|
|
7
|
+
parameters: {
|
|
8
|
+
task_description: { type: 'string', description: 'Detailed description of the task', required: true },
|
|
9
|
+
units: { type: 'string', description: 'Units for the estimate (e.g., hours, days, USD)', required: false, default: 'hours' },
|
|
10
|
+
},
|
|
11
|
+
tier: 'free',
|
|
12
|
+
async execute(args) {
|
|
13
|
+
const taskDescription = String(args.task_description);
|
|
14
|
+
const units = String(args.units) || 'hours';
|
|
15
|
+
// Placeholder estimation logic — replace with a more sophisticated model
|
|
16
|
+
let estimate = Math.round(Math.random() * 10);
|
|
17
|
+
return `Based on the description "${taskDescription}", I estimate this will take approximately ${estimate} ${units}.`;
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=estimation.js.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// kbot Idempotency Check Tool — Prevent duplicate actions
|
|
2
|
+
// This tool verifies if a task has already been executed to avoid unintended side effects.
|
|
3
|
+
import { registerTool } from './index.js';
|
|
4
|
+
export function registerIdempotencyTools() {
|
|
5
|
+
registerTool({
|
|
6
|
+
name: 'idempotency_check',
|
|
7
|
+
description: 'Checks if an action has already been performed based on a unique identifier. Returns true if the action has been done, false otherwise.',
|
|
8
|
+
parameters: {
|
|
9
|
+
identifier: { type: 'string', description: 'Unique identifier for the action', required: true },
|
|
10
|
+
},
|
|
11
|
+
tier: 'free',
|
|
12
|
+
async execute(args) {
|
|
13
|
+
const identifier = String(args.identifier);
|
|
14
|
+
// Simulate a database check (replace with actual DB query)
|
|
15
|
+
const hasRun = await simulateDatabaseCheck(identifier);
|
|
16
|
+
if (hasRun) {
|
|
17
|
+
return 'true';
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
return 'false';
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
async function simulateDatabaseCheck(identifier) {
|
|
26
|
+
// Replace with actual database query logic
|
|
27
|
+
// This is a placeholder for demonstration purposes
|
|
28
|
+
console.log(`Simulating database check for identifier: ${identifier}`);
|
|
29
|
+
return false; // Assume not run for now
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=idempotency-check.js.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// kbot Idempotency Checker Tool — Ensures function calls are safe to repeat.
|
|
2
|
+
import { registerTool } from './index.js';
|
|
3
|
+
export function registerIdempotencyCheckerTool() {
|
|
4
|
+
registerTool({
|
|
5
|
+
name: 'is_idempotent',
|
|
6
|
+
description: 'Checks if a function is idempotent — meaning it produces the same output given the same input, regardless of how many times it is called.',
|
|
7
|
+
parameters: {
|
|
8
|
+
functionName: { type: 'string', description: 'Name of the function to check', required: true },
|
|
9
|
+
input: { type: 'string', description: 'Input to the function', required: true },
|
|
10
|
+
},
|
|
11
|
+
tier: 'free',
|
|
12
|
+
async execute(args) {
|
|
13
|
+
const functionName = String(args.functionName);
|
|
14
|
+
const input = String(args.input);
|
|
15
|
+
// Placeholder for actual idempotency check logic.
|
|
16
|
+
// In a real implementation, this would involve analyzing the function's code
|
|
17
|
+
// or executing it multiple times with the same input and comparing the results.
|
|
18
|
+
// For now, we simply return a canned response.
|
|
19
|
+
return `The idempotency of '${functionName}' with input '${input}' is currently unknown. Further analysis is required.`;
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=idempotency-checker.js.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// kbot Image Variation Tool — Generates variations of an image.
|
|
2
|
+
import { registerTool } from './index.js';
|
|
3
|
+
export function registerImageVariationTools() {
|
|
4
|
+
registerTool({
|
|
5
|
+
name: 'image_variation',
|
|
6
|
+
description: 'Generate variations of an image using a URL. Supports different sizes and formats.',
|
|
7
|
+
parameters: {
|
|
8
|
+
image_url: { type: 'string', description: 'URL of the image to generate variations for', required: true },
|
|
9
|
+
width: { type: 'integer', description: 'Width of the generated image in pixels (optional)', default: 256 },
|
|
10
|
+
height: { type: 'integer', description: 'Height of the generated image in pixels (optional)', default: 256 },
|
|
11
|
+
format: { type: 'string', description: 'Format of the generated image (jpg, png, webp) (optional)', default: 'jpg' },
|
|
12
|
+
},
|
|
13
|
+
tier: 'pro',
|
|
14
|
+
async execute(args) {
|
|
15
|
+
const imageUrl = String(args.image_url);
|
|
16
|
+
const width = Number(args.width) || 256;
|
|
17
|
+
const height = Number(args.height) || 256;
|
|
18
|
+
const format = String(args.format).toLowerCase() || 'jpg';
|
|
19
|
+
try {
|
|
20
|
+
const url = `https://api.imgproxy.net/kbot/resize?width=${width}&height=${height}&format=${format}&url=${encodeURIComponent(imageUrl)}`;
|
|
21
|
+
const res = await fetch(url, { signal: AbortSignal.timeout(8000) });
|
|
22
|
+
const imageBuffer = await res.arrayBuffer();
|
|
23
|
+
return `data:image/${format};base64,${Buffer.from(imageBuffer).toString('base64')}`;
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
return `Error generating image variation: ${error}`;
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=image-variation.js.map
|
package/dist/tools/index.js
CHANGED
|
@@ -311,6 +311,7 @@ const LAZY_MODULE_IMPORTS = [
|
|
|
311
311
|
{ path: './financial-analysis.js', registerFn: 'registerFinancialAnalysisTools' },
|
|
312
312
|
{ path: './ai-analysis.js', registerFn: 'registerAIAnalysisTools' },
|
|
313
313
|
{ path: './music-gen.js', registerFn: 'registerMusicGenTools' },
|
|
314
|
+
{ path: './one-prompt-producer.js', registerFn: 'registerOnePromptTools' },
|
|
314
315
|
{ path: './mobile-automation.js', registerFn: 'registerMobileAutomationTools' },
|
|
315
316
|
{ path: './iphone.js', registerFn: 'registerIPhoneTools' },
|
|
316
317
|
{ path: './ghost.js', registerFn: 'registerGhostTools' },
|