@llmist/cli 15.19.0 → 16.0.1

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