llmist 2.5.0 → 2.6.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.
@@ -260,7 +260,9 @@ var init_input_content = __esm({
260
260
  // WAV (RIFF)
261
261
  { bytes: [82, 73, 70, 70], mimeType: "audio/wav" },
262
262
  // WebM
263
- { bytes: [26, 69, 223, 163], mimeType: "audio/webm" }
263
+ { bytes: [26, 69, 223, 163], mimeType: "audio/webm" },
264
+ // FLAC (fLaC)
265
+ { bytes: [102, 76, 97, 67], mimeType: "audio/flac" }
264
266
  ];
265
267
  }
266
268
  });
@@ -684,7 +686,7 @@ Produces: { "items": ["first", "second"] }`);
684
686
  this.messages.push({ role: "user", content: parts });
685
687
  return this;
686
688
  }
687
- addGadgetCall(gadget, parameters, result) {
689
+ addGadgetCall(gadget, parameters, result, media, mediaIds) {
688
690
  const paramStr = this.formatBlockParameters(parameters, "");
689
691
  this.messages.push({
690
692
  role: "assistant",
@@ -692,10 +694,25 @@ Produces: { "items": ["first", "second"] }`);
692
694
  ${paramStr}
693
695
  ${this.endPrefix}`
694
696
  });
695
- this.messages.push({
696
- role: "user",
697
- content: `Result: ${result}`
698
- });
697
+ if (media && media.length > 0 && mediaIds && mediaIds.length > 0) {
698
+ const idRefs = media.map((m, i) => `[Media: ${mediaIds[i]} (${m.kind})]`).join("\n");
699
+ const textWithIds = `Result: ${result}
700
+ ${idRefs}`;
701
+ const parts = [text(textWithIds)];
702
+ for (const item of media) {
703
+ if (item.kind === "image") {
704
+ parts.push(imageFromBase64(item.data, item.mimeType));
705
+ } else if (item.kind === "audio") {
706
+ parts.push(audioFromBase64(item.data, item.mimeType));
707
+ }
708
+ }
709
+ this.messages.push({ role: "user", content: parts });
710
+ } else {
711
+ this.messages.push({
712
+ role: "user",
713
+ content: `Result: ${result}`
714
+ });
715
+ }
699
716
  return this;
700
717
  }
701
718
  /**
@@ -1045,6 +1062,210 @@ var init_registry = __esm({
1045
1062
  }
1046
1063
  });
1047
1064
 
1065
+ // src/gadgets/media-store.ts
1066
+ import { randomBytes } from "node:crypto";
1067
+ import { mkdir, rm, writeFile } from "node:fs/promises";
1068
+ import { homedir } from "node:os";
1069
+ import { join } from "node:path";
1070
+ function getLlmistTmpDir() {
1071
+ return join(homedir(), ".llmist", "tmp");
1072
+ }
1073
+ var MIME_TO_EXTENSION, MediaStore;
1074
+ var init_media_store = __esm({
1075
+ "src/gadgets/media-store.ts"() {
1076
+ "use strict";
1077
+ MIME_TO_EXTENSION = {
1078
+ // Images
1079
+ "image/png": ".png",
1080
+ "image/jpeg": ".jpg",
1081
+ "image/gif": ".gif",
1082
+ "image/webp": ".webp",
1083
+ "image/svg+xml": ".svg",
1084
+ "image/bmp": ".bmp",
1085
+ "image/tiff": ".tiff",
1086
+ // Audio
1087
+ "audio/mp3": ".mp3",
1088
+ "audio/mpeg": ".mp3",
1089
+ "audio/wav": ".wav",
1090
+ "audio/webm": ".webm",
1091
+ "audio/ogg": ".ogg",
1092
+ "audio/flac": ".flac",
1093
+ "audio/aac": ".aac",
1094
+ // Video
1095
+ "video/mp4": ".mp4",
1096
+ "video/webm": ".webm",
1097
+ "video/ogg": ".ogv",
1098
+ "video/quicktime": ".mov",
1099
+ "video/x-msvideo": ".avi",
1100
+ // Documents
1101
+ "application/pdf": ".pdf",
1102
+ "application/json": ".json",
1103
+ "text/plain": ".txt",
1104
+ "text/html": ".html",
1105
+ "text/css": ".css",
1106
+ "text/javascript": ".js"
1107
+ };
1108
+ MediaStore = class {
1109
+ items = /* @__PURE__ */ new Map();
1110
+ outputDir;
1111
+ counter = 0;
1112
+ initialized = false;
1113
+ /**
1114
+ * Create a new MediaStore.
1115
+ *
1116
+ * @param sessionId - Optional session ID for the output directory.
1117
+ * If not provided, a random ID is generated.
1118
+ */
1119
+ constructor(sessionId) {
1120
+ const id = sessionId ?? randomBytes(8).toString("hex");
1121
+ this.outputDir = join(getLlmistTmpDir(), `media-${id}`);
1122
+ }
1123
+ /**
1124
+ * Get the output directory path.
1125
+ */
1126
+ getOutputDir() {
1127
+ return this.outputDir;
1128
+ }
1129
+ /**
1130
+ * Ensure the output directory exists.
1131
+ * @throws Error if directory creation fails
1132
+ */
1133
+ async ensureDir() {
1134
+ if (this.initialized) return;
1135
+ try {
1136
+ await mkdir(this.outputDir, { recursive: true });
1137
+ this.initialized = true;
1138
+ } catch (error) {
1139
+ throw new Error(
1140
+ `MediaStore: Failed to create directory ${this.outputDir}: ${error instanceof Error ? error.message : String(error)}`
1141
+ );
1142
+ }
1143
+ }
1144
+ /**
1145
+ * Generate a unique media ID.
1146
+ * Format: "media_" + 6 random alphanumeric characters
1147
+ */
1148
+ generateId() {
1149
+ const chars = "abcdefghijklmnopqrstuvwxyz0123456789";
1150
+ let id = "media_";
1151
+ const bytes = randomBytes(6);
1152
+ for (let i = 0; i < 6; i++) {
1153
+ id += chars[bytes[i] % chars.length];
1154
+ }
1155
+ return id;
1156
+ }
1157
+ /**
1158
+ * Get file extension from MIME type.
1159
+ */
1160
+ getExtension(mimeType) {
1161
+ return MIME_TO_EXTENSION[mimeType] ?? ".bin";
1162
+ }
1163
+ /**
1164
+ * Store media and return stored metadata with ID.
1165
+ *
1166
+ * @param media - The media output from a gadget
1167
+ * @param gadgetName - Name of the gadget that created this media
1168
+ * @returns Stored media information including generated ID
1169
+ * @throws Error if file write fails
1170
+ */
1171
+ async store(media, gadgetName) {
1172
+ await this.ensureDir();
1173
+ const id = this.generateId();
1174
+ const ext = this.getExtension(media.mimeType);
1175
+ const filename = media.fileName ?? `${gadgetName}_${String(++this.counter).padStart(3, "0")}${ext}`;
1176
+ const filePath = join(this.outputDir, filename);
1177
+ const buffer = Buffer.from(media.data, "base64");
1178
+ try {
1179
+ await writeFile(filePath, buffer);
1180
+ } catch (error) {
1181
+ throw new Error(
1182
+ `MediaStore: Failed to write media file ${filePath}: ${error instanceof Error ? error.message : String(error)}`
1183
+ );
1184
+ }
1185
+ const stored = {
1186
+ id,
1187
+ kind: media.kind,
1188
+ path: filePath,
1189
+ mimeType: media.mimeType,
1190
+ sizeBytes: buffer.length,
1191
+ description: media.description,
1192
+ metadata: media.metadata,
1193
+ gadgetName,
1194
+ createdAt: /* @__PURE__ */ new Date()
1195
+ };
1196
+ this.items.set(id, stored);
1197
+ return stored;
1198
+ }
1199
+ /**
1200
+ * Get stored media by ID.
1201
+ *
1202
+ * @param id - The media ID (e.g., "media_a1b2c3")
1203
+ * @returns The stored media or undefined if not found
1204
+ */
1205
+ get(id) {
1206
+ return this.items.get(id);
1207
+ }
1208
+ /**
1209
+ * Get the actual file path for a media ID.
1210
+ * Convenience method for gadgets that need the raw path.
1211
+ *
1212
+ * @param id - The media ID
1213
+ * @returns The file path or undefined if not found
1214
+ */
1215
+ getPath(id) {
1216
+ return this.items.get(id)?.path;
1217
+ }
1218
+ /**
1219
+ * List all stored media, optionally filtered by kind.
1220
+ *
1221
+ * @param kind - Optional media kind to filter by
1222
+ * @returns Array of stored media items
1223
+ */
1224
+ list(kind) {
1225
+ const all = Array.from(this.items.values());
1226
+ if (kind) {
1227
+ return all.filter((item) => item.kind === kind);
1228
+ }
1229
+ return all;
1230
+ }
1231
+ /**
1232
+ * Get the count of stored media items.
1233
+ */
1234
+ get size() {
1235
+ return this.items.size;
1236
+ }
1237
+ /**
1238
+ * Check if a media ID exists.
1239
+ */
1240
+ has(id) {
1241
+ return this.items.has(id);
1242
+ }
1243
+ /**
1244
+ * Clear in-memory store without deleting files.
1245
+ * Resets the counter but leaves files on disk.
1246
+ */
1247
+ clear() {
1248
+ this.items.clear();
1249
+ this.counter = 0;
1250
+ }
1251
+ /**
1252
+ * Delete all stored files and clear memory.
1253
+ * Removes the entire session directory.
1254
+ */
1255
+ async cleanup() {
1256
+ if (this.initialized) {
1257
+ try {
1258
+ await rm(this.outputDir, { recursive: true, force: true });
1259
+ } catch {
1260
+ }
1261
+ this.initialized = false;
1262
+ }
1263
+ this.clear();
1264
+ }
1265
+ };
1266
+ }
1267
+ });
1268
+
1048
1269
  // src/gadgets/exceptions.ts
1049
1270
  var BreakLoopException, HumanInputException, TimeoutException, AbortError;
1050
1271
  var init_exceptions = __esm({
@@ -1479,7 +1700,9 @@ var init_gadget = __esm({
1479
1700
  parts.push(`# ${example.comment}`);
1480
1701
  }
1481
1702
  parts.push(`${effectiveStartPrefix}${gadgetName}`);
1482
- parts.push(formatParamsAsBlock(example.params, "", effectiveArgPrefix));
1703
+ parts.push(
1704
+ formatParamsAsBlock(example.params, "", effectiveArgPrefix)
1705
+ );
1483
1706
  parts.push(effectiveEndPrefix);
1484
1707
  if (example.output !== void 0) {
1485
1708
  parts.push("");
@@ -1681,6 +1904,18 @@ var init_output_viewer = __esm({
1681
1904
  }
1682
1905
  });
1683
1906
 
1907
+ // src/agent/agent-internal-key.ts
1908
+ function isValidAgentKey(key) {
1909
+ return key === AGENT_INTERNAL_KEY;
1910
+ }
1911
+ var AGENT_INTERNAL_KEY;
1912
+ var init_agent_internal_key = __esm({
1913
+ "src/agent/agent-internal-key.ts"() {
1914
+ "use strict";
1915
+ AGENT_INTERNAL_KEY = Symbol("AGENT_INTERNAL_KEY");
1916
+ }
1917
+ });
1918
+
1684
1919
  // src/agent/compaction/config.ts
1685
1920
  function resolveCompactionConfig(config = {}) {
1686
1921
  const trigger = config.triggerThresholdPercent ?? DEFAULT_COMPACTION_CONFIG.triggerThresholdPercent;
@@ -1928,9 +2163,9 @@ var init_hybrid = __esm({
1928
2163
  var init_strategies = __esm({
1929
2164
  "src/agent/compaction/strategies/index.ts"() {
1930
2165
  "use strict";
2166
+ init_hybrid();
1931
2167
  init_sliding_window();
1932
2168
  init_summarization();
1933
- init_hybrid();
1934
2169
  }
1935
2170
  });
1936
2171
 
@@ -2092,98 +2327,6 @@ var init_manager = __esm({
2092
2327
  }
2093
2328
  });
2094
2329
 
2095
- // src/agent/gadget-output-store.ts
2096
- import { randomBytes } from "node:crypto";
2097
- var GadgetOutputStore;
2098
- var init_gadget_output_store = __esm({
2099
- "src/agent/gadget-output-store.ts"() {
2100
- "use strict";
2101
- GadgetOutputStore = class {
2102
- outputs = /* @__PURE__ */ new Map();
2103
- /**
2104
- * Store a gadget output and return its ID.
2105
- *
2106
- * @param gadgetName - Name of the gadget that produced the output
2107
- * @param content - Full output content to store
2108
- * @returns Generated ID for retrieving the output later
2109
- */
2110
- store(gadgetName, content) {
2111
- const id = this.generateId(gadgetName);
2112
- const encoder = new TextEncoder();
2113
- const stored = {
2114
- id,
2115
- gadgetName,
2116
- content,
2117
- byteSize: encoder.encode(content).length,
2118
- lineCount: content.split("\n").length,
2119
- timestamp: /* @__PURE__ */ new Date()
2120
- };
2121
- this.outputs.set(id, stored);
2122
- return id;
2123
- }
2124
- /**
2125
- * Retrieve a stored output by ID.
2126
- *
2127
- * @param id - The output ID (e.g., "Search_d34db33f")
2128
- * @returns The stored output or undefined if not found
2129
- */
2130
- get(id) {
2131
- return this.outputs.get(id);
2132
- }
2133
- /**
2134
- * Check if an output exists.
2135
- *
2136
- * @param id - The output ID to check
2137
- * @returns True if the output exists
2138
- */
2139
- has(id) {
2140
- return this.outputs.has(id);
2141
- }
2142
- /**
2143
- * Get all stored output IDs.
2144
- *
2145
- * @returns Array of output IDs
2146
- */
2147
- getIds() {
2148
- return Array.from(this.outputs.keys());
2149
- }
2150
- /**
2151
- * Get the number of stored outputs.
2152
- */
2153
- get size() {
2154
- return this.outputs.size;
2155
- }
2156
- /**
2157
- * Clear all stored outputs.
2158
- * Called when the agent run completes.
2159
- */
2160
- clear() {
2161
- this.outputs.clear();
2162
- }
2163
- /**
2164
- * Generate a unique ID for a stored output.
2165
- * Format: {GadgetName}_{8 hex chars}
2166
- */
2167
- generateId(gadgetName) {
2168
- const hex = randomBytes(4).toString("hex");
2169
- return `${gadgetName}_${hex}`;
2170
- }
2171
- };
2172
- }
2173
- });
2174
-
2175
- // src/agent/agent-internal-key.ts
2176
- function isValidAgentKey(key) {
2177
- return key === AGENT_INTERNAL_KEY;
2178
- }
2179
- var AGENT_INTERNAL_KEY;
2180
- var init_agent_internal_key = __esm({
2181
- "src/agent/agent-internal-key.ts"() {
2182
- "use strict";
2183
- AGENT_INTERNAL_KEY = Symbol("AGENT_INTERNAL_KEY");
2184
- }
2185
- });
2186
-
2187
2330
  // src/agent/conversation-manager.ts
2188
2331
  var ConversationManager;
2189
2332
  var init_conversation_manager = __esm({
@@ -2214,8 +2357,8 @@ var init_conversation_manager = __esm({
2214
2357
  addAssistantMessage(content) {
2215
2358
  this.historyBuilder.addAssistant(content);
2216
2359
  }
2217
- addGadgetCall(gadgetName, parameters, result) {
2218
- this.historyBuilder.addGadgetCall(gadgetName, parameters, result);
2360
+ addGadgetCall(gadgetName, parameters, result, media, mediaIds) {
2361
+ this.historyBuilder.addGadgetCall(gadgetName, parameters, result, media, mediaIds);
2219
2362
  }
2220
2363
  getMessages() {
2221
2364
  return [...this.baseMessages, ...this.initialMessages, ...this.historyBuilder.build()];
@@ -2329,70 +2472,150 @@ var init_event_handlers = __esm({
2329
2472
  }
2330
2473
  });
2331
2474
 
2332
- // src/agent/hook-validators.ts
2333
- function validateBeforeLLMCallAction(action) {
2334
- if (!action || typeof action !== "object" || !("action" in action)) {
2335
- throw new HookValidationError(
2336
- "beforeLLMCall",
2337
- "Must return an action object with an 'action' field"
2338
- );
2339
- }
2340
- const actionType = action.action;
2341
- if (actionType !== "proceed" && actionType !== "skip") {
2342
- throw new HookValidationError(
2343
- "beforeLLMCall",
2344
- `Invalid action type: ${actionType}. Must be 'proceed' or 'skip'`
2345
- );
2346
- }
2347
- if (actionType === "skip" && !action.syntheticResponse) {
2348
- throw new HookValidationError(
2349
- "beforeLLMCall",
2350
- "When action is 'skip', syntheticResponse is required"
2351
- );
2352
- }
2353
- }
2354
- function validateAfterLLMCallAction(action) {
2355
- if (!action || typeof action !== "object" || !("action" in action)) {
2356
- throw new HookValidationError(
2357
- "afterLLMCall",
2358
- "Must return an action object with an 'action' field"
2359
- );
2360
- }
2361
- const actionType = action.action;
2362
- const validActions = ["continue", "append_messages", "modify_and_continue", "append_and_modify"];
2363
- if (!validActions.includes(actionType)) {
2364
- throw new HookValidationError(
2365
- "afterLLMCall",
2366
- `Invalid action type: ${actionType}. Must be one of: ${validActions.join(", ")}`
2367
- );
2368
- }
2369
- if (actionType === "append_messages" || actionType === "append_and_modify") {
2370
- if (!("messages" in action) || !action.messages || !Array.isArray(action.messages)) {
2371
- throw new HookValidationError(
2372
- "afterLLMCall",
2373
- `When action is '${actionType}', messages array is required`
2374
- );
2375
- }
2376
- if (action.messages.length === 0) {
2377
- throw new HookValidationError(
2378
- "afterLLMCall",
2379
- `When action is '${actionType}', messages array must not be empty`
2380
- );
2381
- }
2382
- for (let i = 0; i < action.messages.length; i++) {
2383
- const msg = action.messages[i];
2384
- if (!msg || typeof msg !== "object") {
2385
- throw new HookValidationError("afterLLMCall", `Message at index ${i} must be an object`);
2386
- }
2387
- if (!msg.role || !msg.content) {
2388
- throw new HookValidationError(
2389
- "afterLLMCall",
2390
- `Message at index ${i} must have 'role' and 'content' fields`
2391
- );
2392
- }
2393
- if (!["system", "user", "assistant"].includes(msg.role)) {
2394
- throw new HookValidationError(
2395
- "afterLLMCall",
2475
+ // src/agent/gadget-output-store.ts
2476
+ import { randomBytes as randomBytes2 } from "node:crypto";
2477
+ var GadgetOutputStore;
2478
+ var init_gadget_output_store = __esm({
2479
+ "src/agent/gadget-output-store.ts"() {
2480
+ "use strict";
2481
+ GadgetOutputStore = class {
2482
+ outputs = /* @__PURE__ */ new Map();
2483
+ /**
2484
+ * Store a gadget output and return its ID.
2485
+ *
2486
+ * @param gadgetName - Name of the gadget that produced the output
2487
+ * @param content - Full output content to store
2488
+ * @returns Generated ID for retrieving the output later
2489
+ */
2490
+ store(gadgetName, content) {
2491
+ const id = this.generateId(gadgetName);
2492
+ const encoder = new TextEncoder();
2493
+ const stored = {
2494
+ id,
2495
+ gadgetName,
2496
+ content,
2497
+ byteSize: encoder.encode(content).length,
2498
+ lineCount: content.split("\n").length,
2499
+ timestamp: /* @__PURE__ */ new Date()
2500
+ };
2501
+ this.outputs.set(id, stored);
2502
+ return id;
2503
+ }
2504
+ /**
2505
+ * Retrieve a stored output by ID.
2506
+ *
2507
+ * @param id - The output ID (e.g., "Search_d34db33f")
2508
+ * @returns The stored output or undefined if not found
2509
+ */
2510
+ get(id) {
2511
+ return this.outputs.get(id);
2512
+ }
2513
+ /**
2514
+ * Check if an output exists.
2515
+ *
2516
+ * @param id - The output ID to check
2517
+ * @returns True if the output exists
2518
+ */
2519
+ has(id) {
2520
+ return this.outputs.has(id);
2521
+ }
2522
+ /**
2523
+ * Get all stored output IDs.
2524
+ *
2525
+ * @returns Array of output IDs
2526
+ */
2527
+ getIds() {
2528
+ return Array.from(this.outputs.keys());
2529
+ }
2530
+ /**
2531
+ * Get the number of stored outputs.
2532
+ */
2533
+ get size() {
2534
+ return this.outputs.size;
2535
+ }
2536
+ /**
2537
+ * Clear all stored outputs.
2538
+ * Called when the agent run completes.
2539
+ */
2540
+ clear() {
2541
+ this.outputs.clear();
2542
+ }
2543
+ /**
2544
+ * Generate a unique ID for a stored output.
2545
+ * Format: {GadgetName}_{8 hex chars}
2546
+ */
2547
+ generateId(gadgetName) {
2548
+ const hex = randomBytes2(4).toString("hex");
2549
+ return `${gadgetName}_${hex}`;
2550
+ }
2551
+ };
2552
+ }
2553
+ });
2554
+
2555
+ // src/agent/hook-validators.ts
2556
+ function validateBeforeLLMCallAction(action) {
2557
+ if (!action || typeof action !== "object" || !("action" in action)) {
2558
+ throw new HookValidationError(
2559
+ "beforeLLMCall",
2560
+ "Must return an action object with an 'action' field"
2561
+ );
2562
+ }
2563
+ const actionType = action.action;
2564
+ if (actionType !== "proceed" && actionType !== "skip") {
2565
+ throw new HookValidationError(
2566
+ "beforeLLMCall",
2567
+ `Invalid action type: ${actionType}. Must be 'proceed' or 'skip'`
2568
+ );
2569
+ }
2570
+ if (actionType === "skip" && !action.syntheticResponse) {
2571
+ throw new HookValidationError(
2572
+ "beforeLLMCall",
2573
+ "When action is 'skip', syntheticResponse is required"
2574
+ );
2575
+ }
2576
+ }
2577
+ function validateAfterLLMCallAction(action) {
2578
+ if (!action || typeof action !== "object" || !("action" in action)) {
2579
+ throw new HookValidationError(
2580
+ "afterLLMCall",
2581
+ "Must return an action object with an 'action' field"
2582
+ );
2583
+ }
2584
+ const actionType = action.action;
2585
+ const validActions = ["continue", "append_messages", "modify_and_continue", "append_and_modify"];
2586
+ if (!validActions.includes(actionType)) {
2587
+ throw new HookValidationError(
2588
+ "afterLLMCall",
2589
+ `Invalid action type: ${actionType}. Must be one of: ${validActions.join(", ")}`
2590
+ );
2591
+ }
2592
+ if (actionType === "append_messages" || actionType === "append_and_modify") {
2593
+ if (!("messages" in action) || !action.messages || !Array.isArray(action.messages)) {
2594
+ throw new HookValidationError(
2595
+ "afterLLMCall",
2596
+ `When action is '${actionType}', messages array is required`
2597
+ );
2598
+ }
2599
+ if (action.messages.length === 0) {
2600
+ throw new HookValidationError(
2601
+ "afterLLMCall",
2602
+ `When action is '${actionType}', messages array must not be empty`
2603
+ );
2604
+ }
2605
+ for (let i = 0; i < action.messages.length; i++) {
2606
+ const msg = action.messages[i];
2607
+ if (!msg || typeof msg !== "object") {
2608
+ throw new HookValidationError("afterLLMCall", `Message at index ${i} must be an object`);
2609
+ }
2610
+ if (!msg.role || !msg.content) {
2611
+ throw new HookValidationError(
2612
+ "afterLLMCall",
2613
+ `Message at index ${i} must have 'role' and 'content' fields`
2614
+ );
2615
+ }
2616
+ if (!["system", "user", "assistant"].includes(msg.role)) {
2617
+ throw new HookValidationError(
2618
+ "afterLLMCall",
2396
2619
  `Message at index ${i} has invalid role: ${msg.role}`
2397
2620
  );
2398
2621
  }
@@ -2639,8 +2862,7 @@ var init_schema_introspector = __esm({
2639
2862
  const values = def?.values;
2640
2863
  const value = values?.[0] ?? def?.value;
2641
2864
  if (typeof value === "string") return "string";
2642
- if (typeof value === "number" || typeof value === "bigint")
2643
- return "number";
2865
+ if (typeof value === "number" || typeof value === "bigint") return "number";
2644
2866
  if (typeof value === "boolean") return "boolean";
2645
2867
  return "unknown";
2646
2868
  }
@@ -2912,7 +3134,13 @@ var init_cost_reporting_client = __esm({
2912
3134
  cacheCreationInputTokens = chunk.usage.cacheCreationInputTokens ?? 0;
2913
3135
  }
2914
3136
  }
2915
- this.reportCostFromUsage(model, inputTokens, outputTokens, cachedInputTokens, cacheCreationInputTokens);
3137
+ this.reportCostFromUsage(
3138
+ model,
3139
+ inputTokens,
3140
+ outputTokens,
3141
+ cachedInputTokens,
3142
+ cacheCreationInputTokens
3143
+ );
2916
3144
  return result;
2917
3145
  }
2918
3146
  /**
@@ -2952,7 +3180,13 @@ var init_cost_reporting_client = __esm({
2952
3180
  }
2953
3181
  }
2954
3182
  } finally {
2955
- this.reportCostFromUsage(model, inputTokens, outputTokens, cachedInputTokens, cacheCreationInputTokens);
3183
+ this.reportCostFromUsage(
3184
+ model,
3185
+ inputTokens,
3186
+ outputTokens,
3187
+ cachedInputTokens,
3188
+ cacheCreationInputTokens
3189
+ );
2956
3190
  }
2957
3191
  }
2958
3192
  /**
@@ -2990,7 +3224,13 @@ var init_cost_reporting_client = __esm({
2990
3224
  }
2991
3225
  } finally {
2992
3226
  if (inputTokens > 0 || outputTokens > 0) {
2993
- reportCostFromUsage(model, inputTokens, outputTokens, cachedInputTokens, cacheCreationInputTokens);
3227
+ reportCostFromUsage(
3228
+ model,
3229
+ inputTokens,
3230
+ outputTokens,
3231
+ cachedInputTokens,
3232
+ cacheCreationInputTokens
3233
+ );
2994
3234
  }
2995
3235
  }
2996
3236
  }
@@ -3202,7 +3442,11 @@ var init_parser = __esm({
3202
3442
  const metadataEndIndex = this.buffer.indexOf("\n", metadataStartIndex);
3203
3443
  if (metadataEndIndex === -1) break;
3204
3444
  const gadgetName = this.buffer.substring(metadataStartIndex, metadataEndIndex).trim();
3205
- const { actualName: actualGadgetName, invocationId, dependencies } = this.parseGadgetName(gadgetName);
3445
+ const {
3446
+ actualName: actualGadgetName,
3447
+ invocationId,
3448
+ dependencies
3449
+ } = this.parseGadgetName(gadgetName);
3206
3450
  const contentStartIndex = metadataEndIndex + 1;
3207
3451
  let partEndIndex;
3208
3452
  let endMarkerLength = 0;
@@ -3250,7 +3494,11 @@ var init_parser = __esm({
3250
3494
  const metadataEndIndex = this.buffer.indexOf("\n", metadataStartIndex);
3251
3495
  if (metadataEndIndex !== -1) {
3252
3496
  const gadgetName = this.buffer.substring(metadataStartIndex, metadataEndIndex).trim();
3253
- const { actualName: actualGadgetName, invocationId, dependencies } = this.parseGadgetName(gadgetName);
3497
+ const {
3498
+ actualName: actualGadgetName,
3499
+ invocationId,
3500
+ dependencies
3501
+ } = this.parseGadgetName(gadgetName);
3254
3502
  const contentStartIndex = metadataEndIndex + 1;
3255
3503
  const parametersRaw = this.buffer.substring(contentStartIndex).trim();
3256
3504
  const { parameters, parseError } = this.parseParameters(parametersRaw);
@@ -3295,11 +3543,12 @@ var init_executor = __esm({
3295
3543
  init_exceptions();
3296
3544
  init_parser();
3297
3545
  GadgetExecutor = class {
3298
- constructor(registry, onHumanInputRequired, logger, defaultGadgetTimeoutMs, errorFormatterOptions, client) {
3546
+ constructor(registry, onHumanInputRequired, logger, defaultGadgetTimeoutMs, errorFormatterOptions, client, mediaStore) {
3299
3547
  this.registry = registry;
3300
3548
  this.onHumanInputRequired = onHumanInputRequired;
3301
3549
  this.defaultGadgetTimeoutMs = defaultGadgetTimeoutMs;
3302
3550
  this.client = client;
3551
+ this.mediaStore = mediaStore;
3303
3552
  this.logger = logger ?? createLogger({ name: "llmist:executor" });
3304
3553
  this.errorFormatter = new GadgetErrorFormatter(errorFormatterOptions);
3305
3554
  this.argPrefix = errorFormatterOptions?.argPrefix ?? GADGET_ARG_PREFIX;
@@ -3322,12 +3571,16 @@ var init_executor = __esm({
3322
3571
  }
3323
3572
  /**
3324
3573
  * Normalizes gadget execute result to consistent format.
3325
- * Handles both string returns (backwards compat) and object returns with cost.
3574
+ * Handles string returns (backwards compat), object returns with cost,
3575
+ * and object returns with media.
3326
3576
  */
3327
3577
  normalizeExecuteResult(raw) {
3328
3578
  if (typeof raw === "string") {
3329
3579
  return { result: raw, cost: 0 };
3330
3580
  }
3581
+ if ("media" in raw && raw.media) {
3582
+ return { result: raw.result, media: raw.media, cost: raw.cost ?? 0 };
3583
+ }
3331
3584
  return { result: raw.result, cost: raw.cost ?? 0 };
3332
3585
  }
3333
3586
  // Execute a gadget call asynchronously
@@ -3454,8 +3707,21 @@ var init_executor = __esm({
3454
3707
  } else {
3455
3708
  rawResult = await Promise.resolve(gadget.execute(validatedParameters, ctx));
3456
3709
  }
3457
- const { result, cost: returnCost } = this.normalizeExecuteResult(rawResult);
3710
+ const { result, media, cost: returnCost } = this.normalizeExecuteResult(rawResult);
3458
3711
  const totalCost = callbackCost + returnCost;
3712
+ let mediaIds;
3713
+ let storedMedia;
3714
+ if (media && media.length > 0 && this.mediaStore) {
3715
+ storedMedia = await Promise.all(
3716
+ media.map((item) => this.mediaStore.store(item, call.gadgetName))
3717
+ );
3718
+ mediaIds = storedMedia.map((m) => m.id);
3719
+ this.logger.debug("Stored media outputs", {
3720
+ gadgetName: call.gadgetName,
3721
+ mediaIds,
3722
+ count: media.length
3723
+ });
3724
+ }
3459
3725
  const executionTimeMs = Date.now() - startTime;
3460
3726
  this.logger.info("Gadget executed successfully", {
3461
3727
  gadgetName: call.gadgetName,
@@ -3463,7 +3729,8 @@ var init_executor = __esm({
3463
3729
  executionTimeMs,
3464
3730
  cost: totalCost > 0 ? totalCost : void 0,
3465
3731
  callbackCost: callbackCost > 0 ? callbackCost : void 0,
3466
- returnCost: returnCost > 0 ? returnCost : void 0
3732
+ returnCost: returnCost > 0 ? returnCost : void 0,
3733
+ mediaCount: media?.length
3467
3734
  });
3468
3735
  this.logger.debug("Gadget result", {
3469
3736
  gadgetName: call.gadgetName,
@@ -3471,7 +3738,8 @@ var init_executor = __esm({
3471
3738
  parameters: validatedParameters,
3472
3739
  result,
3473
3740
  cost: totalCost,
3474
- executionTimeMs
3741
+ executionTimeMs,
3742
+ mediaIds
3475
3743
  });
3476
3744
  return {
3477
3745
  gadgetName: call.gadgetName,
@@ -3479,7 +3747,10 @@ var init_executor = __esm({
3479
3747
  parameters: validatedParameters,
3480
3748
  result,
3481
3749
  executionTimeMs,
3482
- cost: totalCost
3750
+ cost: totalCost,
3751
+ media,
3752
+ mediaIds,
3753
+ storedMedia
3483
3754
  };
3484
3755
  } catch (error) {
3485
3756
  if (error instanceof BreakLoopException) {
@@ -3657,7 +3928,8 @@ var init_stream_processor = __esm({
3657
3928
  this.logger.getSubLogger({ name: "executor" }),
3658
3929
  options.defaultGadgetTimeoutMs,
3659
3930
  { argPrefix: options.gadgetArgPrefix },
3660
- options.client
3931
+ options.client,
3932
+ options.mediaStore
3661
3933
  );
3662
3934
  }
3663
3935
  /**
@@ -4246,13 +4518,14 @@ var init_agent = __esm({
4246
4518
  init_constants();
4247
4519
  init_messages();
4248
4520
  init_model_shortcuts();
4521
+ init_media_store();
4249
4522
  init_output_viewer();
4250
4523
  init_logger();
4251
- init_manager();
4252
- init_gadget_output_store();
4253
4524
  init_agent_internal_key();
4525
+ init_manager();
4254
4526
  init_conversation_manager();
4255
4527
  init_event_handlers();
4528
+ init_gadget_output_store();
4256
4529
  init_hook_validators();
4257
4530
  init_stream_processor();
4258
4531
  Agent = class {
@@ -4281,6 +4554,8 @@ var init_agent = __esm({
4281
4554
  outputLimitCharLimit;
4282
4555
  // Context compaction
4283
4556
  compactionManager;
4557
+ // Media storage (for gadgets returning images, audio, etc.)
4558
+ mediaStore;
4284
4559
  // Cancellation
4285
4560
  signal;
4286
4561
  /**
@@ -4311,6 +4586,7 @@ var init_agent = __esm({
4311
4586
  this.defaultMaxTokens = this.resolveMaxTokensFromCatalog(options.model);
4312
4587
  this.outputLimitEnabled = options.gadgetOutputLimit ?? DEFAULT_GADGET_OUTPUT_LIMIT;
4313
4588
  this.outputStore = new GadgetOutputStore();
4589
+ this.mediaStore = new MediaStore();
4314
4590
  const limitPercent = options.gadgetOutputLimitPercent ?? DEFAULT_GADGET_OUTPUT_LIMIT_PERCENT;
4315
4591
  const limits = this.client.modelRegistry.getModelLimits(this.model);
4316
4592
  const contextWindow = limits?.contextWindow ?? FALLBACK_CONTEXT_WINDOW;
@@ -4376,6 +4652,36 @@ var init_agent = __esm({
4376
4652
  getRegistry() {
4377
4653
  return this.registry;
4378
4654
  }
4655
+ /**
4656
+ * Get the media store for this agent session.
4657
+ *
4658
+ * The media store holds all media outputs (images, audio, etc.) produced by gadgets
4659
+ * during this agent's execution. Use this to:
4660
+ * - Access stored media files by ID
4661
+ * - List all stored media
4662
+ * - Clean up temporary files after execution
4663
+ *
4664
+ * @returns The MediaStore instance for this agent
4665
+ *
4666
+ * @example
4667
+ * ```typescript
4668
+ * const agent = new AgentBuilder()
4669
+ * .withModel("sonnet")
4670
+ * .build();
4671
+ *
4672
+ * // After execution, access stored media
4673
+ * const store = agent.getMediaStore();
4674
+ * for (const media of store.list()) {
4675
+ * console.log(`${media.id}: ${media.path}`);
4676
+ * }
4677
+ *
4678
+ * // Clean up when done
4679
+ * await store.cleanup();
4680
+ * ```
4681
+ */
4682
+ getMediaStore() {
4683
+ return this.mediaStore;
4684
+ }
4379
4685
  /**
4380
4686
  * Manually trigger context compaction.
4381
4687
  *
@@ -4551,7 +4857,8 @@ var init_agent = __esm({
4551
4857
  stopOnGadgetError: this.stopOnGadgetError,
4552
4858
  shouldContinueAfterError: this.shouldContinueAfterError,
4553
4859
  defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
4554
- client: this.client
4860
+ client: this.client,
4861
+ mediaStore: this.mediaStore
4555
4862
  });
4556
4863
  const result = await processor.process(stream2);
4557
4864
  for (const output of result.outputs) {
@@ -4613,7 +4920,9 @@ var init_agent = __esm({
4613
4920
  }
4614
4921
  if (result.didExecuteGadgets) {
4615
4922
  if (this.textWithGadgetsHandler) {
4616
- const textContent = result.outputs.filter((output) => output.type === "text").map((output) => output.content).join("");
4923
+ const textContent = result.outputs.filter(
4924
+ (output) => output.type === "text"
4925
+ ).map((output) => output.content).join("");
4617
4926
  if (textContent.trim()) {
4618
4927
  const { gadgetName, parameterMapping, resultMapping } = this.textWithGadgetsHandler;
4619
4928
  this.conversation.addGadgetCall(
@@ -4629,7 +4938,9 @@ var init_agent = __esm({
4629
4938
  this.conversation.addGadgetCall(
4630
4939
  gadgetResult.gadgetName,
4631
4940
  gadgetResult.parameters,
4632
- gadgetResult.error ?? gadgetResult.result ?? ""
4941
+ gadgetResult.error ?? gadgetResult.result ?? "",
4942
+ gadgetResult.media,
4943
+ gadgetResult.mediaIds
4633
4944
  );
4634
4945
  }
4635
4946
  }
@@ -7721,14 +8032,7 @@ var OPENAI_TTS_VOICES, OPENAI_TTS_EXTENDED_VOICES, OPENAI_TTS_FORMATS, openaiSpe
7721
8032
  var init_openai_speech_models = __esm({
7722
8033
  "src/providers/openai-speech-models.ts"() {
7723
8034
  "use strict";
7724
- OPENAI_TTS_VOICES = [
7725
- "alloy",
7726
- "echo",
7727
- "fable",
7728
- "onyx",
7729
- "nova",
7730
- "shimmer"
7731
- ];
8035
+ OPENAI_TTS_VOICES = ["alloy", "echo", "fable", "onyx", "nova", "shimmer"];
7732
8036
  OPENAI_TTS_EXTENDED_VOICES = [
7733
8037
  ...OPENAI_TTS_VOICES,
7734
8038
  "ash",
@@ -8426,9 +8730,7 @@ var init_image = __esm({
8426
8730
  return this.findImageAdapter(modelId) !== void 0;
8427
8731
  }
8428
8732
  findImageAdapter(modelId) {
8429
- return this.adapters.find(
8430
- (adapter) => adapter.supportsImageGeneration?.(modelId) ?? false
8431
- );
8733
+ return this.adapters.find((adapter) => adapter.supportsImageGeneration?.(modelId) ?? false);
8432
8734
  }
8433
8735
  };
8434
8736
  }
@@ -8480,9 +8782,7 @@ var init_speech = __esm({
8480
8782
  return this.findSpeechAdapter(modelId) !== void 0;
8481
8783
  }
8482
8784
  findSpeechAdapter(modelId) {
8483
- return this.adapters.find(
8484
- (adapter) => adapter.supportsSpeechGeneration?.(modelId) ?? false
8485
- );
8785
+ return this.adapters.find((adapter) => adapter.supportsSpeechGeneration?.(modelId) ?? false);
8486
8786
  }
8487
8787
  };
8488
8788
  }
@@ -8593,11 +8893,7 @@ var init_vision = __esm({
8593
8893
  if (!parsed) {
8594
8894
  throw new Error("Invalid data URL format");
8595
8895
  }
8596
- builder.addUserWithImage(
8597
- options.prompt,
8598
- parsed.data,
8599
- parsed.mimeType
8600
- );
8896
+ builder.addUserWithImage(options.prompt, parsed.data, parsed.mimeType);
8601
8897
  } else {
8602
8898
  const buffer = Buffer.from(options.image, "base64");
8603
8899
  builder.addUserWithImage(options.prompt, buffer, options.mimeType);
@@ -8983,48 +9279,273 @@ var init_client = __esm({
8983
9279
  }
8984
9280
  });
8985
9281
 
8986
- // src/gadgets/validation.ts
8987
- function validateAndApplyDefaults(schema, params) {
8988
- const result = schema.safeParse(params);
8989
- if (result.success) {
8990
- return {
8991
- success: true,
8992
- data: result.data
8993
- };
8994
- }
8995
- const issues = result.error.issues.map((issue) => ({
8996
- path: issue.path.join(".") || "root",
8997
- message: issue.message
8998
- }));
8999
- const formattedError = `Invalid parameters: ${issues.map((i) => `${i.path}: ${i.message}`).join("; ")}`;
9282
+ // src/testing/cli-helpers.ts
9283
+ import { PassThrough, Readable, Writable } from "node:stream";
9284
+ function createTestEnvironment(options = {}) {
9285
+ const stdin = createMockReadable(options.stdin);
9286
+ const stdout = new PassThrough();
9287
+ const stderr = new PassThrough();
9288
+ let exitCode;
9000
9289
  return {
9001
- success: false,
9002
- error: formattedError,
9003
- issues
9290
+ stdin,
9291
+ stdout,
9292
+ stderr,
9293
+ isTTY: options.isTTY ?? false,
9294
+ argv: options.argv ?? ["node", "llmist"],
9295
+ env: { ...filterDefinedEnv(process.env), ...options.env },
9296
+ get exitCode() {
9297
+ return exitCode;
9298
+ },
9299
+ setExitCode: (code) => {
9300
+ exitCode = code;
9301
+ }
9004
9302
  };
9005
9303
  }
9006
- function validateGadgetParams(gadget, params) {
9007
- if (!gadget.parameterSchema) {
9008
- return {
9009
- success: true,
9010
- data: params
9011
- };
9304
+ function createMockReadable(input) {
9305
+ if (!input) {
9306
+ const stream3 = new Readable({ read() {
9307
+ } });
9308
+ stream3.push(null);
9309
+ return stream3;
9012
9310
  }
9013
- return validateAndApplyDefaults(gadget.parameterSchema, params);
9311
+ const content = Array.isArray(input) ? `${input.join("\n")}
9312
+ ` : input;
9313
+ const stream2 = new Readable({ read() {
9314
+ } });
9315
+ stream2.push(content);
9316
+ stream2.push(null);
9317
+ return stream2;
9014
9318
  }
9015
-
9016
- // src/testing/gadget-testing.ts
9017
- async function testGadget(gadget, params, options) {
9018
- let validatedParams = params;
9019
- if (!options?.skipValidation) {
9020
- const validationResult = validateGadgetParams(gadget, params);
9021
- if (!validationResult.success) {
9022
- return {
9023
- error: validationResult.error,
9024
- validatedParams: params
9025
- };
9026
- }
9027
- validatedParams = validationResult.data;
9319
+ function createMockWritable() {
9320
+ const chunks = [];
9321
+ const stream2 = new Writable({
9322
+ write(chunk, _encoding, callback) {
9323
+ chunks.push(Buffer.from(chunk));
9324
+ callback();
9325
+ }
9326
+ });
9327
+ stream2.getData = () => Buffer.concat(chunks).toString("utf8");
9328
+ return stream2;
9329
+ }
9330
+ async function collectOutput(stream2, timeout = 5e3) {
9331
+ return new Promise((resolve, reject) => {
9332
+ const chunks = [];
9333
+ const timeoutId = setTimeout(() => {
9334
+ resolve(Buffer.concat(chunks).toString("utf8"));
9335
+ }, timeout);
9336
+ stream2.on("data", (chunk) => {
9337
+ chunks.push(Buffer.from(chunk));
9338
+ });
9339
+ stream2.on("end", () => {
9340
+ clearTimeout(timeoutId);
9341
+ resolve(Buffer.concat(chunks).toString("utf8"));
9342
+ });
9343
+ stream2.on("error", (err) => {
9344
+ clearTimeout(timeoutId);
9345
+ reject(err);
9346
+ });
9347
+ });
9348
+ }
9349
+ function getBufferedOutput(stream2) {
9350
+ const chunks = [];
9351
+ for (; ; ) {
9352
+ const chunk = stream2.read();
9353
+ if (chunk === null) break;
9354
+ chunks.push(chunk);
9355
+ }
9356
+ return Buffer.concat(chunks).toString("utf8");
9357
+ }
9358
+ function createMockPrompt(responses) {
9359
+ let index = 0;
9360
+ return async (_question) => {
9361
+ if (index >= responses.length) {
9362
+ throw new Error(`Mock prompt exhausted: no response for question ${index + 1}`);
9363
+ }
9364
+ return responses[index++];
9365
+ };
9366
+ }
9367
+ var MockPromptRecorder = class {
9368
+ responses;
9369
+ index = 0;
9370
+ questions = [];
9371
+ constructor(responses) {
9372
+ this.responses = responses;
9373
+ }
9374
+ /**
9375
+ * The prompt function to use in tests.
9376
+ */
9377
+ prompt = async (question) => {
9378
+ this.questions.push(question);
9379
+ if (this.index >= this.responses.length) {
9380
+ throw new Error(`Mock prompt exhausted after ${this.index} questions`);
9381
+ }
9382
+ return this.responses[this.index++];
9383
+ };
9384
+ /**
9385
+ * Get all questions that were asked.
9386
+ */
9387
+ getQuestions() {
9388
+ return [...this.questions];
9389
+ }
9390
+ /**
9391
+ * Get the number of questions asked.
9392
+ */
9393
+ getQuestionCount() {
9394
+ return this.questions.length;
9395
+ }
9396
+ /**
9397
+ * Reset the recorder state.
9398
+ */
9399
+ reset(newResponses) {
9400
+ this.index = 0;
9401
+ this.questions = [];
9402
+ if (newResponses) {
9403
+ this.responses = newResponses;
9404
+ }
9405
+ }
9406
+ };
9407
+ async function waitFor(condition, timeout = 5e3, interval = 50) {
9408
+ const startTime = Date.now();
9409
+ while (!condition()) {
9410
+ if (Date.now() - startTime > timeout) {
9411
+ throw new Error(`waitFor timed out after ${timeout}ms`);
9412
+ }
9413
+ await sleep(interval);
9414
+ }
9415
+ }
9416
+ function sleep(ms) {
9417
+ return new Promise((resolve) => setTimeout(resolve, ms));
9418
+ }
9419
+ function filterDefinedEnv(env) {
9420
+ const result = {};
9421
+ for (const [key, value] of Object.entries(env)) {
9422
+ if (value !== void 0) {
9423
+ result[key] = value;
9424
+ }
9425
+ }
9426
+ return result;
9427
+ }
9428
+
9429
+ // src/testing/conversation-fixtures.ts
9430
+ function createConversation(turnCount, options) {
9431
+ const messages = [];
9432
+ const userPrefix = options?.userPrefix ?? "User message";
9433
+ const assistantPrefix = options?.assistantPrefix ?? "Assistant response";
9434
+ const contentLength = options?.contentLength ?? 100;
9435
+ for (let i = 0; i < turnCount; i++) {
9436
+ const padding = " ".repeat(Math.max(0, contentLength - 30));
9437
+ messages.push({
9438
+ role: "user",
9439
+ content: `${userPrefix} ${i + 1}: This is turn ${i + 1} of the conversation.${padding}`
9440
+ });
9441
+ messages.push({
9442
+ role: "assistant",
9443
+ content: `${assistantPrefix} ${i + 1}: I acknowledge turn ${i + 1}.${padding}`
9444
+ });
9445
+ }
9446
+ return messages;
9447
+ }
9448
+ function createConversationWithGadgets(turnCount, gadgetCallsPerTurn = 1, options) {
9449
+ const messages = [];
9450
+ const gadgetNames = options?.gadgetNames ?? ["search", "calculate", "read"];
9451
+ const contentLength = options?.contentLength ?? 50;
9452
+ let gadgetIndex = 0;
9453
+ for (let turn = 0; turn < turnCount; turn++) {
9454
+ messages.push({
9455
+ role: "user",
9456
+ content: `User request ${turn + 1}${"x".repeat(contentLength)}`
9457
+ });
9458
+ for (let g = 0; g < gadgetCallsPerTurn; g++) {
9459
+ const gadgetName = gadgetNames[gadgetIndex % gadgetNames.length];
9460
+ gadgetIndex++;
9461
+ messages.push({
9462
+ role: "assistant",
9463
+ content: `!!!GADGET_START:${gadgetName}
9464
+ !!!ARG:query
9465
+ test query ${turn}-${g}
9466
+ !!!GADGET_END`
9467
+ });
9468
+ messages.push({
9469
+ role: "user",
9470
+ content: `Result: Gadget ${gadgetName} returned result for query ${turn}-${g}`
9471
+ });
9472
+ }
9473
+ messages.push({
9474
+ role: "assistant",
9475
+ content: `Final response for turn ${turn + 1}${"y".repeat(contentLength)}`
9476
+ });
9477
+ }
9478
+ return messages;
9479
+ }
9480
+ function estimateTokens(messages) {
9481
+ return Math.ceil(messages.reduce((sum, msg) => sum + (msg.content?.length ?? 0), 0) / 4);
9482
+ }
9483
+ function createUserMessage(content) {
9484
+ return { role: "user", content };
9485
+ }
9486
+ function createAssistantMessage(content) {
9487
+ return { role: "assistant", content };
9488
+ }
9489
+ function createSystemMessage(content) {
9490
+ return { role: "system", content };
9491
+ }
9492
+ function createMinimalConversation() {
9493
+ return [
9494
+ { role: "user", content: "Hello" },
9495
+ { role: "assistant", content: "Hi there!" }
9496
+ ];
9497
+ }
9498
+ function createLargeConversation(targetTokens, options) {
9499
+ const tokensPerTurn = options?.tokensPerTurn ?? 200;
9500
+ const turnsNeeded = Math.ceil(targetTokens / tokensPerTurn);
9501
+ const charsPerMessage = Math.floor(tokensPerTurn * 4 / 2);
9502
+ return createConversation(turnsNeeded, {
9503
+ contentLength: charsPerMessage
9504
+ });
9505
+ }
9506
+
9507
+ // src/gadgets/validation.ts
9508
+ function validateAndApplyDefaults(schema, params) {
9509
+ const result = schema.safeParse(params);
9510
+ if (result.success) {
9511
+ return {
9512
+ success: true,
9513
+ data: result.data
9514
+ };
9515
+ }
9516
+ const issues = result.error.issues.map((issue) => ({
9517
+ path: issue.path.join(".") || "root",
9518
+ message: issue.message
9519
+ }));
9520
+ const formattedError = `Invalid parameters: ${issues.map((i) => `${i.path}: ${i.message}`).join("; ")}`;
9521
+ return {
9522
+ success: false,
9523
+ error: formattedError,
9524
+ issues
9525
+ };
9526
+ }
9527
+ function validateGadgetParams(gadget, params) {
9528
+ if (!gadget.parameterSchema) {
9529
+ return {
9530
+ success: true,
9531
+ data: params
9532
+ };
9533
+ }
9534
+ return validateAndApplyDefaults(gadget.parameterSchema, params);
9535
+ }
9536
+
9537
+ // src/testing/gadget-testing.ts
9538
+ async function testGadget(gadget, params, options) {
9539
+ let validatedParams = params;
9540
+ if (!options?.skipValidation) {
9541
+ const validationResult = validateGadgetParams(gadget, params);
9542
+ if (!validationResult.success) {
9543
+ return {
9544
+ error: validationResult.error,
9545
+ validatedParams: params
9546
+ };
9547
+ }
9548
+ validatedParams = validationResult.data;
9028
9549
  }
9029
9550
  try {
9030
9551
  const rawResult = await Promise.resolve(gadget.execute(validatedParams));
@@ -9220,7 +9741,7 @@ function getMockManager(options) {
9220
9741
 
9221
9742
  // src/testing/mock-stream.ts
9222
9743
  init_constants();
9223
- function sleep(ms) {
9744
+ function sleep2(ms) {
9224
9745
  return new Promise((resolve) => setTimeout(resolve, ms));
9225
9746
  }
9226
9747
  function generateInvocationId() {
@@ -9301,7 +9822,7 @@ ${blockParams}${GADGET_END_PREFIX}`;
9301
9822
  }
9302
9823
  async function* createMockStream(response) {
9303
9824
  if (response.delayMs) {
9304
- await sleep(response.delayMs);
9825
+ await sleep2(response.delayMs);
9305
9826
  }
9306
9827
  const streamDelay = response.streamDelayMs ?? 0;
9307
9828
  let fullText = response.text ?? "";
@@ -9326,7 +9847,7 @@ async function* createMockStream(response) {
9326
9847
  }
9327
9848
  yield chunk;
9328
9849
  if (streamDelay > 0 && !isLast) {
9329
- await sleep(streamDelay);
9850
+ await sleep2(streamDelay);
9330
9851
  }
9331
9852
  }
9332
9853
  } else {
@@ -9603,7 +10124,9 @@ var MockBuilder = class {
9603
10124
  */
9604
10125
  whenMessageContains(text3) {
9605
10126
  this.matchers.push(
9606
- (ctx) => ctx.messages.some((msg) => extractText(msg.content).toLowerCase().includes(text3.toLowerCase()))
10127
+ (ctx) => ctx.messages.some(
10128
+ (msg) => extractText(msg.content).toLowerCase().includes(text3.toLowerCase())
10129
+ )
9607
10130
  );
9608
10131
  return this;
9609
10132
  }
@@ -10041,29 +10564,158 @@ function createMockClient(options) {
10041
10564
  });
10042
10565
  }
10043
10566
 
10044
- // src/testing/mock-gadget.ts
10045
- init_gadget();
10046
- var MockGadgetImpl = class extends BaseGadget {
10047
- name;
10048
- description;
10049
- parameterSchema;
10050
- timeoutMs;
10051
- calls = [];
10052
- resultValue;
10053
- resultFn;
10054
- errorToThrow;
10055
- delayMs;
10056
- shouldTrackCalls;
10057
- constructor(config) {
10058
- super();
10059
- this.name = config.name;
10060
- this.description = config.description ?? `Mock gadget: ${config.name}`;
10061
- this.parameterSchema = config.schema;
10062
- this.resultValue = config.result;
10063
- this.resultFn = config.resultFn;
10064
- this.delayMs = config.delayMs ?? 0;
10065
- this.shouldTrackCalls = config.trackCalls ?? true;
10066
- this.timeoutMs = config.timeoutMs;
10567
+ // src/testing/mock-conversation.ts
10568
+ var MockConversationManager = class {
10569
+ history;
10570
+ baseMessages;
10571
+ replacementHistory;
10572
+ replaceHistoryCallCount = 0;
10573
+ addedMessages = [];
10574
+ constructor(history = [], baseMessages = []) {
10575
+ this.history = [...history];
10576
+ this.baseMessages = [...baseMessages];
10577
+ }
10578
+ addUserMessage(content) {
10579
+ const msg = { role: "user", content };
10580
+ this.history.push(msg);
10581
+ this.addedMessages.push(msg);
10582
+ }
10583
+ addAssistantMessage(content) {
10584
+ const msg = { role: "assistant", content };
10585
+ this.history.push(msg);
10586
+ this.addedMessages.push(msg);
10587
+ }
10588
+ addGadgetCall(gadgetName, parameters, result) {
10589
+ const assistantMsg = {
10590
+ role: "assistant",
10591
+ content: `!!!GADGET_START:${gadgetName}
10592
+ ${JSON.stringify(parameters)}
10593
+ !!!GADGET_END`
10594
+ };
10595
+ const resultMsg = {
10596
+ role: "user",
10597
+ content: `Result: ${result}`
10598
+ };
10599
+ this.history.push(assistantMsg);
10600
+ this.history.push(resultMsg);
10601
+ this.addedMessages.push(assistantMsg);
10602
+ this.addedMessages.push(resultMsg);
10603
+ }
10604
+ getMessages() {
10605
+ return [...this.baseMessages, ...this.history];
10606
+ }
10607
+ getHistoryMessages() {
10608
+ return [...this.history];
10609
+ }
10610
+ getBaseMessages() {
10611
+ return [...this.baseMessages];
10612
+ }
10613
+ replaceHistory(newHistory) {
10614
+ this.replacementHistory = [...newHistory];
10615
+ this.history = [...newHistory];
10616
+ this.replaceHistoryCallCount++;
10617
+ }
10618
+ // ============================================
10619
+ // Test Helper Methods
10620
+ // ============================================
10621
+ /**
10622
+ * Check if replaceHistory was called.
10623
+ */
10624
+ wasReplaceHistoryCalled() {
10625
+ return this.replaceHistoryCallCount > 0;
10626
+ }
10627
+ /**
10628
+ * Get the number of times replaceHistory was called.
10629
+ */
10630
+ getReplaceHistoryCallCount() {
10631
+ return this.replaceHistoryCallCount;
10632
+ }
10633
+ /**
10634
+ * Get the most recent history passed to replaceHistory.
10635
+ * Returns undefined if replaceHistory was never called.
10636
+ */
10637
+ getReplacementHistory() {
10638
+ return this.replacementHistory;
10639
+ }
10640
+ /**
10641
+ * Get all messages that were added via add* methods.
10642
+ */
10643
+ getAddedMessages() {
10644
+ return [...this.addedMessages];
10645
+ }
10646
+ /**
10647
+ * Reset all tracking state while preserving the conversation.
10648
+ */
10649
+ resetTracking() {
10650
+ this.replacementHistory = void 0;
10651
+ this.replaceHistoryCallCount = 0;
10652
+ this.addedMessages = [];
10653
+ }
10654
+ /**
10655
+ * Completely reset the mock to initial state.
10656
+ * Note: baseMessages cannot be changed after construction.
10657
+ */
10658
+ reset(history = []) {
10659
+ this.history = [...history];
10660
+ this.resetTracking();
10661
+ }
10662
+ /**
10663
+ * Set the history directly (for test setup).
10664
+ */
10665
+ setHistory(messages) {
10666
+ this.history = [...messages];
10667
+ }
10668
+ /**
10669
+ * Get the current history length.
10670
+ */
10671
+ getHistoryLength() {
10672
+ return this.history.length;
10673
+ }
10674
+ /**
10675
+ * Get total message count (base + history).
10676
+ */
10677
+ getTotalMessageCount() {
10678
+ return this.baseMessages.length + this.history.length;
10679
+ }
10680
+ };
10681
+ function createMockConversationManager(turnCount, baseMessages = []) {
10682
+ const history = [];
10683
+ for (let i = 0; i < turnCount; i++) {
10684
+ history.push({
10685
+ role: "user",
10686
+ content: `User message ${i + 1}: This is turn ${i + 1} of the conversation.`
10687
+ });
10688
+ history.push({
10689
+ role: "assistant",
10690
+ content: `Assistant response ${i + 1}: I acknowledge turn ${i + 1}.`
10691
+ });
10692
+ }
10693
+ return new MockConversationManager(history, baseMessages);
10694
+ }
10695
+
10696
+ // src/testing/mock-gadget.ts
10697
+ init_gadget();
10698
+ var MockGadgetImpl = class extends BaseGadget {
10699
+ name;
10700
+ description;
10701
+ parameterSchema;
10702
+ timeoutMs;
10703
+ calls = [];
10704
+ resultValue;
10705
+ resultFn;
10706
+ errorToThrow;
10707
+ delayMs;
10708
+ shouldTrackCalls;
10709
+ constructor(config) {
10710
+ super();
10711
+ this.name = config.name;
10712
+ this.description = config.description ?? `Mock gadget: ${config.name}`;
10713
+ this.parameterSchema = config.schema;
10714
+ this.resultValue = config.result;
10715
+ this.resultFn = config.resultFn;
10716
+ this.delayMs = config.delayMs ?? 0;
10717
+ this.shouldTrackCalls = config.trackCalls ?? true;
10718
+ this.timeoutMs = config.timeoutMs;
10067
10719
  if (config.error) {
10068
10720
  this.errorToThrow = typeof config.error === "string" ? new Error(config.error) : config.error;
10069
10721
  }
@@ -10200,7 +10852,7 @@ function createTestStream(chunks) {
10200
10852
  function createTextStream(text3, options) {
10201
10853
  return async function* () {
10202
10854
  if (options?.delayMs) {
10203
- await sleep2(options.delayMs);
10855
+ await sleep3(options.delayMs);
10204
10856
  }
10205
10857
  const chunkSize = options?.chunkSize ?? text3.length;
10206
10858
  const chunks = [];
@@ -10222,7 +10874,7 @@ function createTextStream(text3, options) {
10222
10874
  }
10223
10875
  yield chunk;
10224
10876
  if (options?.chunkDelayMs && !isLast) {
10225
- await sleep2(options.chunkDelayMs);
10877
+ await sleep3(options.chunkDelayMs);
10226
10878
  }
10227
10879
  }
10228
10880
  }();
@@ -10260,366 +10912,10 @@ function createErrorStream(chunksBeforeError, error) {
10260
10912
  throw error;
10261
10913
  }();
10262
10914
  }
10263
- function sleep2(ms) {
10915
+ function sleep3(ms) {
10264
10916
  return new Promise((resolve) => setTimeout(resolve, ms));
10265
10917
  }
10266
10918
 
10267
- // src/testing/conversation-fixtures.ts
10268
- function createConversation(turnCount, options) {
10269
- const messages = [];
10270
- const userPrefix = options?.userPrefix ?? "User message";
10271
- const assistantPrefix = options?.assistantPrefix ?? "Assistant response";
10272
- const contentLength = options?.contentLength ?? 100;
10273
- for (let i = 0; i < turnCount; i++) {
10274
- const padding = " ".repeat(Math.max(0, contentLength - 30));
10275
- messages.push({
10276
- role: "user",
10277
- content: `${userPrefix} ${i + 1}: This is turn ${i + 1} of the conversation.${padding}`
10278
- });
10279
- messages.push({
10280
- role: "assistant",
10281
- content: `${assistantPrefix} ${i + 1}: I acknowledge turn ${i + 1}.${padding}`
10282
- });
10283
- }
10284
- return messages;
10285
- }
10286
- function createConversationWithGadgets(turnCount, gadgetCallsPerTurn = 1, options) {
10287
- const messages = [];
10288
- const gadgetNames = options?.gadgetNames ?? ["search", "calculate", "read"];
10289
- const contentLength = options?.contentLength ?? 50;
10290
- let gadgetIndex = 0;
10291
- for (let turn = 0; turn < turnCount; turn++) {
10292
- messages.push({
10293
- role: "user",
10294
- content: `User request ${turn + 1}${"x".repeat(contentLength)}`
10295
- });
10296
- for (let g = 0; g < gadgetCallsPerTurn; g++) {
10297
- const gadgetName = gadgetNames[gadgetIndex % gadgetNames.length];
10298
- gadgetIndex++;
10299
- messages.push({
10300
- role: "assistant",
10301
- content: `!!!GADGET_START:${gadgetName}
10302
- !!!ARG:query
10303
- test query ${turn}-${g}
10304
- !!!GADGET_END`
10305
- });
10306
- messages.push({
10307
- role: "user",
10308
- content: `Result: Gadget ${gadgetName} returned result for query ${turn}-${g}`
10309
- });
10310
- }
10311
- messages.push({
10312
- role: "assistant",
10313
- content: `Final response for turn ${turn + 1}${"y".repeat(contentLength)}`
10314
- });
10315
- }
10316
- return messages;
10317
- }
10318
- function estimateTokens(messages) {
10319
- return Math.ceil(
10320
- messages.reduce((sum, msg) => sum + (msg.content?.length ?? 0), 0) / 4
10321
- );
10322
- }
10323
- function createUserMessage(content) {
10324
- return { role: "user", content };
10325
- }
10326
- function createAssistantMessage(content) {
10327
- return { role: "assistant", content };
10328
- }
10329
- function createSystemMessage(content) {
10330
- return { role: "system", content };
10331
- }
10332
- function createMinimalConversation() {
10333
- return [
10334
- { role: "user", content: "Hello" },
10335
- { role: "assistant", content: "Hi there!" }
10336
- ];
10337
- }
10338
- function createLargeConversation(targetTokens, options) {
10339
- const tokensPerTurn = options?.tokensPerTurn ?? 200;
10340
- const turnsNeeded = Math.ceil(targetTokens / tokensPerTurn);
10341
- const charsPerMessage = Math.floor(tokensPerTurn * 4 / 2);
10342
- return createConversation(turnsNeeded, {
10343
- contentLength: charsPerMessage
10344
- });
10345
- }
10346
-
10347
- // src/testing/mock-conversation.ts
10348
- var MockConversationManager = class {
10349
- history;
10350
- baseMessages;
10351
- replacementHistory;
10352
- replaceHistoryCallCount = 0;
10353
- addedMessages = [];
10354
- constructor(history = [], baseMessages = []) {
10355
- this.history = [...history];
10356
- this.baseMessages = [...baseMessages];
10357
- }
10358
- addUserMessage(content) {
10359
- const msg = { role: "user", content };
10360
- this.history.push(msg);
10361
- this.addedMessages.push(msg);
10362
- }
10363
- addAssistantMessage(content) {
10364
- const msg = { role: "assistant", content };
10365
- this.history.push(msg);
10366
- this.addedMessages.push(msg);
10367
- }
10368
- addGadgetCall(gadgetName, parameters, result) {
10369
- const assistantMsg = {
10370
- role: "assistant",
10371
- content: `!!!GADGET_START:${gadgetName}
10372
- ${JSON.stringify(parameters)}
10373
- !!!GADGET_END`
10374
- };
10375
- const resultMsg = {
10376
- role: "user",
10377
- content: `Result: ${result}`
10378
- };
10379
- this.history.push(assistantMsg);
10380
- this.history.push(resultMsg);
10381
- this.addedMessages.push(assistantMsg);
10382
- this.addedMessages.push(resultMsg);
10383
- }
10384
- getMessages() {
10385
- return [...this.baseMessages, ...this.history];
10386
- }
10387
- getHistoryMessages() {
10388
- return [...this.history];
10389
- }
10390
- getBaseMessages() {
10391
- return [...this.baseMessages];
10392
- }
10393
- replaceHistory(newHistory) {
10394
- this.replacementHistory = [...newHistory];
10395
- this.history = [...newHistory];
10396
- this.replaceHistoryCallCount++;
10397
- }
10398
- // ============================================
10399
- // Test Helper Methods
10400
- // ============================================
10401
- /**
10402
- * Check if replaceHistory was called.
10403
- */
10404
- wasReplaceHistoryCalled() {
10405
- return this.replaceHistoryCallCount > 0;
10406
- }
10407
- /**
10408
- * Get the number of times replaceHistory was called.
10409
- */
10410
- getReplaceHistoryCallCount() {
10411
- return this.replaceHistoryCallCount;
10412
- }
10413
- /**
10414
- * Get the most recent history passed to replaceHistory.
10415
- * Returns undefined if replaceHistory was never called.
10416
- */
10417
- getReplacementHistory() {
10418
- return this.replacementHistory;
10419
- }
10420
- /**
10421
- * Get all messages that were added via add* methods.
10422
- */
10423
- getAddedMessages() {
10424
- return [...this.addedMessages];
10425
- }
10426
- /**
10427
- * Reset all tracking state while preserving the conversation.
10428
- */
10429
- resetTracking() {
10430
- this.replacementHistory = void 0;
10431
- this.replaceHistoryCallCount = 0;
10432
- this.addedMessages = [];
10433
- }
10434
- /**
10435
- * Completely reset the mock to initial state.
10436
- * Note: baseMessages cannot be changed after construction.
10437
- */
10438
- reset(history = []) {
10439
- this.history = [...history];
10440
- this.resetTracking();
10441
- }
10442
- /**
10443
- * Set the history directly (for test setup).
10444
- */
10445
- setHistory(messages) {
10446
- this.history = [...messages];
10447
- }
10448
- /**
10449
- * Get the current history length.
10450
- */
10451
- getHistoryLength() {
10452
- return this.history.length;
10453
- }
10454
- /**
10455
- * Get total message count (base + history).
10456
- */
10457
- getTotalMessageCount() {
10458
- return this.baseMessages.length + this.history.length;
10459
- }
10460
- };
10461
- function createMockConversationManager(turnCount, baseMessages = []) {
10462
- const history = [];
10463
- for (let i = 0; i < turnCount; i++) {
10464
- history.push({
10465
- role: "user",
10466
- content: `User message ${i + 1}: This is turn ${i + 1} of the conversation.`
10467
- });
10468
- history.push({
10469
- role: "assistant",
10470
- content: `Assistant response ${i + 1}: I acknowledge turn ${i + 1}.`
10471
- });
10472
- }
10473
- return new MockConversationManager(history, baseMessages);
10474
- }
10475
-
10476
- // src/testing/cli-helpers.ts
10477
- import { PassThrough, Readable, Writable } from "node:stream";
10478
- function createTestEnvironment(options = {}) {
10479
- const stdin = createMockReadable(options.stdin);
10480
- const stdout = new PassThrough();
10481
- const stderr = new PassThrough();
10482
- let exitCode;
10483
- return {
10484
- stdin,
10485
- stdout,
10486
- stderr,
10487
- isTTY: options.isTTY ?? false,
10488
- argv: options.argv ?? ["node", "llmist"],
10489
- env: { ...filterDefinedEnv(process.env), ...options.env },
10490
- get exitCode() {
10491
- return exitCode;
10492
- },
10493
- setExitCode: (code) => {
10494
- exitCode = code;
10495
- }
10496
- };
10497
- }
10498
- function createMockReadable(input) {
10499
- if (!input) {
10500
- const stream3 = new Readable({ read() {
10501
- } });
10502
- stream3.push(null);
10503
- return stream3;
10504
- }
10505
- const content = Array.isArray(input) ? `${input.join("\n")}
10506
- ` : input;
10507
- const stream2 = new Readable({ read() {
10508
- } });
10509
- stream2.push(content);
10510
- stream2.push(null);
10511
- return stream2;
10512
- }
10513
- function createMockWritable() {
10514
- const chunks = [];
10515
- const stream2 = new Writable({
10516
- write(chunk, _encoding, callback) {
10517
- chunks.push(Buffer.from(chunk));
10518
- callback();
10519
- }
10520
- });
10521
- stream2.getData = () => Buffer.concat(chunks).toString("utf8");
10522
- return stream2;
10523
- }
10524
- async function collectOutput(stream2, timeout = 5e3) {
10525
- return new Promise((resolve, reject) => {
10526
- const chunks = [];
10527
- const timeoutId = setTimeout(() => {
10528
- resolve(Buffer.concat(chunks).toString("utf8"));
10529
- }, timeout);
10530
- stream2.on("data", (chunk) => {
10531
- chunks.push(Buffer.from(chunk));
10532
- });
10533
- stream2.on("end", () => {
10534
- clearTimeout(timeoutId);
10535
- resolve(Buffer.concat(chunks).toString("utf8"));
10536
- });
10537
- stream2.on("error", (err) => {
10538
- clearTimeout(timeoutId);
10539
- reject(err);
10540
- });
10541
- });
10542
- }
10543
- function getBufferedOutput(stream2) {
10544
- const chunks = [];
10545
- for (; ; ) {
10546
- const chunk = stream2.read();
10547
- if (chunk === null) break;
10548
- chunks.push(chunk);
10549
- }
10550
- return Buffer.concat(chunks).toString("utf8");
10551
- }
10552
- function createMockPrompt(responses) {
10553
- let index = 0;
10554
- return async (_question) => {
10555
- if (index >= responses.length) {
10556
- throw new Error(`Mock prompt exhausted: no response for question ${index + 1}`);
10557
- }
10558
- return responses[index++];
10559
- };
10560
- }
10561
- var MockPromptRecorder = class {
10562
- responses;
10563
- index = 0;
10564
- questions = [];
10565
- constructor(responses) {
10566
- this.responses = responses;
10567
- }
10568
- /**
10569
- * The prompt function to use in tests.
10570
- */
10571
- prompt = async (question) => {
10572
- this.questions.push(question);
10573
- if (this.index >= this.responses.length) {
10574
- throw new Error(`Mock prompt exhausted after ${this.index} questions`);
10575
- }
10576
- return this.responses[this.index++];
10577
- };
10578
- /**
10579
- * Get all questions that were asked.
10580
- */
10581
- getQuestions() {
10582
- return [...this.questions];
10583
- }
10584
- /**
10585
- * Get the number of questions asked.
10586
- */
10587
- getQuestionCount() {
10588
- return this.questions.length;
10589
- }
10590
- /**
10591
- * Reset the recorder state.
10592
- */
10593
- reset(newResponses) {
10594
- this.index = 0;
10595
- this.questions = [];
10596
- if (newResponses) {
10597
- this.responses = newResponses;
10598
- }
10599
- }
10600
- };
10601
- async function waitFor(condition, timeout = 5e3, interval = 50) {
10602
- const startTime = Date.now();
10603
- while (!condition()) {
10604
- if (Date.now() - startTime > timeout) {
10605
- throw new Error(`waitFor timed out after ${timeout}ms`);
10606
- }
10607
- await sleep3(interval);
10608
- }
10609
- }
10610
- function sleep3(ms) {
10611
- return new Promise((resolve) => setTimeout(resolve, ms));
10612
- }
10613
- function filterDefinedEnv(env) {
10614
- const result = {};
10615
- for (const [key, value] of Object.entries(env)) {
10616
- if (value !== void 0) {
10617
- result[key] = value;
10618
- }
10619
- }
10620
- return result;
10621
- }
10622
-
10623
10919
  export {
10624
10920
  isTextPart,
10625
10921
  isImagePart,
@@ -10656,6 +10952,8 @@ export {
10656
10952
  extractText,
10657
10953
  LLMMessageBuilder,
10658
10954
  init_messages,
10955
+ MediaStore,
10956
+ init_media_store,
10659
10957
  BreakLoopException,
10660
10958
  HumanInputException,
10661
10959
  AbortError,
@@ -10681,14 +10979,14 @@ export {
10681
10979
  init_strategies,
10682
10980
  CompactionManager,
10683
10981
  init_manager,
10684
- GadgetOutputStore,
10685
- init_gadget_output_store,
10686
10982
  ConversationManager,
10687
10983
  init_conversation_manager,
10688
10984
  runWithHandlers,
10689
10985
  collectEvents,
10690
10986
  collectText,
10691
10987
  init_event_handlers,
10988
+ GadgetOutputStore,
10989
+ init_gadget_output_store,
10692
10990
  StreamParser,
10693
10991
  init_parser,
10694
10992
  GadgetExecutor,
@@ -10721,6 +11019,22 @@ export {
10721
11019
  init_builder,
10722
11020
  validateAndApplyDefaults,
10723
11021
  validateGadgetParams,
11022
+ createTestEnvironment,
11023
+ createMockReadable,
11024
+ createMockWritable,
11025
+ collectOutput,
11026
+ getBufferedOutput,
11027
+ createMockPrompt,
11028
+ MockPromptRecorder,
11029
+ waitFor,
11030
+ createConversation,
11031
+ createConversationWithGadgets,
11032
+ estimateTokens,
11033
+ createUserMessage,
11034
+ createAssistantMessage,
11035
+ createSystemMessage,
11036
+ createMinimalConversation,
11037
+ createLargeConversation,
10724
11038
  testGadget,
10725
11039
  testGadgetBatch,
10726
11040
  MockManager,
@@ -10732,6 +11046,8 @@ export {
10732
11046
  MockBuilder,
10733
11047
  mockLLM,
10734
11048
  createMockClient,
11049
+ MockConversationManager,
11050
+ createMockConversationManager,
10735
11051
  createMockGadget,
10736
11052
  MockGadgetBuilder,
10737
11053
  mockGadget,
@@ -10741,24 +11057,6 @@ export {
10741
11057
  collectStreamText,
10742
11058
  getStreamFinalChunk,
10743
11059
  createEmptyStream,
10744
- createErrorStream,
10745
- createConversation,
10746
- createConversationWithGadgets,
10747
- estimateTokens,
10748
- createUserMessage,
10749
- createAssistantMessage,
10750
- createSystemMessage,
10751
- createMinimalConversation,
10752
- createLargeConversation,
10753
- MockConversationManager,
10754
- createMockConversationManager,
10755
- createTestEnvironment,
10756
- createMockReadable,
10757
- createMockWritable,
10758
- collectOutput,
10759
- getBufferedOutput,
10760
- createMockPrompt,
10761
- MockPromptRecorder,
10762
- waitFor
11060
+ createErrorStream
10763
11061
  };
10764
- //# sourceMappingURL=chunk-YHS2DYXP.js.map
11062
+ //# sourceMappingURL=chunk-364PEMVT.js.map