llmist 2.6.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -1
- package/dist/{chunk-364PEMVT.js → chunk-67MMSOAT.js} +221 -174
- package/dist/chunk-67MMSOAT.js.map +1 -0
- package/dist/{chunk-4IHLIYW5.js → chunk-NBPKLSXJ.js} +6 -6
- package/dist/chunk-NBPKLSXJ.js.map +1 -0
- package/dist/cli.cjs +721 -219
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +501 -45
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +230 -182
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +100 -52
- package/dist/index.d.ts +100 -52
- package/dist/index.js +20 -18
- package/dist/{mock-stream-Jgg5u6Uf.d.cts → mock-stream-COHw8h9b.d.cts} +182 -54
- package/dist/{mock-stream-Jgg5u6Uf.d.ts → mock-stream-COHw8h9b.d.ts} +182 -54
- package/dist/testing/index.cjs +212 -166
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.cts +6 -6
- package/dist/testing/index.d.ts +6 -6
- package/dist/testing/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-364PEMVT.js.map +0 -1
- package/dist/chunk-4IHLIYW5.js.map +0 -1
package/dist/cli.cjs
CHANGED
|
@@ -317,7 +317,7 @@ Example fixes:
|
|
|
317
317
|
);
|
|
318
318
|
}
|
|
319
319
|
}
|
|
320
|
-
function findUnknownTypes(schema,
|
|
320
|
+
function findUnknownTypes(schema, path6 = []) {
|
|
321
321
|
const issues = [];
|
|
322
322
|
if (!schema || typeof schema !== "object") {
|
|
323
323
|
return issues;
|
|
@@ -329,7 +329,7 @@ function findUnknownTypes(schema, path5 = []) {
|
|
|
329
329
|
}
|
|
330
330
|
if (schema.properties) {
|
|
331
331
|
for (const [propName, propSchema] of Object.entries(schema.properties)) {
|
|
332
|
-
const propPath = [...
|
|
332
|
+
const propPath = [...path6, propName];
|
|
333
333
|
if (hasNoType(propSchema)) {
|
|
334
334
|
issues.push(propPath.join(".") || propName);
|
|
335
335
|
}
|
|
@@ -337,7 +337,7 @@ function findUnknownTypes(schema, path5 = []) {
|
|
|
337
337
|
}
|
|
338
338
|
}
|
|
339
339
|
if (schema.items) {
|
|
340
|
-
const itemPath = [...
|
|
340
|
+
const itemPath = [...path6, "[]"];
|
|
341
341
|
if (hasNoType(schema.items)) {
|
|
342
342
|
issues.push(itemPath.join("."));
|
|
343
343
|
}
|
|
@@ -345,17 +345,17 @@ function findUnknownTypes(schema, path5 = []) {
|
|
|
345
345
|
}
|
|
346
346
|
if (schema.anyOf) {
|
|
347
347
|
schema.anyOf.forEach((subSchema, index) => {
|
|
348
|
-
issues.push(...findUnknownTypes(subSchema, [...
|
|
348
|
+
issues.push(...findUnknownTypes(subSchema, [...path6, `anyOf[${index}]`]));
|
|
349
349
|
});
|
|
350
350
|
}
|
|
351
351
|
if (schema.oneOf) {
|
|
352
352
|
schema.oneOf.forEach((subSchema, index) => {
|
|
353
|
-
issues.push(...findUnknownTypes(subSchema, [...
|
|
353
|
+
issues.push(...findUnknownTypes(subSchema, [...path6, `oneOf[${index}]`]));
|
|
354
354
|
});
|
|
355
355
|
}
|
|
356
356
|
if (schema.allOf) {
|
|
357
357
|
schema.allOf.forEach((subSchema, index) => {
|
|
358
|
-
issues.push(...findUnknownTypes(subSchema, [...
|
|
358
|
+
issues.push(...findUnknownTypes(subSchema, [...path6, `allOf[${index}]`]));
|
|
359
359
|
});
|
|
360
360
|
}
|
|
361
361
|
return issues;
|
|
@@ -530,13 +530,13 @@ var init_prompt_config = __esm({
|
|
|
530
530
|
});
|
|
531
531
|
|
|
532
532
|
// src/core/messages.ts
|
|
533
|
-
function
|
|
533
|
+
function normalizeMessageContent(content) {
|
|
534
534
|
if (typeof content === "string") {
|
|
535
535
|
return [{ type: "text", text: content }];
|
|
536
536
|
}
|
|
537
537
|
return content;
|
|
538
538
|
}
|
|
539
|
-
function
|
|
539
|
+
function extractMessageText(content) {
|
|
540
540
|
if (typeof content === "string") {
|
|
541
541
|
return content;
|
|
542
542
|
}
|
|
@@ -896,7 +896,17 @@ Produces: { "items": ["first", "second"] }`);
|
|
|
896
896
|
this.messages.push({ role: "user", content: parts });
|
|
897
897
|
return this;
|
|
898
898
|
}
|
|
899
|
-
|
|
899
|
+
/**
|
|
900
|
+
* Record a gadget execution result in the message history.
|
|
901
|
+
* Creates an assistant message with the gadget invocation and a user message with the result.
|
|
902
|
+
*
|
|
903
|
+
* @param gadget - Name of the gadget that was executed
|
|
904
|
+
* @param parameters - Parameters that were passed to the gadget
|
|
905
|
+
* @param result - Text result from the gadget execution
|
|
906
|
+
* @param media - Optional media outputs from the gadget
|
|
907
|
+
* @param mediaIds - Optional IDs for the media outputs
|
|
908
|
+
*/
|
|
909
|
+
addGadgetCallResult(gadget, parameters, result, media, mediaIds) {
|
|
900
910
|
const paramStr = this.formatBlockParameters(parameters, "");
|
|
901
911
|
this.messages.push({
|
|
902
912
|
role: "assistant",
|
|
@@ -1164,21 +1174,21 @@ var init_media_store = __esm({
|
|
|
1164
1174
|
});
|
|
1165
1175
|
|
|
1166
1176
|
// src/gadgets/exceptions.ts
|
|
1167
|
-
var
|
|
1177
|
+
var TaskCompletionSignal, HumanInputRequiredException, TimeoutException, AbortException;
|
|
1168
1178
|
var init_exceptions = __esm({
|
|
1169
1179
|
"src/gadgets/exceptions.ts"() {
|
|
1170
1180
|
"use strict";
|
|
1171
|
-
|
|
1181
|
+
TaskCompletionSignal = class extends Error {
|
|
1172
1182
|
constructor(message) {
|
|
1173
1183
|
super(message ?? "Agent loop terminated by gadget");
|
|
1174
|
-
this.name = "
|
|
1184
|
+
this.name = "TaskCompletionSignal";
|
|
1175
1185
|
}
|
|
1176
1186
|
};
|
|
1177
|
-
|
|
1187
|
+
HumanInputRequiredException = class extends Error {
|
|
1178
1188
|
question;
|
|
1179
1189
|
constructor(question) {
|
|
1180
1190
|
super(`Human input required: ${question}`);
|
|
1181
|
-
this.name = "
|
|
1191
|
+
this.name = "HumanInputRequiredException";
|
|
1182
1192
|
this.question = question;
|
|
1183
1193
|
}
|
|
1184
1194
|
};
|
|
@@ -1192,10 +1202,10 @@ var init_exceptions = __esm({
|
|
|
1192
1202
|
this.timeoutMs = timeoutMs;
|
|
1193
1203
|
}
|
|
1194
1204
|
};
|
|
1195
|
-
|
|
1205
|
+
AbortException = class extends Error {
|
|
1196
1206
|
constructor(message) {
|
|
1197
1207
|
super(message || "Gadget execution was aborted");
|
|
1198
|
-
this.name = "
|
|
1208
|
+
this.name = "AbortException";
|
|
1199
1209
|
}
|
|
1200
1210
|
};
|
|
1201
1211
|
}
|
|
@@ -1294,29 +1304,29 @@ function schemaToJSONSchema(schema, options) {
|
|
|
1294
1304
|
}
|
|
1295
1305
|
function detectDescriptionMismatch(schema, jsonSchema) {
|
|
1296
1306
|
const mismatches = [];
|
|
1297
|
-
function checkSchema(zodSchema, json,
|
|
1307
|
+
function checkSchema(zodSchema, json, path6) {
|
|
1298
1308
|
if (!zodSchema || typeof zodSchema !== "object") return;
|
|
1299
1309
|
const def = zodSchema._def;
|
|
1300
1310
|
const jsonObj = json;
|
|
1301
1311
|
if (def?.description && !jsonObj?.description) {
|
|
1302
|
-
mismatches.push(
|
|
1312
|
+
mismatches.push(path6 || "root");
|
|
1303
1313
|
}
|
|
1304
1314
|
if (def?.typeName === "ZodObject" && def?.shape) {
|
|
1305
1315
|
const shape = typeof def.shape === "function" ? def.shape() : def.shape;
|
|
1306
1316
|
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
1307
1317
|
const properties = jsonObj?.properties;
|
|
1308
1318
|
const jsonProp = properties?.[key];
|
|
1309
|
-
checkSchema(fieldSchema, jsonProp,
|
|
1319
|
+
checkSchema(fieldSchema, jsonProp, path6 ? `${path6}.${key}` : key);
|
|
1310
1320
|
}
|
|
1311
1321
|
}
|
|
1312
1322
|
if (def?.typeName === "ZodArray" && def?.type) {
|
|
1313
|
-
checkSchema(def.type, jsonObj?.items,
|
|
1323
|
+
checkSchema(def.type, jsonObj?.items, path6 ? `${path6}[]` : "[]");
|
|
1314
1324
|
}
|
|
1315
1325
|
if ((def?.typeName === "ZodOptional" || def?.typeName === "ZodNullable") && def?.innerType) {
|
|
1316
|
-
checkSchema(def.innerType, json,
|
|
1326
|
+
checkSchema(def.innerType, json, path6);
|
|
1317
1327
|
}
|
|
1318
1328
|
if (def?.typeName === "ZodDefault" && def?.innerType) {
|
|
1319
|
-
checkSchema(def.innerType, json,
|
|
1329
|
+
checkSchema(def.innerType, json, path6);
|
|
1320
1330
|
}
|
|
1321
1331
|
}
|
|
1322
1332
|
checkSchema(schema, jsonSchema, "");
|
|
@@ -1364,7 +1374,7 @@ var init_schema_to_json = __esm({
|
|
|
1364
1374
|
});
|
|
1365
1375
|
|
|
1366
1376
|
// src/gadgets/gadget.ts
|
|
1367
|
-
function
|
|
1377
|
+
function formatParamsForBlockExample(params, prefix = "", argPrefix = GADGET_ARG_PREFIX) {
|
|
1368
1378
|
const lines = [];
|
|
1369
1379
|
for (const [key, value] of Object.entries(params)) {
|
|
1370
1380
|
const fullPath = prefix ? `${prefix}/${key}` : key;
|
|
@@ -1372,14 +1382,14 @@ function formatParamsAsBlock(params, prefix = "", argPrefix = GADGET_ARG_PREFIX)
|
|
|
1372
1382
|
value.forEach((item, index) => {
|
|
1373
1383
|
const itemPath = `${fullPath}/${index}`;
|
|
1374
1384
|
if (typeof item === "object" && item !== null) {
|
|
1375
|
-
lines.push(
|
|
1385
|
+
lines.push(formatParamsForBlockExample(item, itemPath, argPrefix));
|
|
1376
1386
|
} else {
|
|
1377
1387
|
lines.push(`${argPrefix}${itemPath}`);
|
|
1378
1388
|
lines.push(String(item));
|
|
1379
1389
|
}
|
|
1380
1390
|
});
|
|
1381
1391
|
} else if (typeof value === "object" && value !== null) {
|
|
1382
|
-
lines.push(
|
|
1392
|
+
lines.push(formatParamsForBlockExample(value, fullPath, argPrefix));
|
|
1383
1393
|
} else {
|
|
1384
1394
|
lines.push(`${argPrefix}${fullPath}`);
|
|
1385
1395
|
lines.push(String(value));
|
|
@@ -1468,7 +1478,7 @@ function formatSchemaAsPlainText(schema, indent = "", atRoot = true) {
|
|
|
1468
1478
|
}
|
|
1469
1479
|
return lines.join("\n");
|
|
1470
1480
|
}
|
|
1471
|
-
var
|
|
1481
|
+
var AbstractGadget;
|
|
1472
1482
|
var init_gadget = __esm({
|
|
1473
1483
|
"src/gadgets/gadget.ts"() {
|
|
1474
1484
|
"use strict";
|
|
@@ -1476,7 +1486,7 @@ var init_gadget = __esm({
|
|
|
1476
1486
|
init_exceptions();
|
|
1477
1487
|
init_schema_to_json();
|
|
1478
1488
|
init_schema_validator();
|
|
1479
|
-
|
|
1489
|
+
AbstractGadget = class {
|
|
1480
1490
|
/**
|
|
1481
1491
|
* The name of the gadget. Used for identification when LLM calls it.
|
|
1482
1492
|
* If not provided, defaults to the class name.
|
|
@@ -1504,14 +1514,14 @@ var init_gadget = __esm({
|
|
|
1504
1514
|
*/
|
|
1505
1515
|
examples;
|
|
1506
1516
|
/**
|
|
1507
|
-
* Throws an
|
|
1517
|
+
* Throws an AbortException if the execution has been aborted.
|
|
1508
1518
|
*
|
|
1509
1519
|
* Call this at key checkpoints in long-running gadgets to allow early exit
|
|
1510
1520
|
* when the gadget has been cancelled (e.g., due to timeout). This enables
|
|
1511
1521
|
* resource cleanup and prevents unnecessary work after cancellation.
|
|
1512
1522
|
*
|
|
1513
1523
|
* @param ctx - The execution context containing the abort signal
|
|
1514
|
-
* @throws
|
|
1524
|
+
* @throws AbortException if ctx.signal.aborted is true
|
|
1515
1525
|
*
|
|
1516
1526
|
* @example
|
|
1517
1527
|
* ```typescript
|
|
@@ -1536,7 +1546,7 @@ var init_gadget = __esm({
|
|
|
1536
1546
|
*/
|
|
1537
1547
|
throwIfAborted(ctx) {
|
|
1538
1548
|
if (ctx?.signal?.aborted) {
|
|
1539
|
-
throw new
|
|
1549
|
+
throw new AbortException();
|
|
1540
1550
|
}
|
|
1541
1551
|
}
|
|
1542
1552
|
/**
|
|
@@ -1678,7 +1688,7 @@ var init_gadget = __esm({
|
|
|
1678
1688
|
}
|
|
1679
1689
|
parts.push(`${effectiveStartPrefix}${gadgetName}`);
|
|
1680
1690
|
parts.push(
|
|
1681
|
-
|
|
1691
|
+
formatParamsForBlockExample(example.params, "", effectiveArgPrefix)
|
|
1682
1692
|
);
|
|
1683
1693
|
parts.push(effectiveEndPrefix);
|
|
1684
1694
|
if (example.output !== void 0) {
|
|
@@ -1696,7 +1706,7 @@ var init_gadget = __esm({
|
|
|
1696
1706
|
|
|
1697
1707
|
// src/gadgets/create-gadget.ts
|
|
1698
1708
|
function createGadget(config) {
|
|
1699
|
-
class DynamicGadget extends
|
|
1709
|
+
class DynamicGadget extends AbstractGadget {
|
|
1700
1710
|
name = config.name;
|
|
1701
1711
|
description = config.description;
|
|
1702
1712
|
parameterSchema = config.schema;
|
|
@@ -2334,8 +2344,8 @@ var init_conversation_manager = __esm({
|
|
|
2334
2344
|
addAssistantMessage(content) {
|
|
2335
2345
|
this.historyBuilder.addAssistant(content);
|
|
2336
2346
|
}
|
|
2337
|
-
|
|
2338
|
-
this.historyBuilder.
|
|
2347
|
+
addGadgetCallResult(gadgetName, parameters, result, media, mediaIds) {
|
|
2348
|
+
this.historyBuilder.addGadgetCallResult(gadgetName, parameters, result, media, mediaIds);
|
|
2339
2349
|
}
|
|
2340
2350
|
getMessages() {
|
|
2341
2351
|
return [...this.baseMessages, ...this.initialMessages, ...this.historyBuilder.build()];
|
|
@@ -2355,7 +2365,7 @@ var init_conversation_manager = __esm({
|
|
|
2355
2365
|
if (msg.role === "user") {
|
|
2356
2366
|
this.historyBuilder.addUser(msg.content);
|
|
2357
2367
|
} else if (msg.role === "assistant") {
|
|
2358
|
-
this.historyBuilder.addAssistant(
|
|
2368
|
+
this.historyBuilder.addAssistant(extractMessageText(msg.content));
|
|
2359
2369
|
}
|
|
2360
2370
|
}
|
|
2361
2371
|
}
|
|
@@ -3205,12 +3215,12 @@ var init_cost_reporting_client = __esm({
|
|
|
3205
3215
|
});
|
|
3206
3216
|
|
|
3207
3217
|
// src/gadgets/error-formatter.ts
|
|
3208
|
-
var
|
|
3218
|
+
var GadgetExecutionErrorFormatter;
|
|
3209
3219
|
var init_error_formatter = __esm({
|
|
3210
3220
|
"src/gadgets/error-formatter.ts"() {
|
|
3211
3221
|
"use strict";
|
|
3212
3222
|
init_constants();
|
|
3213
|
-
|
|
3223
|
+
GadgetExecutionErrorFormatter = class {
|
|
3214
3224
|
argPrefix;
|
|
3215
3225
|
startPrefix;
|
|
3216
3226
|
endPrefix;
|
|
@@ -3231,8 +3241,8 @@ var init_error_formatter = __esm({
|
|
|
3231
3241
|
const parts = [];
|
|
3232
3242
|
parts.push(`Error: Invalid parameters for '${gadgetName}':`);
|
|
3233
3243
|
for (const issue of zodError.issues) {
|
|
3234
|
-
const
|
|
3235
|
-
parts.push(` - ${
|
|
3244
|
+
const path6 = issue.path.join(".") || "root";
|
|
3245
|
+
parts.push(` - ${path6}: ${issue.message}`);
|
|
3236
3246
|
}
|
|
3237
3247
|
parts.push("");
|
|
3238
3248
|
parts.push("Gadget Usage:");
|
|
@@ -3296,16 +3306,16 @@ function stripMarkdownFences(content) {
|
|
|
3296
3306
|
cleaned = cleaned.replace(closingFence, "");
|
|
3297
3307
|
return cleaned.trim();
|
|
3298
3308
|
}
|
|
3299
|
-
var globalInvocationCounter,
|
|
3309
|
+
var globalInvocationCounter, GadgetCallParser;
|
|
3300
3310
|
var init_parser = __esm({
|
|
3301
3311
|
"src/gadgets/parser.ts"() {
|
|
3302
3312
|
"use strict";
|
|
3303
3313
|
init_constants();
|
|
3304
3314
|
init_block_params();
|
|
3305
3315
|
globalInvocationCounter = 0;
|
|
3306
|
-
|
|
3316
|
+
GadgetCallParser = class {
|
|
3307
3317
|
buffer = "";
|
|
3308
|
-
|
|
3318
|
+
lastEmittedTextOffset = 0;
|
|
3309
3319
|
startPrefix;
|
|
3310
3320
|
endPrefix;
|
|
3311
3321
|
argPrefix;
|
|
@@ -3314,16 +3324,20 @@ var init_parser = __esm({
|
|
|
3314
3324
|
this.endPrefix = options.endPrefix ?? GADGET_END_PREFIX;
|
|
3315
3325
|
this.argPrefix = options.argPrefix ?? GADGET_ARG_PREFIX;
|
|
3316
3326
|
}
|
|
3317
|
-
|
|
3318
|
-
|
|
3327
|
+
/**
|
|
3328
|
+
* Extract and consume text up to the given index.
|
|
3329
|
+
* Returns undefined if no meaningful text to emit.
|
|
3330
|
+
*/
|
|
3331
|
+
extractTextSegment(index) {
|
|
3332
|
+
if (index <= this.lastEmittedTextOffset) {
|
|
3319
3333
|
return void 0;
|
|
3320
3334
|
}
|
|
3321
|
-
const segment = this.buffer.slice(this.
|
|
3322
|
-
this.
|
|
3335
|
+
const segment = this.buffer.slice(this.lastEmittedTextOffset, index);
|
|
3336
|
+
this.lastEmittedTextOffset = index;
|
|
3323
3337
|
return segment.trim().length > 0 ? segment : void 0;
|
|
3324
3338
|
}
|
|
3325
3339
|
/**
|
|
3326
|
-
* Parse gadget
|
|
3340
|
+
* Parse gadget invocation metadata from the header line.
|
|
3327
3341
|
*
|
|
3328
3342
|
* Supported formats:
|
|
3329
3343
|
* - `GadgetName` - Auto-generate ID, no dependencies
|
|
@@ -3332,24 +3346,24 @@ var init_parser = __esm({
|
|
|
3332
3346
|
*
|
|
3333
3347
|
* Dependencies must be comma-separated invocation IDs.
|
|
3334
3348
|
*/
|
|
3335
|
-
|
|
3336
|
-
const parts =
|
|
3349
|
+
parseInvocationMetadata(headerLine) {
|
|
3350
|
+
const parts = headerLine.split(":");
|
|
3337
3351
|
if (parts.length === 1) {
|
|
3338
3352
|
return {
|
|
3339
|
-
|
|
3353
|
+
gadgetName: parts[0],
|
|
3340
3354
|
invocationId: `gadget_${++globalInvocationCounter}`,
|
|
3341
3355
|
dependencies: []
|
|
3342
3356
|
};
|
|
3343
3357
|
} else if (parts.length === 2) {
|
|
3344
3358
|
return {
|
|
3345
|
-
|
|
3359
|
+
gadgetName: parts[0],
|
|
3346
3360
|
invocationId: parts[1].trim(),
|
|
3347
3361
|
dependencies: []
|
|
3348
3362
|
};
|
|
3349
3363
|
} else {
|
|
3350
3364
|
const deps = parts[2].split(",").map((d) => d.trim()).filter((d) => d.length > 0);
|
|
3351
3365
|
return {
|
|
3352
|
-
|
|
3366
|
+
gadgetName: parts[0],
|
|
3353
3367
|
invocationId: parts[1].trim(),
|
|
3354
3368
|
dependencies: deps
|
|
3355
3369
|
};
|
|
@@ -3381,19 +3395,15 @@ var init_parser = __esm({
|
|
|
3381
3395
|
while (true) {
|
|
3382
3396
|
const partStartIndex = this.buffer.indexOf(this.startPrefix, startIndex);
|
|
3383
3397
|
if (partStartIndex === -1) break;
|
|
3384
|
-
const textBefore = this.
|
|
3398
|
+
const textBefore = this.extractTextSegment(partStartIndex);
|
|
3385
3399
|
if (textBefore !== void 0) {
|
|
3386
3400
|
yield { type: "text", content: textBefore };
|
|
3387
3401
|
}
|
|
3388
3402
|
const metadataStartIndex = partStartIndex + this.startPrefix.length;
|
|
3389
3403
|
const metadataEndIndex = this.buffer.indexOf("\n", metadataStartIndex);
|
|
3390
3404
|
if (metadataEndIndex === -1) break;
|
|
3391
|
-
const
|
|
3392
|
-
const {
|
|
3393
|
-
actualName: actualGadgetName,
|
|
3394
|
-
invocationId,
|
|
3395
|
-
dependencies
|
|
3396
|
-
} = this.parseGadgetName(gadgetName);
|
|
3405
|
+
const headerLine = this.buffer.substring(metadataStartIndex, metadataEndIndex).trim();
|
|
3406
|
+
const { gadgetName, invocationId, dependencies } = this.parseInvocationMetadata(headerLine);
|
|
3397
3407
|
const contentStartIndex = metadataEndIndex + 1;
|
|
3398
3408
|
let partEndIndex;
|
|
3399
3409
|
let endMarkerLength = 0;
|
|
@@ -3413,7 +3423,7 @@ var init_parser = __esm({
|
|
|
3413
3423
|
yield {
|
|
3414
3424
|
type: "gadget_call",
|
|
3415
3425
|
call: {
|
|
3416
|
-
gadgetName
|
|
3426
|
+
gadgetName,
|
|
3417
3427
|
invocationId,
|
|
3418
3428
|
parametersRaw,
|
|
3419
3429
|
parameters,
|
|
@@ -3422,37 +3432,33 @@ var init_parser = __esm({
|
|
|
3422
3432
|
}
|
|
3423
3433
|
};
|
|
3424
3434
|
startIndex = partEndIndex + endMarkerLength;
|
|
3425
|
-
this.
|
|
3435
|
+
this.lastEmittedTextOffset = startIndex;
|
|
3426
3436
|
}
|
|
3427
3437
|
if (startIndex > 0) {
|
|
3428
3438
|
this.buffer = this.buffer.substring(startIndex);
|
|
3429
|
-
this.
|
|
3439
|
+
this.lastEmittedTextOffset = 0;
|
|
3430
3440
|
}
|
|
3431
3441
|
}
|
|
3432
3442
|
// Finalize parsing and return remaining text or incomplete gadgets
|
|
3433
3443
|
*finalize() {
|
|
3434
|
-
const startIndex = this.buffer.indexOf(this.startPrefix, this.
|
|
3444
|
+
const startIndex = this.buffer.indexOf(this.startPrefix, this.lastEmittedTextOffset);
|
|
3435
3445
|
if (startIndex !== -1) {
|
|
3436
|
-
const textBefore = this.
|
|
3446
|
+
const textBefore = this.extractTextSegment(startIndex);
|
|
3437
3447
|
if (textBefore !== void 0) {
|
|
3438
3448
|
yield { type: "text", content: textBefore };
|
|
3439
3449
|
}
|
|
3440
3450
|
const metadataStartIndex = startIndex + this.startPrefix.length;
|
|
3441
3451
|
const metadataEndIndex = this.buffer.indexOf("\n", metadataStartIndex);
|
|
3442
3452
|
if (metadataEndIndex !== -1) {
|
|
3443
|
-
const
|
|
3444
|
-
const {
|
|
3445
|
-
actualName: actualGadgetName,
|
|
3446
|
-
invocationId,
|
|
3447
|
-
dependencies
|
|
3448
|
-
} = this.parseGadgetName(gadgetName);
|
|
3453
|
+
const headerLine = this.buffer.substring(metadataStartIndex, metadataEndIndex).trim();
|
|
3454
|
+
const { gadgetName, invocationId, dependencies } = this.parseInvocationMetadata(headerLine);
|
|
3449
3455
|
const contentStartIndex = metadataEndIndex + 1;
|
|
3450
3456
|
const parametersRaw = this.buffer.substring(contentStartIndex).trim();
|
|
3451
3457
|
const { parameters, parseError } = this.parseParameters(parametersRaw);
|
|
3452
3458
|
yield {
|
|
3453
3459
|
type: "gadget_call",
|
|
3454
3460
|
call: {
|
|
3455
|
-
gadgetName
|
|
3461
|
+
gadgetName,
|
|
3456
3462
|
invocationId,
|
|
3457
3463
|
parametersRaw,
|
|
3458
3464
|
parameters,
|
|
@@ -3463,7 +3469,7 @@ var init_parser = __esm({
|
|
|
3463
3469
|
return;
|
|
3464
3470
|
}
|
|
3465
3471
|
}
|
|
3466
|
-
const remainingText = this.
|
|
3472
|
+
const remainingText = this.extractTextSegment(this.buffer.length);
|
|
3467
3473
|
if (remainingText !== void 0) {
|
|
3468
3474
|
yield { type: "text", content: remainingText };
|
|
3469
3475
|
}
|
|
@@ -3471,7 +3477,7 @@ var init_parser = __esm({
|
|
|
3471
3477
|
// Reset parser state (note: global invocation counter is NOT reset to ensure unique IDs)
|
|
3472
3478
|
reset() {
|
|
3473
3479
|
this.buffer = "";
|
|
3474
|
-
this.
|
|
3480
|
+
this.lastEmittedTextOffset = 0;
|
|
3475
3481
|
}
|
|
3476
3482
|
};
|
|
3477
3483
|
}
|
|
@@ -3490,14 +3496,16 @@ var init_executor = __esm({
|
|
|
3490
3496
|
init_exceptions();
|
|
3491
3497
|
init_parser();
|
|
3492
3498
|
GadgetExecutor = class {
|
|
3493
|
-
constructor(registry,
|
|
3499
|
+
constructor(registry, requestHumanInput, logger, defaultGadgetTimeoutMs, errorFormatterOptions, client, mediaStore, agentConfig, subagentConfig) {
|
|
3494
3500
|
this.registry = registry;
|
|
3495
|
-
this.
|
|
3501
|
+
this.requestHumanInput = requestHumanInput;
|
|
3496
3502
|
this.defaultGadgetTimeoutMs = defaultGadgetTimeoutMs;
|
|
3497
3503
|
this.client = client;
|
|
3498
3504
|
this.mediaStore = mediaStore;
|
|
3505
|
+
this.agentConfig = agentConfig;
|
|
3506
|
+
this.subagentConfig = subagentConfig;
|
|
3499
3507
|
this.logger = logger ?? createLogger({ name: "llmist:executor" });
|
|
3500
|
-
this.errorFormatter = new
|
|
3508
|
+
this.errorFormatter = new GadgetExecutionErrorFormatter(errorFormatterOptions);
|
|
3501
3509
|
this.argPrefix = errorFormatterOptions?.argPrefix ?? GADGET_ARG_PREFIX;
|
|
3502
3510
|
}
|
|
3503
3511
|
logger;
|
|
@@ -3517,11 +3525,11 @@ var init_executor = __esm({
|
|
|
3517
3525
|
});
|
|
3518
3526
|
}
|
|
3519
3527
|
/**
|
|
3520
|
-
*
|
|
3528
|
+
* Unify gadget execute result to consistent internal format.
|
|
3521
3529
|
* Handles string returns (backwards compat), object returns with cost,
|
|
3522
3530
|
* and object returns with media.
|
|
3523
3531
|
*/
|
|
3524
|
-
|
|
3532
|
+
unifyExecuteResult(raw) {
|
|
3525
3533
|
if (typeof raw === "string") {
|
|
3526
3534
|
return { result: raw, cost: 0 };
|
|
3527
3535
|
}
|
|
@@ -3639,7 +3647,9 @@ var init_executor = __esm({
|
|
|
3639
3647
|
const ctx = {
|
|
3640
3648
|
reportCost,
|
|
3641
3649
|
llmist: this.client ? new CostReportingLLMistWrapper(this.client, reportCost) : void 0,
|
|
3642
|
-
signal: abortController.signal
|
|
3650
|
+
signal: abortController.signal,
|
|
3651
|
+
agentConfig: this.agentConfig,
|
|
3652
|
+
subagentConfig: this.subagentConfig
|
|
3643
3653
|
};
|
|
3644
3654
|
let rawResult;
|
|
3645
3655
|
if (timeoutMs && timeoutMs > 0) {
|
|
@@ -3654,7 +3664,7 @@ var init_executor = __esm({
|
|
|
3654
3664
|
} else {
|
|
3655
3665
|
rawResult = await Promise.resolve(gadget.execute(validatedParameters, ctx));
|
|
3656
3666
|
}
|
|
3657
|
-
const { result, media, cost: returnCost } = this.
|
|
3667
|
+
const { result, media, cost: returnCost } = this.unifyExecuteResult(rawResult);
|
|
3658
3668
|
const totalCost = callbackCost + returnCost;
|
|
3659
3669
|
let mediaIds;
|
|
3660
3670
|
let storedMedia;
|
|
@@ -3700,7 +3710,7 @@ var init_executor = __esm({
|
|
|
3700
3710
|
storedMedia
|
|
3701
3711
|
};
|
|
3702
3712
|
} catch (error) {
|
|
3703
|
-
if (error instanceof
|
|
3713
|
+
if (error instanceof TaskCompletionSignal) {
|
|
3704
3714
|
this.logger.info("Gadget requested loop termination", {
|
|
3705
3715
|
gadgetName: call.gadgetName,
|
|
3706
3716
|
message: error.message
|
|
@@ -3728,7 +3738,7 @@ var init_executor = __esm({
|
|
|
3728
3738
|
executionTimeMs: Date.now() - startTime
|
|
3729
3739
|
};
|
|
3730
3740
|
}
|
|
3731
|
-
if (error instanceof
|
|
3741
|
+
if (error instanceof AbortException) {
|
|
3732
3742
|
this.logger.info("Gadget execution was aborted", {
|
|
3733
3743
|
gadgetName: call.gadgetName,
|
|
3734
3744
|
executionTimeMs: Date.now() - startTime
|
|
@@ -3741,14 +3751,14 @@ var init_executor = __esm({
|
|
|
3741
3751
|
executionTimeMs: Date.now() - startTime
|
|
3742
3752
|
};
|
|
3743
3753
|
}
|
|
3744
|
-
if (error instanceof
|
|
3754
|
+
if (error instanceof HumanInputRequiredException) {
|
|
3745
3755
|
this.logger.info("Gadget requested human input", {
|
|
3746
3756
|
gadgetName: call.gadgetName,
|
|
3747
3757
|
question: error.question
|
|
3748
3758
|
});
|
|
3749
|
-
if (this.
|
|
3759
|
+
if (this.requestHumanInput) {
|
|
3750
3760
|
try {
|
|
3751
|
-
const answer = await this.
|
|
3761
|
+
const answer = await this.requestHumanInput(error.question);
|
|
3752
3762
|
this.logger.debug("Human input received", {
|
|
3753
3763
|
gadgetName: call.gadgetName,
|
|
3754
3764
|
answerLength: answer.length
|
|
@@ -3846,13 +3856,13 @@ var init_stream_processor = __esm({
|
|
|
3846
3856
|
parser;
|
|
3847
3857
|
executor;
|
|
3848
3858
|
stopOnGadgetError;
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3859
|
+
canRecoverFromGadgetError;
|
|
3860
|
+
responseText = "";
|
|
3861
|
+
executionHalted = false;
|
|
3852
3862
|
observerFailureCount = 0;
|
|
3853
3863
|
// Dependency tracking for gadget execution DAG
|
|
3854
3864
|
/** Gadgets waiting for their dependencies to complete */
|
|
3855
|
-
|
|
3865
|
+
gadgetsAwaitingDependencies = /* @__PURE__ */ new Map();
|
|
3856
3866
|
/** Completed gadget results, keyed by invocation ID */
|
|
3857
3867
|
completedResults = /* @__PURE__ */ new Map();
|
|
3858
3868
|
/** Invocation IDs of gadgets that have failed (error or skipped due to dependency) */
|
|
@@ -3863,20 +3873,22 @@ var init_stream_processor = __esm({
|
|
|
3863
3873
|
this.hooks = options.hooks ?? {};
|
|
3864
3874
|
this.logger = options.logger ?? createLogger({ name: "llmist:stream-processor" });
|
|
3865
3875
|
this.stopOnGadgetError = options.stopOnGadgetError ?? true;
|
|
3866
|
-
this.
|
|
3867
|
-
this.parser = new
|
|
3876
|
+
this.canRecoverFromGadgetError = options.canRecoverFromGadgetError;
|
|
3877
|
+
this.parser = new GadgetCallParser({
|
|
3868
3878
|
startPrefix: options.gadgetStartPrefix,
|
|
3869
3879
|
endPrefix: options.gadgetEndPrefix,
|
|
3870
3880
|
argPrefix: options.gadgetArgPrefix
|
|
3871
3881
|
});
|
|
3872
3882
|
this.executor = new GadgetExecutor(
|
|
3873
3883
|
options.registry,
|
|
3874
|
-
options.
|
|
3884
|
+
options.requestHumanInput,
|
|
3875
3885
|
this.logger.getSubLogger({ name: "executor" }),
|
|
3876
3886
|
options.defaultGadgetTimeoutMs,
|
|
3877
3887
|
{ argPrefix: options.gadgetArgPrefix },
|
|
3878
3888
|
options.client,
|
|
3879
|
-
options.mediaStore
|
|
3889
|
+
options.mediaStore,
|
|
3890
|
+
options.agentConfig,
|
|
3891
|
+
options.subagentConfig
|
|
3880
3892
|
);
|
|
3881
3893
|
}
|
|
3882
3894
|
/**
|
|
@@ -3897,7 +3909,7 @@ var init_stream_processor = __esm({
|
|
|
3897
3909
|
if (this.hooks.interceptors?.interceptRawChunk) {
|
|
3898
3910
|
const context = {
|
|
3899
3911
|
iteration: this.iteration,
|
|
3900
|
-
accumulatedText: this.
|
|
3912
|
+
accumulatedText: this.responseText,
|
|
3901
3913
|
logger: this.logger
|
|
3902
3914
|
};
|
|
3903
3915
|
const intercepted = this.hooks.interceptors.interceptRawChunk(processedChunk, context);
|
|
@@ -3908,7 +3920,7 @@ var init_stream_processor = __esm({
|
|
|
3908
3920
|
}
|
|
3909
3921
|
}
|
|
3910
3922
|
if (processedChunk) {
|
|
3911
|
-
this.
|
|
3923
|
+
this.responseText += processedChunk;
|
|
3912
3924
|
}
|
|
3913
3925
|
}
|
|
3914
3926
|
if (this.hooks.observers?.onStreamChunk && (processedChunk || chunk.usage)) {
|
|
@@ -3917,7 +3929,7 @@ var init_stream_processor = __esm({
|
|
|
3917
3929
|
const context = {
|
|
3918
3930
|
iteration: this.iteration,
|
|
3919
3931
|
rawChunk: processedChunk,
|
|
3920
|
-
accumulatedText: this.
|
|
3932
|
+
accumulatedText: this.responseText,
|
|
3921
3933
|
usage,
|
|
3922
3934
|
logger: this.logger
|
|
3923
3935
|
};
|
|
@@ -3940,12 +3952,12 @@ var init_stream_processor = __esm({
|
|
|
3940
3952
|
}
|
|
3941
3953
|
}
|
|
3942
3954
|
}
|
|
3943
|
-
if (this.
|
|
3955
|
+
if (this.executionHalted) {
|
|
3944
3956
|
this.logger.info("Breaking from LLM stream due to gadget error");
|
|
3945
3957
|
break;
|
|
3946
3958
|
}
|
|
3947
3959
|
}
|
|
3948
|
-
if (!this.
|
|
3960
|
+
if (!this.executionHalted) {
|
|
3949
3961
|
for (const event of this.parser.finalize()) {
|
|
3950
3962
|
const processedEvents = await this.processEvent(event);
|
|
3951
3963
|
outputs.push(...processedEvents);
|
|
@@ -3969,11 +3981,11 @@ var init_stream_processor = __esm({
|
|
|
3969
3981
|
}
|
|
3970
3982
|
}
|
|
3971
3983
|
}
|
|
3972
|
-
let finalMessage = this.
|
|
3984
|
+
let finalMessage = this.responseText;
|
|
3973
3985
|
if (this.hooks.interceptors?.interceptAssistantMessage) {
|
|
3974
3986
|
const context = {
|
|
3975
3987
|
iteration: this.iteration,
|
|
3976
|
-
rawResponse: this.
|
|
3988
|
+
rawResponse: this.responseText,
|
|
3977
3989
|
logger: this.logger
|
|
3978
3990
|
};
|
|
3979
3991
|
finalMessage = this.hooks.interceptors.interceptAssistantMessage(finalMessage, context);
|
|
@@ -3984,7 +3996,7 @@ var init_stream_processor = __esm({
|
|
|
3984
3996
|
didExecuteGadgets,
|
|
3985
3997
|
finishReason,
|
|
3986
3998
|
usage,
|
|
3987
|
-
rawResponse: this.
|
|
3999
|
+
rawResponse: this.responseText,
|
|
3988
4000
|
finalMessage
|
|
3989
4001
|
};
|
|
3990
4002
|
}
|
|
@@ -4007,7 +4019,7 @@ var init_stream_processor = __esm({
|
|
|
4007
4019
|
if (this.hooks.interceptors?.interceptTextChunk) {
|
|
4008
4020
|
const context = {
|
|
4009
4021
|
iteration: this.iteration,
|
|
4010
|
-
accumulatedText: this.
|
|
4022
|
+
accumulatedText: this.responseText,
|
|
4011
4023
|
logger: this.logger
|
|
4012
4024
|
};
|
|
4013
4025
|
const intercepted = this.hooks.interceptors.interceptTextChunk(content, context);
|
|
@@ -4026,7 +4038,7 @@ var init_stream_processor = __esm({
|
|
|
4026
4038
|
* After each execution, pending gadgets are checked to see if they can now run.
|
|
4027
4039
|
*/
|
|
4028
4040
|
async processGadgetCall(call) {
|
|
4029
|
-
if (this.
|
|
4041
|
+
if (this.executionHalted) {
|
|
4030
4042
|
this.logger.debug("Skipping gadget execution due to previous error", {
|
|
4031
4043
|
gadgetName: call.gadgetName
|
|
4032
4044
|
});
|
|
@@ -4065,7 +4077,7 @@ var init_stream_processor = __esm({
|
|
|
4065
4077
|
invocationId: call.invocationId,
|
|
4066
4078
|
waitingOn: unsatisfied
|
|
4067
4079
|
});
|
|
4068
|
-
this.
|
|
4080
|
+
this.gadgetsAwaitingDependencies.set(call.invocationId, call);
|
|
4069
4081
|
return events;
|
|
4070
4082
|
}
|
|
4071
4083
|
}
|
|
@@ -4087,14 +4099,14 @@ var init_stream_processor = __esm({
|
|
|
4087
4099
|
error: call.parseError,
|
|
4088
4100
|
rawParameters: call.parametersRaw
|
|
4089
4101
|
});
|
|
4090
|
-
const shouldContinue = await this.
|
|
4102
|
+
const shouldContinue = await this.checkCanRecoverFromError(
|
|
4091
4103
|
call.parseError,
|
|
4092
4104
|
call.gadgetName,
|
|
4093
4105
|
"parse",
|
|
4094
4106
|
call.parameters
|
|
4095
4107
|
);
|
|
4096
4108
|
if (!shouldContinue) {
|
|
4097
|
-
this.
|
|
4109
|
+
this.executionHalted = true;
|
|
4098
4110
|
}
|
|
4099
4111
|
}
|
|
4100
4112
|
let parameters = call.parameters ?? {};
|
|
@@ -4218,14 +4230,14 @@ var init_stream_processor = __esm({
|
|
|
4218
4230
|
events.push({ type: "gadget_result", result });
|
|
4219
4231
|
if (result.error) {
|
|
4220
4232
|
const errorType = this.determineErrorType(call, result);
|
|
4221
|
-
const shouldContinue = await this.
|
|
4233
|
+
const shouldContinue = await this.checkCanRecoverFromError(
|
|
4222
4234
|
result.error,
|
|
4223
4235
|
result.gadgetName,
|
|
4224
4236
|
errorType,
|
|
4225
4237
|
result.parameters
|
|
4226
4238
|
);
|
|
4227
4239
|
if (!shouldContinue) {
|
|
4228
|
-
this.
|
|
4240
|
+
this.executionHalted = true;
|
|
4229
4241
|
}
|
|
4230
4242
|
}
|
|
4231
4243
|
return events;
|
|
@@ -4312,11 +4324,11 @@ var init_stream_processor = __esm({
|
|
|
4312
4324
|
async processPendingGadgets() {
|
|
4313
4325
|
const events = [];
|
|
4314
4326
|
let progress = true;
|
|
4315
|
-
while (progress && this.
|
|
4327
|
+
while (progress && this.gadgetsAwaitingDependencies.size > 0) {
|
|
4316
4328
|
progress = false;
|
|
4317
4329
|
const readyToExecute = [];
|
|
4318
4330
|
const readyToSkip = [];
|
|
4319
|
-
for (const [invocationId, call] of this.
|
|
4331
|
+
for (const [invocationId, call] of this.gadgetsAwaitingDependencies) {
|
|
4320
4332
|
const failedDep = call.dependencies.find((dep) => this.failedInvocations.has(dep));
|
|
4321
4333
|
if (failedDep) {
|
|
4322
4334
|
readyToSkip.push({ call, failedDep });
|
|
@@ -4328,7 +4340,7 @@ var init_stream_processor = __esm({
|
|
|
4328
4340
|
}
|
|
4329
4341
|
}
|
|
4330
4342
|
for (const { call, failedDep } of readyToSkip) {
|
|
4331
|
-
this.
|
|
4343
|
+
this.gadgetsAwaitingDependencies.delete(call.invocationId);
|
|
4332
4344
|
const skipEvents = await this.handleFailedDependency(call, failedDep);
|
|
4333
4345
|
events.push(...skipEvents);
|
|
4334
4346
|
progress = true;
|
|
@@ -4339,7 +4351,7 @@ var init_stream_processor = __esm({
|
|
|
4339
4351
|
invocationIds: readyToExecute.map((c) => c.invocationId)
|
|
4340
4352
|
});
|
|
4341
4353
|
for (const call of readyToExecute) {
|
|
4342
|
-
this.
|
|
4354
|
+
this.gadgetsAwaitingDependencies.delete(call.invocationId);
|
|
4343
4355
|
}
|
|
4344
4356
|
const executePromises = readyToExecute.map((call) => this.executeGadgetWithHooks(call));
|
|
4345
4357
|
const results = await Promise.all(executePromises);
|
|
@@ -4349,9 +4361,9 @@ var init_stream_processor = __esm({
|
|
|
4349
4361
|
progress = true;
|
|
4350
4362
|
}
|
|
4351
4363
|
}
|
|
4352
|
-
if (this.
|
|
4353
|
-
const pendingIds = new Set(this.
|
|
4354
|
-
for (const [invocationId, call] of this.
|
|
4364
|
+
if (this.gadgetsAwaitingDependencies.size > 0) {
|
|
4365
|
+
const pendingIds = new Set(this.gadgetsAwaitingDependencies.keys());
|
|
4366
|
+
for (const [invocationId, call] of this.gadgetsAwaitingDependencies) {
|
|
4355
4367
|
const missingDeps = call.dependencies.filter((dep) => !this.completedResults.has(dep));
|
|
4356
4368
|
const circularDeps = missingDeps.filter((dep) => pendingIds.has(dep));
|
|
4357
4369
|
const trulyMissingDeps = missingDeps.filter((dep) => !pendingIds.has(dep));
|
|
@@ -4382,7 +4394,7 @@ var init_stream_processor = __esm({
|
|
|
4382
4394
|
};
|
|
4383
4395
|
events.push(skipEvent);
|
|
4384
4396
|
}
|
|
4385
|
-
this.
|
|
4397
|
+
this.gadgetsAwaitingDependencies.clear();
|
|
4386
4398
|
}
|
|
4387
4399
|
return events;
|
|
4388
4400
|
}
|
|
@@ -4412,19 +4424,19 @@ var init_stream_processor = __esm({
|
|
|
4412
4424
|
);
|
|
4413
4425
|
}
|
|
4414
4426
|
/**
|
|
4415
|
-
* Check if execution
|
|
4427
|
+
* Check if execution can recover from an error.
|
|
4416
4428
|
*
|
|
4417
4429
|
* Returns true if we should continue processing subsequent gadgets, false if we should stop.
|
|
4418
4430
|
*
|
|
4419
4431
|
* Logic:
|
|
4420
|
-
* - If custom
|
|
4432
|
+
* - If custom canRecoverFromGadgetError is provided, use it
|
|
4421
4433
|
* - Otherwise, use stopOnGadgetError config:
|
|
4422
4434
|
* - stopOnGadgetError=true → return false (stop execution)
|
|
4423
4435
|
* - stopOnGadgetError=false → return true (continue execution)
|
|
4424
4436
|
*/
|
|
4425
|
-
async
|
|
4426
|
-
if (this.
|
|
4427
|
-
return await this.
|
|
4437
|
+
async checkCanRecoverFromError(error, gadgetName, errorType, parameters) {
|
|
4438
|
+
if (this.canRecoverFromGadgetError) {
|
|
4439
|
+
return await this.canRecoverFromGadgetError({
|
|
4428
4440
|
error,
|
|
4429
4441
|
gadgetName,
|
|
4430
4442
|
errorType,
|
|
@@ -4487,14 +4499,14 @@ var init_agent = __esm({
|
|
|
4487
4499
|
gadgetStartPrefix;
|
|
4488
4500
|
gadgetEndPrefix;
|
|
4489
4501
|
gadgetArgPrefix;
|
|
4490
|
-
|
|
4502
|
+
requestHumanInput;
|
|
4491
4503
|
textOnlyHandler;
|
|
4492
4504
|
textWithGadgetsHandler;
|
|
4493
4505
|
stopOnGadgetError;
|
|
4494
|
-
|
|
4506
|
+
canRecoverFromGadgetError;
|
|
4495
4507
|
defaultGadgetTimeoutMs;
|
|
4496
4508
|
defaultMaxTokens;
|
|
4497
|
-
|
|
4509
|
+
hasUserPrompt;
|
|
4498
4510
|
// Gadget output limiting
|
|
4499
4511
|
outputStore;
|
|
4500
4512
|
outputLimitEnabled;
|
|
@@ -4505,6 +4517,9 @@ var init_agent = __esm({
|
|
|
4505
4517
|
mediaStore;
|
|
4506
4518
|
// Cancellation
|
|
4507
4519
|
signal;
|
|
4520
|
+
// Subagent configuration
|
|
4521
|
+
agentContextConfig;
|
|
4522
|
+
subagentConfig;
|
|
4508
4523
|
/**
|
|
4509
4524
|
* Creates a new Agent instance.
|
|
4510
4525
|
* @internal This constructor is private. Use LLMist.createAgent() or AgentBuilder instead.
|
|
@@ -4524,11 +4539,11 @@ var init_agent = __esm({
|
|
|
4524
4539
|
this.gadgetStartPrefix = options.gadgetStartPrefix;
|
|
4525
4540
|
this.gadgetEndPrefix = options.gadgetEndPrefix;
|
|
4526
4541
|
this.gadgetArgPrefix = options.gadgetArgPrefix;
|
|
4527
|
-
this.
|
|
4542
|
+
this.requestHumanInput = options.requestHumanInput;
|
|
4528
4543
|
this.textOnlyHandler = options.textOnlyHandler ?? "terminate";
|
|
4529
4544
|
this.textWithGadgetsHandler = options.textWithGadgetsHandler;
|
|
4530
4545
|
this.stopOnGadgetError = options.stopOnGadgetError ?? true;
|
|
4531
|
-
this.
|
|
4546
|
+
this.canRecoverFromGadgetError = options.canRecoverFromGadgetError;
|
|
4532
4547
|
this.defaultGadgetTimeoutMs = options.defaultGadgetTimeoutMs;
|
|
4533
4548
|
this.defaultMaxTokens = this.resolveMaxTokensFromCatalog(options.model);
|
|
4534
4549
|
this.outputLimitEnabled = options.gadgetOutputLimit ?? DEFAULT_GADGET_OUTPUT_LIMIT;
|
|
@@ -4544,7 +4559,7 @@ var init_agent = __esm({
|
|
|
4544
4559
|
createGadgetOutputViewer(this.outputStore, this.outputLimitCharLimit)
|
|
4545
4560
|
);
|
|
4546
4561
|
}
|
|
4547
|
-
this.hooks = this.
|
|
4562
|
+
this.hooks = this.chainOutputLimiterWithUserHooks(options.hooks);
|
|
4548
4563
|
const baseBuilder = new LLMMessageBuilder(options.promptConfig);
|
|
4549
4564
|
if (options.systemPrompt) {
|
|
4550
4565
|
baseBuilder.addSystem(options.systemPrompt);
|
|
@@ -4564,7 +4579,7 @@ var init_agent = __esm({
|
|
|
4564
4579
|
endPrefix: options.gadgetEndPrefix,
|
|
4565
4580
|
argPrefix: options.gadgetArgPrefix
|
|
4566
4581
|
});
|
|
4567
|
-
this.
|
|
4582
|
+
this.hasUserPrompt = !!options.userPrompt;
|
|
4568
4583
|
if (options.userPrompt) {
|
|
4569
4584
|
this.conversation.addUserMessage(options.userPrompt);
|
|
4570
4585
|
}
|
|
@@ -4577,6 +4592,11 @@ var init_agent = __esm({
|
|
|
4577
4592
|
);
|
|
4578
4593
|
}
|
|
4579
4594
|
this.signal = options.signal;
|
|
4595
|
+
this.agentContextConfig = {
|
|
4596
|
+
model: this.model,
|
|
4597
|
+
temperature: this.temperature
|
|
4598
|
+
};
|
|
4599
|
+
this.subagentConfig = options.subagentConfig;
|
|
4580
4600
|
}
|
|
4581
4601
|
/**
|
|
4582
4602
|
* Get the gadget registry for this agent.
|
|
@@ -4683,7 +4703,7 @@ var init_agent = __esm({
|
|
|
4683
4703
|
* @throws {Error} If no user prompt was provided (when using build() without ask())
|
|
4684
4704
|
*/
|
|
4685
4705
|
async *run() {
|
|
4686
|
-
if (!this.
|
|
4706
|
+
if (!this.hasUserPrompt) {
|
|
4687
4707
|
throw new Error(
|
|
4688
4708
|
"No user prompt provided. Use .ask(prompt) instead of .build(), or call agent.run() after providing a prompt."
|
|
4689
4709
|
);
|
|
@@ -4800,12 +4820,14 @@ var init_agent = __esm({
|
|
|
4800
4820
|
gadgetArgPrefix: this.gadgetArgPrefix,
|
|
4801
4821
|
hooks: this.hooks,
|
|
4802
4822
|
logger: this.logger.getSubLogger({ name: "stream-processor" }),
|
|
4803
|
-
|
|
4823
|
+
requestHumanInput: this.requestHumanInput,
|
|
4804
4824
|
stopOnGadgetError: this.stopOnGadgetError,
|
|
4805
|
-
|
|
4825
|
+
canRecoverFromGadgetError: this.canRecoverFromGadgetError,
|
|
4806
4826
|
defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
|
|
4807
4827
|
client: this.client,
|
|
4808
|
-
mediaStore: this.mediaStore
|
|
4828
|
+
mediaStore: this.mediaStore,
|
|
4829
|
+
agentConfig: this.agentContextConfig,
|
|
4830
|
+
subagentConfig: this.subagentConfig
|
|
4809
4831
|
});
|
|
4810
4832
|
const result = await processor.process(stream2);
|
|
4811
4833
|
for (const output of result.outputs) {
|
|
@@ -4858,9 +4880,9 @@ var init_agent = __esm({
|
|
|
4858
4880
|
if (msg.role === "user") {
|
|
4859
4881
|
this.conversation.addUserMessage(msg.content);
|
|
4860
4882
|
} else if (msg.role === "assistant") {
|
|
4861
|
-
this.conversation.addAssistantMessage(
|
|
4883
|
+
this.conversation.addAssistantMessage(extractMessageText(msg.content));
|
|
4862
4884
|
} else if (msg.role === "system") {
|
|
4863
|
-
this.conversation.addUserMessage(`[System] ${
|
|
4885
|
+
this.conversation.addUserMessage(`[System] ${extractMessageText(msg.content)}`);
|
|
4864
4886
|
}
|
|
4865
4887
|
}
|
|
4866
4888
|
}
|
|
@@ -4872,7 +4894,7 @@ var init_agent = __esm({
|
|
|
4872
4894
|
).map((output) => output.content).join("");
|
|
4873
4895
|
if (textContent.trim()) {
|
|
4874
4896
|
const { gadgetName, parameterMapping, resultMapping } = this.textWithGadgetsHandler;
|
|
4875
|
-
this.conversation.
|
|
4897
|
+
this.conversation.addGadgetCallResult(
|
|
4876
4898
|
gadgetName,
|
|
4877
4899
|
parameterMapping(textContent),
|
|
4878
4900
|
resultMapping ? resultMapping(textContent) : textContent
|
|
@@ -4882,7 +4904,7 @@ var init_agent = __esm({
|
|
|
4882
4904
|
for (const output of result.outputs) {
|
|
4883
4905
|
if (output.type === "gadget_result") {
|
|
4884
4906
|
const gadgetResult = output.result;
|
|
4885
|
-
this.conversation.
|
|
4907
|
+
this.conversation.addGadgetCallResult(
|
|
4886
4908
|
gadgetResult.gadgetName,
|
|
4887
4909
|
gadgetResult.parameters,
|
|
4888
4910
|
gadgetResult.error ?? gadgetResult.result ?? "",
|
|
@@ -4893,7 +4915,7 @@ var init_agent = __esm({
|
|
|
4893
4915
|
}
|
|
4894
4916
|
} else {
|
|
4895
4917
|
if (finalMessage.trim()) {
|
|
4896
|
-
this.conversation.
|
|
4918
|
+
this.conversation.addGadgetCallResult(
|
|
4897
4919
|
"TellUser",
|
|
4898
4920
|
{ message: finalMessage, done: false, type: "info" },
|
|
4899
4921
|
`\u2139\uFE0F ${finalMessage}`
|
|
@@ -5019,10 +5041,10 @@ var init_agent = __esm({
|
|
|
5019
5041
|
return this.client.modelRegistry.getModelLimits(unprefixedModelId)?.maxOutputTokens;
|
|
5020
5042
|
}
|
|
5021
5043
|
/**
|
|
5022
|
-
*
|
|
5044
|
+
* Chain the output limiter interceptor with user-provided hooks.
|
|
5023
5045
|
* The limiter runs first, then chains to any user interceptor.
|
|
5024
5046
|
*/
|
|
5025
|
-
|
|
5047
|
+
chainOutputLimiterWithUserHooks(userHooks) {
|
|
5026
5048
|
if (!this.outputLimitEnabled) {
|
|
5027
5049
|
return userHooks ?? {};
|
|
5028
5050
|
}
|
|
@@ -5376,9 +5398,9 @@ var init_base_provider = __esm({
|
|
|
5376
5398
|
*/
|
|
5377
5399
|
async *stream(options, descriptor, spec) {
|
|
5378
5400
|
const preparedMessages = this.prepareMessages(options.messages);
|
|
5379
|
-
const payload = this.
|
|
5401
|
+
const payload = this.buildApiRequest(options, descriptor, spec, preparedMessages);
|
|
5380
5402
|
const rawStream = await this.executeStreamRequest(payload, options.signal);
|
|
5381
|
-
yield* this.
|
|
5403
|
+
yield* this.normalizeProviderStream(rawStream);
|
|
5382
5404
|
}
|
|
5383
5405
|
/**
|
|
5384
5406
|
* Prepare messages for the request.
|
|
@@ -5478,11 +5500,11 @@ var init_anthropic = __esm({
|
|
|
5478
5500
|
"Anthropic does not support speech generation. Use OpenAI (TTS) or Google Gemini (TTS) instead."
|
|
5479
5501
|
);
|
|
5480
5502
|
}
|
|
5481
|
-
|
|
5503
|
+
buildApiRequest(options, descriptor, spec, messages) {
|
|
5482
5504
|
const systemMessages = messages.filter((message) => message.role === "system");
|
|
5483
5505
|
const system = systemMessages.length > 0 ? systemMessages.map((m, index) => ({
|
|
5484
5506
|
type: "text",
|
|
5485
|
-
text:
|
|
5507
|
+
text: extractMessageText(m.content),
|
|
5486
5508
|
// Add cache_control to the LAST system message block
|
|
5487
5509
|
...index === systemMessages.length - 1 ? { cache_control: { type: "ephemeral" } } : {}
|
|
5488
5510
|
})) : void 0;
|
|
@@ -5519,7 +5541,7 @@ var init_anthropic = __esm({
|
|
|
5519
5541
|
* Handles text, images (base64 only), and applies cache_control.
|
|
5520
5542
|
*/
|
|
5521
5543
|
convertToAnthropicContent(content, addCacheControl) {
|
|
5522
|
-
const parts =
|
|
5544
|
+
const parts = normalizeMessageContent(content);
|
|
5523
5545
|
return parts.map((part, index) => {
|
|
5524
5546
|
const isLastPart = index === parts.length - 1;
|
|
5525
5547
|
const cacheControl = addCacheControl && isLastPart ? { cache_control: { type: "ephemeral" } } : {};
|
|
@@ -5565,7 +5587,7 @@ var init_anthropic = __esm({
|
|
|
5565
5587
|
const stream2 = await client.messages.create(payload, signal ? { signal } : void 0);
|
|
5566
5588
|
return stream2;
|
|
5567
5589
|
}
|
|
5568
|
-
async *
|
|
5590
|
+
async *normalizeProviderStream(iterable) {
|
|
5569
5591
|
const stream2 = iterable;
|
|
5570
5592
|
let inputTokens = 0;
|
|
5571
5593
|
let cachedInputTokens = 0;
|
|
@@ -5642,7 +5664,7 @@ var init_anthropic = __esm({
|
|
|
5642
5664
|
async countTokens(messages, descriptor, _spec) {
|
|
5643
5665
|
const client = this.client;
|
|
5644
5666
|
const systemMessages = messages.filter((message) => message.role === "system");
|
|
5645
|
-
const system = systemMessages.length > 0 ? systemMessages.map((m) =>
|
|
5667
|
+
const system = systemMessages.length > 0 ? systemMessages.map((m) => extractMessageText(m.content)).join("\n\n") : void 0;
|
|
5646
5668
|
const conversation = messages.filter(
|
|
5647
5669
|
(message) => message.role !== "system"
|
|
5648
5670
|
).map((message) => ({
|
|
@@ -5664,7 +5686,7 @@ var init_anthropic = __esm({
|
|
|
5664
5686
|
let totalChars = 0;
|
|
5665
5687
|
let imageCount = 0;
|
|
5666
5688
|
for (const msg of messages) {
|
|
5667
|
-
const parts =
|
|
5689
|
+
const parts = normalizeMessageContent(msg.content);
|
|
5668
5690
|
for (const part of parts) {
|
|
5669
5691
|
if (part.type === "text") {
|
|
5670
5692
|
totalChars += part.text.length;
|
|
@@ -6355,7 +6377,7 @@ var init_gemini = __esm({
|
|
|
6355
6377
|
format: spec?.defaultFormat ?? "wav"
|
|
6356
6378
|
};
|
|
6357
6379
|
}
|
|
6358
|
-
|
|
6380
|
+
buildApiRequest(options, descriptor, _spec, messages) {
|
|
6359
6381
|
const contents = this.convertMessagesToContents(messages);
|
|
6360
6382
|
const generationConfig = this.buildGenerationConfig(options);
|
|
6361
6383
|
const config = {
|
|
@@ -6407,7 +6429,7 @@ var init_gemini = __esm({
|
|
|
6407
6429
|
if (message.role === "system") {
|
|
6408
6430
|
expandedMessages.push({
|
|
6409
6431
|
role: "user",
|
|
6410
|
-
content:
|
|
6432
|
+
content: extractMessageText(message.content)
|
|
6411
6433
|
});
|
|
6412
6434
|
expandedMessages.push({
|
|
6413
6435
|
role: "assistant",
|
|
@@ -6457,7 +6479,7 @@ var init_gemini = __esm({
|
|
|
6457
6479
|
* Handles text, images, and audio (Gemini supports all three).
|
|
6458
6480
|
*/
|
|
6459
6481
|
convertToGeminiParts(content) {
|
|
6460
|
-
const parts =
|
|
6482
|
+
const parts = normalizeMessageContent(content);
|
|
6461
6483
|
return parts.map((part) => {
|
|
6462
6484
|
if (part.type === "text") {
|
|
6463
6485
|
return { text: part.text };
|
|
@@ -6502,10 +6524,10 @@ var init_gemini = __esm({
|
|
|
6502
6524
|
}
|
|
6503
6525
|
return Object.keys(config).length > 0 ? config : null;
|
|
6504
6526
|
}
|
|
6505
|
-
async *
|
|
6527
|
+
async *normalizeProviderStream(iterable) {
|
|
6506
6528
|
const stream2 = iterable;
|
|
6507
6529
|
for await (const chunk of stream2) {
|
|
6508
|
-
const text3 = this.
|
|
6530
|
+
const text3 = this.extractMessageText(chunk);
|
|
6509
6531
|
if (text3) {
|
|
6510
6532
|
yield { text: text3, rawEvent: chunk };
|
|
6511
6533
|
}
|
|
@@ -6516,7 +6538,7 @@ var init_gemini = __esm({
|
|
|
6516
6538
|
}
|
|
6517
6539
|
}
|
|
6518
6540
|
}
|
|
6519
|
-
|
|
6541
|
+
extractMessageText(chunk) {
|
|
6520
6542
|
if (!chunk?.candidates) {
|
|
6521
6543
|
return "";
|
|
6522
6544
|
}
|
|
@@ -6581,7 +6603,7 @@ var init_gemini = __esm({
|
|
|
6581
6603
|
let totalChars = 0;
|
|
6582
6604
|
let mediaCount = 0;
|
|
6583
6605
|
for (const msg of messages) {
|
|
6584
|
-
const parts =
|
|
6606
|
+
const parts = normalizeMessageContent(msg.content);
|
|
6585
6607
|
for (const part of parts) {
|
|
6586
6608
|
if (part.type === "text") {
|
|
6587
6609
|
totalChars += part.text.length;
|
|
@@ -7327,7 +7349,7 @@ var init_openai = __esm({
|
|
|
7327
7349
|
format
|
|
7328
7350
|
};
|
|
7329
7351
|
}
|
|
7330
|
-
|
|
7352
|
+
buildApiRequest(options, descriptor, spec, messages) {
|
|
7331
7353
|
const { maxTokens, temperature, topP, stopSequences, extra } = options;
|
|
7332
7354
|
const supportsTemperature = spec?.metadata?.supportsTemperature !== false;
|
|
7333
7355
|
const shouldIncludeTemperature = typeof temperature === "number" && supportsTemperature;
|
|
@@ -7362,7 +7384,7 @@ var init_openai = __esm({
|
|
|
7362
7384
|
...message.name ? { name: message.name } : {}
|
|
7363
7385
|
};
|
|
7364
7386
|
}
|
|
7365
|
-
const textContent = typeof message.content === "string" ? message.content :
|
|
7387
|
+
const textContent = typeof message.content === "string" ? message.content : extractMessageText(message.content);
|
|
7366
7388
|
if (role === "system") {
|
|
7367
7389
|
return {
|
|
7368
7390
|
role: "system",
|
|
@@ -7422,7 +7444,7 @@ var init_openai = __esm({
|
|
|
7422
7444
|
const stream2 = await client.chat.completions.create(payload, signal ? { signal } : void 0);
|
|
7423
7445
|
return stream2;
|
|
7424
7446
|
}
|
|
7425
|
-
async *
|
|
7447
|
+
async *normalizeProviderStream(iterable) {
|
|
7426
7448
|
const stream2 = iterable;
|
|
7427
7449
|
for await (const chunk of stream2) {
|
|
7428
7450
|
const text3 = chunk.choices.map((choice) => choice.delta?.content ?? "").join("");
|
|
@@ -7480,9 +7502,9 @@ var init_openai = __esm({
|
|
|
7480
7502
|
tokenCount += OPENAI_MESSAGE_OVERHEAD_TOKENS;
|
|
7481
7503
|
const roleText = ROLE_MAP[message.role];
|
|
7482
7504
|
tokenCount += encoding.encode(roleText).length;
|
|
7483
|
-
const textContent =
|
|
7505
|
+
const textContent = extractMessageText(message.content);
|
|
7484
7506
|
tokenCount += encoding.encode(textContent).length;
|
|
7485
|
-
const parts =
|
|
7507
|
+
const parts = normalizeMessageContent(message.content);
|
|
7486
7508
|
for (const part of parts) {
|
|
7487
7509
|
if (part.type === "image") {
|
|
7488
7510
|
imageCount++;
|
|
@@ -7507,7 +7529,7 @@ var init_openai = __esm({
|
|
|
7507
7529
|
let totalChars = 0;
|
|
7508
7530
|
let imageCount = 0;
|
|
7509
7531
|
for (const msg of messages) {
|
|
7510
|
-
const parts =
|
|
7532
|
+
const parts = normalizeMessageContent(msg.content);
|
|
7511
7533
|
for (const part of parts) {
|
|
7512
7534
|
if (part.type === "text") {
|
|
7513
7535
|
totalChars += part.text.length;
|
|
@@ -8372,20 +8394,21 @@ var init_builder = __esm({
|
|
|
8372
8394
|
promptConfig;
|
|
8373
8395
|
gadgets = [];
|
|
8374
8396
|
initialMessages = [];
|
|
8375
|
-
|
|
8397
|
+
requestHumanInput;
|
|
8376
8398
|
gadgetStartPrefix;
|
|
8377
8399
|
gadgetEndPrefix;
|
|
8378
8400
|
gadgetArgPrefix;
|
|
8379
8401
|
textOnlyHandler;
|
|
8380
8402
|
textWithGadgetsHandler;
|
|
8381
8403
|
stopOnGadgetError;
|
|
8382
|
-
|
|
8404
|
+
canRecoverFromGadgetError;
|
|
8383
8405
|
defaultGadgetTimeoutMs;
|
|
8384
8406
|
gadgetOutputLimit;
|
|
8385
8407
|
gadgetOutputLimitPercent;
|
|
8386
8408
|
compactionConfig;
|
|
8387
8409
|
signal;
|
|
8388
8410
|
trailingMessage;
|
|
8411
|
+
subagentConfig;
|
|
8389
8412
|
constructor(client) {
|
|
8390
8413
|
this.client = client;
|
|
8391
8414
|
}
|
|
@@ -8476,13 +8499,13 @@ var init_builder = __esm({
|
|
|
8476
8499
|
*
|
|
8477
8500
|
* @example
|
|
8478
8501
|
* ```typescript
|
|
8479
|
-
* .
|
|
8502
|
+
* .withPromptTemplateConfig({
|
|
8480
8503
|
* mainInstruction: "Use the gadget markers below:",
|
|
8481
8504
|
* rules: ["Always use markers", "Never use function calling"]
|
|
8482
8505
|
* })
|
|
8483
8506
|
* ```
|
|
8484
8507
|
*/
|
|
8485
|
-
|
|
8508
|
+
withPromptTemplateConfig(config) {
|
|
8486
8509
|
this.promptConfig = config;
|
|
8487
8510
|
return this;
|
|
8488
8511
|
}
|
|
@@ -8562,7 +8585,7 @@ var init_builder = __esm({
|
|
|
8562
8585
|
* ```
|
|
8563
8586
|
*/
|
|
8564
8587
|
onHumanInput(handler) {
|
|
8565
|
-
this.
|
|
8588
|
+
this.requestHumanInput = handler;
|
|
8566
8589
|
return this;
|
|
8567
8590
|
}
|
|
8568
8591
|
/**
|
|
@@ -8697,9 +8720,9 @@ var init_builder = __esm({
|
|
|
8697
8720
|
* Provides fine-grained control over whether to continue after different types of errors.
|
|
8698
8721
|
* Overrides `stopOnGadgetError` when provided.
|
|
8699
8722
|
*
|
|
8700
|
-
* **Note:** This builder method configures the underlying `
|
|
8723
|
+
* **Note:** This builder method configures the underlying `canRecoverFromGadgetError` option
|
|
8701
8724
|
* in `AgentOptions`. The method is named `withErrorHandler` for better developer experience,
|
|
8702
|
-
* but maps to the `
|
|
8725
|
+
* but maps to the `canRecoverFromGadgetError` property internally.
|
|
8703
8726
|
*
|
|
8704
8727
|
* @param handler - Function that decides whether to continue after an error.
|
|
8705
8728
|
* Return `true` to continue execution, `false` to stop.
|
|
@@ -8720,7 +8743,7 @@ var init_builder = __esm({
|
|
|
8720
8743
|
* ```
|
|
8721
8744
|
*/
|
|
8722
8745
|
withErrorHandler(handler) {
|
|
8723
|
-
this.
|
|
8746
|
+
this.canRecoverFromGadgetError = handler;
|
|
8724
8747
|
return this;
|
|
8725
8748
|
}
|
|
8726
8749
|
/**
|
|
@@ -8861,6 +8884,27 @@ var init_builder = __esm({
|
|
|
8861
8884
|
this.signal = signal;
|
|
8862
8885
|
return this;
|
|
8863
8886
|
}
|
|
8887
|
+
/**
|
|
8888
|
+
* Set subagent configuration overrides.
|
|
8889
|
+
*
|
|
8890
|
+
* Subagent gadgets (like BrowseWeb) can read these settings from ExecutionContext
|
|
8891
|
+
* to inherit model and other options from the CLI configuration.
|
|
8892
|
+
*
|
|
8893
|
+
* @param config - Subagent configuration map keyed by gadget name
|
|
8894
|
+
* @returns This builder for chaining
|
|
8895
|
+
*
|
|
8896
|
+
* @example
|
|
8897
|
+
* ```typescript
|
|
8898
|
+
* .withSubagentConfig({
|
|
8899
|
+
* BrowseWeb: { model: "inherit", maxIterations: 20, headless: true },
|
|
8900
|
+
* CodeAnalyzer: { model: "sonnet", maxIterations: 10 }
|
|
8901
|
+
* })
|
|
8902
|
+
* ```
|
|
8903
|
+
*/
|
|
8904
|
+
withSubagentConfig(config) {
|
|
8905
|
+
this.subagentConfig = config;
|
|
8906
|
+
return this;
|
|
8907
|
+
}
|
|
8864
8908
|
/**
|
|
8865
8909
|
* Add an ephemeral trailing message that appears at the end of each LLM request.
|
|
8866
8910
|
*
|
|
@@ -9025,19 +9069,20 @@ ${endPrefix}`
|
|
|
9025
9069
|
hooks: this.composeHooks(),
|
|
9026
9070
|
promptConfig: this.promptConfig,
|
|
9027
9071
|
initialMessages: this.initialMessages,
|
|
9028
|
-
|
|
9072
|
+
requestHumanInput: this.requestHumanInput,
|
|
9029
9073
|
gadgetStartPrefix: this.gadgetStartPrefix,
|
|
9030
9074
|
gadgetEndPrefix: this.gadgetEndPrefix,
|
|
9031
9075
|
gadgetArgPrefix: this.gadgetArgPrefix,
|
|
9032
9076
|
textOnlyHandler: this.textOnlyHandler,
|
|
9033
9077
|
textWithGadgetsHandler: this.textWithGadgetsHandler,
|
|
9034
9078
|
stopOnGadgetError: this.stopOnGadgetError,
|
|
9035
|
-
|
|
9079
|
+
canRecoverFromGadgetError: this.canRecoverFromGadgetError,
|
|
9036
9080
|
defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
|
|
9037
9081
|
gadgetOutputLimit: this.gadgetOutputLimit,
|
|
9038
9082
|
gadgetOutputLimitPercent: this.gadgetOutputLimitPercent,
|
|
9039
9083
|
compactionConfig: this.compactionConfig,
|
|
9040
|
-
signal: this.signal
|
|
9084
|
+
signal: this.signal,
|
|
9085
|
+
subagentConfig: this.subagentConfig
|
|
9041
9086
|
};
|
|
9042
9087
|
}
|
|
9043
9088
|
ask(userPrompt) {
|
|
@@ -9206,19 +9251,20 @@ ${endPrefix}`
|
|
|
9206
9251
|
hooks: this.composeHooks(),
|
|
9207
9252
|
promptConfig: this.promptConfig,
|
|
9208
9253
|
initialMessages: this.initialMessages,
|
|
9209
|
-
|
|
9254
|
+
requestHumanInput: this.requestHumanInput,
|
|
9210
9255
|
gadgetStartPrefix: this.gadgetStartPrefix,
|
|
9211
9256
|
gadgetEndPrefix: this.gadgetEndPrefix,
|
|
9212
9257
|
gadgetArgPrefix: this.gadgetArgPrefix,
|
|
9213
9258
|
textOnlyHandler: this.textOnlyHandler,
|
|
9214
9259
|
textWithGadgetsHandler: this.textWithGadgetsHandler,
|
|
9215
9260
|
stopOnGadgetError: this.stopOnGadgetError,
|
|
9216
|
-
|
|
9261
|
+
canRecoverFromGadgetError: this.canRecoverFromGadgetError,
|
|
9217
9262
|
defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
|
|
9218
9263
|
gadgetOutputLimit: this.gadgetOutputLimit,
|
|
9219
9264
|
gadgetOutputLimitPercent: this.gadgetOutputLimitPercent,
|
|
9220
9265
|
compactionConfig: this.compactionConfig,
|
|
9221
|
-
signal: this.signal
|
|
9266
|
+
signal: this.signal,
|
|
9267
|
+
subagentConfig: this.subagentConfig
|
|
9222
9268
|
};
|
|
9223
9269
|
return new Agent(AGENT_INTERNAL_KEY, options);
|
|
9224
9270
|
}
|
|
@@ -9236,7 +9282,8 @@ var COMMANDS = {
|
|
|
9236
9282
|
gadget: "gadget",
|
|
9237
9283
|
image: "image",
|
|
9238
9284
|
speech: "speech",
|
|
9239
|
-
vision: "vision"
|
|
9285
|
+
vision: "vision",
|
|
9286
|
+
init: "init"
|
|
9240
9287
|
};
|
|
9241
9288
|
var LOG_LEVELS = ["silly", "trace", "debug", "info", "warn", "error", "fatal"];
|
|
9242
9289
|
var DEFAULT_MODEL = "openai:gpt-5-nano";
|
|
@@ -9312,7 +9359,7 @@ var import_commander2 = require("commander");
|
|
|
9312
9359
|
// package.json
|
|
9313
9360
|
var package_default = {
|
|
9314
9361
|
name: "llmist",
|
|
9315
|
-
version: "
|
|
9362
|
+
version: "3.0.0",
|
|
9316
9363
|
description: "TypeScript LLM client with streaming tool execution. Tools fire mid-stream. Built-in function calling works with any model\u2014no structured outputs or native tool support required.",
|
|
9317
9364
|
type: "module",
|
|
9318
9365
|
main: "dist/index.cjs",
|
|
@@ -9720,7 +9767,7 @@ var askUser = createGadget({
|
|
|
9720
9767
|
}
|
|
9721
9768
|
],
|
|
9722
9769
|
execute: ({ question }) => {
|
|
9723
|
-
throw new
|
|
9770
|
+
throw new HumanInputRequiredException(question);
|
|
9724
9771
|
}
|
|
9725
9772
|
});
|
|
9726
9773
|
var tellUser = createGadget({
|
|
@@ -9770,11 +9817,59 @@ var finish = createGadget({
|
|
|
9770
9817
|
}
|
|
9771
9818
|
],
|
|
9772
9819
|
execute: () => {
|
|
9773
|
-
throw new
|
|
9820
|
+
throw new TaskCompletionSignal("Task completed");
|
|
9774
9821
|
}
|
|
9775
9822
|
});
|
|
9776
9823
|
var builtinGadgets = [askUser, tellUser, finish];
|
|
9777
9824
|
|
|
9825
|
+
// src/cli/subagent-config.ts
|
|
9826
|
+
var INHERIT_MODEL = "inherit";
|
|
9827
|
+
function resolveSubagentConfig(subagentName, parentModel, profileConfig, globalConfig) {
|
|
9828
|
+
const resolved = {};
|
|
9829
|
+
const globalDefaultModel = globalConfig?.["default-model"];
|
|
9830
|
+
const globalSubagent = extractSubagentConfig(globalConfig, subagentName);
|
|
9831
|
+
const profileSubagent = profileConfig?.[subagentName] ?? {};
|
|
9832
|
+
const merged = { ...globalSubagent, ...profileSubagent };
|
|
9833
|
+
const configModel = merged.model ?? globalDefaultModel ?? INHERIT_MODEL;
|
|
9834
|
+
resolved.model = configModel === INHERIT_MODEL ? parentModel : configModel;
|
|
9835
|
+
for (const [key, value] of Object.entries(merged)) {
|
|
9836
|
+
if (key !== "model") {
|
|
9837
|
+
resolved[key] = value;
|
|
9838
|
+
}
|
|
9839
|
+
}
|
|
9840
|
+
return resolved;
|
|
9841
|
+
}
|
|
9842
|
+
function buildSubagentConfigMap(parentModel, profileConfig, globalConfig) {
|
|
9843
|
+
const subagentNames = /* @__PURE__ */ new Set();
|
|
9844
|
+
if (globalConfig) {
|
|
9845
|
+
for (const key of Object.keys(globalConfig)) {
|
|
9846
|
+
if (key !== "default-model" && typeof globalConfig[key] === "object") {
|
|
9847
|
+
subagentNames.add(key);
|
|
9848
|
+
}
|
|
9849
|
+
}
|
|
9850
|
+
}
|
|
9851
|
+
if (profileConfig) {
|
|
9852
|
+
for (const key of Object.keys(profileConfig)) {
|
|
9853
|
+
subagentNames.add(key);
|
|
9854
|
+
}
|
|
9855
|
+
}
|
|
9856
|
+
const result = {};
|
|
9857
|
+
for (const name of subagentNames) {
|
|
9858
|
+
result[name] = resolveSubagentConfig(name, parentModel, profileConfig, globalConfig);
|
|
9859
|
+
}
|
|
9860
|
+
return result;
|
|
9861
|
+
}
|
|
9862
|
+
function extractSubagentConfig(globalConfig, subagentName) {
|
|
9863
|
+
if (!globalConfig) {
|
|
9864
|
+
return {};
|
|
9865
|
+
}
|
|
9866
|
+
const value = globalConfig[subagentName];
|
|
9867
|
+
if (typeof value === "object" && value !== null) {
|
|
9868
|
+
return value;
|
|
9869
|
+
}
|
|
9870
|
+
return {};
|
|
9871
|
+
}
|
|
9872
|
+
|
|
9778
9873
|
// src/cli/config.ts
|
|
9779
9874
|
var import_node_fs3 = require("fs");
|
|
9780
9875
|
var import_node_os2 = require("os");
|
|
@@ -9863,7 +9958,7 @@ function hasTemplateSyntax(str) {
|
|
|
9863
9958
|
}
|
|
9864
9959
|
|
|
9865
9960
|
// src/cli/config.ts
|
|
9866
|
-
var
|
|
9961
|
+
var VALID_PERMISSION_LEVELS = ["allowed", "denied", "approval-required"];
|
|
9867
9962
|
var GLOBAL_CONFIG_KEYS = /* @__PURE__ */ new Set(["log-level", "log-file", "log-reset"]);
|
|
9868
9963
|
var VALID_LOG_LEVELS = ["silly", "trace", "debug", "info", "warn", "error", "fatal"];
|
|
9869
9964
|
var COMPLETE_CONFIG_KEYS = /* @__PURE__ */ new Set([
|
|
@@ -9903,6 +9998,8 @@ var AGENT_CONFIG_KEYS = /* @__PURE__ */ new Set([
|
|
|
9903
9998
|
"gadget-end-prefix",
|
|
9904
9999
|
"gadget-arg-prefix",
|
|
9905
10000
|
"gadget-approval",
|
|
10001
|
+
"subagents",
|
|
10002
|
+
// Per-subagent configuration overrides
|
|
9906
10003
|
"quiet",
|
|
9907
10004
|
"inherits",
|
|
9908
10005
|
"log-level",
|
|
@@ -9928,9 +10025,9 @@ function getConfigPath() {
|
|
|
9928
10025
|
return (0, import_node_path4.join)((0, import_node_os2.homedir)(), ".llmist", "cli.toml");
|
|
9929
10026
|
}
|
|
9930
10027
|
var ConfigError = class extends Error {
|
|
9931
|
-
constructor(message,
|
|
9932
|
-
super(
|
|
9933
|
-
this.path =
|
|
10028
|
+
constructor(message, path6) {
|
|
10029
|
+
super(path6 ? `${path6}: ${message}` : message);
|
|
10030
|
+
this.path = path6;
|
|
9934
10031
|
this.name = "ConfigError";
|
|
9935
10032
|
}
|
|
9936
10033
|
};
|
|
@@ -9986,6 +10083,63 @@ function validateInherits(value, section) {
|
|
|
9986
10083
|
}
|
|
9987
10084
|
throw new ConfigError(`[${section}].inherits must be a string or array of strings`);
|
|
9988
10085
|
}
|
|
10086
|
+
function validateSingleSubagentConfig(value, subagentName, section) {
|
|
10087
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
10088
|
+
throw new ConfigError(
|
|
10089
|
+
`[${section}].${subagentName} must be a table (e.g., { model = "inherit", maxIterations = 20 })`
|
|
10090
|
+
);
|
|
10091
|
+
}
|
|
10092
|
+
const result = {};
|
|
10093
|
+
const rawObj = value;
|
|
10094
|
+
for (const [key, val] of Object.entries(rawObj)) {
|
|
10095
|
+
if (key === "model") {
|
|
10096
|
+
if (typeof val !== "string") {
|
|
10097
|
+
throw new ConfigError(`[${section}].${subagentName}.model must be a string`);
|
|
10098
|
+
}
|
|
10099
|
+
result.model = val;
|
|
10100
|
+
} else if (key === "maxIterations") {
|
|
10101
|
+
if (typeof val !== "number" || !Number.isInteger(val) || val < 1) {
|
|
10102
|
+
throw new ConfigError(
|
|
10103
|
+
`[${section}].${subagentName}.maxIterations must be a positive integer`
|
|
10104
|
+
);
|
|
10105
|
+
}
|
|
10106
|
+
result.maxIterations = val;
|
|
10107
|
+
} else {
|
|
10108
|
+
result[key] = val;
|
|
10109
|
+
}
|
|
10110
|
+
}
|
|
10111
|
+
return result;
|
|
10112
|
+
}
|
|
10113
|
+
function validateSubagentConfigMap(value, section) {
|
|
10114
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
10115
|
+
throw new ConfigError(
|
|
10116
|
+
`[${section}].subagents must be a table (e.g., { BrowseWeb = { model = "inherit" } })`
|
|
10117
|
+
);
|
|
10118
|
+
}
|
|
10119
|
+
const result = {};
|
|
10120
|
+
for (const [subagentName, config] of Object.entries(value)) {
|
|
10121
|
+
result[subagentName] = validateSingleSubagentConfig(config, subagentName, `${section}.subagents`);
|
|
10122
|
+
}
|
|
10123
|
+
return result;
|
|
10124
|
+
}
|
|
10125
|
+
function validateGlobalSubagentConfig(value, section) {
|
|
10126
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
10127
|
+
throw new ConfigError(`[${section}] must be a table`);
|
|
10128
|
+
}
|
|
10129
|
+
const result = {};
|
|
10130
|
+
const rawObj = value;
|
|
10131
|
+
for (const [key, val] of Object.entries(rawObj)) {
|
|
10132
|
+
if (key === "default-model") {
|
|
10133
|
+
if (typeof val !== "string") {
|
|
10134
|
+
throw new ConfigError(`[${section}].default-model must be a string`);
|
|
10135
|
+
}
|
|
10136
|
+
result["default-model"] = val;
|
|
10137
|
+
} else {
|
|
10138
|
+
result[key] = validateSingleSubagentConfig(val, key, section);
|
|
10139
|
+
}
|
|
10140
|
+
}
|
|
10141
|
+
return result;
|
|
10142
|
+
}
|
|
9989
10143
|
function validateGadgetApproval(value, section) {
|
|
9990
10144
|
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
9991
10145
|
throw new ConfigError(
|
|
@@ -9997,9 +10151,9 @@ function validateGadgetApproval(value, section) {
|
|
|
9997
10151
|
if (typeof mode !== "string") {
|
|
9998
10152
|
throw new ConfigError(`[${section}].gadget-approval.${gadgetName} must be a string`);
|
|
9999
10153
|
}
|
|
10000
|
-
if (!
|
|
10154
|
+
if (!VALID_PERMISSION_LEVELS.includes(mode)) {
|
|
10001
10155
|
throw new ConfigError(
|
|
10002
|
-
`[${section}].gadget-approval.${gadgetName} must be one of: ${
|
|
10156
|
+
`[${section}].gadget-approval.${gadgetName} must be one of: ${VALID_PERMISSION_LEVELS.join(", ")}`
|
|
10003
10157
|
);
|
|
10004
10158
|
}
|
|
10005
10159
|
result[gadgetName] = mode;
|
|
@@ -10168,6 +10322,9 @@ function validateAgentConfig(raw, section) {
|
|
|
10168
10322
|
if ("gadget-approval" in rawObj) {
|
|
10169
10323
|
result["gadget-approval"] = validateGadgetApproval(rawObj["gadget-approval"], section);
|
|
10170
10324
|
}
|
|
10325
|
+
if ("subagents" in rawObj) {
|
|
10326
|
+
result.subagents = validateSubagentConfigMap(rawObj.subagents, section);
|
|
10327
|
+
}
|
|
10171
10328
|
if ("quiet" in rawObj) {
|
|
10172
10329
|
result.quiet = validateBoolean(rawObj.quiet, "quiet", section);
|
|
10173
10330
|
}
|
|
@@ -10336,6 +10493,9 @@ function validateCustomConfig(raw, section) {
|
|
|
10336
10493
|
if ("gadget-approval" in rawObj) {
|
|
10337
10494
|
result["gadget-approval"] = validateGadgetApproval(rawObj["gadget-approval"], section);
|
|
10338
10495
|
}
|
|
10496
|
+
if ("subagents" in rawObj) {
|
|
10497
|
+
result.subagents = validateSubagentConfigMap(rawObj.subagents, section);
|
|
10498
|
+
}
|
|
10339
10499
|
if ("max-tokens" in rawObj) {
|
|
10340
10500
|
result["max-tokens"] = validateNumber(rawObj["max-tokens"], "max-tokens", section, {
|
|
10341
10501
|
integer: true,
|
|
@@ -10383,6 +10543,8 @@ function validateConfig(raw, configPath) {
|
|
|
10383
10543
|
result.prompts = validatePromptsConfig(value, key);
|
|
10384
10544
|
} else if (key === "docker") {
|
|
10385
10545
|
result.docker = validateDockerConfig(value, key);
|
|
10546
|
+
} else if (key === "subagents") {
|
|
10547
|
+
result.subagents = validateGlobalSubagentConfig(value, key);
|
|
10386
10548
|
} else {
|
|
10387
10549
|
result[key] = validateCustomConfig(value, key);
|
|
10388
10550
|
}
|
|
@@ -10423,7 +10585,16 @@ function loadConfig() {
|
|
|
10423
10585
|
return resolveTemplatesInConfig(inherited, configPath);
|
|
10424
10586
|
}
|
|
10425
10587
|
function getCustomCommandNames(config) {
|
|
10426
|
-
const reserved = /* @__PURE__ */ new Set([
|
|
10588
|
+
const reserved = /* @__PURE__ */ new Set([
|
|
10589
|
+
"global",
|
|
10590
|
+
"complete",
|
|
10591
|
+
"agent",
|
|
10592
|
+
"image",
|
|
10593
|
+
"speech",
|
|
10594
|
+
"prompts",
|
|
10595
|
+
"docker",
|
|
10596
|
+
"subagents"
|
|
10597
|
+
]);
|
|
10427
10598
|
return Object.keys(config).filter((key) => !reserved.has(key));
|
|
10428
10599
|
}
|
|
10429
10600
|
function resolveTemplatesInConfig(config, configPath) {
|
|
@@ -10957,11 +11128,11 @@ function resolveDevMode(config, cliDevMode) {
|
|
|
10957
11128
|
}
|
|
10958
11129
|
return { enabled: true, sourcePath };
|
|
10959
11130
|
}
|
|
10960
|
-
function expandHome(
|
|
10961
|
-
if (
|
|
10962
|
-
return
|
|
11131
|
+
function expandHome(path6) {
|
|
11132
|
+
if (path6.startsWith("~")) {
|
|
11133
|
+
return path6.replace(/^~/, (0, import_node_os4.homedir)());
|
|
10963
11134
|
}
|
|
10964
|
-
return
|
|
11135
|
+
return path6;
|
|
10965
11136
|
}
|
|
10966
11137
|
function buildDockerRunArgs(ctx, imageName, devMode) {
|
|
10967
11138
|
const args = ["run", "--rm"];
|
|
@@ -11138,9 +11309,9 @@ async function readFileBuffer(filePath, options = {}) {
|
|
|
11138
11309
|
}
|
|
11139
11310
|
|
|
11140
11311
|
// src/cli/gadgets.ts
|
|
11141
|
-
var
|
|
11142
|
-
var
|
|
11143
|
-
var
|
|
11312
|
+
var import_node_fs11 = __toESM(require("fs"), 1);
|
|
11313
|
+
var import_node_path12 = __toESM(require("path"), 1);
|
|
11314
|
+
var import_node_url2 = require("url");
|
|
11144
11315
|
init_gadget();
|
|
11145
11316
|
|
|
11146
11317
|
// src/cli/builtins/filesystem/edit-file.ts
|
|
@@ -11665,6 +11836,208 @@ function isBuiltinGadgetName(name) {
|
|
|
11665
11836
|
return name in builtinGadgetRegistry;
|
|
11666
11837
|
}
|
|
11667
11838
|
|
|
11839
|
+
// src/cli/external-gadgets.ts
|
|
11840
|
+
var import_node_child_process = require("child_process");
|
|
11841
|
+
var import_node_fs10 = __toESM(require("fs"), 1);
|
|
11842
|
+
var import_node_path11 = __toESM(require("path"), 1);
|
|
11843
|
+
var import_node_os5 = __toESM(require("os"), 1);
|
|
11844
|
+
var import_node_url = require("url");
|
|
11845
|
+
var CACHE_DIR2 = import_node_path11.default.join(import_node_os5.default.homedir(), ".llmist", "gadget-cache");
|
|
11846
|
+
function isExternalPackageSpecifier(specifier) {
|
|
11847
|
+
if (/^@?[a-z0-9][\w.-]*(?:@[\w.-]+)?(?::[a-z]+)?(?:\/\w+)?$/i.test(specifier)) {
|
|
11848
|
+
return true;
|
|
11849
|
+
}
|
|
11850
|
+
if (specifier.startsWith("git+")) {
|
|
11851
|
+
return true;
|
|
11852
|
+
}
|
|
11853
|
+
return false;
|
|
11854
|
+
}
|
|
11855
|
+
function parseGadgetSpecifier(specifier) {
|
|
11856
|
+
if (specifier.startsWith("git+")) {
|
|
11857
|
+
const url = specifier.slice(4);
|
|
11858
|
+
const [baseUrl, ref] = url.split("#");
|
|
11859
|
+
return {
|
|
11860
|
+
type: "git",
|
|
11861
|
+
package: baseUrl,
|
|
11862
|
+
version: ref
|
|
11863
|
+
};
|
|
11864
|
+
}
|
|
11865
|
+
const npmMatch = specifier.match(
|
|
11866
|
+
/^(@?[a-z0-9][\w.-]*)(?:@([\w.-]+))?(?::([a-z]+))?(?:\/(\w+))?$/i
|
|
11867
|
+
);
|
|
11868
|
+
if (npmMatch) {
|
|
11869
|
+
const [, pkg, version, preset, gadgetName] = npmMatch;
|
|
11870
|
+
return {
|
|
11871
|
+
type: "npm",
|
|
11872
|
+
package: pkg,
|
|
11873
|
+
version,
|
|
11874
|
+
preset,
|
|
11875
|
+
gadgetName
|
|
11876
|
+
};
|
|
11877
|
+
}
|
|
11878
|
+
return null;
|
|
11879
|
+
}
|
|
11880
|
+
function getCacheDir(spec) {
|
|
11881
|
+
const versionSuffix = spec.version ? `@${spec.version}` : "@latest";
|
|
11882
|
+
if (spec.type === "npm") {
|
|
11883
|
+
return import_node_path11.default.join(CACHE_DIR2, "npm", `${spec.package}${versionSuffix}`);
|
|
11884
|
+
}
|
|
11885
|
+
const sanitizedUrl = spec.package.replace(/[/:]/g, "-").replace(/^-+|-+$/g, "");
|
|
11886
|
+
return import_node_path11.default.join(CACHE_DIR2, "git", `${sanitizedUrl}${versionSuffix}`);
|
|
11887
|
+
}
|
|
11888
|
+
function isCached(cacheDir) {
|
|
11889
|
+
const packageJsonPath = import_node_path11.default.join(cacheDir, "package.json");
|
|
11890
|
+
return import_node_fs10.default.existsSync(packageJsonPath);
|
|
11891
|
+
}
|
|
11892
|
+
async function installNpmPackage(spec, cacheDir) {
|
|
11893
|
+
import_node_fs10.default.mkdirSync(cacheDir, { recursive: true });
|
|
11894
|
+
const packageJson = {
|
|
11895
|
+
name: "llmist-gadget-cache",
|
|
11896
|
+
private: true,
|
|
11897
|
+
type: "module"
|
|
11898
|
+
};
|
|
11899
|
+
import_node_fs10.default.writeFileSync(import_node_path11.default.join(cacheDir, "package.json"), JSON.stringify(packageJson, null, 2));
|
|
11900
|
+
const packageSpec = spec.version ? `${spec.package}@${spec.version}` : spec.package;
|
|
11901
|
+
try {
|
|
11902
|
+
(0, import_node_child_process.execSync)(`npm install --prefix "${cacheDir}" "${packageSpec}" --save`, {
|
|
11903
|
+
stdio: "pipe",
|
|
11904
|
+
cwd: cacheDir
|
|
11905
|
+
});
|
|
11906
|
+
} catch (error) {
|
|
11907
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
11908
|
+
throw new Error(`Failed to install npm package '${packageSpec}': ${message}`);
|
|
11909
|
+
}
|
|
11910
|
+
}
|
|
11911
|
+
async function installGitPackage(spec, cacheDir) {
|
|
11912
|
+
import_node_fs10.default.mkdirSync(import_node_path11.default.dirname(cacheDir), { recursive: true });
|
|
11913
|
+
if (import_node_fs10.default.existsSync(cacheDir)) {
|
|
11914
|
+
try {
|
|
11915
|
+
(0, import_node_child_process.execSync)("git fetch", { cwd: cacheDir, stdio: "pipe" });
|
|
11916
|
+
if (spec.version) {
|
|
11917
|
+
(0, import_node_child_process.execSync)(`git checkout ${spec.version}`, { cwd: cacheDir, stdio: "pipe" });
|
|
11918
|
+
}
|
|
11919
|
+
} catch (error) {
|
|
11920
|
+
import_node_fs10.default.rmSync(cacheDir, { recursive: true, force: true });
|
|
11921
|
+
}
|
|
11922
|
+
}
|
|
11923
|
+
if (!import_node_fs10.default.existsSync(cacheDir)) {
|
|
11924
|
+
try {
|
|
11925
|
+
const cloneCmd = spec.version ? `git clone --branch ${spec.version} "${spec.package}" "${cacheDir}"` : `git clone "${spec.package}" "${cacheDir}"`;
|
|
11926
|
+
(0, import_node_child_process.execSync)(cloneCmd, { stdio: "pipe" });
|
|
11927
|
+
} catch (error) {
|
|
11928
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
11929
|
+
throw new Error(`Failed to clone git repository '${spec.package}': ${message}`);
|
|
11930
|
+
}
|
|
11931
|
+
if (import_node_fs10.default.existsSync(import_node_path11.default.join(cacheDir, "package.json"))) {
|
|
11932
|
+
try {
|
|
11933
|
+
(0, import_node_child_process.execSync)("npm install", { cwd: cacheDir, stdio: "pipe" });
|
|
11934
|
+
} catch (error) {
|
|
11935
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
11936
|
+
throw new Error(`Failed to install dependencies for '${spec.package}': ${message}`);
|
|
11937
|
+
}
|
|
11938
|
+
try {
|
|
11939
|
+
const packageJson = JSON.parse(import_node_fs10.default.readFileSync(import_node_path11.default.join(cacheDir, "package.json"), "utf-8"));
|
|
11940
|
+
if (packageJson.scripts?.build) {
|
|
11941
|
+
(0, import_node_child_process.execSync)("npm run build", { cwd: cacheDir, stdio: "pipe" });
|
|
11942
|
+
}
|
|
11943
|
+
} catch (error) {
|
|
11944
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
11945
|
+
throw new Error(`Failed to build package '${spec.package}': ${message}`);
|
|
11946
|
+
}
|
|
11947
|
+
}
|
|
11948
|
+
}
|
|
11949
|
+
}
|
|
11950
|
+
function readManifest(packageDir) {
|
|
11951
|
+
const packageJsonPath = import_node_path11.default.join(packageDir, "package.json");
|
|
11952
|
+
if (!import_node_fs10.default.existsSync(packageJsonPath)) {
|
|
11953
|
+
return null;
|
|
11954
|
+
}
|
|
11955
|
+
try {
|
|
11956
|
+
const packageJson = JSON.parse(import_node_fs10.default.readFileSync(packageJsonPath, "utf-8"));
|
|
11957
|
+
return packageJson.llmist || null;
|
|
11958
|
+
} catch {
|
|
11959
|
+
return null;
|
|
11960
|
+
}
|
|
11961
|
+
}
|
|
11962
|
+
function getPackagePath(cacheDir, packageName) {
|
|
11963
|
+
const nodeModulesPath = import_node_path11.default.join(cacheDir, "node_modules", packageName);
|
|
11964
|
+
if (import_node_fs10.default.existsSync(nodeModulesPath)) {
|
|
11965
|
+
return nodeModulesPath;
|
|
11966
|
+
}
|
|
11967
|
+
return cacheDir;
|
|
11968
|
+
}
|
|
11969
|
+
async function loadExternalGadgets(specifier, forceInstall = false) {
|
|
11970
|
+
const spec = parseGadgetSpecifier(specifier);
|
|
11971
|
+
if (!spec) {
|
|
11972
|
+
throw new Error(`Invalid external package specifier: ${specifier}`);
|
|
11973
|
+
}
|
|
11974
|
+
const cacheDir = getCacheDir(spec);
|
|
11975
|
+
if (!isCached(cacheDir) || forceInstall) {
|
|
11976
|
+
if (spec.type === "npm") {
|
|
11977
|
+
await installNpmPackage(spec, cacheDir);
|
|
11978
|
+
} else {
|
|
11979
|
+
await installGitPackage(spec, cacheDir);
|
|
11980
|
+
}
|
|
11981
|
+
}
|
|
11982
|
+
const packagePath = getPackagePath(cacheDir, spec.package);
|
|
11983
|
+
const manifest = readManifest(packagePath);
|
|
11984
|
+
let entryPoint;
|
|
11985
|
+
let gadgetNames = null;
|
|
11986
|
+
if (spec.gadgetName) {
|
|
11987
|
+
gadgetNames = [spec.gadgetName];
|
|
11988
|
+
if (manifest?.subagents?.[spec.gadgetName]) {
|
|
11989
|
+
entryPoint = manifest.subagents[spec.gadgetName].entryPoint;
|
|
11990
|
+
} else {
|
|
11991
|
+
entryPoint = manifest?.gadgets || "./dist/index.js";
|
|
11992
|
+
}
|
|
11993
|
+
} else if (spec.preset) {
|
|
11994
|
+
if (!manifest?.presets?.[spec.preset]) {
|
|
11995
|
+
throw new Error(`Unknown preset '${spec.preset}' in package '${spec.package}'`);
|
|
11996
|
+
}
|
|
11997
|
+
const preset = manifest.presets[spec.preset];
|
|
11998
|
+
if (preset === "*") {
|
|
11999
|
+
gadgetNames = null;
|
|
12000
|
+
} else {
|
|
12001
|
+
gadgetNames = preset;
|
|
12002
|
+
}
|
|
12003
|
+
entryPoint = manifest?.gadgets || "./dist/index.js";
|
|
12004
|
+
} else {
|
|
12005
|
+
entryPoint = manifest?.gadgets || "./dist/index.js";
|
|
12006
|
+
}
|
|
12007
|
+
const resolvedEntryPoint = import_node_path11.default.resolve(packagePath, entryPoint);
|
|
12008
|
+
if (!import_node_fs10.default.existsSync(resolvedEntryPoint)) {
|
|
12009
|
+
throw new Error(
|
|
12010
|
+
`Entry point not found: ${resolvedEntryPoint}. Make sure the package is built (run 'npm run build' in the package directory).`
|
|
12011
|
+
);
|
|
12012
|
+
}
|
|
12013
|
+
const moduleUrl = (0, import_node_url.pathToFileURL)(resolvedEntryPoint).href;
|
|
12014
|
+
let exports2;
|
|
12015
|
+
try {
|
|
12016
|
+
exports2 = await import(moduleUrl);
|
|
12017
|
+
} catch (error) {
|
|
12018
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
12019
|
+
throw new Error(`Failed to import '${specifier}': ${message}`);
|
|
12020
|
+
}
|
|
12021
|
+
let gadgets = extractGadgetsFromModule(exports2);
|
|
12022
|
+
if (gadgetNames) {
|
|
12023
|
+
const gadgetSet = new Set(gadgetNames.map((n) => n.toLowerCase()));
|
|
12024
|
+
gadgets = gadgets.filter((g) => {
|
|
12025
|
+
const name = g.name?.toLowerCase() || "";
|
|
12026
|
+
return gadgetSet.has(name);
|
|
12027
|
+
});
|
|
12028
|
+
const foundNames = new Set(gadgets.map((g) => g.name?.toLowerCase() || ""));
|
|
12029
|
+
for (const requested of gadgetNames) {
|
|
12030
|
+
if (!foundNames.has(requested.toLowerCase())) {
|
|
12031
|
+
throw new Error(`Gadget '${requested}' not found in package '${spec.package}'`);
|
|
12032
|
+
}
|
|
12033
|
+
}
|
|
12034
|
+
}
|
|
12035
|
+
if (gadgets.length === 0) {
|
|
12036
|
+
throw new Error(`No gadgets found in package '${spec.package}'`);
|
|
12037
|
+
}
|
|
12038
|
+
return gadgets;
|
|
12039
|
+
}
|
|
12040
|
+
|
|
11668
12041
|
// src/cli/gadgets.ts
|
|
11669
12042
|
var PATH_PREFIXES = [".", "/", "~"];
|
|
11670
12043
|
var BUILTIN_PREFIX = "builtin:";
|
|
@@ -11680,7 +12053,17 @@ function isGadgetConstructor(value) {
|
|
|
11680
12053
|
return false;
|
|
11681
12054
|
}
|
|
11682
12055
|
const prototype = value.prototype;
|
|
11683
|
-
|
|
12056
|
+
if (!prototype) {
|
|
12057
|
+
return false;
|
|
12058
|
+
}
|
|
12059
|
+
if (prototype instanceof AbstractGadget) {
|
|
12060
|
+
return true;
|
|
12061
|
+
}
|
|
12062
|
+
const proto = prototype;
|
|
12063
|
+
if (typeof proto.execute === "function") {
|
|
12064
|
+
return true;
|
|
12065
|
+
}
|
|
12066
|
+
return isGadgetLike(prototype);
|
|
11684
12067
|
}
|
|
11685
12068
|
function expandHomePath(input) {
|
|
11686
12069
|
if (!input.startsWith("~")) {
|
|
@@ -11690,10 +12073,10 @@ function expandHomePath(input) {
|
|
|
11690
12073
|
if (!home) {
|
|
11691
12074
|
return input;
|
|
11692
12075
|
}
|
|
11693
|
-
return
|
|
12076
|
+
return import_node_path12.default.join(home, input.slice(1));
|
|
11694
12077
|
}
|
|
11695
12078
|
function isFileLikeSpecifier(specifier) {
|
|
11696
|
-
return PATH_PREFIXES.some((prefix) => specifier.startsWith(prefix)) || specifier.includes(
|
|
12079
|
+
return PATH_PREFIXES.some((prefix) => specifier.startsWith(prefix)) || specifier.includes(import_node_path12.default.sep);
|
|
11697
12080
|
}
|
|
11698
12081
|
function tryResolveBuiltin(specifier) {
|
|
11699
12082
|
if (specifier.startsWith(BUILTIN_PREFIX)) {
|
|
@@ -11716,11 +12099,11 @@ function resolveGadgetSpecifier(specifier, cwd) {
|
|
|
11716
12099
|
return specifier;
|
|
11717
12100
|
}
|
|
11718
12101
|
const expanded = expandHomePath(specifier);
|
|
11719
|
-
const resolvedPath =
|
|
11720
|
-
if (!
|
|
12102
|
+
const resolvedPath = import_node_path12.default.resolve(cwd, expanded);
|
|
12103
|
+
if (!import_node_fs11.default.existsSync(resolvedPath)) {
|
|
11721
12104
|
throw new Error(`Gadget module not found at ${resolvedPath}`);
|
|
11722
12105
|
}
|
|
11723
|
-
return (0,
|
|
12106
|
+
return (0, import_node_url2.pathToFileURL)(resolvedPath).href;
|
|
11724
12107
|
}
|
|
11725
12108
|
function extractGadgetsFromModule(moduleExports) {
|
|
11726
12109
|
const results = [];
|
|
@@ -11733,7 +12116,7 @@ function extractGadgetsFromModule(moduleExports) {
|
|
|
11733
12116
|
return;
|
|
11734
12117
|
}
|
|
11735
12118
|
visited.add(value);
|
|
11736
|
-
if (value instanceof
|
|
12119
|
+
if (value instanceof AbstractGadget || isGadgetLike(value)) {
|
|
11737
12120
|
results.push(value);
|
|
11738
12121
|
return;
|
|
11739
12122
|
}
|
|
@@ -11758,12 +12141,23 @@ function extractGadgetsFromModule(moduleExports) {
|
|
|
11758
12141
|
}
|
|
11759
12142
|
async function loadGadgets(specifiers, cwd, importer = (specifier) => import(specifier)) {
|
|
11760
12143
|
const gadgets = [];
|
|
12144
|
+
const usingDefaultImporter = importer.toString().includes("import(specifier)");
|
|
11761
12145
|
for (const specifier of specifiers) {
|
|
11762
12146
|
const builtin = tryResolveBuiltin(specifier);
|
|
11763
12147
|
if (builtin) {
|
|
11764
12148
|
gadgets.push(builtin);
|
|
11765
12149
|
continue;
|
|
11766
12150
|
}
|
|
12151
|
+
if (usingDefaultImporter && isExternalPackageSpecifier(specifier)) {
|
|
12152
|
+
try {
|
|
12153
|
+
const externalGadgets = await loadExternalGadgets(specifier);
|
|
12154
|
+
gadgets.push(...externalGadgets);
|
|
12155
|
+
continue;
|
|
12156
|
+
} catch (error) {
|
|
12157
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
12158
|
+
throw new Error(`Failed to load external package '${specifier}': ${message}`);
|
|
12159
|
+
}
|
|
12160
|
+
}
|
|
11767
12161
|
const resolved = resolveGadgetSpecifier(specifier, cwd);
|
|
11768
12162
|
let exports2;
|
|
11769
12163
|
try {
|
|
@@ -11789,13 +12183,13 @@ async function loadGadgets(specifiers, cwd, importer = (specifier) => import(spe
|
|
|
11789
12183
|
|
|
11790
12184
|
// src/cli/llm-logging.ts
|
|
11791
12185
|
var import_promises4 = require("fs/promises");
|
|
11792
|
-
var
|
|
11793
|
-
var
|
|
12186
|
+
var import_node_os6 = require("os");
|
|
12187
|
+
var import_node_path13 = require("path");
|
|
11794
12188
|
init_messages();
|
|
11795
|
-
var DEFAULT_LLM_LOG_DIR = (0,
|
|
12189
|
+
var DEFAULT_LLM_LOG_DIR = (0, import_node_path13.join)((0, import_node_os6.homedir)(), ".llmist", "logs");
|
|
11796
12190
|
function resolveLogDir(option, subdir) {
|
|
11797
12191
|
if (option === true) {
|
|
11798
|
-
return (0,
|
|
12192
|
+
return (0, import_node_path13.join)(DEFAULT_LLM_LOG_DIR, subdir);
|
|
11799
12193
|
}
|
|
11800
12194
|
if (typeof option === "string") {
|
|
11801
12195
|
return option;
|
|
@@ -11806,14 +12200,14 @@ function formatLlmRequest(messages) {
|
|
|
11806
12200
|
const lines = [];
|
|
11807
12201
|
for (const msg of messages) {
|
|
11808
12202
|
lines.push(`=== ${msg.role.toUpperCase()} ===`);
|
|
11809
|
-
lines.push(msg.content ?
|
|
12203
|
+
lines.push(msg.content ? extractMessageText(msg.content) : "");
|
|
11810
12204
|
lines.push("");
|
|
11811
12205
|
}
|
|
11812
12206
|
return lines.join("\n");
|
|
11813
12207
|
}
|
|
11814
12208
|
async function writeLogFile(dir, filename, content) {
|
|
11815
12209
|
await (0, import_promises4.mkdir)(dir, { recursive: true });
|
|
11816
|
-
await (0, import_promises4.writeFile)((0,
|
|
12210
|
+
await (0, import_promises4.writeFile)((0, import_node_path13.join)(dir, filename), content, "utf-8");
|
|
11817
12211
|
}
|
|
11818
12212
|
function formatSessionTimestamp(date = /* @__PURE__ */ new Date()) {
|
|
11819
12213
|
const pad = (n) => n.toString().padStart(2, "0");
|
|
@@ -11827,7 +12221,7 @@ function formatSessionTimestamp(date = /* @__PURE__ */ new Date()) {
|
|
|
11827
12221
|
}
|
|
11828
12222
|
async function createSessionDir(baseDir) {
|
|
11829
12223
|
const timestamp = formatSessionTimestamp();
|
|
11830
|
-
const sessionDir = (0,
|
|
12224
|
+
const sessionDir = (0, import_node_path13.join)(baseDir, timestamp);
|
|
11831
12225
|
try {
|
|
11832
12226
|
await (0, import_promises4.mkdir)(sessionDir, { recursive: true });
|
|
11833
12227
|
return sessionDir;
|
|
@@ -12021,8 +12415,8 @@ function formatMediaLine(media) {
|
|
|
12021
12415
|
const id = import_chalk3.default.cyan(media.id);
|
|
12022
12416
|
const mimeType = import_chalk3.default.dim(media.mimeType);
|
|
12023
12417
|
const size = import_chalk3.default.yellow(formatBytes(media.sizeBytes));
|
|
12024
|
-
const
|
|
12025
|
-
return `${import_chalk3.default.dim("[")}${icon} ${id} ${mimeType} ${size}${import_chalk3.default.dim("]")} ${import_chalk3.default.dim("\u2192")} ${
|
|
12418
|
+
const path6 = import_chalk3.default.dim(media.path);
|
|
12419
|
+
return `${import_chalk3.default.dim("[")}${icon} ${id} ${mimeType} ${size}${import_chalk3.default.dim("]")} ${import_chalk3.default.dim("\u2192")} ${path6}`;
|
|
12026
12420
|
}
|
|
12027
12421
|
function formatGadgetSummary2(result) {
|
|
12028
12422
|
const gadgetLabel = import_chalk3.default.magenta.bold(result.gadgetName);
|
|
@@ -12642,6 +13036,7 @@ function configToAgentOptions(config) {
|
|
|
12642
13036
|
if (config.docker !== void 0) result.docker = config.docker;
|
|
12643
13037
|
if (config["docker-cwd-permission"] !== void 0)
|
|
12644
13038
|
result.dockerCwdPermission = config["docker-cwd-permission"];
|
|
13039
|
+
if (config.subagents !== void 0) result.subagents = config.subagents;
|
|
12645
13040
|
return result;
|
|
12646
13041
|
}
|
|
12647
13042
|
|
|
@@ -12829,7 +13224,12 @@ async function executeAgent(promptArg, options, env) {
|
|
|
12829
13224
|
return void 0;
|
|
12830
13225
|
}
|
|
12831
13226
|
};
|
|
12832
|
-
const
|
|
13227
|
+
const resolvedSubagentConfig = buildSubagentConfigMap(
|
|
13228
|
+
options.model,
|
|
13229
|
+
options.subagents,
|
|
13230
|
+
options.globalSubagents
|
|
13231
|
+
);
|
|
13232
|
+
const builder = new AgentBuilder(client).withModel(options.model).withSubagentConfig(resolvedSubagentConfig).withLogger(env.createLogger("llmist:cli:agent")).withHooks({
|
|
12833
13233
|
observers: {
|
|
12834
13234
|
// onLLMCallStart: Start progress indicator for each LLM call
|
|
12835
13235
|
// This showcases how to react to agent lifecycle events
|
|
@@ -13099,14 +13499,16 @@ Denied: ${result.reason ?? "by user"}`
|
|
|
13099
13499
|
}
|
|
13100
13500
|
}
|
|
13101
13501
|
}
|
|
13102
|
-
function registerAgentCommand(program, env, config) {
|
|
13502
|
+
function registerAgentCommand(program, env, config, globalSubagents) {
|
|
13103
13503
|
const cmd = program.command(COMMANDS.agent).description("Run the llmist agent loop with optional gadgets.").argument("[prompt]", "Prompt for the agent loop. Falls back to stdin when available.");
|
|
13104
13504
|
addAgentOptions(cmd, config);
|
|
13105
13505
|
cmd.action(
|
|
13106
13506
|
(prompt, options) => executeAction(() => {
|
|
13107
13507
|
const mergedOptions = {
|
|
13108
13508
|
...options,
|
|
13109
|
-
gadgetApproval: config?.["gadget-approval"]
|
|
13509
|
+
gadgetApproval: config?.["gadget-approval"],
|
|
13510
|
+
subagents: config?.subagents,
|
|
13511
|
+
globalSubagents
|
|
13110
13512
|
};
|
|
13111
13513
|
return executeAgent(prompt, mergedOptions, env);
|
|
13112
13514
|
}, env)
|
|
@@ -13206,6 +13608,104 @@ function registerCompleteCommand(program, env, config) {
|
|
|
13206
13608
|
);
|
|
13207
13609
|
}
|
|
13208
13610
|
|
|
13611
|
+
// src/cli/init-command.ts
|
|
13612
|
+
var import_node_fs12 = require("fs");
|
|
13613
|
+
var import_node_path14 = require("path");
|
|
13614
|
+
var STARTER_CONFIG = `# ~/.llmist/cli.toml
|
|
13615
|
+
# llmist CLI configuration file
|
|
13616
|
+
#
|
|
13617
|
+
# This is a minimal starter config. For a comprehensive example with all options:
|
|
13618
|
+
# https://github.com/zbigniewsobiecki/llmist/blob/main/examples/cli.example.toml
|
|
13619
|
+
#
|
|
13620
|
+
# Key concepts:
|
|
13621
|
+
# - Any section can inherit from others using: inherits = "section-name"
|
|
13622
|
+
# - Prompts can use templates with Eta syntax: <%~ include("@prompt-name") %>
|
|
13623
|
+
# - Custom sections become CLI commands: [my-command] -> llmist my-command
|
|
13624
|
+
|
|
13625
|
+
#\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
13626
|
+
# GLOBAL OPTIONS
|
|
13627
|
+
# These apply to all commands. CLI flags override these settings.
|
|
13628
|
+
#\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
13629
|
+
[global]
|
|
13630
|
+
# log-level = "info" # silly, trace, debug, info, warn, error, fatal
|
|
13631
|
+
# log-file = "/tmp/llmist.log" # Enable file logging (JSON format)
|
|
13632
|
+
|
|
13633
|
+
#\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
13634
|
+
# COMPLETE COMMAND DEFAULTS
|
|
13635
|
+
# For single LLM responses: llmist complete "prompt"
|
|
13636
|
+
# Model format: provider:model (e.g., openai:gpt-4o, anthropic:claude-sonnet-4-5)
|
|
13637
|
+
#\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
13638
|
+
[complete]
|
|
13639
|
+
# model = "openai:gpt-4o"
|
|
13640
|
+
# temperature = 0.7 # 0-2, higher = more creative
|
|
13641
|
+
# max-tokens = 4096 # Maximum response length
|
|
13642
|
+
|
|
13643
|
+
#\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
13644
|
+
# AGENT COMMAND DEFAULTS
|
|
13645
|
+
# For tool-using agents: llmist agent "prompt"
|
|
13646
|
+
#\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
13647
|
+
[agent]
|
|
13648
|
+
# model = "anthropic:claude-sonnet-4-5"
|
|
13649
|
+
# max-iterations = 15 # Max tool-use loops before stopping
|
|
13650
|
+
# gadgets = [ # Tools the agent can use
|
|
13651
|
+
# "ListDirectory",
|
|
13652
|
+
# "ReadFile",
|
|
13653
|
+
# "WriteFile",
|
|
13654
|
+
# ]
|
|
13655
|
+
|
|
13656
|
+
#\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
13657
|
+
# CUSTOM COMMANDS
|
|
13658
|
+
# Any other section becomes a new CLI command!
|
|
13659
|
+
# Uncomment below to create: llmist summarize "your text"
|
|
13660
|
+
#\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
13661
|
+
# [summarize]
|
|
13662
|
+
# type = "complete" # "complete" or "agent"
|
|
13663
|
+
# description = "Summarize text concisely."
|
|
13664
|
+
# system = "Summarize the following text in 2-3 bullet points."
|
|
13665
|
+
# temperature = 0.3
|
|
13666
|
+
`;
|
|
13667
|
+
async function executeInit(_options, env) {
|
|
13668
|
+
const configPath = getConfigPath();
|
|
13669
|
+
const configDir = (0, import_node_path14.dirname)(configPath);
|
|
13670
|
+
if ((0, import_node_fs12.existsSync)(configPath)) {
|
|
13671
|
+
env.stderr.write(`Configuration already exists at ${configPath}
|
|
13672
|
+
`);
|
|
13673
|
+
env.stderr.write("\n");
|
|
13674
|
+
env.stderr.write(`To view it: cat ${configPath}
|
|
13675
|
+
`);
|
|
13676
|
+
env.stderr.write(`To reset: rm ${configPath} && llmist init
|
|
13677
|
+
`);
|
|
13678
|
+
return;
|
|
13679
|
+
}
|
|
13680
|
+
if (!(0, import_node_fs12.existsSync)(configDir)) {
|
|
13681
|
+
(0, import_node_fs12.mkdirSync)(configDir, { recursive: true });
|
|
13682
|
+
}
|
|
13683
|
+
(0, import_node_fs12.writeFileSync)(configPath, STARTER_CONFIG, "utf-8");
|
|
13684
|
+
env.stderr.write(`Created ${configPath}
|
|
13685
|
+
`);
|
|
13686
|
+
env.stderr.write("\n");
|
|
13687
|
+
env.stderr.write("Next steps:\n");
|
|
13688
|
+
env.stderr.write(" 1. Set your API key:\n");
|
|
13689
|
+
env.stderr.write(" export OPENAI_API_KEY=sk-...\n");
|
|
13690
|
+
env.stderr.write(" export ANTHROPIC_API_KEY=sk-...\n");
|
|
13691
|
+
env.stderr.write(" export GEMINI_API_KEY=...\n");
|
|
13692
|
+
env.stderr.write("\n");
|
|
13693
|
+
env.stderr.write(` 2. Customize your config:
|
|
13694
|
+
`);
|
|
13695
|
+
env.stderr.write(` $EDITOR ${configPath}
|
|
13696
|
+
`);
|
|
13697
|
+
env.stderr.write("\n");
|
|
13698
|
+
env.stderr.write(" 3. See all options:\n");
|
|
13699
|
+
env.stderr.write(
|
|
13700
|
+
" https://github.com/zbigniewsobiecki/llmist/blob/main/examples/cli.example.toml\n"
|
|
13701
|
+
);
|
|
13702
|
+
env.stderr.write("\n");
|
|
13703
|
+
env.stderr.write('Try it: llmist complete "Hello, world!"\n');
|
|
13704
|
+
}
|
|
13705
|
+
function registerInitCommand(program, env) {
|
|
13706
|
+
program.command(COMMANDS.init).description("Initialize llmist configuration at ~/.llmist/cli.toml").action((options) => executeAction(() => executeInit(options, env), env));
|
|
13707
|
+
}
|
|
13708
|
+
|
|
13209
13709
|
// src/cli/environment.ts
|
|
13210
13710
|
var import_node_readline = __toESM(require("readline"), 1);
|
|
13211
13711
|
var import_chalk6 = __toESM(require("chalk"), 1);
|
|
@@ -13308,7 +13808,7 @@ function createCommandEnvironment(baseEnv, config) {
|
|
|
13308
13808
|
createLogger: createLoggerFactory(loggerConfig)
|
|
13309
13809
|
};
|
|
13310
13810
|
}
|
|
13311
|
-
function registerCustomCommand(program, name, config, env) {
|
|
13811
|
+
function registerCustomCommand(program, name, config, env, globalSubagents) {
|
|
13312
13812
|
const type = config.type ?? "agent";
|
|
13313
13813
|
const description = config.description ?? `Custom ${type} command`;
|
|
13314
13814
|
const cmd = program.command(name).description(description).argument("[prompt]", "Prompt for the command. Falls back to stdin when available.");
|
|
@@ -13333,7 +13833,8 @@ function registerCustomCommand(program, name, config, env) {
|
|
|
13333
13833
|
const configDefaults = configToAgentOptions(config);
|
|
13334
13834
|
const options = {
|
|
13335
13835
|
...configDefaults,
|
|
13336
|
-
...cliOptions
|
|
13836
|
+
...cliOptions,
|
|
13837
|
+
globalSubagents
|
|
13337
13838
|
};
|
|
13338
13839
|
await executeAgent(prompt, options, cmdEnv);
|
|
13339
13840
|
}, cmdEnv);
|
|
@@ -13776,7 +14277,7 @@ function registerGadgetCommand(program, env) {
|
|
|
13776
14277
|
}
|
|
13777
14278
|
|
|
13778
14279
|
// src/cli/image-command.ts
|
|
13779
|
-
var
|
|
14280
|
+
var import_node_fs13 = require("fs");
|
|
13780
14281
|
var DEFAULT_IMAGE_MODEL = "dall-e-3";
|
|
13781
14282
|
async function executeImage(promptArg, options, env) {
|
|
13782
14283
|
const prompt = await resolvePrompt(promptArg, env);
|
|
@@ -13800,7 +14301,7 @@ async function executeImage(promptArg, options, env) {
|
|
|
13800
14301
|
const imageData = result.images[0];
|
|
13801
14302
|
if (imageData.b64Json) {
|
|
13802
14303
|
const buffer = Buffer.from(imageData.b64Json, "base64");
|
|
13803
|
-
(0,
|
|
14304
|
+
(0, import_node_fs13.writeFileSync)(options.output, buffer);
|
|
13804
14305
|
if (!options.quiet) {
|
|
13805
14306
|
env.stderr.write(`${SUMMARY_PREFIX} Image saved to ${options.output}
|
|
13806
14307
|
`);
|
|
@@ -14241,7 +14742,7 @@ function registerModelsCommand(program, env) {
|
|
|
14241
14742
|
}
|
|
14242
14743
|
|
|
14243
14744
|
// src/cli/speech-command.ts
|
|
14244
|
-
var
|
|
14745
|
+
var import_node_fs14 = require("fs");
|
|
14245
14746
|
var DEFAULT_SPEECH_MODEL = "tts-1";
|
|
14246
14747
|
var DEFAULT_VOICE = "nova";
|
|
14247
14748
|
async function executeSpeech(textArg, options, env) {
|
|
@@ -14264,7 +14765,7 @@ async function executeSpeech(textArg, options, env) {
|
|
|
14264
14765
|
});
|
|
14265
14766
|
const audioBuffer = Buffer.from(result.audio);
|
|
14266
14767
|
if (options.output) {
|
|
14267
|
-
(0,
|
|
14768
|
+
(0, import_node_fs14.writeFileSync)(options.output, audioBuffer);
|
|
14268
14769
|
if (!options.quiet) {
|
|
14269
14770
|
env.stderr.write(`${SUMMARY_PREFIX} Audio saved to ${options.output}
|
|
14270
14771
|
`);
|
|
@@ -14338,17 +14839,18 @@ function createProgram(env, config) {
|
|
|
14338
14839
|
writeErr: (str) => env.stderr.write(str)
|
|
14339
14840
|
});
|
|
14340
14841
|
registerCompleteCommand(program, env, config?.complete);
|
|
14341
|
-
registerAgentCommand(program, env, config?.agent);
|
|
14842
|
+
registerAgentCommand(program, env, config?.agent, config?.subagents);
|
|
14342
14843
|
registerImageCommand(program, env, config?.image);
|
|
14343
14844
|
registerSpeechCommand(program, env, config?.speech);
|
|
14344
14845
|
registerVisionCommand(program, env);
|
|
14345
14846
|
registerModelsCommand(program, env);
|
|
14346
14847
|
registerGadgetCommand(program, env);
|
|
14848
|
+
registerInitCommand(program, env);
|
|
14347
14849
|
if (config) {
|
|
14348
14850
|
const customNames = getCustomCommandNames(config);
|
|
14349
14851
|
for (const name of customNames) {
|
|
14350
14852
|
const cmdConfig = config[name];
|
|
14351
|
-
registerCustomCommand(program, name, cmdConfig, env);
|
|
14853
|
+
registerCustomCommand(program, name, cmdConfig, env, config.subagents);
|
|
14352
14854
|
}
|
|
14353
14855
|
}
|
|
14354
14856
|
return program;
|