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.
package/dist/index.cjs CHANGED
@@ -192,7 +192,9 @@ var init_input_content = __esm({
192
192
  // WAV (RIFF)
193
193
  { bytes: [82, 73, 70, 70], mimeType: "audio/wav" },
194
194
  // WebM
195
- { bytes: [26, 69, 223, 163], mimeType: "audio/webm" }
195
+ { bytes: [26, 69, 223, 163], mimeType: "audio/webm" },
196
+ // FLAC (fLaC)
197
+ { bytes: [102, 76, 97, 67], mimeType: "audio/flac" }
196
198
  ];
197
199
  }
198
200
  });
@@ -930,7 +932,7 @@ Produces: { "items": ["first", "second"] }`);
930
932
  this.messages.push({ role: "user", content: parts });
931
933
  return this;
932
934
  }
933
- addGadgetCall(gadget, parameters, result) {
935
+ addGadgetCall(gadget, parameters, result, media, mediaIds) {
934
936
  const paramStr = this.formatBlockParameters(parameters, "");
935
937
  this.messages.push({
936
938
  role: "assistant",
@@ -938,10 +940,25 @@ Produces: { "items": ["first", "second"] }`);
938
940
  ${paramStr}
939
941
  ${this.endPrefix}`
940
942
  });
941
- this.messages.push({
942
- role: "user",
943
- content: `Result: ${result}`
944
- });
943
+ if (media && media.length > 0 && mediaIds && mediaIds.length > 0) {
944
+ const idRefs = media.map((m, i) => `[Media: ${mediaIds[i]} (${m.kind})]`).join("\n");
945
+ const textWithIds = `Result: ${result}
946
+ ${idRefs}`;
947
+ const parts = [text(textWithIds)];
948
+ for (const item of media) {
949
+ if (item.kind === "image") {
950
+ parts.push(imageFromBase64(item.data, item.mimeType));
951
+ } else if (item.kind === "audio") {
952
+ parts.push(audioFromBase64(item.data, item.mimeType));
953
+ }
954
+ }
955
+ this.messages.push({ role: "user", content: parts });
956
+ } else {
957
+ this.messages.push({
958
+ role: "user",
959
+ content: `Result: ${result}`
960
+ });
961
+ }
945
962
  return this;
946
963
  }
947
964
  /**
@@ -978,6 +995,210 @@ ${this.endPrefix}`
978
995
  }
979
996
  });
980
997
 
998
+ // src/gadgets/media-store.ts
999
+ function getLlmistTmpDir() {
1000
+ return (0, import_node_path.join)((0, import_node_os.homedir)(), ".llmist", "tmp");
1001
+ }
1002
+ var import_node_crypto, import_promises, import_node_os, import_node_path, MIME_TO_EXTENSION, MediaStore;
1003
+ var init_media_store = __esm({
1004
+ "src/gadgets/media-store.ts"() {
1005
+ "use strict";
1006
+ import_node_crypto = require("crypto");
1007
+ import_promises = require("fs/promises");
1008
+ import_node_os = require("os");
1009
+ import_node_path = require("path");
1010
+ MIME_TO_EXTENSION = {
1011
+ // Images
1012
+ "image/png": ".png",
1013
+ "image/jpeg": ".jpg",
1014
+ "image/gif": ".gif",
1015
+ "image/webp": ".webp",
1016
+ "image/svg+xml": ".svg",
1017
+ "image/bmp": ".bmp",
1018
+ "image/tiff": ".tiff",
1019
+ // Audio
1020
+ "audio/mp3": ".mp3",
1021
+ "audio/mpeg": ".mp3",
1022
+ "audio/wav": ".wav",
1023
+ "audio/webm": ".webm",
1024
+ "audio/ogg": ".ogg",
1025
+ "audio/flac": ".flac",
1026
+ "audio/aac": ".aac",
1027
+ // Video
1028
+ "video/mp4": ".mp4",
1029
+ "video/webm": ".webm",
1030
+ "video/ogg": ".ogv",
1031
+ "video/quicktime": ".mov",
1032
+ "video/x-msvideo": ".avi",
1033
+ // Documents
1034
+ "application/pdf": ".pdf",
1035
+ "application/json": ".json",
1036
+ "text/plain": ".txt",
1037
+ "text/html": ".html",
1038
+ "text/css": ".css",
1039
+ "text/javascript": ".js"
1040
+ };
1041
+ MediaStore = class {
1042
+ items = /* @__PURE__ */ new Map();
1043
+ outputDir;
1044
+ counter = 0;
1045
+ initialized = false;
1046
+ /**
1047
+ * Create a new MediaStore.
1048
+ *
1049
+ * @param sessionId - Optional session ID for the output directory.
1050
+ * If not provided, a random ID is generated.
1051
+ */
1052
+ constructor(sessionId) {
1053
+ const id = sessionId ?? (0, import_node_crypto.randomBytes)(8).toString("hex");
1054
+ this.outputDir = (0, import_node_path.join)(getLlmistTmpDir(), `media-${id}`);
1055
+ }
1056
+ /**
1057
+ * Get the output directory path.
1058
+ */
1059
+ getOutputDir() {
1060
+ return this.outputDir;
1061
+ }
1062
+ /**
1063
+ * Ensure the output directory exists.
1064
+ * @throws Error if directory creation fails
1065
+ */
1066
+ async ensureDir() {
1067
+ if (this.initialized) return;
1068
+ try {
1069
+ await (0, import_promises.mkdir)(this.outputDir, { recursive: true });
1070
+ this.initialized = true;
1071
+ } catch (error) {
1072
+ throw new Error(
1073
+ `MediaStore: Failed to create directory ${this.outputDir}: ${error instanceof Error ? error.message : String(error)}`
1074
+ );
1075
+ }
1076
+ }
1077
+ /**
1078
+ * Generate a unique media ID.
1079
+ * Format: "media_" + 6 random alphanumeric characters
1080
+ */
1081
+ generateId() {
1082
+ const chars = "abcdefghijklmnopqrstuvwxyz0123456789";
1083
+ let id = "media_";
1084
+ const bytes = (0, import_node_crypto.randomBytes)(6);
1085
+ for (let i = 0; i < 6; i++) {
1086
+ id += chars[bytes[i] % chars.length];
1087
+ }
1088
+ return id;
1089
+ }
1090
+ /**
1091
+ * Get file extension from MIME type.
1092
+ */
1093
+ getExtension(mimeType) {
1094
+ return MIME_TO_EXTENSION[mimeType] ?? ".bin";
1095
+ }
1096
+ /**
1097
+ * Store media and return stored metadata with ID.
1098
+ *
1099
+ * @param media - The media output from a gadget
1100
+ * @param gadgetName - Name of the gadget that created this media
1101
+ * @returns Stored media information including generated ID
1102
+ * @throws Error if file write fails
1103
+ */
1104
+ async store(media, gadgetName) {
1105
+ await this.ensureDir();
1106
+ const id = this.generateId();
1107
+ const ext = this.getExtension(media.mimeType);
1108
+ const filename = media.fileName ?? `${gadgetName}_${String(++this.counter).padStart(3, "0")}${ext}`;
1109
+ const filePath = (0, import_node_path.join)(this.outputDir, filename);
1110
+ const buffer = Buffer.from(media.data, "base64");
1111
+ try {
1112
+ await (0, import_promises.writeFile)(filePath, buffer);
1113
+ } catch (error) {
1114
+ throw new Error(
1115
+ `MediaStore: Failed to write media file ${filePath}: ${error instanceof Error ? error.message : String(error)}`
1116
+ );
1117
+ }
1118
+ const stored = {
1119
+ id,
1120
+ kind: media.kind,
1121
+ path: filePath,
1122
+ mimeType: media.mimeType,
1123
+ sizeBytes: buffer.length,
1124
+ description: media.description,
1125
+ metadata: media.metadata,
1126
+ gadgetName,
1127
+ createdAt: /* @__PURE__ */ new Date()
1128
+ };
1129
+ this.items.set(id, stored);
1130
+ return stored;
1131
+ }
1132
+ /**
1133
+ * Get stored media by ID.
1134
+ *
1135
+ * @param id - The media ID (e.g., "media_a1b2c3")
1136
+ * @returns The stored media or undefined if not found
1137
+ */
1138
+ get(id) {
1139
+ return this.items.get(id);
1140
+ }
1141
+ /**
1142
+ * Get the actual file path for a media ID.
1143
+ * Convenience method for gadgets that need the raw path.
1144
+ *
1145
+ * @param id - The media ID
1146
+ * @returns The file path or undefined if not found
1147
+ */
1148
+ getPath(id) {
1149
+ return this.items.get(id)?.path;
1150
+ }
1151
+ /**
1152
+ * List all stored media, optionally filtered by kind.
1153
+ *
1154
+ * @param kind - Optional media kind to filter by
1155
+ * @returns Array of stored media items
1156
+ */
1157
+ list(kind) {
1158
+ const all = Array.from(this.items.values());
1159
+ if (kind) {
1160
+ return all.filter((item) => item.kind === kind);
1161
+ }
1162
+ return all;
1163
+ }
1164
+ /**
1165
+ * Get the count of stored media items.
1166
+ */
1167
+ get size() {
1168
+ return this.items.size;
1169
+ }
1170
+ /**
1171
+ * Check if a media ID exists.
1172
+ */
1173
+ has(id) {
1174
+ return this.items.has(id);
1175
+ }
1176
+ /**
1177
+ * Clear in-memory store without deleting files.
1178
+ * Resets the counter but leaves files on disk.
1179
+ */
1180
+ clear() {
1181
+ this.items.clear();
1182
+ this.counter = 0;
1183
+ }
1184
+ /**
1185
+ * Delete all stored files and clear memory.
1186
+ * Removes the entire session directory.
1187
+ */
1188
+ async cleanup() {
1189
+ if (this.initialized) {
1190
+ try {
1191
+ await (0, import_promises.rm)(this.outputDir, { recursive: true, force: true });
1192
+ } catch {
1193
+ }
1194
+ this.initialized = false;
1195
+ }
1196
+ this.clear();
1197
+ }
1198
+ };
1199
+ }
1200
+ });
1201
+
981
1202
  // src/gadgets/exceptions.ts
982
1203
  var BreakLoopException, HumanInputException, TimeoutException, AbortError;
983
1204
  var init_exceptions = __esm({
@@ -1050,7 +1271,7 @@ function createLogger(options = {}) {
1050
1271
  let finalType = defaultType;
1051
1272
  if (envLogFile) {
1052
1273
  try {
1053
- (0, import_node_fs.mkdirSync)((0, import_node_path.dirname)(envLogFile), { recursive: true });
1274
+ (0, import_node_fs.mkdirSync)((0, import_node_path2.dirname)(envLogFile), { recursive: true });
1054
1275
  const flags = logReset ? "w" : "a";
1055
1276
  logFileStream = (0, import_node_fs.createWriteStream)(envLogFile, { flags });
1056
1277
  finalType = "hidden";
@@ -1075,12 +1296,12 @@ function createLogger(options = {}) {
1075
1296
  }
1076
1297
  return logger;
1077
1298
  }
1078
- var import_node_fs, import_node_path, import_tslog, LEVEL_NAME_TO_ID, defaultLogger;
1299
+ var import_node_fs, import_node_path2, import_tslog, LEVEL_NAME_TO_ID, defaultLogger;
1079
1300
  var init_logger = __esm({
1080
1301
  "src/logging/logger.ts"() {
1081
1302
  "use strict";
1082
1303
  import_node_fs = require("fs");
1083
- import_node_path = require("path");
1304
+ import_node_path2 = require("path");
1084
1305
  import_tslog = require("tslog");
1085
1306
  LEVEL_NAME_TO_ID = {
1086
1307
  silly: 0,
@@ -1492,7 +1713,9 @@ var init_gadget = __esm({
1492
1713
  parts.push(`# ${example.comment}`);
1493
1714
  }
1494
1715
  parts.push(`${effectiveStartPrefix}${gadgetName}`);
1495
- parts.push(formatParamsAsBlock(example.params, "", effectiveArgPrefix));
1716
+ parts.push(
1717
+ formatParamsAsBlock(example.params, "", effectiveArgPrefix)
1718
+ );
1496
1719
  parts.push(effectiveEndPrefix);
1497
1720
  if (example.output !== void 0) {
1498
1721
  parts.push("");
@@ -1694,6 +1917,18 @@ var init_output_viewer = __esm({
1694
1917
  }
1695
1918
  });
1696
1919
 
1920
+ // src/agent/agent-internal-key.ts
1921
+ function isValidAgentKey(key) {
1922
+ return key === AGENT_INTERNAL_KEY;
1923
+ }
1924
+ var AGENT_INTERNAL_KEY;
1925
+ var init_agent_internal_key = __esm({
1926
+ "src/agent/agent-internal-key.ts"() {
1927
+ "use strict";
1928
+ AGENT_INTERNAL_KEY = Symbol("AGENT_INTERNAL_KEY");
1929
+ }
1930
+ });
1931
+
1697
1932
  // src/agent/compaction/config.ts
1698
1933
  function resolveCompactionConfig(config = {}) {
1699
1934
  const trigger = config.triggerThresholdPercent ?? DEFAULT_COMPACTION_CONFIG.triggerThresholdPercent;
@@ -1941,9 +2176,9 @@ var init_hybrid = __esm({
1941
2176
  var init_strategies = __esm({
1942
2177
  "src/agent/compaction/strategies/index.ts"() {
1943
2178
  "use strict";
2179
+ init_hybrid();
1944
2180
  init_sliding_window();
1945
2181
  init_summarization();
1946
- init_hybrid();
1947
2182
  }
1948
2183
  });
1949
2184
 
@@ -2105,98 +2340,6 @@ var init_manager = __esm({
2105
2340
  }
2106
2341
  });
2107
2342
 
2108
- // src/agent/gadget-output-store.ts
2109
- var import_node_crypto, GadgetOutputStore;
2110
- var init_gadget_output_store = __esm({
2111
- "src/agent/gadget-output-store.ts"() {
2112
- "use strict";
2113
- import_node_crypto = require("crypto");
2114
- GadgetOutputStore = class {
2115
- outputs = /* @__PURE__ */ new Map();
2116
- /**
2117
- * Store a gadget output and return its ID.
2118
- *
2119
- * @param gadgetName - Name of the gadget that produced the output
2120
- * @param content - Full output content to store
2121
- * @returns Generated ID for retrieving the output later
2122
- */
2123
- store(gadgetName, content) {
2124
- const id = this.generateId(gadgetName);
2125
- const encoder = new TextEncoder();
2126
- const stored = {
2127
- id,
2128
- gadgetName,
2129
- content,
2130
- byteSize: encoder.encode(content).length,
2131
- lineCount: content.split("\n").length,
2132
- timestamp: /* @__PURE__ */ new Date()
2133
- };
2134
- this.outputs.set(id, stored);
2135
- return id;
2136
- }
2137
- /**
2138
- * Retrieve a stored output by ID.
2139
- *
2140
- * @param id - The output ID (e.g., "Search_d34db33f")
2141
- * @returns The stored output or undefined if not found
2142
- */
2143
- get(id) {
2144
- return this.outputs.get(id);
2145
- }
2146
- /**
2147
- * Check if an output exists.
2148
- *
2149
- * @param id - The output ID to check
2150
- * @returns True if the output exists
2151
- */
2152
- has(id) {
2153
- return this.outputs.has(id);
2154
- }
2155
- /**
2156
- * Get all stored output IDs.
2157
- *
2158
- * @returns Array of output IDs
2159
- */
2160
- getIds() {
2161
- return Array.from(this.outputs.keys());
2162
- }
2163
- /**
2164
- * Get the number of stored outputs.
2165
- */
2166
- get size() {
2167
- return this.outputs.size;
2168
- }
2169
- /**
2170
- * Clear all stored outputs.
2171
- * Called when the agent run completes.
2172
- */
2173
- clear() {
2174
- this.outputs.clear();
2175
- }
2176
- /**
2177
- * Generate a unique ID for a stored output.
2178
- * Format: {GadgetName}_{8 hex chars}
2179
- */
2180
- generateId(gadgetName) {
2181
- const hex = (0, import_node_crypto.randomBytes)(4).toString("hex");
2182
- return `${gadgetName}_${hex}`;
2183
- }
2184
- };
2185
- }
2186
- });
2187
-
2188
- // src/agent/agent-internal-key.ts
2189
- function isValidAgentKey(key) {
2190
- return key === AGENT_INTERNAL_KEY;
2191
- }
2192
- var AGENT_INTERNAL_KEY;
2193
- var init_agent_internal_key = __esm({
2194
- "src/agent/agent-internal-key.ts"() {
2195
- "use strict";
2196
- AGENT_INTERNAL_KEY = Symbol("AGENT_INTERNAL_KEY");
2197
- }
2198
- });
2199
-
2200
2343
  // src/agent/conversation-manager.ts
2201
2344
  var ConversationManager;
2202
2345
  var init_conversation_manager = __esm({
@@ -2227,8 +2370,8 @@ var init_conversation_manager = __esm({
2227
2370
  addAssistantMessage(content) {
2228
2371
  this.historyBuilder.addAssistant(content);
2229
2372
  }
2230
- addGadgetCall(gadgetName, parameters, result) {
2231
- this.historyBuilder.addGadgetCall(gadgetName, parameters, result);
2373
+ addGadgetCall(gadgetName, parameters, result, media, mediaIds) {
2374
+ this.historyBuilder.addGadgetCall(gadgetName, parameters, result, media, mediaIds);
2232
2375
  }
2233
2376
  getMessages() {
2234
2377
  return [...this.baseMessages, ...this.initialMessages, ...this.historyBuilder.build()];
@@ -2342,6 +2485,86 @@ var init_event_handlers = __esm({
2342
2485
  }
2343
2486
  });
2344
2487
 
2488
+ // src/agent/gadget-output-store.ts
2489
+ var import_node_crypto2, GadgetOutputStore;
2490
+ var init_gadget_output_store = __esm({
2491
+ "src/agent/gadget-output-store.ts"() {
2492
+ "use strict";
2493
+ import_node_crypto2 = require("crypto");
2494
+ GadgetOutputStore = class {
2495
+ outputs = /* @__PURE__ */ new Map();
2496
+ /**
2497
+ * Store a gadget output and return its ID.
2498
+ *
2499
+ * @param gadgetName - Name of the gadget that produced the output
2500
+ * @param content - Full output content to store
2501
+ * @returns Generated ID for retrieving the output later
2502
+ */
2503
+ store(gadgetName, content) {
2504
+ const id = this.generateId(gadgetName);
2505
+ const encoder = new TextEncoder();
2506
+ const stored = {
2507
+ id,
2508
+ gadgetName,
2509
+ content,
2510
+ byteSize: encoder.encode(content).length,
2511
+ lineCount: content.split("\n").length,
2512
+ timestamp: /* @__PURE__ */ new Date()
2513
+ };
2514
+ this.outputs.set(id, stored);
2515
+ return id;
2516
+ }
2517
+ /**
2518
+ * Retrieve a stored output by ID.
2519
+ *
2520
+ * @param id - The output ID (e.g., "Search_d34db33f")
2521
+ * @returns The stored output or undefined if not found
2522
+ */
2523
+ get(id) {
2524
+ return this.outputs.get(id);
2525
+ }
2526
+ /**
2527
+ * Check if an output exists.
2528
+ *
2529
+ * @param id - The output ID to check
2530
+ * @returns True if the output exists
2531
+ */
2532
+ has(id) {
2533
+ return this.outputs.has(id);
2534
+ }
2535
+ /**
2536
+ * Get all stored output IDs.
2537
+ *
2538
+ * @returns Array of output IDs
2539
+ */
2540
+ getIds() {
2541
+ return Array.from(this.outputs.keys());
2542
+ }
2543
+ /**
2544
+ * Get the number of stored outputs.
2545
+ */
2546
+ get size() {
2547
+ return this.outputs.size;
2548
+ }
2549
+ /**
2550
+ * Clear all stored outputs.
2551
+ * Called when the agent run completes.
2552
+ */
2553
+ clear() {
2554
+ this.outputs.clear();
2555
+ }
2556
+ /**
2557
+ * Generate a unique ID for a stored output.
2558
+ * Format: {GadgetName}_{8 hex chars}
2559
+ */
2560
+ generateId(gadgetName) {
2561
+ const hex = (0, import_node_crypto2.randomBytes)(4).toString("hex");
2562
+ return `${gadgetName}_${hex}`;
2563
+ }
2564
+ };
2565
+ }
2566
+ });
2567
+
2345
2568
  // src/agent/hook-validators.ts
2346
2569
  function validateBeforeLLMCallAction(action) {
2347
2570
  if (!action || typeof action !== "object" || !("action" in action)) {
@@ -2652,8 +2875,7 @@ var init_schema_introspector = __esm({
2652
2875
  const values = def?.values;
2653
2876
  const value = values?.[0] ?? def?.value;
2654
2877
  if (typeof value === "string") return "string";
2655
- if (typeof value === "number" || typeof value === "bigint")
2656
- return "number";
2878
+ if (typeof value === "number" || typeof value === "bigint") return "number";
2657
2879
  if (typeof value === "boolean") return "boolean";
2658
2880
  return "unknown";
2659
2881
  }
@@ -2925,7 +3147,13 @@ var init_cost_reporting_client = __esm({
2925
3147
  cacheCreationInputTokens = chunk.usage.cacheCreationInputTokens ?? 0;
2926
3148
  }
2927
3149
  }
2928
- this.reportCostFromUsage(model, inputTokens, outputTokens, cachedInputTokens, cacheCreationInputTokens);
3150
+ this.reportCostFromUsage(
3151
+ model,
3152
+ inputTokens,
3153
+ outputTokens,
3154
+ cachedInputTokens,
3155
+ cacheCreationInputTokens
3156
+ );
2929
3157
  return result;
2930
3158
  }
2931
3159
  /**
@@ -2965,7 +3193,13 @@ var init_cost_reporting_client = __esm({
2965
3193
  }
2966
3194
  }
2967
3195
  } finally {
2968
- this.reportCostFromUsage(model, inputTokens, outputTokens, cachedInputTokens, cacheCreationInputTokens);
3196
+ this.reportCostFromUsage(
3197
+ model,
3198
+ inputTokens,
3199
+ outputTokens,
3200
+ cachedInputTokens,
3201
+ cacheCreationInputTokens
3202
+ );
2969
3203
  }
2970
3204
  }
2971
3205
  /**
@@ -3003,7 +3237,13 @@ var init_cost_reporting_client = __esm({
3003
3237
  }
3004
3238
  } finally {
3005
3239
  if (inputTokens > 0 || outputTokens > 0) {
3006
- reportCostFromUsage(model, inputTokens, outputTokens, cachedInputTokens, cacheCreationInputTokens);
3240
+ reportCostFromUsage(
3241
+ model,
3242
+ inputTokens,
3243
+ outputTokens,
3244
+ cachedInputTokens,
3245
+ cacheCreationInputTokens
3246
+ );
3007
3247
  }
3008
3248
  }
3009
3249
  }
@@ -3215,7 +3455,11 @@ var init_parser = __esm({
3215
3455
  const metadataEndIndex = this.buffer.indexOf("\n", metadataStartIndex);
3216
3456
  if (metadataEndIndex === -1) break;
3217
3457
  const gadgetName = this.buffer.substring(metadataStartIndex, metadataEndIndex).trim();
3218
- const { actualName: actualGadgetName, invocationId, dependencies } = this.parseGadgetName(gadgetName);
3458
+ const {
3459
+ actualName: actualGadgetName,
3460
+ invocationId,
3461
+ dependencies
3462
+ } = this.parseGadgetName(gadgetName);
3219
3463
  const contentStartIndex = metadataEndIndex + 1;
3220
3464
  let partEndIndex;
3221
3465
  let endMarkerLength = 0;
@@ -3263,7 +3507,11 @@ var init_parser = __esm({
3263
3507
  const metadataEndIndex = this.buffer.indexOf("\n", metadataStartIndex);
3264
3508
  if (metadataEndIndex !== -1) {
3265
3509
  const gadgetName = this.buffer.substring(metadataStartIndex, metadataEndIndex).trim();
3266
- const { actualName: actualGadgetName, invocationId, dependencies } = this.parseGadgetName(gadgetName);
3510
+ const {
3511
+ actualName: actualGadgetName,
3512
+ invocationId,
3513
+ dependencies
3514
+ } = this.parseGadgetName(gadgetName);
3267
3515
  const contentStartIndex = metadataEndIndex + 1;
3268
3516
  const parametersRaw = this.buffer.substring(contentStartIndex).trim();
3269
3517
  const { parameters, parseError } = this.parseParameters(parametersRaw);
@@ -3308,11 +3556,12 @@ var init_executor = __esm({
3308
3556
  init_exceptions();
3309
3557
  init_parser();
3310
3558
  GadgetExecutor = class {
3311
- constructor(registry, onHumanInputRequired, logger, defaultGadgetTimeoutMs, errorFormatterOptions, client) {
3559
+ constructor(registry, onHumanInputRequired, logger, defaultGadgetTimeoutMs, errorFormatterOptions, client, mediaStore) {
3312
3560
  this.registry = registry;
3313
3561
  this.onHumanInputRequired = onHumanInputRequired;
3314
3562
  this.defaultGadgetTimeoutMs = defaultGadgetTimeoutMs;
3315
3563
  this.client = client;
3564
+ this.mediaStore = mediaStore;
3316
3565
  this.logger = logger ?? createLogger({ name: "llmist:executor" });
3317
3566
  this.errorFormatter = new GadgetErrorFormatter(errorFormatterOptions);
3318
3567
  this.argPrefix = errorFormatterOptions?.argPrefix ?? GADGET_ARG_PREFIX;
@@ -3335,12 +3584,16 @@ var init_executor = __esm({
3335
3584
  }
3336
3585
  /**
3337
3586
  * Normalizes gadget execute result to consistent format.
3338
- * Handles both string returns (backwards compat) and object returns with cost.
3587
+ * Handles string returns (backwards compat), object returns with cost,
3588
+ * and object returns with media.
3339
3589
  */
3340
3590
  normalizeExecuteResult(raw) {
3341
3591
  if (typeof raw === "string") {
3342
3592
  return { result: raw, cost: 0 };
3343
3593
  }
3594
+ if ("media" in raw && raw.media) {
3595
+ return { result: raw.result, media: raw.media, cost: raw.cost ?? 0 };
3596
+ }
3344
3597
  return { result: raw.result, cost: raw.cost ?? 0 };
3345
3598
  }
3346
3599
  // Execute a gadget call asynchronously
@@ -3467,8 +3720,21 @@ var init_executor = __esm({
3467
3720
  } else {
3468
3721
  rawResult = await Promise.resolve(gadget.execute(validatedParameters, ctx));
3469
3722
  }
3470
- const { result, cost: returnCost } = this.normalizeExecuteResult(rawResult);
3723
+ const { result, media, cost: returnCost } = this.normalizeExecuteResult(rawResult);
3471
3724
  const totalCost = callbackCost + returnCost;
3725
+ let mediaIds;
3726
+ let storedMedia;
3727
+ if (media && media.length > 0 && this.mediaStore) {
3728
+ storedMedia = await Promise.all(
3729
+ media.map((item) => this.mediaStore.store(item, call.gadgetName))
3730
+ );
3731
+ mediaIds = storedMedia.map((m) => m.id);
3732
+ this.logger.debug("Stored media outputs", {
3733
+ gadgetName: call.gadgetName,
3734
+ mediaIds,
3735
+ count: media.length
3736
+ });
3737
+ }
3472
3738
  const executionTimeMs = Date.now() - startTime;
3473
3739
  this.logger.info("Gadget executed successfully", {
3474
3740
  gadgetName: call.gadgetName,
@@ -3476,7 +3742,8 @@ var init_executor = __esm({
3476
3742
  executionTimeMs,
3477
3743
  cost: totalCost > 0 ? totalCost : void 0,
3478
3744
  callbackCost: callbackCost > 0 ? callbackCost : void 0,
3479
- returnCost: returnCost > 0 ? returnCost : void 0
3745
+ returnCost: returnCost > 0 ? returnCost : void 0,
3746
+ mediaCount: media?.length
3480
3747
  });
3481
3748
  this.logger.debug("Gadget result", {
3482
3749
  gadgetName: call.gadgetName,
@@ -3484,7 +3751,8 @@ var init_executor = __esm({
3484
3751
  parameters: validatedParameters,
3485
3752
  result,
3486
3753
  cost: totalCost,
3487
- executionTimeMs
3754
+ executionTimeMs,
3755
+ mediaIds
3488
3756
  });
3489
3757
  return {
3490
3758
  gadgetName: call.gadgetName,
@@ -3492,7 +3760,10 @@ var init_executor = __esm({
3492
3760
  parameters: validatedParameters,
3493
3761
  result,
3494
3762
  executionTimeMs,
3495
- cost: totalCost
3763
+ cost: totalCost,
3764
+ media,
3765
+ mediaIds,
3766
+ storedMedia
3496
3767
  };
3497
3768
  } catch (error) {
3498
3769
  if (error instanceof BreakLoopException) {
@@ -3670,7 +3941,8 @@ var init_stream_processor = __esm({
3670
3941
  this.logger.getSubLogger({ name: "executor" }),
3671
3942
  options.defaultGadgetTimeoutMs,
3672
3943
  { argPrefix: options.gadgetArgPrefix },
3673
- options.client
3944
+ options.client,
3945
+ options.mediaStore
3674
3946
  );
3675
3947
  }
3676
3948
  /**
@@ -4259,13 +4531,14 @@ var init_agent = __esm({
4259
4531
  init_constants();
4260
4532
  init_messages();
4261
4533
  init_model_shortcuts();
4534
+ init_media_store();
4262
4535
  init_output_viewer();
4263
4536
  init_logger();
4264
- init_manager();
4265
- init_gadget_output_store();
4266
4537
  init_agent_internal_key();
4538
+ init_manager();
4267
4539
  init_conversation_manager();
4268
4540
  init_event_handlers();
4541
+ init_gadget_output_store();
4269
4542
  init_hook_validators();
4270
4543
  init_stream_processor();
4271
4544
  Agent = class {
@@ -4294,6 +4567,8 @@ var init_agent = __esm({
4294
4567
  outputLimitCharLimit;
4295
4568
  // Context compaction
4296
4569
  compactionManager;
4570
+ // Media storage (for gadgets returning images, audio, etc.)
4571
+ mediaStore;
4297
4572
  // Cancellation
4298
4573
  signal;
4299
4574
  /**
@@ -4324,6 +4599,7 @@ var init_agent = __esm({
4324
4599
  this.defaultMaxTokens = this.resolveMaxTokensFromCatalog(options.model);
4325
4600
  this.outputLimitEnabled = options.gadgetOutputLimit ?? DEFAULT_GADGET_OUTPUT_LIMIT;
4326
4601
  this.outputStore = new GadgetOutputStore();
4602
+ this.mediaStore = new MediaStore();
4327
4603
  const limitPercent = options.gadgetOutputLimitPercent ?? DEFAULT_GADGET_OUTPUT_LIMIT_PERCENT;
4328
4604
  const limits = this.client.modelRegistry.getModelLimits(this.model);
4329
4605
  const contextWindow = limits?.contextWindow ?? FALLBACK_CONTEXT_WINDOW;
@@ -4389,6 +4665,36 @@ var init_agent = __esm({
4389
4665
  getRegistry() {
4390
4666
  return this.registry;
4391
4667
  }
4668
+ /**
4669
+ * Get the media store for this agent session.
4670
+ *
4671
+ * The media store holds all media outputs (images, audio, etc.) produced by gadgets
4672
+ * during this agent's execution. Use this to:
4673
+ * - Access stored media files by ID
4674
+ * - List all stored media
4675
+ * - Clean up temporary files after execution
4676
+ *
4677
+ * @returns The MediaStore instance for this agent
4678
+ *
4679
+ * @example
4680
+ * ```typescript
4681
+ * const agent = new AgentBuilder()
4682
+ * .withModel("sonnet")
4683
+ * .build();
4684
+ *
4685
+ * // After execution, access stored media
4686
+ * const store = agent.getMediaStore();
4687
+ * for (const media of store.list()) {
4688
+ * console.log(`${media.id}: ${media.path}`);
4689
+ * }
4690
+ *
4691
+ * // Clean up when done
4692
+ * await store.cleanup();
4693
+ * ```
4694
+ */
4695
+ getMediaStore() {
4696
+ return this.mediaStore;
4697
+ }
4392
4698
  /**
4393
4699
  * Manually trigger context compaction.
4394
4700
  *
@@ -4564,7 +4870,8 @@ var init_agent = __esm({
4564
4870
  stopOnGadgetError: this.stopOnGadgetError,
4565
4871
  shouldContinueAfterError: this.shouldContinueAfterError,
4566
4872
  defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
4567
- client: this.client
4873
+ client: this.client,
4874
+ mediaStore: this.mediaStore
4568
4875
  });
4569
4876
  const result = await processor.process(stream2);
4570
4877
  for (const output of result.outputs) {
@@ -4626,7 +4933,9 @@ var init_agent = __esm({
4626
4933
  }
4627
4934
  if (result.didExecuteGadgets) {
4628
4935
  if (this.textWithGadgetsHandler) {
4629
- const textContent = result.outputs.filter((output) => output.type === "text").map((output) => output.content).join("");
4936
+ const textContent = result.outputs.filter(
4937
+ (output) => output.type === "text"
4938
+ ).map((output) => output.content).join("");
4630
4939
  if (textContent.trim()) {
4631
4940
  const { gadgetName, parameterMapping, resultMapping } = this.textWithGadgetsHandler;
4632
4941
  this.conversation.addGadgetCall(
@@ -4642,7 +4951,9 @@ var init_agent = __esm({
4642
4951
  this.conversation.addGadgetCall(
4643
4952
  gadgetResult.gadgetName,
4644
4953
  gadgetResult.parameters,
4645
- gadgetResult.error ?? gadgetResult.result ?? ""
4954
+ gadgetResult.error ?? gadgetResult.result ?? "",
4955
+ gadgetResult.media,
4956
+ gadgetResult.mediaIds
4646
4957
  );
4647
4958
  }
4648
4959
  }
@@ -6857,14 +7168,7 @@ var OPENAI_TTS_VOICES, OPENAI_TTS_EXTENDED_VOICES, OPENAI_TTS_FORMATS, openaiSpe
6857
7168
  var init_openai_speech_models = __esm({
6858
7169
  "src/providers/openai-speech-models.ts"() {
6859
7170
  "use strict";
6860
- OPENAI_TTS_VOICES = [
6861
- "alloy",
6862
- "echo",
6863
- "fable",
6864
- "onyx",
6865
- "nova",
6866
- "shimmer"
6867
- ];
7171
+ OPENAI_TTS_VOICES = ["alloy", "echo", "fable", "onyx", "nova", "shimmer"];
6868
7172
  OPENAI_TTS_EXTENDED_VOICES = [
6869
7173
  ...OPENAI_TTS_VOICES,
6870
7174
  "ash",
@@ -7562,9 +7866,7 @@ var init_image = __esm({
7562
7866
  return this.findImageAdapter(modelId) !== void 0;
7563
7867
  }
7564
7868
  findImageAdapter(modelId) {
7565
- return this.adapters.find(
7566
- (adapter) => adapter.supportsImageGeneration?.(modelId) ?? false
7567
- );
7869
+ return this.adapters.find((adapter) => adapter.supportsImageGeneration?.(modelId) ?? false);
7568
7870
  }
7569
7871
  };
7570
7872
  }
@@ -7616,9 +7918,7 @@ var init_speech = __esm({
7616
7918
  return this.findSpeechAdapter(modelId) !== void 0;
7617
7919
  }
7618
7920
  findSpeechAdapter(modelId) {
7619
- return this.adapters.find(
7620
- (adapter) => adapter.supportsSpeechGeneration?.(modelId) ?? false
7621
- );
7921
+ return this.adapters.find((adapter) => adapter.supportsSpeechGeneration?.(modelId) ?? false);
7622
7922
  }
7623
7923
  };
7624
7924
  }
@@ -7729,11 +8029,7 @@ var init_vision = __esm({
7729
8029
  if (!parsed) {
7730
8030
  throw new Error("Invalid data URL format");
7731
8031
  }
7732
- builder.addUserWithImage(
7733
- options.prompt,
7734
- parsed.data,
7735
- parsed.mimeType
7736
- );
8032
+ builder.addUserWithImage(options.prompt, parsed.data, parsed.mimeType);
7737
8033
  } else {
7738
8034
  const buffer = Buffer.from(options.image, "base64");
7739
8035
  builder.addUserWithImage(options.prompt, buffer, options.mimeType);
@@ -9021,6 +9317,7 @@ __export(index_exports, {
9021
9317
  LLMMessageBuilder: () => LLMMessageBuilder,
9022
9318
  LLMist: () => LLMist,
9023
9319
  MODEL_ALIASES: () => MODEL_ALIASES,
9320
+ MediaStore: () => MediaStore,
9024
9321
  MockBuilder: () => MockBuilder,
9025
9322
  MockManager: () => MockManager,
9026
9323
  MockProviderAdapter: () => MockProviderAdapter,
@@ -9042,6 +9339,7 @@ __export(index_exports, {
9042
9339
  createGeminiProviderFromEnv: () => createGeminiProviderFromEnv,
9043
9340
  createHints: () => createHints,
9044
9341
  createLogger: () => createLogger,
9342
+ createMedia: () => createMedia,
9045
9343
  createMockAdapter: () => createMockAdapter,
9046
9344
  createMockClient: () => createMockClient,
9047
9345
  createMockStream: () => createMockStream,
@@ -9072,6 +9370,11 @@ __export(index_exports, {
9072
9370
  resolveModel: () => resolveModel,
9073
9371
  resolvePromptTemplate: () => resolvePromptTemplate,
9074
9372
  resolveRulesTemplate: () => resolveRulesTemplate,
9373
+ resultWithAudio: () => resultWithAudio,
9374
+ resultWithFile: () => resultWithFile,
9375
+ resultWithImage: () => resultWithImage,
9376
+ resultWithImages: () => resultWithImages,
9377
+ resultWithMedia: () => resultWithMedia,
9075
9378
  runWithHandlers: () => runWithHandlers,
9076
9379
  stream: () => stream,
9077
9380
  text: () => text,
@@ -9625,9 +9928,7 @@ var HookPresets = class _HookPresets {
9625
9928
  console.log(
9626
9929
  `\u{1F5DC}\uFE0F Compaction (${ctx.event.strategy}): ${ctx.event.tokensBefore} \u2192 ${ctx.event.tokensAfter} tokens (saved ${saved}, ${percent}%)`
9627
9930
  );
9628
- console.log(
9629
- ` Messages: ${ctx.event.messagesBefore} \u2192 ${ctx.event.messagesAfter}`
9630
- );
9931
+ console.log(` Messages: ${ctx.event.messagesBefore} \u2192 ${ctx.event.messagesAfter}`);
9631
9932
  if (ctx.stats.totalCompactions > 1) {
9632
9933
  console.log(
9633
9934
  ` Cumulative: ${ctx.stats.totalCompactions} compactions, ${ctx.stats.totalTokensSaved} tokens saved`
@@ -9862,16 +10163,15 @@ var HookPresets = class _HookPresets {
9862
10163
  }
9863
10164
  };
9864
10165
 
9865
- // src/agent/index.ts
9866
- init_conversation_manager();
9867
- init_stream_processor();
9868
- init_gadget_output_store();
9869
-
9870
10166
  // src/agent/compaction/index.ts
9871
10167
  init_config();
9872
- init_strategy();
9873
- init_strategies();
9874
10168
  init_manager();
10169
+ init_strategies();
10170
+ init_strategy();
10171
+
10172
+ // src/agent/index.ts
10173
+ init_conversation_manager();
10174
+ init_gadget_output_store();
9875
10175
 
9876
10176
  // src/agent/hints.ts
9877
10177
  init_prompt_config();
@@ -9895,11 +10195,7 @@ function iterationProgressHint(options) {
9895
10195
  maxIterations,
9896
10196
  remaining
9897
10197
  };
9898
- let hint = resolveHintTemplate(
9899
- template,
9900
- DEFAULT_HINTS.iterationProgressHint,
9901
- hintContext
9902
- );
10198
+ let hint = resolveHintTemplate(template, DEFAULT_HINTS.iterationProgressHint, hintContext);
9903
10199
  if (showUrgency && progress >= 0.8) {
9904
10200
  hint += " \u26A0\uFE0F Running low on iterations - focus on completing the task.";
9905
10201
  }
@@ -9974,6 +10270,9 @@ function createHints(config) {
9974
10270
  return HookPresets.merge(...hooksToMerge);
9975
10271
  }
9976
10272
 
10273
+ // src/agent/index.ts
10274
+ init_stream_processor();
10275
+
9977
10276
  // src/index.ts
9978
10277
  init_client();
9979
10278
  init_input_content();
@@ -9984,10 +10283,10 @@ init_options();
9984
10283
  init_prompt_config();
9985
10284
  init_quick_methods();
9986
10285
  init_create_gadget();
9987
- init_output_viewer();
9988
10286
  init_exceptions();
9989
10287
  init_executor();
9990
10288
  init_gadget();
10289
+ init_output_viewer();
9991
10290
  init_parser();
9992
10291
  init_registry();
9993
10292
 
@@ -10012,6 +10311,119 @@ function Gadget(config) {
10012
10311
  return GadgetBase;
10013
10312
  }
10014
10313
 
10314
+ // src/gadgets/helpers.ts
10315
+ init_input_content();
10316
+ function createMedia(kind, data, mimeType, options) {
10317
+ const buffer = data instanceof Buffer ? data : Buffer.from(data);
10318
+ return {
10319
+ kind,
10320
+ data: buffer.toString("base64"),
10321
+ mimeType,
10322
+ description: options?.description,
10323
+ metadata: options?.metadata,
10324
+ fileName: options?.fileName
10325
+ };
10326
+ }
10327
+ function resultWithMedia(result, media, cost) {
10328
+ if (media.length === 0) {
10329
+ throw new Error("resultWithMedia: media array cannot be empty");
10330
+ }
10331
+ return {
10332
+ result,
10333
+ media,
10334
+ cost
10335
+ };
10336
+ }
10337
+ function resultWithImage(result, imageData, options) {
10338
+ const buffer = imageData instanceof Buffer ? imageData : Buffer.from(imageData);
10339
+ const mimeType = options?.mimeType ?? detectImageMimeType(buffer);
10340
+ if (!mimeType) {
10341
+ throw new Error(
10342
+ "Could not detect image MIME type. Please provide mimeType explicitly in options."
10343
+ );
10344
+ }
10345
+ return {
10346
+ result,
10347
+ media: [
10348
+ {
10349
+ kind: "image",
10350
+ data: buffer.toString("base64"),
10351
+ mimeType,
10352
+ description: options?.description,
10353
+ metadata: options?.metadata,
10354
+ fileName: options?.fileName
10355
+ }
10356
+ ],
10357
+ cost: options?.cost
10358
+ };
10359
+ }
10360
+ function resultWithImages(result, images, cost) {
10361
+ if (images.length === 0) {
10362
+ throw new Error("resultWithImages: images array cannot be empty");
10363
+ }
10364
+ const media = images.map((img, index) => {
10365
+ const buffer = img.data instanceof Buffer ? img.data : Buffer.from(img.data);
10366
+ const mimeType = img.mimeType ?? detectImageMimeType(buffer);
10367
+ if (!mimeType) {
10368
+ throw new Error(
10369
+ `Could not detect MIME type for image at index ${index}. Please provide mimeType explicitly.`
10370
+ );
10371
+ }
10372
+ return {
10373
+ kind: "image",
10374
+ data: buffer.toString("base64"),
10375
+ mimeType,
10376
+ description: img.description,
10377
+ metadata: img.metadata,
10378
+ fileName: img.fileName
10379
+ };
10380
+ });
10381
+ return { result, media, cost };
10382
+ }
10383
+ function resultWithAudio(result, audioData, options) {
10384
+ const buffer = audioData instanceof Buffer ? audioData : Buffer.from(audioData);
10385
+ const mimeType = options?.mimeType ?? detectAudioMimeType(buffer);
10386
+ if (!mimeType) {
10387
+ throw new Error(
10388
+ "Could not detect audio MIME type. Please provide mimeType explicitly in options."
10389
+ );
10390
+ }
10391
+ const metadata = options?.durationMs ? { durationMs: options.durationMs } : void 0;
10392
+ return {
10393
+ result,
10394
+ media: [
10395
+ {
10396
+ kind: "audio",
10397
+ data: buffer.toString("base64"),
10398
+ mimeType,
10399
+ description: options?.description,
10400
+ metadata,
10401
+ fileName: options?.fileName
10402
+ }
10403
+ ],
10404
+ cost: options?.cost
10405
+ };
10406
+ }
10407
+ function resultWithFile(result, fileData, mimeType, options) {
10408
+ const buffer = fileData instanceof Buffer ? fileData : Buffer.from(fileData);
10409
+ return {
10410
+ result,
10411
+ media: [
10412
+ {
10413
+ kind: "file",
10414
+ data: buffer.toString("base64"),
10415
+ mimeType,
10416
+ description: options?.description,
10417
+ fileName: options?.fileName
10418
+ }
10419
+ ],
10420
+ cost: options?.cost
10421
+ };
10422
+ }
10423
+
10424
+ // src/index.ts
10425
+ init_media_store();
10426
+
10015
10427
  // src/gadgets/validation.ts
10016
10428
  function validateAndApplyDefaults(schema, params) {
10017
10429
  const result = schema.safeParse(params);
@@ -10049,6 +10461,9 @@ init_discovery();
10049
10461
  init_gemini();
10050
10462
  init_openai();
10051
10463
 
10464
+ // src/testing/cli-helpers.ts
10465
+ var import_node_stream = require("stream");
10466
+
10052
10467
  // src/testing/mock-manager.ts
10053
10468
  init_logger();
10054
10469
  var MockManager = class _MockManager {
@@ -10601,7 +11016,9 @@ var MockBuilder = class {
10601
11016
  */
10602
11017
  whenMessageContains(text3) {
10603
11018
  this.matchers.push(
10604
- (ctx) => ctx.messages.some((msg) => extractText(msg.content).toLowerCase().includes(text3.toLowerCase()))
11019
+ (ctx) => ctx.messages.some(
11020
+ (msg) => extractText(msg.content).toLowerCase().includes(text3.toLowerCase())
11021
+ )
10605
11022
  );
10606
11023
  return this;
10607
11024
  }
@@ -11041,9 +11458,6 @@ function createMockClient(options) {
11041
11458
 
11042
11459
  // src/testing/mock-gadget.ts
11043
11460
  init_gadget();
11044
-
11045
- // src/testing/cli-helpers.ts
11046
- var import_node_stream = require("stream");
11047
11461
  // Annotate the CommonJS export names for ESM import in node:
11048
11462
  0 && (module.exports = {
11049
11463
  AbortError,
@@ -11068,6 +11482,7 @@ var import_node_stream = require("stream");
11068
11482
  LLMMessageBuilder,
11069
11483
  LLMist,
11070
11484
  MODEL_ALIASES,
11485
+ MediaStore,
11071
11486
  MockBuilder,
11072
11487
  MockManager,
11073
11488
  MockProviderAdapter,
@@ -11089,6 +11504,7 @@ var import_node_stream = require("stream");
11089
11504
  createGeminiProviderFromEnv,
11090
11505
  createHints,
11091
11506
  createLogger,
11507
+ createMedia,
11092
11508
  createMockAdapter,
11093
11509
  createMockClient,
11094
11510
  createMockStream,
@@ -11119,6 +11535,11 @@ var import_node_stream = require("stream");
11119
11535
  resolveModel,
11120
11536
  resolvePromptTemplate,
11121
11537
  resolveRulesTemplate,
11538
+ resultWithAudio,
11539
+ resultWithFile,
11540
+ resultWithImage,
11541
+ resultWithImages,
11542
+ resultWithMedia,
11122
11543
  runWithHandlers,
11123
11544
  stream,
11124
11545
  text,