@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 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.18.1",
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: "^15.18.1",
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": "^15.18.1",
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
- var askUser = createGadget({
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: z.object({
204
- question: z.string().describe("The question to ask the user in plain-text or Markdown")
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 = createGadget({
403
+ var tellUser = createGadget2({
223
404
  name: "TellUser",
224
405
  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")
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 = createGadget({
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: z.object({}),
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 createGadget2 } from "llmist";
1534
- import { z as z2 } from "zod";
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 = createGadget2({
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: 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)")
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 createGadget3 } from "llmist";
1959
- import { z as z3 } from "zod";
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 = createGadget3({
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: 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(
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 createGadget4 } from "llmist";
2081
- import { z as z4 } from "zod";
2082
- var readFile2 = createGadget4({
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: z4.object({
2086
- filePath: z4.string().describe("Path to the file to read (relative or absolute)")
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 createGadget5 } from "llmist";
2113
- import { z as z5 } from "zod";
2114
- var writeFile = createGadget5({
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: 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")
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 createGadget6 } from "llmist";
2167
- import { z as z6 } from "zod";
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 spawn(argv, options = {}) {
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 = createGadget6({
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: 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)")
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 = spawn(argv, {
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, result, error, executionTimeMs, cost) {
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
- this.completeGadget(
5943
- event.invocationId,
5944
- event.result,
5945
- void 0,
5946
- event.executionTimeMs,
5947
- event.cost
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, void 0, event.error, event.executionTimeMs);
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
- const currentValue = this.inputBar.getValue();
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
- for (const gadget of builtinGadgets) {
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 {