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/{chunk-YHS2DYXP.js → chunk-364PEMVT.js} +947 -649
- package/dist/chunk-364PEMVT.js.map +1 -0
- package/dist/{chunk-IHSZUAYN.js → chunk-4IHLIYW5.js} +134 -18
- package/dist/chunk-4IHLIYW5.js.map +1 -0
- package/dist/cli.cjs +3345 -2981
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +2758 -2708
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +584 -163
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +659 -454
- package/dist/index.d.ts +659 -454
- package/dist/index.js +16 -2
- package/dist/{mock-stream-ga4KIiwX.d.cts → mock-stream-Jgg5u6Uf.d.cts} +262 -7
- package/dist/{mock-stream-ga4KIiwX.d.ts → mock-stream-Jgg5u6Uf.d.ts} +262 -7
- package/dist/testing/index.cjs +932 -624
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.cts +343 -343
- package/dist/testing/index.d.ts +343 -343
- package/dist/testing/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-IHSZUAYN.js.map +0 -1
- package/dist/chunk-YHS2DYXP.js.map +0 -1
|
@@ -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
|
-
|
|
696
|
-
|
|
697
|
-
|
|
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(
|
|
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/
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
}
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
}
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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 {
|
|
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 {
|
|
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
|
|
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(
|
|
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/
|
|
8987
|
-
|
|
8988
|
-
|
|
8989
|
-
|
|
8990
|
-
|
|
8991
|
-
|
|
8992
|
-
|
|
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
|
-
|
|
9002
|
-
|
|
9003
|
-
|
|
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
|
|
9007
|
-
if (!
|
|
9008
|
-
|
|
9009
|
-
|
|
9010
|
-
|
|
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
|
-
|
|
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
|
-
|
|
9017
|
-
|
|
9018
|
-
|
|
9019
|
-
|
|
9020
|
-
|
|
9021
|
-
|
|
9022
|
-
|
|
9023
|
-
|
|
9024
|
-
|
|
9025
|
-
|
|
9026
|
-
|
|
9027
|
-
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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-
|
|
10045
|
-
|
|
10046
|
-
|
|
10047
|
-
|
|
10048
|
-
|
|
10049
|
-
|
|
10050
|
-
|
|
10051
|
-
|
|
10052
|
-
|
|
10053
|
-
|
|
10054
|
-
|
|
10055
|
-
|
|
10056
|
-
|
|
10057
|
-
|
|
10058
|
-
|
|
10059
|
-
|
|
10060
|
-
|
|
10061
|
-
|
|
10062
|
-
this.
|
|
10063
|
-
this.
|
|
10064
|
-
|
|
10065
|
-
|
|
10066
|
-
|
|
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
|
|
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
|
|
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
|
|
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-
|
|
11062
|
+
//# sourceMappingURL=chunk-364PEMVT.js.map
|