@llmist/cli 15.18.1 → 16.0.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/dist/cli.js +273 -64
- package/dist/cli.js.map +1 -1
- package/package.json +3 -3
package/dist/cli.js
CHANGED
|
@@ -110,7 +110,7 @@ import { Command, InvalidArgumentError as InvalidArgumentError2 } from "commande
|
|
|
110
110
|
// package.json
|
|
111
111
|
var package_default = {
|
|
112
112
|
name: "@llmist/cli",
|
|
113
|
-
version: "
|
|
113
|
+
version: "16.0.0",
|
|
114
114
|
description: "CLI for llmist - run LLM agents from the command line",
|
|
115
115
|
type: "module",
|
|
116
116
|
main: "dist/cli.js",
|
|
@@ -166,7 +166,7 @@ var package_default = {
|
|
|
166
166
|
node: ">=22.0.0"
|
|
167
167
|
},
|
|
168
168
|
dependencies: {
|
|
169
|
-
llmist: "^
|
|
169
|
+
llmist: "^16.0.0",
|
|
170
170
|
"@unblessed/node": "^1.0.0-alpha.23",
|
|
171
171
|
chalk: "^5.6.2",
|
|
172
172
|
commander: "^12.1.0",
|
|
@@ -180,7 +180,7 @@ var package_default = {
|
|
|
180
180
|
zod: "^4.1.12"
|
|
181
181
|
},
|
|
182
182
|
devDependencies: {
|
|
183
|
-
"@llmist/testing": "^
|
|
183
|
+
"@llmist/testing": "^16.0.0",
|
|
184
184
|
"@types/diff": "^8.0.0",
|
|
185
185
|
"@types/js-yaml": "^4.0.9",
|
|
186
186
|
"@types/marked-terminal": "^6.1.1",
|
|
@@ -195,13 +195,194 @@ var package_default = {
|
|
|
195
195
|
import { AgentBuilder, GadgetRegistry, HookPresets, isAbortError, text } from "llmist";
|
|
196
196
|
|
|
197
197
|
// src/builtin-gadgets.ts
|
|
198
|
-
import { createGadget, HumanInputRequiredException, TaskCompletionSignal } from "llmist";
|
|
198
|
+
import { createGadget as createGadget2, HumanInputRequiredException, TaskCompletionSignal } from "llmist";
|
|
199
|
+
import { z as z2 } from "zod";
|
|
200
|
+
|
|
201
|
+
// src/builtins/text-to-speech.ts
|
|
202
|
+
import { createGadget, getErrorMessage, resultWithAudio } from "llmist";
|
|
199
203
|
import { z } from "zod";
|
|
200
|
-
|
|
204
|
+
|
|
205
|
+
// src/ffmpeg.ts
|
|
206
|
+
import { spawn } from "child_process";
|
|
207
|
+
var CONVERSION_TIMEOUT_MS = 3e4;
|
|
208
|
+
var ffmpegCheckPromise = null;
|
|
209
|
+
async function isFFmpegAvailable() {
|
|
210
|
+
if (ffmpegCheckPromise !== null) return ffmpegCheckPromise;
|
|
211
|
+
ffmpegCheckPromise = new Promise((resolve3) => {
|
|
212
|
+
const proc = spawn("ffmpeg", ["-version"], { stdio: "ignore" });
|
|
213
|
+
proc.on("error", () => resolve3(false));
|
|
214
|
+
proc.on("close", (code) => resolve3(code === 0));
|
|
215
|
+
});
|
|
216
|
+
return ffmpegCheckPromise;
|
|
217
|
+
}
|
|
218
|
+
async function convertToMp3(input, inputFormat, timeout = CONVERSION_TIMEOUT_MS) {
|
|
219
|
+
return new Promise((resolve3) => {
|
|
220
|
+
let timeoutId;
|
|
221
|
+
const inputArgs = inputFormat === "pcm16" ? ["-f", "s16le", "-ar", "24000", "-ac", "1"] : ["-f", inputFormat];
|
|
222
|
+
const proc = spawn(
|
|
223
|
+
"ffmpeg",
|
|
224
|
+
[
|
|
225
|
+
...inputArgs,
|
|
226
|
+
"-i",
|
|
227
|
+
"pipe:0",
|
|
228
|
+
// Read from stdin
|
|
229
|
+
"-f",
|
|
230
|
+
"mp3",
|
|
231
|
+
// Output format
|
|
232
|
+
"-ab",
|
|
233
|
+
"128k",
|
|
234
|
+
// Bitrate
|
|
235
|
+
"pipe:1"
|
|
236
|
+
// Write to stdout
|
|
237
|
+
],
|
|
238
|
+
{ stdio: ["pipe", "pipe", "ignore"] }
|
|
239
|
+
);
|
|
240
|
+
const chunks = [];
|
|
241
|
+
proc.stdout.on("data", (chunk) => chunks.push(chunk));
|
|
242
|
+
proc.on("error", () => {
|
|
243
|
+
clearTimeout(timeoutId);
|
|
244
|
+
resolve3(null);
|
|
245
|
+
});
|
|
246
|
+
proc.on("close", (code) => {
|
|
247
|
+
clearTimeout(timeoutId);
|
|
248
|
+
resolve3(code === 0 ? Buffer.concat(chunks) : null);
|
|
249
|
+
});
|
|
250
|
+
timeoutId = setTimeout(() => {
|
|
251
|
+
proc.kill();
|
|
252
|
+
resolve3(null);
|
|
253
|
+
}, timeout);
|
|
254
|
+
proc.stdin.on("error", () => {
|
|
255
|
+
});
|
|
256
|
+
proc.stdin.write(input);
|
|
257
|
+
proc.stdin.end();
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// src/builtins/text-to-speech.ts
|
|
262
|
+
var TTS_VOICES = ["alloy", "echo", "fable", "onyx", "nova", "shimmer"];
|
|
263
|
+
var TTS_FORMATS = ["mp3", "opus", "aac", "flac", "wav", "pcm16"];
|
|
264
|
+
function createTextToSpeech(config) {
|
|
265
|
+
if (config?.voice && !TTS_VOICES.includes(config.voice)) {
|
|
266
|
+
throw new Error(`Invalid TTS voice "${config.voice}". Valid voices: ${TTS_VOICES.join(", ")}`);
|
|
267
|
+
}
|
|
268
|
+
if (config?.format && !TTS_FORMATS.includes(config.format)) {
|
|
269
|
+
throw new Error(
|
|
270
|
+
`Invalid TTS format "${config.format}". Valid formats: ${TTS_FORMATS.join(", ")}`
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
if (config?.speed !== void 0 && (config.speed < 0.25 || config.speed > 4)) {
|
|
274
|
+
throw new Error(`Invalid TTS speed "${config.speed}". Must be between 0.25 and 4.0`);
|
|
275
|
+
}
|
|
276
|
+
const defaultModel = config?.model ?? "tts-1";
|
|
277
|
+
const defaultVoice = config?.voice ?? "nova";
|
|
278
|
+
const defaultFormat = config?.format ?? "mp3";
|
|
279
|
+
const defaultSpeed = config?.speed ?? 1;
|
|
280
|
+
return createGadget({
|
|
281
|
+
name: "TextToSpeech",
|
|
282
|
+
description: `Convert text to speech audio. Uses configured TTS model. Defaults: ${defaultVoice} voice, ${defaultFormat} format.`,
|
|
283
|
+
schema: z.object({
|
|
284
|
+
text: z.string().min(1).describe("Text to convert to speech"),
|
|
285
|
+
voice: z.enum(TTS_VOICES).optional().describe(`Voice to use (default: ${defaultVoice})`),
|
|
286
|
+
format: z.enum(TTS_FORMATS).optional().describe(`Output format (default: ${defaultFormat})`),
|
|
287
|
+
speed: z.number().min(0.25).max(4).optional().describe(`Speech speed 0.25-4.0 (default: ${defaultSpeed})`)
|
|
288
|
+
}),
|
|
289
|
+
examples: [
|
|
290
|
+
{
|
|
291
|
+
comment: "Generate speech with default settings",
|
|
292
|
+
params: { text: "Hello, welcome to our application!" },
|
|
293
|
+
output: "Generated audio (mp3, 35 chars, $0.000525)"
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
comment: "Use a specific voice",
|
|
297
|
+
params: {
|
|
298
|
+
text: "This is an important announcement.",
|
|
299
|
+
voice: "onyx"
|
|
300
|
+
},
|
|
301
|
+
output: "Generated audio (mp3, 35 chars, $0.001050)"
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
comment: "Generate slower speech in WAV format",
|
|
305
|
+
params: {
|
|
306
|
+
text: "Please listen carefully to these instructions.",
|
|
307
|
+
format: "wav",
|
|
308
|
+
speed: 0.8
|
|
309
|
+
},
|
|
310
|
+
output: "Generated audio (wav, 46 chars, $0.000690)"
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
comment: "Result when cost is unavailable (some providers)",
|
|
314
|
+
params: { text: "Hello there!" },
|
|
315
|
+
output: "Generated audio (mp3, 12 chars, $N/A)"
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
comment: "Auto-converted to MP3 (when ffmpeg is available and format isn't MP3)",
|
|
319
|
+
params: { text: "Converted audio.", format: "pcm16" },
|
|
320
|
+
output: "Generated audio (mp3, 16 chars, $0.000240) [converted from pcm16]"
|
|
321
|
+
}
|
|
322
|
+
],
|
|
323
|
+
execute: async ({ text: text3, voice, format, speed }, ctx) => {
|
|
324
|
+
if (!ctx?.llmist?.speech?.generate) {
|
|
325
|
+
return "status=1\n\nerror: Speech generation requires LLMist client with speech capability.";
|
|
326
|
+
}
|
|
327
|
+
const selectedModel = defaultModel;
|
|
328
|
+
const selectedVoice = voice ?? defaultVoice;
|
|
329
|
+
const selectedFormat = format ?? defaultFormat;
|
|
330
|
+
const selectedSpeed = speed ?? (defaultSpeed !== 1 ? defaultSpeed : void 0);
|
|
331
|
+
const maxRetries = 2;
|
|
332
|
+
let lastError;
|
|
333
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
334
|
+
try {
|
|
335
|
+
const result = await ctx.llmist.speech.generate({
|
|
336
|
+
model: selectedModel,
|
|
337
|
+
input: text3,
|
|
338
|
+
voice: selectedVoice,
|
|
339
|
+
// Cast is safe: Zod validates LLM input, config values validated at factory time
|
|
340
|
+
responseFormat: selectedFormat,
|
|
341
|
+
...selectedSpeed !== void 0 ? { speed: selectedSpeed } : {}
|
|
342
|
+
});
|
|
343
|
+
let audioBuffer = Buffer.from(result.audio);
|
|
344
|
+
let finalFormat = result.format;
|
|
345
|
+
if (finalFormat !== "mp3" && await isFFmpegAvailable()) {
|
|
346
|
+
const mp3Buffer = await convertToMp3(audioBuffer, finalFormat);
|
|
347
|
+
if (mp3Buffer) {
|
|
348
|
+
audioBuffer = mp3Buffer;
|
|
349
|
+
finalFormat = "mp3";
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
const conversionNote = finalFormat !== result.format ? ` [converted from ${result.format}]` : "";
|
|
353
|
+
return resultWithAudio(
|
|
354
|
+
`Generated audio (${finalFormat}, ${result.usage.characterCount} chars, $${result.cost?.toFixed(6) ?? "N/A"})${conversionNote}`,
|
|
355
|
+
audioBuffer,
|
|
356
|
+
{
|
|
357
|
+
mimeType: `audio/${finalFormat}`,
|
|
358
|
+
cost: result.cost,
|
|
359
|
+
description: `TTS: "${text3.slice(0, 50)}${text3.length > 50 ? "..." : ""}"`
|
|
360
|
+
}
|
|
361
|
+
);
|
|
362
|
+
} catch (error) {
|
|
363
|
+
lastError = error;
|
|
364
|
+
const errorMsg = getErrorMessage(error);
|
|
365
|
+
const isRetryable = errorMsg.includes("HTTP 4") || errorMsg.includes("HTTP 5");
|
|
366
|
+
if (!isRetryable || attempt === maxRetries) {
|
|
367
|
+
break;
|
|
368
|
+
}
|
|
369
|
+
await new Promise((r) => setTimeout(r, 500 * (attempt + 1)));
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
return `status=1
|
|
373
|
+
|
|
374
|
+
error: ${getErrorMessage(lastError)}`;
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
var textToSpeech = createTextToSpeech();
|
|
379
|
+
|
|
380
|
+
// src/builtin-gadgets.ts
|
|
381
|
+
var askUser = createGadget2({
|
|
201
382
|
name: "AskUser",
|
|
202
383
|
description: "Ask the user a question when you need more information or clarification. The user's response will be provided back to you.",
|
|
203
|
-
schema:
|
|
204
|
-
question:
|
|
384
|
+
schema: z2.object({
|
|
385
|
+
question: z2.string().describe("The question to ask the user in plain-text or Markdown")
|
|
205
386
|
}),
|
|
206
387
|
examples: [
|
|
207
388
|
{
|
|
@@ -219,12 +400,12 @@ var askUser = createGadget({
|
|
|
219
400
|
throw new HumanInputRequiredException(question);
|
|
220
401
|
}
|
|
221
402
|
});
|
|
222
|
-
var tellUser =
|
|
403
|
+
var tellUser = createGadget2({
|
|
223
404
|
name: "TellUser",
|
|
224
405
|
description: "Tell the user something important.",
|
|
225
|
-
schema:
|
|
226
|
-
message:
|
|
227
|
-
type:
|
|
406
|
+
schema: z2.object({
|
|
407
|
+
message: z2.string().optional().describe("The message to display to the user in Markdown"),
|
|
408
|
+
type: z2.enum(["info", "success", "warning", "error"]).default("info").describe("Message type: info, success, warning, or error")
|
|
228
409
|
}),
|
|
229
410
|
examples: [
|
|
230
411
|
{
|
|
@@ -255,10 +436,10 @@ var tellUser = createGadget({
|
|
|
255
436
|
return prefixes[type] + message;
|
|
256
437
|
}
|
|
257
438
|
});
|
|
258
|
-
var finish =
|
|
439
|
+
var finish = createGadget2({
|
|
259
440
|
name: "Finish",
|
|
260
441
|
description: "Signal that you have completed your task. Call this when your work is done.",
|
|
261
|
-
schema:
|
|
442
|
+
schema: z2.object({}),
|
|
262
443
|
examples: [
|
|
263
444
|
{
|
|
264
445
|
comment: "Signal task completion",
|
|
@@ -269,7 +450,10 @@ var finish = createGadget({
|
|
|
269
450
|
throw new TaskCompletionSignal("Task completed");
|
|
270
451
|
}
|
|
271
452
|
});
|
|
272
|
-
var builtinGadgets = [askUser, tellUser, finish];
|
|
453
|
+
var builtinGadgets = [askUser, tellUser, finish, createTextToSpeech()];
|
|
454
|
+
function getBuiltinGadgets(speechConfig) {
|
|
455
|
+
return [askUser, tellUser, finish, createTextToSpeech(speechConfig)];
|
|
456
|
+
}
|
|
273
457
|
|
|
274
458
|
// src/config.ts
|
|
275
459
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
@@ -1530,8 +1714,8 @@ import { AbstractGadget } from "llmist";
|
|
|
1530
1714
|
|
|
1531
1715
|
// src/builtins/filesystem/edit-file.ts
|
|
1532
1716
|
import { readFileSync as readFileSync3, writeFileSync } from "fs";
|
|
1533
|
-
import { createGadget as
|
|
1534
|
-
import { z as
|
|
1717
|
+
import { createGadget as createGadget3 } from "llmist";
|
|
1718
|
+
import { z as z3 } from "zod";
|
|
1535
1719
|
|
|
1536
1720
|
// src/builtins/filesystem/editfile/matcher.ts
|
|
1537
1721
|
var DEFAULT_OPTIONS = {
|
|
@@ -1844,7 +2028,7 @@ function formatFailure(filePath, search, failure, fileContent) {
|
|
|
1844
2028
|
lines.push("", "CURRENT FILE CONTENT:", "```", fileContent, "```");
|
|
1845
2029
|
return lines.join("\n");
|
|
1846
2030
|
}
|
|
1847
|
-
var editFile =
|
|
2031
|
+
var editFile = createGadget3({
|
|
1848
2032
|
name: "EditFile",
|
|
1849
2033
|
description: `Edit a file by searching for content and replacing it.
|
|
1850
2034
|
|
|
@@ -1858,10 +2042,10 @@ For multiple edits to the same file, call this gadget multiple times.
|
|
|
1858
2042
|
Each call provides immediate feedback, allowing you to adjust subsequent edits.`,
|
|
1859
2043
|
maxConcurrent: 1,
|
|
1860
2044
|
// Sequential execution to prevent race conditions
|
|
1861
|
-
schema:
|
|
1862
|
-
filePath:
|
|
1863
|
-
search:
|
|
1864
|
-
replace:
|
|
2045
|
+
schema: z3.object({
|
|
2046
|
+
filePath: z3.string().describe("Path to the file to edit (relative or absolute)"),
|
|
2047
|
+
search: z3.string().describe("The content to search for in the file"),
|
|
2048
|
+
replace: z3.string().describe("The content to replace it with (empty string to delete)")
|
|
1865
2049
|
}),
|
|
1866
2050
|
examples: [
|
|
1867
2051
|
{
|
|
@@ -1955,8 +2139,8 @@ ${newContent}
|
|
|
1955
2139
|
// src/builtins/filesystem/list-directory.ts
|
|
1956
2140
|
import fs2 from "fs";
|
|
1957
2141
|
import path2 from "path";
|
|
1958
|
-
import { createGadget as
|
|
1959
|
-
import { z as
|
|
2142
|
+
import { createGadget as createGadget4 } from "llmist";
|
|
2143
|
+
import { z as z4 } from "zod";
|
|
1960
2144
|
function listFiles(dirPath, basePath = dirPath, maxDepth = 1, currentDepth = 1) {
|
|
1961
2145
|
const entries = [];
|
|
1962
2146
|
try {
|
|
@@ -2040,12 +2224,12 @@ function formatEntriesAsString(entries) {
|
|
|
2040
2224
|
);
|
|
2041
2225
|
return [header, ...rows].join("\n");
|
|
2042
2226
|
}
|
|
2043
|
-
var listDirectory =
|
|
2227
|
+
var listDirectory = createGadget4({
|
|
2044
2228
|
name: "ListDirectory",
|
|
2045
2229
|
description: "List files and directories in a directory with full details (names, types, sizes, modification dates). Use maxDepth to explore subdirectories recursively. The directory path must be within the current working directory or its subdirectories.",
|
|
2046
|
-
schema:
|
|
2047
|
-
directoryPath:
|
|
2048
|
-
maxDepth:
|
|
2230
|
+
schema: z4.object({
|
|
2231
|
+
directoryPath: z4.string().default(".").describe("Path to the directory to list"),
|
|
2232
|
+
maxDepth: z4.number().int().min(1).max(10).default(3).describe(
|
|
2049
2233
|
"Maximum depth to recurse (1 = immediate children only, 2 = include grandchildren, etc.)"
|
|
2050
2234
|
)
|
|
2051
2235
|
}),
|
|
@@ -2077,13 +2261,13 @@ ${formattedList}`;
|
|
|
2077
2261
|
|
|
2078
2262
|
// src/builtins/filesystem/read-file.ts
|
|
2079
2263
|
import fs3 from "fs";
|
|
2080
|
-
import { createGadget as
|
|
2081
|
-
import { z as
|
|
2082
|
-
var readFile2 =
|
|
2264
|
+
import { createGadget as createGadget5 } from "llmist";
|
|
2265
|
+
import { z as z5 } from "zod";
|
|
2266
|
+
var readFile2 = createGadget5({
|
|
2083
2267
|
name: "ReadFile",
|
|
2084
2268
|
description: "Read the entire content of a file and return it as text. The file path must be within the current working directory or its subdirectories.",
|
|
2085
|
-
schema:
|
|
2086
|
-
filePath:
|
|
2269
|
+
schema: z5.object({
|
|
2270
|
+
filePath: z5.string().describe("Path to the file to read (relative or absolute)")
|
|
2087
2271
|
}),
|
|
2088
2272
|
examples: [
|
|
2089
2273
|
{
|
|
@@ -2109,16 +2293,16 @@ ${content}`;
|
|
|
2109
2293
|
// src/builtins/filesystem/write-file.ts
|
|
2110
2294
|
import fs4 from "fs";
|
|
2111
2295
|
import path3 from "path";
|
|
2112
|
-
import { createGadget as
|
|
2113
|
-
import { z as
|
|
2114
|
-
var writeFile =
|
|
2296
|
+
import { createGadget as createGadget6 } from "llmist";
|
|
2297
|
+
import { z as z6 } from "zod";
|
|
2298
|
+
var writeFile = createGadget6({
|
|
2115
2299
|
name: "WriteFile",
|
|
2116
2300
|
description: "Write content to a file. Creates parent directories if needed. Overwrites existing files. The file path must be within the current working directory or its subdirectories.",
|
|
2117
2301
|
maxConcurrent: 1,
|
|
2118
2302
|
// Sequential execution to prevent race conditions
|
|
2119
|
-
schema:
|
|
2120
|
-
filePath:
|
|
2121
|
-
content:
|
|
2303
|
+
schema: z6.object({
|
|
2304
|
+
filePath: z6.string().describe("Path to the file to write (relative or absolute)"),
|
|
2305
|
+
content: z6.string().describe("Content to write to the file")
|
|
2122
2306
|
}),
|
|
2123
2307
|
examples: [
|
|
2124
2308
|
{
|
|
@@ -2163,8 +2347,8 @@ Wrote ${bytesWritten} bytes${dirNote}`;
|
|
|
2163
2347
|
});
|
|
2164
2348
|
|
|
2165
2349
|
// src/builtins/run-command.ts
|
|
2166
|
-
import { createGadget as
|
|
2167
|
-
import { z as
|
|
2350
|
+
import { createGadget as createGadget7 } from "llmist";
|
|
2351
|
+
import { z as z7 } from "zod";
|
|
2168
2352
|
|
|
2169
2353
|
// src/spawn.ts
|
|
2170
2354
|
import { spawn as nodeSpawn } from "child_process";
|
|
@@ -2187,7 +2371,7 @@ function nodeStreamToReadableStream(nodeStream) {
|
|
|
2187
2371
|
}
|
|
2188
2372
|
});
|
|
2189
2373
|
}
|
|
2190
|
-
function
|
|
2374
|
+
function spawn2(argv, options = {}) {
|
|
2191
2375
|
const [command, ...args] = argv;
|
|
2192
2376
|
const proc = nodeSpawn(command, args, {
|
|
2193
2377
|
cwd: options.cwd,
|
|
@@ -2225,13 +2409,13 @@ function spawn(argv, options = {}) {
|
|
|
2225
2409
|
}
|
|
2226
2410
|
|
|
2227
2411
|
// src/builtins/run-command.ts
|
|
2228
|
-
var runCommand =
|
|
2412
|
+
var runCommand = createGadget7({
|
|
2229
2413
|
name: "RunCommand",
|
|
2230
2414
|
description: "Execute a command with arguments and return its output. Uses argv array to bypass shell - arguments are passed directly without interpretation. Returns stdout/stderr combined with exit status.",
|
|
2231
|
-
schema:
|
|
2232
|
-
argv:
|
|
2233
|
-
cwd:
|
|
2234
|
-
timeout:
|
|
2415
|
+
schema: z7.object({
|
|
2416
|
+
argv: z7.array(z7.string()).describe("Command and arguments as array (e.g., ['git', 'commit', '-m', 'message'])"),
|
|
2417
|
+
cwd: z7.string().optional().describe("Working directory for the command (default: current directory)"),
|
|
2418
|
+
timeout: z7.number().default(3e4).describe("Timeout in milliseconds (default: 30000)")
|
|
2235
2419
|
}),
|
|
2236
2420
|
examples: [
|
|
2237
2421
|
{
|
|
@@ -2294,7 +2478,7 @@ var runCommand = createGadget6({
|
|
|
2294
2478
|
}
|
|
2295
2479
|
let timeoutId;
|
|
2296
2480
|
try {
|
|
2297
|
-
const proc =
|
|
2481
|
+
const proc = spawn2(argv, {
|
|
2298
2482
|
cwd: workingDir,
|
|
2299
2483
|
stdout: "pipe",
|
|
2300
2484
|
stderr: "pipe"
|
|
@@ -2338,7 +2522,8 @@ var builtinGadgetRegistry = {
|
|
|
2338
2522
|
ReadFile: readFile2,
|
|
2339
2523
|
WriteFile: writeFile,
|
|
2340
2524
|
EditFile: editFile,
|
|
2341
|
-
RunCommand: runCommand
|
|
2525
|
+
RunCommand: runCommand,
|
|
2526
|
+
TextToSpeech: textToSpeech
|
|
2342
2527
|
};
|
|
2343
2528
|
function getBuiltinGadget(name) {
|
|
2344
2529
|
return builtinGadgetRegistry[name];
|
|
@@ -4679,6 +4864,17 @@ function formatGadgetExpanded(node) {
|
|
|
4679
4864
|
}
|
|
4680
4865
|
lines.push(`${indent}${chalk3.dim(BOX.bottomLeft + BOX.horizontal.repeat(width - 1))}`);
|
|
4681
4866
|
}
|
|
4867
|
+
if (node.mediaOutputs && node.mediaOutputs.length > 0) {
|
|
4868
|
+
const headerLine = `${BOX.topLeft}${BOX.horizontal} Media ${BOX.horizontal.repeat(width - 9)}`;
|
|
4869
|
+
lines.push(`${indent}${chalk3.dim(headerLine)}`);
|
|
4870
|
+
for (const media of node.mediaOutputs) {
|
|
4871
|
+
const kindEmoji = media.kind === "audio" ? "\u{1F50A}" : media.kind === "image" ? "\u{1F5BC}\uFE0F" : media.kind === "video" ? "\u{1F3AC}" : "\u{1F4C4}";
|
|
4872
|
+
const maxPathLen = width - 8;
|
|
4873
|
+
const displayPath = media.path.length > maxPathLen ? "..." + media.path.slice(-(maxPathLen - 3)) : media.path;
|
|
4874
|
+
lines.push(`${indent}${chalk3.dim(BOX.vertical)} ${kindEmoji} ${chalk3.cyan(displayPath)}`);
|
|
4875
|
+
}
|
|
4876
|
+
lines.push(`${indent}${chalk3.dim(BOX.bottomLeft + BOX.horizontal.repeat(width - 1))}`);
|
|
4877
|
+
}
|
|
4682
4878
|
if (node.children.length > 0) {
|
|
4683
4879
|
const headerLine = `${BOX.topLeft}${BOX.horizontal} Subagent Activity ${BOX.horizontal.repeat(width - 21)}`;
|
|
4684
4880
|
lines.push(`${indent}${chalk3.dim(headerLine)}`);
|
|
@@ -4906,14 +5102,16 @@ var BlockRenderer = class _BlockRenderer {
|
|
|
4906
5102
|
/**
|
|
4907
5103
|
* Complete a gadget with result.
|
|
4908
5104
|
*/
|
|
4909
|
-
completeGadget(invocationId,
|
|
5105
|
+
completeGadget(invocationId, options = {}) {
|
|
4910
5106
|
const node = this.findGadgetByInvocationId(invocationId);
|
|
4911
5107
|
if (!node) return;
|
|
5108
|
+
const { result, error, executionTimeMs, cost, mediaOutputs } = options;
|
|
4912
5109
|
node.isComplete = true;
|
|
4913
5110
|
node.result = result;
|
|
4914
5111
|
node.error = error;
|
|
4915
5112
|
node.executionTimeMs = executionTimeMs;
|
|
4916
5113
|
node.cost = cost;
|
|
5114
|
+
node.mediaOutputs = mediaOutputs;
|
|
4917
5115
|
if (result) {
|
|
4918
5116
|
node.resultTokens = Math.ceil(result.length / 4);
|
|
4919
5117
|
}
|
|
@@ -5939,17 +6137,25 @@ ${indicator}`;
|
|
|
5939
6137
|
break;
|
|
5940
6138
|
}
|
|
5941
6139
|
case "gadget_complete": {
|
|
5942
|
-
|
|
5943
|
-
|
|
5944
|
-
|
|
5945
|
-
|
|
5946
|
-
|
|
5947
|
-
|
|
5948
|
-
|
|
6140
|
+
const mediaOutputs = event.storedMedia?.map((m) => ({
|
|
6141
|
+
kind: m.kind,
|
|
6142
|
+
path: m.path,
|
|
6143
|
+
mimeType: m.mimeType,
|
|
6144
|
+
description: m.description
|
|
6145
|
+
}));
|
|
6146
|
+
this.completeGadget(event.invocationId, {
|
|
6147
|
+
result: event.result,
|
|
6148
|
+
executionTimeMs: event.executionTimeMs,
|
|
6149
|
+
cost: event.cost,
|
|
6150
|
+
mediaOutputs
|
|
6151
|
+
});
|
|
5949
6152
|
break;
|
|
5950
6153
|
}
|
|
5951
6154
|
case "gadget_error": {
|
|
5952
|
-
this.completeGadget(event.invocationId,
|
|
6155
|
+
this.completeGadget(event.invocationId, {
|
|
6156
|
+
error: event.error,
|
|
6157
|
+
executionTimeMs: event.executionTimeMs
|
|
6158
|
+
});
|
|
5953
6159
|
break;
|
|
5954
6160
|
}
|
|
5955
6161
|
case "gadget_skipped": {
|
|
@@ -6776,11 +6982,8 @@ var InputHandler = class {
|
|
|
6776
6982
|
handlePaste(content) {
|
|
6777
6983
|
if (!content) return;
|
|
6778
6984
|
if (content.includes("\n")) {
|
|
6779
|
-
|
|
6780
|
-
this.openEditorForInput(currentValue + content);
|
|
6985
|
+
this.openEditorForInput(this.inputBar.getValue());
|
|
6781
6986
|
} else {
|
|
6782
|
-
const currentValue = this.inputBar.getValue();
|
|
6783
|
-
this.inputBar.setValue(currentValue + content);
|
|
6784
6987
|
this.inputBar.readInput();
|
|
6785
6988
|
}
|
|
6786
6989
|
}
|
|
@@ -8683,8 +8886,15 @@ async function executeAgent(promptArg, options, env, commandName) {
|
|
|
8683
8886
|
prompt = await resolvePrompt(promptArg, env);
|
|
8684
8887
|
}
|
|
8685
8888
|
const registry = new GadgetRegistry();
|
|
8889
|
+
let speechConfig;
|
|
8890
|
+
try {
|
|
8891
|
+
const fullConfig = loadConfig();
|
|
8892
|
+
speechConfig = fullConfig.speech;
|
|
8893
|
+
} catch {
|
|
8894
|
+
}
|
|
8686
8895
|
if (options.builtins !== false) {
|
|
8687
|
-
|
|
8896
|
+
const builtins = getBuiltinGadgets(speechConfig);
|
|
8897
|
+
for (const gadget of builtins) {
|
|
8688
8898
|
if (gadget.name === "AskUser" && (options.builtinInteraction === false || !stdinIsInteractive || !stdoutTTY)) {
|
|
8689
8899
|
continue;
|
|
8690
8900
|
}
|
|
@@ -9005,6 +9215,7 @@ ${ctx.gadgetName} requires interactive approval. Run in a terminal to approve.`
|
|
|
9005
9215
|
if (tui) {
|
|
9006
9216
|
tui.resetAbort();
|
|
9007
9217
|
tui.startNewSession();
|
|
9218
|
+
tui.showUserMessage(userPrompt);
|
|
9008
9219
|
builder.withSignal(tui.getAbortSignal());
|
|
9009
9220
|
}
|
|
9010
9221
|
if (currentAgent) {
|
|
@@ -9070,7 +9281,6 @@ ${ctx.gadgetName} requires interactive approval. Run in a terminal to approve.`
|
|
|
9070
9281
|
if (!currentPrompt) {
|
|
9071
9282
|
tui.setFocusMode("input");
|
|
9072
9283
|
currentPrompt = await tui.waitForPrompt();
|
|
9073
|
-
tui.showUserMessage(currentPrompt);
|
|
9074
9284
|
}
|
|
9075
9285
|
while (true) {
|
|
9076
9286
|
try {
|
|
@@ -9081,7 +9291,6 @@ ${ctx.gadgetName} requires interactive approval. Run in a terminal to approve.`
|
|
|
9081
9291
|
}
|
|
9082
9292
|
}
|
|
9083
9293
|
currentPrompt = await tui.waitForPrompt();
|
|
9084
|
-
tui.showUserMessage(currentPrompt);
|
|
9085
9294
|
}
|
|
9086
9295
|
} else {
|
|
9087
9296
|
try {
|