llm-exe 2.3.10 → 3.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +578 -185
- package/dist/index.d.ts +578 -185
- package/dist/index.js +3027 -863
- package/dist/index.mjs +3024 -863
- package/package.json +3 -4
- package/readme.md +2 -0
package/dist/index.js
CHANGED
|
@@ -46,6 +46,8 @@ __export(index_exports, {
|
|
|
46
46
|
CustomParser: () => CustomParser,
|
|
47
47
|
DefaultState: () => DefaultState,
|
|
48
48
|
DefaultStateItem: () => DefaultStateItem,
|
|
49
|
+
LLM_EXE_ERROR_SYMBOL: () => LLM_EXE_ERROR_SYMBOL,
|
|
50
|
+
LlmExeError: () => LlmExeError,
|
|
49
51
|
LlmExecutorOpenAiFunctions: () => LlmExecutorOpenAiFunctions,
|
|
50
52
|
LlmExecutorWithFunctions: () => LlmExecutorWithFunctions,
|
|
51
53
|
LlmNativeFunctionParser: () => LlmNativeFunctionParser,
|
|
@@ -66,6 +68,7 @@ __export(index_exports, {
|
|
|
66
68
|
createStateItem: () => createStateItem,
|
|
67
69
|
defineSchema: () => defineSchema,
|
|
68
70
|
guards: () => guards_exports,
|
|
71
|
+
isLlmExeError: () => isLlmExeError,
|
|
69
72
|
registerHelpers: () => registerHelpers,
|
|
70
73
|
registerPartials: () => registerPartials,
|
|
71
74
|
useExecutors: () => useExecutors,
|
|
@@ -118,6 +121,11 @@ var ExecutorExecutionMetadataState = class {
|
|
|
118
121
|
output: void 0,
|
|
119
122
|
errorMessage: void 0,
|
|
120
123
|
error: void 0,
|
|
124
|
+
errorCategory: void 0,
|
|
125
|
+
errorCode: void 0,
|
|
126
|
+
errorContext: void 0,
|
|
127
|
+
errorCause: void 0,
|
|
128
|
+
hookErrors: void 0,
|
|
121
129
|
metadata: null
|
|
122
130
|
});
|
|
123
131
|
if (items) {
|
|
@@ -145,6 +153,11 @@ var ExecutorExecutionMetadataState = class {
|
|
|
145
153
|
output: __privateGet(this, _state).output,
|
|
146
154
|
errorMessage: __privateGet(this, _state).errorMessage,
|
|
147
155
|
error: __privateGet(this, _state).error,
|
|
156
|
+
errorCategory: __privateGet(this, _state).errorCategory,
|
|
157
|
+
errorCode: __privateGet(this, _state).errorCode,
|
|
158
|
+
errorContext: __privateGet(this, _state).errorContext,
|
|
159
|
+
errorCause: __privateGet(this, _state).errorCause,
|
|
160
|
+
hookErrors: __privateGet(this, _state).hookErrors,
|
|
148
161
|
metadata: __privateGet(this, _state).metadata
|
|
149
162
|
});
|
|
150
163
|
}
|
|
@@ -159,6 +172,653 @@ var hookOnComplete = `onComplete`;
|
|
|
159
172
|
var hookOnError = `onError`;
|
|
160
173
|
var hookOnSuccess = `onSuccess`;
|
|
161
174
|
|
|
175
|
+
// src/errors/knownCodes.ts
|
|
176
|
+
var ALL_CODES = [
|
|
177
|
+
"configuration.missing_provider",
|
|
178
|
+
"configuration.invalid_provider",
|
|
179
|
+
"configuration.missing_env",
|
|
180
|
+
"configuration.missing_option",
|
|
181
|
+
"configuration.invalid_headers",
|
|
182
|
+
"parser.invalid_type",
|
|
183
|
+
"parser.invalid_input",
|
|
184
|
+
"parser.parse_failed",
|
|
185
|
+
"parser.schema_validation_failed",
|
|
186
|
+
"prompt.missing_input",
|
|
187
|
+
"prompt.invalid_messages",
|
|
188
|
+
"prompt.missing_template_variable",
|
|
189
|
+
"llm.provider_http_error",
|
|
190
|
+
"llm.provider_rate_limited",
|
|
191
|
+
"llm.provider_auth_failed",
|
|
192
|
+
"llm.provider_invalid_request",
|
|
193
|
+
"llm.provider_unavailable",
|
|
194
|
+
"llm.invalid_response_shape",
|
|
195
|
+
"llm.invalid_jsonl_response",
|
|
196
|
+
"embedding.provider_http_error",
|
|
197
|
+
"embedding.provider_rate_limited",
|
|
198
|
+
"embedding.provider_auth_failed",
|
|
199
|
+
"embedding.provider_invalid_request",
|
|
200
|
+
"embedding.provider_unavailable",
|
|
201
|
+
"embedding.missing_provider",
|
|
202
|
+
"embedding.invalid_provider",
|
|
203
|
+
"embedding.unsupported_dimensions",
|
|
204
|
+
"embedding.invalid_response_shape",
|
|
205
|
+
"executor.missing_prompt",
|
|
206
|
+
"executor.hook_limit_reached",
|
|
207
|
+
"executor.hook_failed",
|
|
208
|
+
"callable.invalid_handler",
|
|
209
|
+
"callable.handler_not_found",
|
|
210
|
+
"callable.validation_failed",
|
|
211
|
+
"template.invalid_helper_arguments",
|
|
212
|
+
"state.invalid_arguments",
|
|
213
|
+
"auth.aws_signing_input_missing",
|
|
214
|
+
"request.invalid_url",
|
|
215
|
+
"request.http_error",
|
|
216
|
+
"internal.invariant_failed",
|
|
217
|
+
"unknown.unclassified"
|
|
218
|
+
];
|
|
219
|
+
var KNOWN_ERROR_CODES = new Set(ALL_CODES);
|
|
220
|
+
|
|
221
|
+
// src/errors/serialize.ts
|
|
222
|
+
var MAX_VALUE_DEPTH = 5;
|
|
223
|
+
var MAX_CAUSE_DEPTH = 5;
|
|
224
|
+
var CIRCULAR = "[Circular]";
|
|
225
|
+
var SYMBOL = Symbol.for("llm-exe.error");
|
|
226
|
+
function isLlmExeErrorLike(value) {
|
|
227
|
+
if (!value || typeof value !== "object") return false;
|
|
228
|
+
return value[SYMBOL] === true || value.isLlmExeError === true;
|
|
229
|
+
}
|
|
230
|
+
function isErrorLike(value) {
|
|
231
|
+
if (value instanceof Error) return true;
|
|
232
|
+
if (!value || typeof value !== "object") return false;
|
|
233
|
+
const v = value;
|
|
234
|
+
return typeof v.message === "string" && typeof v.name === "string";
|
|
235
|
+
}
|
|
236
|
+
function isResponseLike(value) {
|
|
237
|
+
if (!value || typeof value !== "object") return false;
|
|
238
|
+
if (typeof Response !== "undefined" && value instanceof Response) return true;
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
function describeOpaque(value) {
|
|
242
|
+
const tag = Object.prototype.toString.call(value).slice(8, -1);
|
|
243
|
+
if (tag === "Object") return "[object Object]";
|
|
244
|
+
return `[object ${tag}]`;
|
|
245
|
+
}
|
|
246
|
+
function safeValue(value, seen, depth) {
|
|
247
|
+
if (value === null) return null;
|
|
248
|
+
if (value === void 0) return null;
|
|
249
|
+
const t = typeof value;
|
|
250
|
+
if (t === "string") return value;
|
|
251
|
+
if (t === "boolean") return value;
|
|
252
|
+
if (t === "number") {
|
|
253
|
+
const n = value;
|
|
254
|
+
return Number.isFinite(n) ? n : null;
|
|
255
|
+
}
|
|
256
|
+
if (t === "bigint") return value.toString();
|
|
257
|
+
if (t === "symbol") return String(value);
|
|
258
|
+
if (t === "function") {
|
|
259
|
+
const name = value.name;
|
|
260
|
+
return name ? `[Function ${name}]` : "[Function]";
|
|
261
|
+
}
|
|
262
|
+
if (depth >= MAX_VALUE_DEPTH) {
|
|
263
|
+
return describeOpaque(value);
|
|
264
|
+
}
|
|
265
|
+
if (seen.has(value)) return CIRCULAR;
|
|
266
|
+
seen.add(value);
|
|
267
|
+
try {
|
|
268
|
+
if (Array.isArray(value)) {
|
|
269
|
+
const arr = [];
|
|
270
|
+
for (let i = 0; i < value.length; i++) {
|
|
271
|
+
arr.push(safeValue(value[i], seen, depth + 1));
|
|
272
|
+
}
|
|
273
|
+
return arr;
|
|
274
|
+
}
|
|
275
|
+
if (value instanceof Date) {
|
|
276
|
+
const ts = value.getTime();
|
|
277
|
+
return Number.isFinite(ts) ? new Date(ts).toISOString() : null;
|
|
278
|
+
}
|
|
279
|
+
if (typeof Buffer !== "undefined" && Buffer.isBuffer && Buffer.isBuffer(value)) {
|
|
280
|
+
return `[Buffer length=${value.length}]`;
|
|
281
|
+
}
|
|
282
|
+
if (value instanceof Map || value instanceof Set || value instanceof WeakMap || value instanceof WeakSet) {
|
|
283
|
+
return describeOpaque(value);
|
|
284
|
+
}
|
|
285
|
+
if (isResponseLike(value)) {
|
|
286
|
+
return {
|
|
287
|
+
name: "Response",
|
|
288
|
+
status: value.status,
|
|
289
|
+
statusText: value.statusText ?? "",
|
|
290
|
+
url: value.url ?? ""
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
const proto = Object.getPrototypeOf(value);
|
|
294
|
+
if (proto !== null && proto !== Object.prototype) {
|
|
295
|
+
const ctor = value.constructor;
|
|
296
|
+
if (ctor && ctor.name && ctor.name !== "Object") {
|
|
297
|
+
const out2 = {};
|
|
298
|
+
for (const key of Object.keys(value)) {
|
|
299
|
+
const v = value[key];
|
|
300
|
+
if (v === void 0) continue;
|
|
301
|
+
out2[key] = safeValue(v, seen, depth + 1);
|
|
302
|
+
}
|
|
303
|
+
return Object.keys(out2).length > 0 ? out2 : describeOpaque(value);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
const out = {};
|
|
307
|
+
for (const key of Object.keys(value)) {
|
|
308
|
+
const v = value[key];
|
|
309
|
+
if (v === void 0) continue;
|
|
310
|
+
out[key] = safeValue(v, seen, depth + 1);
|
|
311
|
+
}
|
|
312
|
+
return out;
|
|
313
|
+
} finally {
|
|
314
|
+
seen.delete(value);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
function freshSafeValue(value) {
|
|
318
|
+
return safeValue(value, /* @__PURE__ */ new WeakSet(), 0);
|
|
319
|
+
}
|
|
320
|
+
function serializeOne(error, errorSeen, causeDepth, options) {
|
|
321
|
+
if (error === null || error === void 0) return null;
|
|
322
|
+
if (typeof error !== "object") return freshSafeValue(error);
|
|
323
|
+
if (errorSeen.has(error)) return CIRCULAR;
|
|
324
|
+
errorSeen.add(error);
|
|
325
|
+
try {
|
|
326
|
+
if (isLlmExeErrorLike(error)) {
|
|
327
|
+
const e = error;
|
|
328
|
+
const out = {
|
|
329
|
+
name: "LlmExeError",
|
|
330
|
+
message: typeof e.message === "string" ? e.message : "",
|
|
331
|
+
category: typeof e.category === "string" ? e.category : "unknown",
|
|
332
|
+
code: typeof e.code === "string" ? e.code : "unknown.unclassified"
|
|
333
|
+
};
|
|
334
|
+
if (e.context !== void 0) {
|
|
335
|
+
out.context = freshSafeValue(e.context);
|
|
336
|
+
}
|
|
337
|
+
if (options.includeStack && typeof e.stack === "string") {
|
|
338
|
+
out.stack = e.stack;
|
|
339
|
+
}
|
|
340
|
+
if (e.cause !== void 0) {
|
|
341
|
+
if (causeDepth + 1 >= MAX_CAUSE_DEPTH) {
|
|
342
|
+
out.cause = { truncated: true };
|
|
343
|
+
} else {
|
|
344
|
+
out.cause = serializeOne(e.cause, errorSeen, causeDepth + 1, options);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
return out;
|
|
348
|
+
}
|
|
349
|
+
if (isResponseLike(error)) {
|
|
350
|
+
return {
|
|
351
|
+
name: "Response",
|
|
352
|
+
status: error.status,
|
|
353
|
+
statusText: error.statusText ?? "",
|
|
354
|
+
url: error.url ?? ""
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
if (isErrorLike(error)) {
|
|
358
|
+
const e = error;
|
|
359
|
+
const out = {
|
|
360
|
+
name: typeof e.name === "string" && e.name ? e.name : "Error",
|
|
361
|
+
message: typeof e.message === "string" ? e.message : ""
|
|
362
|
+
};
|
|
363
|
+
if (options.includeStack && typeof e.stack === "string") {
|
|
364
|
+
out.stack = e.stack;
|
|
365
|
+
}
|
|
366
|
+
if (e.cause !== void 0) {
|
|
367
|
+
if (causeDepth + 1 >= MAX_CAUSE_DEPTH) {
|
|
368
|
+
out.cause = { truncated: true };
|
|
369
|
+
} else {
|
|
370
|
+
out.cause = serializeOne(e.cause, errorSeen, causeDepth + 1, options);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
return out;
|
|
374
|
+
}
|
|
375
|
+
return freshSafeValue(error);
|
|
376
|
+
} finally {
|
|
377
|
+
errorSeen.delete(error);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
function serializeLlmExeError(error, options) {
|
|
381
|
+
return serializeOne(error, /* @__PURE__ */ new WeakSet(), 0, options ?? {});
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// src/errors/LlmExeError.ts
|
|
385
|
+
var LLM_EXE_ERROR_SYMBOL = Symbol.for("llm-exe.error");
|
|
386
|
+
function deriveCategory(code) {
|
|
387
|
+
if (typeof code !== "string") return void 0;
|
|
388
|
+
if (!KNOWN_ERROR_CODES.has(code)) return void 0;
|
|
389
|
+
const dot = code.indexOf(".");
|
|
390
|
+
return code.slice(0, dot);
|
|
391
|
+
}
|
|
392
|
+
var LlmExeError = class _LlmExeError extends Error {
|
|
393
|
+
constructor(message, options) {
|
|
394
|
+
super(message);
|
|
395
|
+
__publicField(this, "category");
|
|
396
|
+
__publicField(this, "code");
|
|
397
|
+
__publicField(this, "context");
|
|
398
|
+
Object.defineProperties(this, {
|
|
399
|
+
name: {
|
|
400
|
+
value: "LlmExeError",
|
|
401
|
+
configurable: true,
|
|
402
|
+
writable: false,
|
|
403
|
+
enumerable: false
|
|
404
|
+
},
|
|
405
|
+
isLlmExeError: {
|
|
406
|
+
value: true,
|
|
407
|
+
configurable: false,
|
|
408
|
+
writable: false,
|
|
409
|
+
enumerable: false
|
|
410
|
+
},
|
|
411
|
+
[LLM_EXE_ERROR_SYMBOL]: {
|
|
412
|
+
value: true,
|
|
413
|
+
configurable: false,
|
|
414
|
+
writable: false,
|
|
415
|
+
enumerable: false
|
|
416
|
+
}
|
|
417
|
+
});
|
|
418
|
+
const providedCode = options ? options.code : void 0;
|
|
419
|
+
const category = deriveCategory(providedCode);
|
|
420
|
+
if (!category) {
|
|
421
|
+
this.code = "internal.invariant_failed";
|
|
422
|
+
this.category = "internal";
|
|
423
|
+
this.context = {
|
|
424
|
+
invariant: "invalid_error_code",
|
|
425
|
+
received: providedCode
|
|
426
|
+
};
|
|
427
|
+
} else {
|
|
428
|
+
this.code = providedCode;
|
|
429
|
+
this.category = category;
|
|
430
|
+
if (options.context !== void 0) {
|
|
431
|
+
this.context = options.context;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
if (options && options.cause !== void 0) {
|
|
435
|
+
Object.defineProperty(this, "cause", {
|
|
436
|
+
value: options.cause,
|
|
437
|
+
configurable: true,
|
|
438
|
+
writable: true,
|
|
439
|
+
enumerable: false
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
const capture = Error.captureStackTrace;
|
|
443
|
+
if (typeof capture === "function") {
|
|
444
|
+
capture(this, _LlmExeError);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
toJSON() {
|
|
448
|
+
return serializeLlmExeError(this);
|
|
449
|
+
}
|
|
450
|
+
};
|
|
451
|
+
Object.defineProperty(LlmExeError, "name", {
|
|
452
|
+
value: "LlmExeError",
|
|
453
|
+
configurable: true
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
// src/errors/isLlmExeError.ts
|
|
457
|
+
function isLlmExeError(error, code) {
|
|
458
|
+
if (!error || typeof error !== "object") return false;
|
|
459
|
+
const marked = error instanceof LlmExeError || error[LLM_EXE_ERROR_SYMBOL] === true || error.isLlmExeError === true;
|
|
460
|
+
if (!marked) return false;
|
|
461
|
+
if (code === void 0) return true;
|
|
462
|
+
const errorCode = error.code;
|
|
463
|
+
if (Array.isArray(code)) {
|
|
464
|
+
return code.includes(errorCode);
|
|
465
|
+
}
|
|
466
|
+
return errorCode === code;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// src/errors/format.ts
|
|
470
|
+
var DEFAULT_VALUE_MAX_LENGTH = 200;
|
|
471
|
+
var DEFAULT_LIST_MAX_ITEMS = 8;
|
|
472
|
+
function truncate(s, maxLength) {
|
|
473
|
+
if (s.length <= maxLength) return s;
|
|
474
|
+
return s.slice(0, Math.max(0, maxLength - 1)) + "\u2026";
|
|
475
|
+
}
|
|
476
|
+
function compactJson(value) {
|
|
477
|
+
try {
|
|
478
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
479
|
+
const replacer = (_key, val) => {
|
|
480
|
+
if (typeof val === "bigint") return val.toString();
|
|
481
|
+
if (typeof val === "function") return "[Function]";
|
|
482
|
+
if (typeof val === "symbol") return String(val);
|
|
483
|
+
if (val && typeof val === "object") {
|
|
484
|
+
if (seen.has(val)) return "[Circular]";
|
|
485
|
+
seen.add(val);
|
|
486
|
+
}
|
|
487
|
+
return val;
|
|
488
|
+
};
|
|
489
|
+
return JSON.stringify(value, replacer);
|
|
490
|
+
} catch {
|
|
491
|
+
return void 0;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
function formatErrorValue(value, options) {
|
|
495
|
+
const maxLength = options?.maxLength ?? DEFAULT_VALUE_MAX_LENGTH;
|
|
496
|
+
if (value === null) return "null";
|
|
497
|
+
if (value === void 0) return "undefined";
|
|
498
|
+
const t = typeof value;
|
|
499
|
+
if (t === "string") {
|
|
500
|
+
const s = value;
|
|
501
|
+
return `"${truncate(s, Math.max(2, maxLength - 2))}"`;
|
|
502
|
+
}
|
|
503
|
+
if (t === "number") {
|
|
504
|
+
const n = value;
|
|
505
|
+
return Number.isFinite(n) ? String(n) : "null";
|
|
506
|
+
}
|
|
507
|
+
if (t === "boolean") return value ? "true" : "false";
|
|
508
|
+
if (t === "bigint") return value.toString();
|
|
509
|
+
if (t === "symbol") return String(value);
|
|
510
|
+
if (t === "function") {
|
|
511
|
+
const name = value.name;
|
|
512
|
+
return name ? `[Function ${name}]` : "[Function]";
|
|
513
|
+
}
|
|
514
|
+
const json = compactJson(value);
|
|
515
|
+
if (json !== void 0) return truncate(json, maxLength);
|
|
516
|
+
const tag = Object.prototype.toString.call(value).slice(8, -1);
|
|
517
|
+
return `[object ${tag}]`;
|
|
518
|
+
}
|
|
519
|
+
function formatErrorList(values, options) {
|
|
520
|
+
const maxItems = options?.maxItems ?? DEFAULT_LIST_MAX_ITEMS;
|
|
521
|
+
const maxLength = options?.maxLength;
|
|
522
|
+
if (!values || values.length === 0) return "";
|
|
523
|
+
const limit = Math.min(values.length, maxItems);
|
|
524
|
+
const parts = [];
|
|
525
|
+
for (let i = 0; i < limit; i++) {
|
|
526
|
+
parts.push(formatErrorValue(values[i], maxLength ? { maxLength } : void 0));
|
|
527
|
+
}
|
|
528
|
+
if (values.length > limit) {
|
|
529
|
+
parts.push(`\u2026 (${values.length - limit} more)`);
|
|
530
|
+
}
|
|
531
|
+
return parts.join(", ");
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// src/errors/createLlmExeError.ts
|
|
535
|
+
var DOCS_BASE_URL = "https://llm-exe.com";
|
|
536
|
+
function resolveDefinitionValue(value, context) {
|
|
537
|
+
if (value === void 0) return void 0;
|
|
538
|
+
return typeof value === "function" ? value(context) : value;
|
|
539
|
+
}
|
|
540
|
+
function resolveDocsUrl(docsPath) {
|
|
541
|
+
if (/^https?:\/\//i.test(docsPath)) return docsPath;
|
|
542
|
+
return `${DOCS_BASE_URL}${docsPath.startsWith("/") ? "" : "/"}${docsPath}`;
|
|
543
|
+
}
|
|
544
|
+
function createLlmExeError(definition, context, options) {
|
|
545
|
+
const message = definition.message(context);
|
|
546
|
+
const resolution = resolveDefinitionValue(definition.resolution, context);
|
|
547
|
+
const docsPath = resolveDefinitionValue(definition.docsPath, context);
|
|
548
|
+
const docsUrl = docsPath ? resolveDocsUrl(docsPath) : void 0;
|
|
549
|
+
const mergedContext = {
|
|
550
|
+
...context,
|
|
551
|
+
...resolution !== void 0 ? { resolution } : null,
|
|
552
|
+
...docsPath !== void 0 ? { docsPath } : null,
|
|
553
|
+
...docsUrl !== void 0 ? { docsUrl } : null
|
|
554
|
+
};
|
|
555
|
+
return new LlmExeError(message, {
|
|
556
|
+
code: definition.code,
|
|
557
|
+
context: mergedContext,
|
|
558
|
+
cause: options?.cause
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// src/utils/modules/redactSecrets.ts
|
|
563
|
+
var TOKEN_MASK_REGEX = /\b(Bearer\s+[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+|Bearer\s+[A-Za-z0-9_-]{20,}|sk-ant-[A-Za-z0-9_-]{16,}|sk-[A-Za-z0-9]{20,}|AIza[0-9A-Za-z_-]{30,}|AKIA[A-Z0-9]{16}|[A-Za-z0-9]{32,})\b/g;
|
|
564
|
+
var FULL_REDACTION_PATTERNS = [
|
|
565
|
+
// Alternate auth schemes.
|
|
566
|
+
[/\b(Basic|Digest|AWS4-HMAC-SHA256)\s+[A-Za-z0-9+/=._-]+/g, "$1 [redacted]"],
|
|
567
|
+
// Header- or query-style key/value pairs. Preserves the original separator
|
|
568
|
+
// ("Authorization: ..." stays colon, "?token=..." stays equals).
|
|
569
|
+
[
|
|
570
|
+
/(authorization|proxy-authorization|cookie|set-cookie|x-api-key|x-amz-security-token|x-amz-signature|api[-_]?key|access[-_]?token|token|secret|password)(\s*[:=]\s*)[^\r\n,;&]+/gi,
|
|
571
|
+
"$1$2[redacted]"
|
|
572
|
+
],
|
|
573
|
+
// JSON-shaped fields.
|
|
574
|
+
[
|
|
575
|
+
/"(authorization|api[-_]?key|secret[-_]?key|access[-_]?key|secret|token|password|cookie|x-amz[a-z-]*)"\s*:\s*"[^"]*"/gi,
|
|
576
|
+
'"$1": "[redacted]"'
|
|
577
|
+
]
|
|
578
|
+
];
|
|
579
|
+
function maskToken(match) {
|
|
580
|
+
if (match.length <= 8) return match;
|
|
581
|
+
const prefix = match.substring(0, 4);
|
|
582
|
+
const suffix = match.substring(match.length - 4);
|
|
583
|
+
return `${prefix}${"*".repeat(match.length - 8)}${suffix}`;
|
|
584
|
+
}
|
|
585
|
+
function redactSecrets(input) {
|
|
586
|
+
let out = input.replace(TOKEN_MASK_REGEX, maskToken);
|
|
587
|
+
for (const [pattern, replacement] of FULL_REDACTION_PATTERNS) {
|
|
588
|
+
out = out.replace(pattern, replacement);
|
|
589
|
+
}
|
|
590
|
+
return out;
|
|
591
|
+
}
|
|
592
|
+
var maskApiKeys = redactSecrets;
|
|
593
|
+
var SECRET_URL_QUERY_KEYS = /* @__PURE__ */ new Set([
|
|
594
|
+
"key",
|
|
595
|
+
"api_key",
|
|
596
|
+
"apikey",
|
|
597
|
+
"token",
|
|
598
|
+
"access_token",
|
|
599
|
+
"refresh_token",
|
|
600
|
+
"id_token",
|
|
601
|
+
"secret",
|
|
602
|
+
"client_secret",
|
|
603
|
+
"password",
|
|
604
|
+
"x-amz-signature",
|
|
605
|
+
"x-amz-security-token",
|
|
606
|
+
"x-amz-credential",
|
|
607
|
+
"signature"
|
|
608
|
+
]);
|
|
609
|
+
function safeRequestUrl(url) {
|
|
610
|
+
if (typeof url !== "string" || !url) return url;
|
|
611
|
+
let working = url;
|
|
612
|
+
try {
|
|
613
|
+
const parsed = new URL(url);
|
|
614
|
+
for (const key of Array.from(parsed.searchParams.keys())) {
|
|
615
|
+
if (SECRET_URL_QUERY_KEYS.has(key.toLowerCase())) {
|
|
616
|
+
parsed.searchParams.set(key, "[redacted]");
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
working = parsed.toString();
|
|
620
|
+
} catch {
|
|
621
|
+
}
|
|
622
|
+
return redactSecrets(working);
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// src/errors/providerErrors.ts
|
|
626
|
+
var PROVIDER_MESSAGE_MAX_LENGTH = 240;
|
|
627
|
+
function safeProviderString(value, maxLength = PROVIDER_MESSAGE_MAX_LENGTH) {
|
|
628
|
+
if (typeof value !== "string" || value.length === 0) return void 0;
|
|
629
|
+
const scrubbed = redactSecrets(value);
|
|
630
|
+
return scrubbed.length > maxLength ? scrubbed.slice(0, maxLength) + "\u2026(truncated)" : scrubbed;
|
|
631
|
+
}
|
|
632
|
+
var SECRET_KEY_REGEX = /authorization|api[-_]?key|secret|token|password|cookie|set-cookie|x-amz/i;
|
|
633
|
+
var REDACTED = "[redacted]";
|
|
634
|
+
var DEFAULT_MAX_BODY_BYTES = 8192;
|
|
635
|
+
var DEFAULT_MAX_STRING_LENGTH = 2e3;
|
|
636
|
+
var MAX_SCRUB_DEPTH = 8;
|
|
637
|
+
var ALLOWED_RESPONSE_HEADERS = /* @__PURE__ */ new Set([
|
|
638
|
+
// Generic diagnostic headers
|
|
639
|
+
"content-type",
|
|
640
|
+
"retry-after",
|
|
641
|
+
// Request/correlation IDs
|
|
642
|
+
"request-id",
|
|
643
|
+
"x-request-id",
|
|
644
|
+
"x-amzn-requestid",
|
|
645
|
+
"x-amz-request-id",
|
|
646
|
+
"x-goog-request-id",
|
|
647
|
+
// OpenAI-style rate-limit headers
|
|
648
|
+
"x-ratelimit-limit-requests",
|
|
649
|
+
"x-ratelimit-remaining-requests",
|
|
650
|
+
"x-ratelimit-reset-requests",
|
|
651
|
+
"x-ratelimit-limit-tokens",
|
|
652
|
+
"x-ratelimit-remaining-tokens",
|
|
653
|
+
"x-ratelimit-reset-tokens",
|
|
654
|
+
// Anthropic-style rate-limit headers
|
|
655
|
+
"anthropic-ratelimit-requests-limit",
|
|
656
|
+
"anthropic-ratelimit-requests-remaining",
|
|
657
|
+
"anthropic-ratelimit-requests-reset",
|
|
658
|
+
"anthropic-ratelimit-tokens-limit",
|
|
659
|
+
"anthropic-ratelimit-tokens-remaining",
|
|
660
|
+
"anthropic-ratelimit-tokens-reset"
|
|
661
|
+
]);
|
|
662
|
+
function truncateString(value, max) {
|
|
663
|
+
if (value.length <= max) return value;
|
|
664
|
+
return value.slice(0, max) + "\u2026(truncated)";
|
|
665
|
+
}
|
|
666
|
+
function scrub(value, seen, depth, maxStringLength) {
|
|
667
|
+
if (value === null || value === void 0) return value;
|
|
668
|
+
const t = typeof value;
|
|
669
|
+
if (t === "string")
|
|
670
|
+
return redactSecrets(truncateString(value, maxStringLength));
|
|
671
|
+
if (t === "number" || t === "boolean") return value;
|
|
672
|
+
if (t === "bigint") return value.toString();
|
|
673
|
+
if (t === "symbol") return String(value);
|
|
674
|
+
if (t === "function") return "[Function]";
|
|
675
|
+
if (depth >= MAX_SCRUB_DEPTH) return "[deep]";
|
|
676
|
+
if (seen.has(value)) return "[Circular]";
|
|
677
|
+
seen.add(value);
|
|
678
|
+
try {
|
|
679
|
+
if (Array.isArray(value)) {
|
|
680
|
+
const arr = [];
|
|
681
|
+
for (let i = 0; i < value.length; i++) {
|
|
682
|
+
arr.push(scrub(value[i], seen, depth + 1, maxStringLength));
|
|
683
|
+
}
|
|
684
|
+
return arr;
|
|
685
|
+
}
|
|
686
|
+
const out = {};
|
|
687
|
+
for (const key of Object.keys(value)) {
|
|
688
|
+
if (SECRET_KEY_REGEX.test(key)) {
|
|
689
|
+
out[key] = REDACTED;
|
|
690
|
+
continue;
|
|
691
|
+
}
|
|
692
|
+
const v = value[key];
|
|
693
|
+
out[key] = scrub(v, seen, depth + 1, maxStringLength);
|
|
694
|
+
}
|
|
695
|
+
return out;
|
|
696
|
+
} finally {
|
|
697
|
+
seen.delete(value);
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
function safeProviderErrorBody(value, options) {
|
|
701
|
+
const maxStringLength = options?.maxStringLength ?? DEFAULT_MAX_STRING_LENGTH;
|
|
702
|
+
const maxBodyBytes = options?.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;
|
|
703
|
+
if (typeof value === "string") {
|
|
704
|
+
return redactSecrets(truncateString(value, maxBodyBytes));
|
|
705
|
+
}
|
|
706
|
+
return scrub(value, /* @__PURE__ */ new WeakSet(), 0, maxStringLength);
|
|
707
|
+
}
|
|
708
|
+
function safeResponseHeaders(headers) {
|
|
709
|
+
const out = {};
|
|
710
|
+
if (!headers) return out;
|
|
711
|
+
if (typeof headers.forEach === "function" && typeof headers.get === "function") {
|
|
712
|
+
headers.forEach((value, key) => {
|
|
713
|
+
const lower = key.toLowerCase();
|
|
714
|
+
if (ALLOWED_RESPONSE_HEADERS.has(lower) && typeof value === "string") {
|
|
715
|
+
out[lower] = value;
|
|
716
|
+
}
|
|
717
|
+
});
|
|
718
|
+
return out;
|
|
719
|
+
}
|
|
720
|
+
for (const key of Object.keys(headers)) {
|
|
721
|
+
const value = headers[key];
|
|
722
|
+
const lower = key.toLowerCase();
|
|
723
|
+
if (ALLOWED_RESPONSE_HEADERS.has(lower) && typeof value === "string") {
|
|
724
|
+
out[lower] = value;
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
return out;
|
|
728
|
+
}
|
|
729
|
+
function parseRetryAfter(value) {
|
|
730
|
+
if (!value) return void 0;
|
|
731
|
+
const trimmed = value.trim();
|
|
732
|
+
if (!trimmed) return void 0;
|
|
733
|
+
if (/^\d+(\.\d+)?$/.test(trimmed)) {
|
|
734
|
+
const seconds = Number(trimmed);
|
|
735
|
+
if (!Number.isFinite(seconds)) return void 0;
|
|
736
|
+
return Math.max(0, Math.round(seconds * 1e3));
|
|
737
|
+
}
|
|
738
|
+
const dateMs = Date.parse(trimmed);
|
|
739
|
+
if (Number.isFinite(dateMs)) {
|
|
740
|
+
return Math.max(0, dateMs - Date.now());
|
|
741
|
+
}
|
|
742
|
+
return void 0;
|
|
743
|
+
}
|
|
744
|
+
function readStringField(obj, key) {
|
|
745
|
+
if (!obj || typeof obj !== "object") return void 0;
|
|
746
|
+
const v = obj[key];
|
|
747
|
+
return typeof v === "string" ? v : void 0;
|
|
748
|
+
}
|
|
749
|
+
function readStringOrNumberField(obj, key) {
|
|
750
|
+
if (!obj || typeof obj !== "object") return void 0;
|
|
751
|
+
const v = obj[key];
|
|
752
|
+
if (typeof v === "string") return v;
|
|
753
|
+
if (typeof v === "number" && Number.isFinite(v)) return String(v);
|
|
754
|
+
return void 0;
|
|
755
|
+
}
|
|
756
|
+
var parseProviderErrorGeneric = (input) => {
|
|
757
|
+
const status = input.status ?? input.response?.status;
|
|
758
|
+
const statusText = input.statusText ?? input.response?.statusText;
|
|
759
|
+
const headers = input.headers ?? {};
|
|
760
|
+
let message;
|
|
761
|
+
let providerType;
|
|
762
|
+
let providerCode;
|
|
763
|
+
const body = input.bodyJson;
|
|
764
|
+
if (body && typeof body === "object") {
|
|
765
|
+
const root = body;
|
|
766
|
+
const errVal = root.error;
|
|
767
|
+
const errObj = errVal && typeof errVal === "object" ? errVal : void 0;
|
|
768
|
+
message = readStringField(errObj, "message") ?? readStringField(root, "message") ?? (typeof errVal === "string" ? errVal : void 0);
|
|
769
|
+
providerType = readStringField(errObj, "type") ?? readStringField(root, "type") ?? // Bedrock-style: top-level "__type" carries the exception class.
|
|
770
|
+
readStringField(root, "__type") ?? readStringField(errObj, "status");
|
|
771
|
+
providerCode = // Accept numeric codes too (Gemini emits error.code: 400 as a number).
|
|
772
|
+
readStringOrNumberField(errObj, "code") ?? readStringOrNumberField(root, "code") ?? readStringField(errObj, "status");
|
|
773
|
+
}
|
|
774
|
+
if (!message && typeof input.bodyText === "string" && input.bodyText.length > 0) {
|
|
775
|
+
message = input.bodyText;
|
|
776
|
+
}
|
|
777
|
+
const retryAfterRaw = headers["retry-after"] ?? headers["Retry-After"];
|
|
778
|
+
const retryAfterMs = parseRetryAfter(retryAfterRaw);
|
|
779
|
+
let retryable;
|
|
780
|
+
if (typeof status === "number") {
|
|
781
|
+
retryable = status === 408 || status === 429 || status >= 500 && status < 600;
|
|
782
|
+
}
|
|
783
|
+
return {
|
|
784
|
+
message: safeProviderString(message),
|
|
785
|
+
providerType: safeProviderString(providerType),
|
|
786
|
+
providerCode: safeProviderString(providerCode),
|
|
787
|
+
status,
|
|
788
|
+
statusText,
|
|
789
|
+
retryable,
|
|
790
|
+
retryAfterMs
|
|
791
|
+
};
|
|
792
|
+
};
|
|
793
|
+
function statusToLlmProviderCode(status) {
|
|
794
|
+
if (status === 429) return "llm.provider_rate_limited";
|
|
795
|
+
if (status === 401 || status === 403) return "llm.provider_auth_failed";
|
|
796
|
+
if (status === 400 || status === 422) return "llm.provider_invalid_request";
|
|
797
|
+
if (status === 408 || status >= 500 && status < 600)
|
|
798
|
+
return "llm.provider_unavailable";
|
|
799
|
+
return "llm.provider_http_error";
|
|
800
|
+
}
|
|
801
|
+
function statusToEmbeddingProviderCode(status) {
|
|
802
|
+
if (status === 429) return "embedding.provider_rate_limited";
|
|
803
|
+
if (status === 401 || status === 403) return "embedding.provider_auth_failed";
|
|
804
|
+
if (status === 400 || status === 422)
|
|
805
|
+
return "embedding.provider_invalid_request";
|
|
806
|
+
if (status === 408 || status >= 500 && status < 600)
|
|
807
|
+
return "embedding.provider_unavailable";
|
|
808
|
+
return "embedding.provider_http_error";
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
// src/errors/getErrorMetadata.ts
|
|
812
|
+
function getErrorMetadata(error) {
|
|
813
|
+
if (!isLlmExeError(error)) return {};
|
|
814
|
+
return {
|
|
815
|
+
errorCategory: error.category,
|
|
816
|
+
errorCode: error.code,
|
|
817
|
+
errorContext: error.context,
|
|
818
|
+
errorCause: error.cause
|
|
819
|
+
};
|
|
820
|
+
}
|
|
821
|
+
|
|
162
822
|
// src/executor/_base.ts
|
|
163
823
|
var BaseExecutor = class {
|
|
164
824
|
constructor(name, type, options) {
|
|
@@ -207,12 +867,41 @@ var BaseExecutor = class {
|
|
|
207
867
|
}
|
|
208
868
|
}
|
|
209
869
|
/**
|
|
870
|
+
* Build a per-call execution context snapshot. Captures the current
|
|
871
|
+
* execution metadata so the snapshot reflects state at the time it was
|
|
872
|
+
* taken (e.g. `handlerInput` becomes available after `getHandlerInput`).
|
|
873
|
+
*/
|
|
874
|
+
snapshotContext(execution) {
|
|
875
|
+
return {
|
|
876
|
+
traceId: this.getTraceId() ?? void 0,
|
|
877
|
+
executor: this.getMetadata(),
|
|
878
|
+
execution,
|
|
879
|
+
attributes: {}
|
|
880
|
+
};
|
|
881
|
+
}
|
|
882
|
+
/**
|
|
883
|
+
*
|
|
884
|
+
* Used to filter the input of the handler.
|
|
885
|
+
*
|
|
886
|
+
* Throws a `TypeError` if `_input` is `null` or `undefined`. The declared
|
|
887
|
+
* input type is `I extends PlainObject`; omitting input or passing an
|
|
888
|
+
* explicit `null` is a contract violation with no valid coercion, so we
|
|
889
|
+
* surface it loudly rather than silently wrapping it.
|
|
890
|
+
*
|
|
891
|
+
* Non-object inputs (strings, numbers, arrays) are intentionally coerced
|
|
892
|
+
* to `{ input: value }` via {@link ensureInputIsObject}. This preserves the
|
|
893
|
+
* convenience pattern used by tool/function callables, which forward raw
|
|
894
|
+
* string arguments into an executor.
|
|
210
895
|
*
|
|
211
|
-
* Used to filter the input of the handler
|
|
212
896
|
* @param _input
|
|
213
897
|
* @returns original input formatted for handler
|
|
214
898
|
*/
|
|
215
899
|
async getHandlerInput(_input, _metadata, _options) {
|
|
900
|
+
if (_input === null || typeof _input === "undefined") {
|
|
901
|
+
throw new TypeError(
|
|
902
|
+
`[llm-exe] Executor "${this.name}" received null or undefined as input. execute() expects an object matching the prompt's input type.`
|
|
903
|
+
);
|
|
904
|
+
}
|
|
216
905
|
return ensureInputIsObject(_input);
|
|
217
906
|
}
|
|
218
907
|
/**
|
|
@@ -221,7 +910,7 @@ var BaseExecutor = class {
|
|
|
221
910
|
* @param _input
|
|
222
911
|
* @returns output O
|
|
223
912
|
*/
|
|
224
|
-
getHandlerOutput(out, _metadata, _options) {
|
|
913
|
+
getHandlerOutput(out, _metadata, _options, _context) {
|
|
225
914
|
return out;
|
|
226
915
|
}
|
|
227
916
|
/**
|
|
@@ -243,25 +932,45 @@ var BaseExecutor = class {
|
|
|
243
932
|
_options
|
|
244
933
|
);
|
|
245
934
|
_metadata.setItem({ handlerInput: input });
|
|
246
|
-
let result = await this.handler(
|
|
935
|
+
let result = await this.handler(
|
|
936
|
+
input,
|
|
937
|
+
_options,
|
|
938
|
+
this.snapshotContext(_metadata.asPlainObject())
|
|
939
|
+
);
|
|
247
940
|
_metadata.setItem({ handlerOutput: result });
|
|
248
941
|
const output = this.getHandlerOutput(
|
|
249
942
|
result,
|
|
250
943
|
_metadata.asPlainObject(),
|
|
251
|
-
_options
|
|
944
|
+
_options,
|
|
945
|
+
this.snapshotContext(_metadata.asPlainObject())
|
|
252
946
|
);
|
|
253
947
|
_metadata.setItem({ output });
|
|
254
|
-
this.
|
|
948
|
+
this.collectHookErrors(
|
|
949
|
+
this.runHook("onSuccess", _metadata.asPlainObject()),
|
|
950
|
+
_metadata
|
|
951
|
+
);
|
|
255
952
|
return output;
|
|
256
953
|
} catch (error) {
|
|
257
|
-
_metadata.setItem({
|
|
258
|
-
|
|
954
|
+
_metadata.setItem({
|
|
955
|
+
error,
|
|
956
|
+
errorMessage: error.message,
|
|
957
|
+
...getErrorMetadata(error)
|
|
958
|
+
});
|
|
959
|
+
this.collectHookErrors(
|
|
960
|
+
this.runHook("onError", _metadata.asPlainObject()),
|
|
961
|
+
_metadata
|
|
962
|
+
);
|
|
259
963
|
throw error;
|
|
260
964
|
} finally {
|
|
261
965
|
_metadata.setItem({ end: (/* @__PURE__ */ new Date()).getTime() });
|
|
262
966
|
this.runHook("onComplete", _metadata.asPlainObject());
|
|
263
967
|
}
|
|
264
968
|
}
|
|
969
|
+
collectHookErrors(fresh, state) {
|
|
970
|
+
if (fresh.length === 0) return;
|
|
971
|
+
const existing = state.asPlainObject().hookErrors ?? [];
|
|
972
|
+
state.setItem({ hookErrors: [...existing, ...fresh] });
|
|
973
|
+
}
|
|
265
974
|
metadata() {
|
|
266
975
|
return {};
|
|
267
976
|
}
|
|
@@ -278,18 +987,23 @@ var BaseExecutor = class {
|
|
|
278
987
|
}
|
|
279
988
|
runHook(hook, _metadata) {
|
|
280
989
|
const { [hook]: hooks = [] } = pick(this.hooks, this.allowedHooks);
|
|
990
|
+
const errors = [];
|
|
281
991
|
for (const hookFn of [...hooks]) {
|
|
282
992
|
if (typeof hookFn === "function") {
|
|
283
993
|
try {
|
|
284
994
|
hookFn(_metadata, this.getMetadata());
|
|
285
995
|
} catch (error) {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
996
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
997
|
+
errors.push({
|
|
998
|
+
hook: String(hook),
|
|
999
|
+
error,
|
|
1000
|
+
errorMessage: message,
|
|
1001
|
+
...getErrorMetadata(error)
|
|
1002
|
+
});
|
|
290
1003
|
}
|
|
291
1004
|
}
|
|
292
1005
|
}
|
|
1006
|
+
return errors;
|
|
293
1007
|
}
|
|
294
1008
|
setHooks(hooks = {}) {
|
|
295
1009
|
const hookKeys = Object.keys(hooks);
|
|
@@ -302,8 +1016,19 @@ var BaseExecutor = class {
|
|
|
302
1016
|
for (const hook of _hooks) {
|
|
303
1017
|
if (hook && typeof hook === "function" && !this.hooks[hookKey].find((h) => h === hook)) {
|
|
304
1018
|
if (this.hooks[hookKey].length >= this.maxHooksPerEvent) {
|
|
305
|
-
throw new
|
|
306
|
-
`Maximum number of hooks (${this.maxHooksPerEvent}) reached for event "${String(hookKey)}". Consider removing unused hooks or increasing the limit
|
|
1019
|
+
throw new LlmExeError(
|
|
1020
|
+
`Maximum number of hooks (${this.maxHooksPerEvent}) reached for event "${String(hookKey)}". Consider removing unused hooks or increasing the limit.`,
|
|
1021
|
+
{
|
|
1022
|
+
code: "executor.hook_limit_reached",
|
|
1023
|
+
context: {
|
|
1024
|
+
operation: "BaseExecutor.setHooks",
|
|
1025
|
+
executorName: this.name,
|
|
1026
|
+
executorType: this.type,
|
|
1027
|
+
hook: String(hookKey),
|
|
1028
|
+
hookCount: this.hooks[hookKey].length,
|
|
1029
|
+
maxHooksPerEvent: this.maxHooksPerEvent
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
307
1032
|
);
|
|
308
1033
|
}
|
|
309
1034
|
this.hooks[hookKey].push(hook);
|
|
@@ -334,13 +1059,27 @@ var BaseExecutor = class {
|
|
|
334
1059
|
once(eventName, fn) {
|
|
335
1060
|
if (typeof fn !== "function") return this;
|
|
336
1061
|
if (this.hooks[eventName] && this.hooks[eventName].length >= this.maxHooksPerEvent) {
|
|
337
|
-
throw new
|
|
338
|
-
`Maximum number of hooks (${this.maxHooksPerEvent}) reached for event "${String(eventName)}". Consider removing unused hooks or increasing the limit
|
|
1062
|
+
throw new LlmExeError(
|
|
1063
|
+
`Maximum number of hooks (${this.maxHooksPerEvent}) reached for event "${String(eventName)}". Consider removing unused hooks or increasing the limit.`,
|
|
1064
|
+
{
|
|
1065
|
+
code: "executor.hook_limit_reached",
|
|
1066
|
+
context: {
|
|
1067
|
+
operation: "BaseExecutor.once",
|
|
1068
|
+
executorName: this.name,
|
|
1069
|
+
executorType: this.type,
|
|
1070
|
+
hook: String(eventName),
|
|
1071
|
+
hookCount: this.hooks[eventName].length,
|
|
1072
|
+
maxHooksPerEvent: this.maxHooksPerEvent
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
339
1075
|
);
|
|
340
1076
|
}
|
|
341
1077
|
const onceWrapper = (...args) => {
|
|
342
|
-
|
|
343
|
-
|
|
1078
|
+
try {
|
|
1079
|
+
fn(...args);
|
|
1080
|
+
} finally {
|
|
1081
|
+
this.off(eventName, onceWrapper);
|
|
1082
|
+
}
|
|
344
1083
|
};
|
|
345
1084
|
if (!this.hooks[eventName]) {
|
|
346
1085
|
this.hooks[eventName] = [];
|
|
@@ -420,25 +1159,16 @@ var BaseParser = class {
|
|
|
420
1159
|
/**
|
|
421
1160
|
* Create a new BaseParser.
|
|
422
1161
|
* @param name - The name of the parser.
|
|
423
|
-
* @param
|
|
1162
|
+
* @param target - Whether the parser consumes text or function-call output.
|
|
424
1163
|
*/
|
|
425
|
-
constructor(name,
|
|
1164
|
+
constructor(name, target = "text") {
|
|
426
1165
|
__publicField(this, "name");
|
|
427
|
-
__publicField(this, "options");
|
|
428
1166
|
__publicField(this, "target", "text");
|
|
429
1167
|
this.name = name;
|
|
430
1168
|
this.target = target;
|
|
431
|
-
if (options) {
|
|
432
|
-
this.options = options;
|
|
433
|
-
}
|
|
434
1169
|
}
|
|
435
1170
|
};
|
|
436
1171
|
var BaseParserWithJson = class extends BaseParser {
|
|
437
|
-
/**
|
|
438
|
-
* Create a new BaseParser.
|
|
439
|
-
* @param name - The name of the parser.
|
|
440
|
-
* @param options - options
|
|
441
|
-
*/
|
|
442
1172
|
constructor(name, options) {
|
|
443
1173
|
super(name);
|
|
444
1174
|
__publicField(this, "schema");
|
|
@@ -451,212 +1181,285 @@ var BaseParserWithJson = class extends BaseParser {
|
|
|
451
1181
|
}
|
|
452
1182
|
};
|
|
453
1183
|
|
|
454
|
-
// src/utils/modules/assert.ts
|
|
455
|
-
function assert(condition, message) {
|
|
456
|
-
if (condition === void 0 || condition === null || condition === false) {
|
|
457
|
-
if (typeof message === "string") {
|
|
458
|
-
throw new Error(message);
|
|
459
|
-
} else if (message instanceof Error) {
|
|
460
|
-
throw message;
|
|
461
|
-
} else {
|
|
462
|
-
throw new Error(`Assertion error`);
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
// src/utils/guards.ts
|
|
468
|
-
var guards_exports = {};
|
|
469
|
-
__export(guards_exports, {
|
|
470
|
-
hasFunctionCall: () => hasFunctionCall,
|
|
471
|
-
hasToolCall: () => hasToolCall,
|
|
472
|
-
isAssistantMessage: () => isAssistantMessage,
|
|
473
|
-
isFunctionCall: () => isFunctionCall,
|
|
474
|
-
isOutputResult: () => isOutputResult,
|
|
475
|
-
isOutputResultContentText: () => isOutputResultContentText,
|
|
476
|
-
isSystemMessage: () => isSystemMessage,
|
|
477
|
-
isToolCall: () => isToolCall,
|
|
478
|
-
isUserMessage: () => isUserMessage
|
|
479
|
-
});
|
|
480
|
-
function isOutputResult(obj) {
|
|
481
|
-
return !!(obj && typeof obj === "object" && "id" in obj && "stopReason" in obj && "content" in obj && Array.isArray(obj.content));
|
|
482
|
-
}
|
|
483
|
-
function isOutputResultContentText(obj) {
|
|
484
|
-
return !!(obj && typeof obj === "object" && "text" in obj && "type" in obj && obj.type === "text" && typeof obj.text === "string");
|
|
485
|
-
}
|
|
486
|
-
function isFunctionCall(result) {
|
|
487
|
-
return !!(result && typeof result === "object" && "functionId" in result && "type" in result && result.type === "function_use");
|
|
488
|
-
}
|
|
489
|
-
function isToolCall(result) {
|
|
490
|
-
return isFunctionCall(result);
|
|
491
|
-
}
|
|
492
|
-
function hasFunctionCall(results) {
|
|
493
|
-
return !!(results && Array.isArray(results) && results.some(isToolCall));
|
|
494
|
-
}
|
|
495
|
-
function hasToolCall(results) {
|
|
496
|
-
return hasFunctionCall(results);
|
|
497
|
-
}
|
|
498
|
-
function isUserMessage(message) {
|
|
499
|
-
return message.role === "user";
|
|
500
|
-
}
|
|
501
|
-
function isAssistantMessage(message) {
|
|
502
|
-
return message.role === "assistant" || message.role === "model";
|
|
503
|
-
}
|
|
504
|
-
function isSystemMessage(message) {
|
|
505
|
-
return message.role === "system";
|
|
506
|
-
}
|
|
507
|
-
|
|
508
1184
|
// src/parser/parsers/StringParser.ts
|
|
509
1185
|
var StringParser = class extends BaseParser {
|
|
510
|
-
constructor(
|
|
511
|
-
super("string"
|
|
1186
|
+
constructor() {
|
|
1187
|
+
super("string");
|
|
512
1188
|
}
|
|
513
|
-
parse(text,
|
|
514
|
-
if (
|
|
515
|
-
|
|
1189
|
+
parse(text, _attributes) {
|
|
1190
|
+
if (typeof text !== "string") {
|
|
1191
|
+
throw new LlmExeError(
|
|
1192
|
+
`Invalid input. Expected string. Received ${text === null ? "null" : Array.isArray(text) ? "array" : typeof text}.`,
|
|
1193
|
+
{
|
|
1194
|
+
code: "parser.invalid_input",
|
|
1195
|
+
context: {
|
|
1196
|
+
operation: "StringParser.parse",
|
|
1197
|
+
parser: "string",
|
|
1198
|
+
reason: "invalid_input_type",
|
|
1199
|
+
expected: "string",
|
|
1200
|
+
received: text === null ? "null" : Array.isArray(text) ? "array" : typeof text
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
);
|
|
516
1204
|
}
|
|
517
|
-
|
|
518
|
-
typeof text === "string",
|
|
519
|
-
`Invalid input. Expected string. Received ${typeof text}.`
|
|
520
|
-
);
|
|
521
|
-
const parsed = text.toString();
|
|
522
|
-
return parsed;
|
|
1205
|
+
return text;
|
|
523
1206
|
}
|
|
524
1207
|
};
|
|
525
1208
|
|
|
526
|
-
// src/
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
assert(
|
|
533
|
-
typeof text === "string",
|
|
534
|
-
`Invalid input. Expected string. Received ${typeof text}.`
|
|
535
|
-
);
|
|
536
|
-
const clean = text.toLowerCase().trim();
|
|
537
|
-
if (clean === "true" || clean === "yes" || clean === "y" || clean === "1") {
|
|
538
|
-
return true;
|
|
539
|
-
}
|
|
540
|
-
return false;
|
|
1209
|
+
// src/utils/modules/getEnvironmentVariable.ts
|
|
1210
|
+
function getEnvironmentVariable(name) {
|
|
1211
|
+
if (typeof process === "object" && process?.env) {
|
|
1212
|
+
return process.env[name];
|
|
1213
|
+
} else {
|
|
1214
|
+
return void 0;
|
|
541
1215
|
}
|
|
542
|
-
};
|
|
543
|
-
|
|
544
|
-
// src/utils/modules/isFinite.ts
|
|
545
|
-
function isFinite(value) {
|
|
546
|
-
return typeof value === "number" && Number.isFinite(value);
|
|
547
1216
|
}
|
|
548
1217
|
|
|
549
|
-
// src/utils/modules/
|
|
550
|
-
function
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
}
|
|
554
|
-
if (typeof value === "string" && value.trim() !== "") {
|
|
555
|
-
return Number(value);
|
|
556
|
-
}
|
|
557
|
-
return NaN;
|
|
1218
|
+
// src/utils/modules/debug.ts
|
|
1219
|
+
function isDebugEnabled() {
|
|
1220
|
+
const debugValue = getEnvironmentVariable("LLM_EXE_DEBUG");
|
|
1221
|
+
return typeof debugValue === "string" && debugValue !== "" && debugValue.toLowerCase() !== "undefined" && debugValue.toLowerCase() !== "null";
|
|
558
1222
|
}
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
constructor(message, code, context) {
|
|
563
|
-
super(message ?? "");
|
|
564
|
-
__publicField(this, "code");
|
|
565
|
-
__publicField(this, "context");
|
|
566
|
-
this.name = this.constructor.name;
|
|
567
|
-
this.code = code ?? "unknown";
|
|
568
|
-
this.context = context;
|
|
569
|
-
if (Error.captureStackTrace) {
|
|
570
|
-
Error.captureStackTrace(this, this.constructor);
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
};
|
|
574
|
-
|
|
575
|
-
// src/parser/parsers/NumberParser.ts
|
|
576
|
-
var NumberParser = class extends BaseParser {
|
|
577
|
-
constructor(options) {
|
|
578
|
-
super("number", options);
|
|
1223
|
+
function debug(...args) {
|
|
1224
|
+
if (!isDebugEnabled()) {
|
|
1225
|
+
return;
|
|
579
1226
|
}
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
if (
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
1227
|
+
const logs = [];
|
|
1228
|
+
for (const arg of args) {
|
|
1229
|
+
if (arg && typeof arg === "object") {
|
|
1230
|
+
if (arg instanceof Error) {
|
|
1231
|
+
} else if (arg instanceof Array) {
|
|
1232
|
+
logs.push(arg.map((item) => JSON.stringify(item, null, 2)));
|
|
1233
|
+
} else if (arg instanceof Map) {
|
|
1234
|
+
logs.push(
|
|
1235
|
+
Array.from(arg.entries()).map(
|
|
1236
|
+
([key, value]) => `${key}: ${JSON.stringify(value, null, 2)}`
|
|
1237
|
+
)
|
|
1238
|
+
);
|
|
1239
|
+
} else if (arg instanceof Set) {
|
|
1240
|
+
logs.push(Array.from(arg).map((item) => JSON.stringify(item, null, 2)));
|
|
1241
|
+
} else if (arg instanceof Date) {
|
|
1242
|
+
logs.push(arg.toISOString());
|
|
1243
|
+
} else if (arg instanceof RegExp) {
|
|
1244
|
+
logs.push(arg.toString());
|
|
1245
|
+
} else {
|
|
1246
|
+
try {
|
|
1247
|
+
const str = maskApiKeys(JSON.stringify(arg, null, 2));
|
|
1248
|
+
logs.push(str);
|
|
1249
|
+
} catch (error) {
|
|
1250
|
+
console.error("Error parsing object:", error);
|
|
1251
|
+
}
|
|
592
1252
|
}
|
|
593
|
-
)
|
|
1253
|
+
} else if (typeof arg === "string") {
|
|
1254
|
+
logs.push(safeRequestUrl(arg));
|
|
1255
|
+
} else {
|
|
1256
|
+
logs.push(arg);
|
|
1257
|
+
}
|
|
594
1258
|
}
|
|
595
|
-
|
|
1259
|
+
if (isDebugEnabled()) {
|
|
1260
|
+
console.debug(...logs);
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
596
1263
|
|
|
597
|
-
// src/
|
|
598
|
-
var
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
}
|
|
1264
|
+
// src/parser/parsers/BooleanParser.ts
|
|
1265
|
+
var BOOLEAN_VALUES = ["true", "false", "yes", "no", "y", "n", "1", "0"];
|
|
1266
|
+
var TRUTHY_VALUES = /* @__PURE__ */ new Set(["true", "yes", "y", "1"]);
|
|
1267
|
+
var FALSY_VALUES = /* @__PURE__ */ new Set(["false", "no", "n", "0"]);
|
|
1268
|
+
var MAX_ERROR_INPUT_EXCERPT_LENGTH = 500;
|
|
1269
|
+
var BooleanParser = class extends BaseParser {
|
|
1270
|
+
constructor() {
|
|
1271
|
+
super("boolean");
|
|
1272
|
+
}
|
|
1273
|
+
getInputErrorContext(text) {
|
|
1274
|
+
const context = {
|
|
1275
|
+
inputLength: text.length
|
|
1276
|
+
};
|
|
1277
|
+
if (isDebugEnabled()) {
|
|
1278
|
+
const truncated = text.length > MAX_ERROR_INPUT_EXCERPT_LENGTH;
|
|
1279
|
+
context.inputExcerpt = truncated ? text.slice(0, MAX_ERROR_INPUT_EXCERPT_LENGTH) : text;
|
|
1280
|
+
context.inputExcerptTruncated = truncated;
|
|
1281
|
+
}
|
|
1282
|
+
return context;
|
|
1283
|
+
}
|
|
1284
|
+
parse(text, _attributes) {
|
|
1285
|
+
if (typeof text !== "string") {
|
|
1286
|
+
throw new LlmExeError(
|
|
1287
|
+
`Invalid input. Expected string. Received ${text === null ? "null" : typeof text}.`,
|
|
1288
|
+
{
|
|
1289
|
+
code: "parser.invalid_input",
|
|
1290
|
+
context: {
|
|
1291
|
+
operation: "BooleanParser.parse",
|
|
1292
|
+
parser: "boolean",
|
|
1293
|
+
reason: "invalid_input_type",
|
|
1294
|
+
expected: "string",
|
|
1295
|
+
received: text === null ? "null" : typeof text
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
);
|
|
1299
|
+
}
|
|
1300
|
+
const clean = text.toLowerCase().trim();
|
|
1301
|
+
if (!clean) {
|
|
1302
|
+
throw new LlmExeError(`No boolean value found in input.`, {
|
|
1303
|
+
code: "parser.parse_failed",
|
|
1304
|
+
context: {
|
|
1305
|
+
operation: "BooleanParser.parse",
|
|
1306
|
+
parser: "boolean",
|
|
1307
|
+
reason: "empty_input",
|
|
1308
|
+
expected: BOOLEAN_VALUES,
|
|
1309
|
+
...this.getInputErrorContext(text)
|
|
1310
|
+
}
|
|
1311
|
+
});
|
|
1312
|
+
}
|
|
1313
|
+
if (TRUTHY_VALUES.has(clean)) {
|
|
1314
|
+
return true;
|
|
1315
|
+
}
|
|
1316
|
+
if (FALSY_VALUES.has(clean)) {
|
|
1317
|
+
return false;
|
|
1318
|
+
}
|
|
1319
|
+
throw new LlmExeError(`No boolean value found in input.`, {
|
|
1320
|
+
code: "parser.parse_failed",
|
|
1321
|
+
context: {
|
|
1322
|
+
operation: "BooleanParser.parse",
|
|
1323
|
+
parser: "boolean",
|
|
1324
|
+
reason: "unrecognized_boolean",
|
|
1325
|
+
expected: BOOLEAN_VALUES,
|
|
1326
|
+
...this.getInputErrorContext(text)
|
|
1327
|
+
}
|
|
1328
|
+
});
|
|
1329
|
+
}
|
|
1330
|
+
};
|
|
615
1331
|
|
|
616
|
-
// src/utils/modules/
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
obj.additionalProperties = false;
|
|
620
|
-
return (0, import_json_schema_to_ts.asConst)(obj);
|
|
1332
|
+
// src/utils/modules/isFinite.ts
|
|
1333
|
+
function isFinite(value) {
|
|
1334
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
621
1335
|
}
|
|
622
1336
|
|
|
623
|
-
// src/utils/modules/
|
|
624
|
-
function
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
const externalPartialKeys = Object.keys(
|
|
628
|
-
_partials
|
|
629
|
-
);
|
|
630
|
-
for (const externalPartialKey of externalPartialKeys) {
|
|
631
|
-
if (typeof externalPartialKey === "string") {
|
|
632
|
-
partials2.push({
|
|
633
|
-
name: externalPartialKey,
|
|
634
|
-
template: _partials[externalPartialKey]
|
|
635
|
-
});
|
|
636
|
-
}
|
|
637
|
-
}
|
|
1337
|
+
// src/utils/modules/toNumber.ts
|
|
1338
|
+
function toNumber(value) {
|
|
1339
|
+
if (typeof value === "number") {
|
|
1340
|
+
return value;
|
|
638
1341
|
}
|
|
639
|
-
|
|
1342
|
+
if (typeof value === "string" && value.trim() !== "") {
|
|
1343
|
+
return Number(value);
|
|
1344
|
+
}
|
|
1345
|
+
return NaN;
|
|
640
1346
|
}
|
|
641
1347
|
|
|
642
|
-
// src/
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
);
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
1348
|
+
// src/parser/parsers/NumberParser.ts
|
|
1349
|
+
var NUMERIC_TOKEN_PATTERN = /(^|[^\w.,])([+-]?(?:(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d+)?|\.\d+)(?:[eE][+-]?\d+)?)(?![\w,])/g;
|
|
1350
|
+
var WHOLE_NUMERIC_PATTERN = /^[+-]?(?:(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d+)?|\.\d+)(?:[eE][+-]?\d+)?$/;
|
|
1351
|
+
var NumberParser = class extends BaseParser {
|
|
1352
|
+
constructor(options) {
|
|
1353
|
+
super("number");
|
|
1354
|
+
__publicField(this, "match");
|
|
1355
|
+
this.match = options?.match ?? "extract";
|
|
1356
|
+
}
|
|
1357
|
+
parse(text, _attributes) {
|
|
1358
|
+
if (typeof text !== "string") {
|
|
1359
|
+
throw new LlmExeError(
|
|
1360
|
+
`Invalid input. Expected string. Received ${text === null ? "null" : Array.isArray(text) ? "array" : typeof text}.`,
|
|
1361
|
+
{
|
|
1362
|
+
code: "parser.invalid_input",
|
|
1363
|
+
context: {
|
|
1364
|
+
operation: "NumberParser.parse",
|
|
1365
|
+
parser: "number",
|
|
1366
|
+
reason: "invalid_input_type",
|
|
1367
|
+
expected: "string",
|
|
1368
|
+
received: text === null ? "null" : Array.isArray(text) ? "array" : typeof text
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
);
|
|
1372
|
+
}
|
|
1373
|
+
if (text.trim() === "") {
|
|
1374
|
+
throw new LlmExeError(`No numeric value found in input.`, {
|
|
1375
|
+
code: "parser.parse_failed",
|
|
1376
|
+
context: {
|
|
1377
|
+
operation: "NumberParser.parse",
|
|
1378
|
+
parser: "number",
|
|
1379
|
+
reason: "empty_input",
|
|
1380
|
+
expected: "number",
|
|
1381
|
+
inputLength: text.length
|
|
1382
|
+
}
|
|
1383
|
+
});
|
|
1384
|
+
}
|
|
1385
|
+
if (this.match === "whole") {
|
|
1386
|
+
const trimmed = text.trim();
|
|
1387
|
+
if (!WHOLE_NUMERIC_PATTERN.test(trimmed)) {
|
|
1388
|
+
throw new LlmExeError(`Input is not a whole numeric value.`, {
|
|
1389
|
+
code: "parser.parse_failed",
|
|
1390
|
+
context: {
|
|
1391
|
+
operation: "NumberParser.parse",
|
|
1392
|
+
parser: "number",
|
|
1393
|
+
reason: "no_numeric_value",
|
|
1394
|
+
expected: "whole number",
|
|
1395
|
+
match: this.match,
|
|
1396
|
+
inputLength: text.length
|
|
1397
|
+
}
|
|
1398
|
+
});
|
|
1399
|
+
}
|
|
1400
|
+
const value2 = toNumber(trimmed.replace(/,/g, ""));
|
|
1401
|
+
if (!isFinite(value2)) {
|
|
1402
|
+
throw new LlmExeError(`Invalid numeric value found in input.`, {
|
|
1403
|
+
code: "parser.parse_failed",
|
|
1404
|
+
context: {
|
|
1405
|
+
operation: "NumberParser.parse",
|
|
1406
|
+
parser: "number",
|
|
1407
|
+
reason: "invalid_number",
|
|
1408
|
+
expected: "finite number",
|
|
1409
|
+
match: this.match,
|
|
1410
|
+
inputLength: text.length
|
|
1411
|
+
}
|
|
654
1412
|
});
|
|
655
1413
|
}
|
|
1414
|
+
return value2;
|
|
1415
|
+
}
|
|
1416
|
+
const matches = Array.from(text.matchAll(NUMERIC_TOKEN_PATTERN)).map(
|
|
1417
|
+
(match) => match[2]
|
|
1418
|
+
);
|
|
1419
|
+
if (matches.length === 0) {
|
|
1420
|
+
throw new LlmExeError(`No numeric value found in input.`, {
|
|
1421
|
+
code: "parser.parse_failed",
|
|
1422
|
+
context: {
|
|
1423
|
+
operation: "NumberParser.parse",
|
|
1424
|
+
parser: "number",
|
|
1425
|
+
reason: "no_numeric_value",
|
|
1426
|
+
expected: "number",
|
|
1427
|
+
match: this.match,
|
|
1428
|
+
inputLength: text.length
|
|
1429
|
+
}
|
|
1430
|
+
});
|
|
1431
|
+
}
|
|
1432
|
+
if (matches.length > 1) {
|
|
1433
|
+
throw new LlmExeError(`Multiple numeric values found in input.`, {
|
|
1434
|
+
code: "parser.parse_failed",
|
|
1435
|
+
context: {
|
|
1436
|
+
operation: "NumberParser.parse",
|
|
1437
|
+
parser: "number",
|
|
1438
|
+
reason: "ambiguous_number",
|
|
1439
|
+
expected: "one numeric value",
|
|
1440
|
+
match: this.match,
|
|
1441
|
+
inputLength: text.length,
|
|
1442
|
+
matchCount: matches.length
|
|
1443
|
+
}
|
|
1444
|
+
});
|
|
656
1445
|
}
|
|
1446
|
+
const value = toNumber(matches[0].replace(/,/g, ""));
|
|
1447
|
+
if (!isFinite(value)) {
|
|
1448
|
+
throw new LlmExeError(`Invalid numeric value found in input.`, {
|
|
1449
|
+
code: "parser.parse_failed",
|
|
1450
|
+
context: {
|
|
1451
|
+
operation: "NumberParser.parse",
|
|
1452
|
+
parser: "number",
|
|
1453
|
+
reason: "invalid_number",
|
|
1454
|
+
expected: "finite number",
|
|
1455
|
+
match: this.match,
|
|
1456
|
+
inputLength: text.length
|
|
1457
|
+
}
|
|
1458
|
+
});
|
|
1459
|
+
}
|
|
1460
|
+
return value;
|
|
657
1461
|
}
|
|
658
|
-
|
|
659
|
-
}
|
|
1462
|
+
};
|
|
660
1463
|
|
|
661
1464
|
// src/utils/modules/get.ts
|
|
662
1465
|
function get(obj, path, defaultValue) {
|
|
@@ -710,10 +1513,22 @@ function filterObjectOnSchema(schema, doc, detach, property) {
|
|
|
710
1513
|
return;
|
|
711
1514
|
}
|
|
712
1515
|
} else {
|
|
713
|
-
|
|
1516
|
+
var childType = getType(sp.type);
|
|
1517
|
+
if (childType === "integer" || childType === "number") {
|
|
714
1518
|
result[key] = toNumber(filteredChild);
|
|
715
|
-
} else if (
|
|
716
|
-
|
|
1519
|
+
} else if (childType === "boolean") {
|
|
1520
|
+
if (typeof filteredChild === "string") {
|
|
1521
|
+
const normalized = filteredChild.trim().toLowerCase();
|
|
1522
|
+
if (normalized === "true") {
|
|
1523
|
+
result[key] = true;
|
|
1524
|
+
} else if (normalized === "false") {
|
|
1525
|
+
result[key] = false;
|
|
1526
|
+
} else {
|
|
1527
|
+
result[key] = filteredChild;
|
|
1528
|
+
}
|
|
1529
|
+
} else {
|
|
1530
|
+
result[key] = filteredChild;
|
|
1531
|
+
}
|
|
717
1532
|
} else {
|
|
718
1533
|
result[key] = filteredChild;
|
|
719
1534
|
}
|
|
@@ -733,67 +1548,566 @@ function filterObjectOnSchema(schema, doc, detach, property) {
|
|
|
733
1548
|
return result;
|
|
734
1549
|
}
|
|
735
1550
|
|
|
736
|
-
// src/
|
|
737
|
-
var
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
1551
|
+
// src/parser/_utils.ts
|
|
1552
|
+
var import_jsonschema = require("jsonschema");
|
|
1553
|
+
function isPlainObject(value) {
|
|
1554
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
1555
|
+
return false;
|
|
1556
|
+
}
|
|
1557
|
+
const proto = Object.getPrototypeOf(value);
|
|
1558
|
+
return proto === Object.prototype || proto === null;
|
|
1559
|
+
}
|
|
1560
|
+
function getSchemaType(schemaType) {
|
|
1561
|
+
if (!Array.isArray(schemaType)) {
|
|
1562
|
+
return schemaType;
|
|
1563
|
+
}
|
|
1564
|
+
return schemaType.find((type) => type !== "null");
|
|
1565
|
+
}
|
|
1566
|
+
function enforceParserSchema(schema, parsed) {
|
|
1567
|
+
if (!schema || !parsed || typeof parsed !== "object") {
|
|
1568
|
+
return parsed;
|
|
1569
|
+
}
|
|
1570
|
+
return filterObjectOnSchema(schema, parsed);
|
|
1571
|
+
}
|
|
1572
|
+
function validateParserSchema(schema, parsed) {
|
|
1573
|
+
if (!schema || !parsed || typeof parsed !== "object") {
|
|
1574
|
+
return null;
|
|
1575
|
+
}
|
|
1576
|
+
const validate = (0, import_jsonschema.validate)(parsed, schema);
|
|
1577
|
+
if (validate.errors.length) {
|
|
1578
|
+
return validate.errors;
|
|
1579
|
+
}
|
|
1580
|
+
return null;
|
|
1581
|
+
}
|
|
1582
|
+
function coerceParserSchemaValues(schema, parsed) {
|
|
1583
|
+
if (!schema || parsed === null || typeof parsed === "undefined") {
|
|
1584
|
+
return parsed;
|
|
1585
|
+
}
|
|
1586
|
+
const type = getSchemaType(schema.type);
|
|
1587
|
+
if (type === "object" && isPlainObject(parsed)) {
|
|
1588
|
+
const properties = schema.properties || {};
|
|
1589
|
+
return Object.keys(parsed).reduce((output, key) => {
|
|
1590
|
+
const propertySchema = properties[key];
|
|
1591
|
+
output[key] = propertySchema ? coerceParserSchemaValues(propertySchema, parsed[key]) : parsed[key];
|
|
1592
|
+
return output;
|
|
1593
|
+
}, {});
|
|
1594
|
+
}
|
|
1595
|
+
if (type === "array" && Array.isArray(parsed) && schema.items) {
|
|
1596
|
+
return parsed.map(
|
|
1597
|
+
(item) => coerceParserSchemaValues(schema.items, item)
|
|
1598
|
+
);
|
|
1599
|
+
}
|
|
1600
|
+
if ((type === "number" || type === "integer") && typeof parsed === "string") {
|
|
1601
|
+
const trimmed = parsed.trim();
|
|
1602
|
+
if (trimmed !== "") {
|
|
1603
|
+
const value = Number(trimmed);
|
|
1604
|
+
if (Number.isFinite(value)) {
|
|
1605
|
+
return value;
|
|
747
1606
|
}
|
|
748
1607
|
}
|
|
749
1608
|
}
|
|
1609
|
+
if (type === "boolean" && typeof parsed === "string") {
|
|
1610
|
+
const normalized = parsed.trim().toLowerCase();
|
|
1611
|
+
if (normalized === "true") {
|
|
1612
|
+
return true;
|
|
1613
|
+
}
|
|
1614
|
+
if (normalized === "false") {
|
|
1615
|
+
return false;
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
return parsed;
|
|
1619
|
+
}
|
|
1620
|
+
function applyParserSchemaDefaultsAndFilter(schema, parsed) {
|
|
1621
|
+
if (!schema || parsed === null || typeof parsed === "undefined") {
|
|
1622
|
+
return parsed;
|
|
1623
|
+
}
|
|
1624
|
+
const type = getSchemaType(schema.type);
|
|
1625
|
+
if (type === "object" && isPlainObject(parsed)) {
|
|
1626
|
+
const properties = schema.properties;
|
|
1627
|
+
if (!properties) {
|
|
1628
|
+
return parsed;
|
|
1629
|
+
}
|
|
1630
|
+
const keepAdditionalProperties = schema.additionalProperties !== false;
|
|
1631
|
+
const initialOutput = keepAdditionalProperties ? { ...parsed } : {};
|
|
1632
|
+
return Object.keys(properties).reduce((output, key) => {
|
|
1633
|
+
const propertySchema = properties[key];
|
|
1634
|
+
const value = parsed[key];
|
|
1635
|
+
if (typeof value === "undefined") {
|
|
1636
|
+
if (typeof propertySchema?.default !== "undefined") {
|
|
1637
|
+
output[key] = propertySchema.default;
|
|
1638
|
+
}
|
|
1639
|
+
return output;
|
|
1640
|
+
}
|
|
1641
|
+
output[key] = applyParserSchemaDefaultsAndFilter(propertySchema, value);
|
|
1642
|
+
return output;
|
|
1643
|
+
}, initialOutput);
|
|
1644
|
+
}
|
|
1645
|
+
if (type === "array" && Array.isArray(parsed) && schema.items) {
|
|
1646
|
+
return parsed.map(
|
|
1647
|
+
(item) => applyParserSchemaDefaultsAndFilter(schema.items, item)
|
|
1648
|
+
);
|
|
1649
|
+
}
|
|
1650
|
+
return parsed;
|
|
750
1651
|
}
|
|
751
1652
|
|
|
752
|
-
// src/
|
|
753
|
-
|
|
754
|
-
{
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
{
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
{
|
|
773
|
-
{{
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
1653
|
+
// src/parser/parsers/JsonParser.ts
|
|
1654
|
+
function isPlainObject2(value) {
|
|
1655
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
1656
|
+
return false;
|
|
1657
|
+
}
|
|
1658
|
+
const proto = Object.getPrototypeOf(value);
|
|
1659
|
+
return proto === Object.prototype || proto === null;
|
|
1660
|
+
}
|
|
1661
|
+
function normalizeWholeResponseJsonText(input) {
|
|
1662
|
+
const trimmed = input.trim();
|
|
1663
|
+
const fenceMatch = trimmed.match(/^```([a-zA-Z]*)[^\S\r\n]*\r?\n([\s\S]*)```$/);
|
|
1664
|
+
if (!fenceMatch) {
|
|
1665
|
+
return trimmed;
|
|
1666
|
+
}
|
|
1667
|
+
const [, language, body] = fenceMatch;
|
|
1668
|
+
if (language && language.toLowerCase() !== "json") {
|
|
1669
|
+
return trimmed;
|
|
1670
|
+
}
|
|
1671
|
+
return body.trim();
|
|
1672
|
+
}
|
|
1673
|
+
var JsonParser = class extends BaseParserWithJson {
|
|
1674
|
+
constructor(options = {}) {
|
|
1675
|
+
super("json", options);
|
|
1676
|
+
__publicField(this, "shouldValidateSchema");
|
|
1677
|
+
this.shouldValidateSchema = !!options.schema && options.validateSchema !== false;
|
|
1678
|
+
}
|
|
1679
|
+
/**
|
|
1680
|
+
* v3 parser contract:
|
|
1681
|
+
* Category: strict
|
|
1682
|
+
* Mode: whole-output
|
|
1683
|
+
*
|
|
1684
|
+
* Parses strict JSON object/array output only. Invalid JSON, empty input,
|
|
1685
|
+
* JSON primitives, and non-plain runtime objects throw typed parser errors.
|
|
1686
|
+
* Schema validation is on by default when a schema is provided unless
|
|
1687
|
+
* validateSchema: false is explicitly set.
|
|
1688
|
+
*
|
|
1689
|
+
*/
|
|
1690
|
+
parse(text, _attributes) {
|
|
1691
|
+
let parsed;
|
|
1692
|
+
let inputLength;
|
|
1693
|
+
if (typeof text === "string") {
|
|
1694
|
+
inputLength = text.length;
|
|
1695
|
+
if (text.trim() === "") {
|
|
1696
|
+
throw new LlmExeError(`No JSON value found in input.`, {
|
|
1697
|
+
code: "parser.parse_failed",
|
|
1698
|
+
context: {
|
|
1699
|
+
operation: "JsonParser.parse",
|
|
1700
|
+
parser: "json",
|
|
1701
|
+
reason: "empty_input",
|
|
1702
|
+
expected: "JSON object or array",
|
|
1703
|
+
inputLength
|
|
1704
|
+
}
|
|
1705
|
+
});
|
|
1706
|
+
}
|
|
1707
|
+
try {
|
|
1708
|
+
parsed = JSON.parse(normalizeWholeResponseJsonText(text));
|
|
1709
|
+
} catch (cause) {
|
|
1710
|
+
throw new LlmExeError(`Invalid JSON input.`, {
|
|
1711
|
+
code: "parser.parse_failed",
|
|
1712
|
+
context: {
|
|
1713
|
+
operation: "JsonParser.parse",
|
|
1714
|
+
parser: "json",
|
|
1715
|
+
reason: "invalid_json",
|
|
1716
|
+
expected: "JSON object or array",
|
|
1717
|
+
inputLength
|
|
1718
|
+
},
|
|
1719
|
+
cause
|
|
1720
|
+
});
|
|
1721
|
+
}
|
|
1722
|
+
} else if (Array.isArray(text) || isPlainObject2(text)) {
|
|
1723
|
+
parsed = text;
|
|
1724
|
+
} else {
|
|
1725
|
+
throw new LlmExeError(
|
|
1726
|
+
`Invalid input. Expected JSON string, plain object, or array. Received ${text === null ? "null" : typeof text}.`,
|
|
1727
|
+
{
|
|
1728
|
+
code: "parser.invalid_input",
|
|
1729
|
+
context: {
|
|
1730
|
+
operation: "JsonParser.parse",
|
|
1731
|
+
parser: "json",
|
|
1732
|
+
reason: "invalid_input_type",
|
|
1733
|
+
expected: "JSON string, plain object, or array",
|
|
1734
|
+
received: text === null ? "null" : typeof text
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
);
|
|
1738
|
+
}
|
|
1739
|
+
if (!Array.isArray(parsed) && !isPlainObject2(parsed)) {
|
|
1740
|
+
throw new LlmExeError(`Invalid JSON root type.`, {
|
|
1741
|
+
code: "parser.parse_failed",
|
|
1742
|
+
context: {
|
|
1743
|
+
operation: "JsonParser.parse",
|
|
1744
|
+
parser: "json",
|
|
1745
|
+
reason: "invalid_json_root_type",
|
|
1746
|
+
expected: "JSON object or array",
|
|
1747
|
+
received: parsed === null ? "null" : typeof parsed,
|
|
1748
|
+
inputLength
|
|
1749
|
+
}
|
|
1750
|
+
});
|
|
1751
|
+
}
|
|
1752
|
+
if (this.schema) {
|
|
1753
|
+
if (this.shouldValidateSchema) {
|
|
1754
|
+
const valid = validateParserSchema(this.schema, parsed);
|
|
1755
|
+
if (valid && valid.length) {
|
|
1756
|
+
throw new LlmExeError(valid[0].message, {
|
|
1757
|
+
code: "parser.schema_validation_failed",
|
|
1758
|
+
context: {
|
|
1759
|
+
operation: "JsonParser.parse",
|
|
1760
|
+
parser: "json",
|
|
1761
|
+
schemaErrors: valid.map((error) => error.message)
|
|
1762
|
+
}
|
|
1763
|
+
});
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
if (this.shouldValidateSchema) {
|
|
1767
|
+
return applyParserSchemaDefaultsAndFilter(
|
|
1768
|
+
this.schema,
|
|
1769
|
+
parsed
|
|
1770
|
+
);
|
|
1771
|
+
}
|
|
1772
|
+
return enforceParserSchema(this.schema, parsed);
|
|
1773
|
+
}
|
|
1774
|
+
return parsed;
|
|
1775
|
+
}
|
|
1776
|
+
};
|
|
1777
|
+
|
|
1778
|
+
// src/utils/modules/camelCase.ts
|
|
1779
|
+
function camelCase(input) {
|
|
1780
|
+
if (!input) return input;
|
|
1781
|
+
input = input.replace(/[^a-zA-Z0-9_]+/g, " ").trim();
|
|
1782
|
+
const words = input.split(/\s+|_/);
|
|
1783
|
+
return words.map((word, index) => {
|
|
1784
|
+
if (index === 0) {
|
|
1785
|
+
return word.toLowerCase();
|
|
1786
|
+
} else {
|
|
1787
|
+
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
|
1788
|
+
}
|
|
1789
|
+
}).join("");
|
|
1790
|
+
}
|
|
1791
|
+
|
|
1792
|
+
// src/parser/_listBoundary.ts
|
|
1793
|
+
var LIST_MARKER_PATTERN = /^(?:[-*]\s+|\d+\.\s+|•\s*)/;
|
|
1794
|
+
function normalizeListLines(input, context) {
|
|
1795
|
+
const lines = input.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
|
|
1796
|
+
if (lines.length === 0) {
|
|
1797
|
+
throw new LlmExeError(`No list items found in input.`, {
|
|
1798
|
+
code: "parser.parse_failed",
|
|
1799
|
+
context: {
|
|
1800
|
+
operation: context.operation,
|
|
1801
|
+
parser: context.parser,
|
|
1802
|
+
reason: "empty_input",
|
|
1803
|
+
inputLength: input.length
|
|
1804
|
+
}
|
|
1805
|
+
});
|
|
1806
|
+
}
|
|
1807
|
+
const markedStates = lines.map((line) => LIST_MARKER_PATTERN.test(line));
|
|
1808
|
+
const hasMarked = markedStates.some(Boolean);
|
|
1809
|
+
const hasUnmarked = markedStates.some((marked) => !marked);
|
|
1810
|
+
if (hasMarked && hasUnmarked) {
|
|
1811
|
+
throw new LlmExeError(`Mixed marked and unmarked list items found.`, {
|
|
1812
|
+
code: "parser.parse_failed",
|
|
1813
|
+
context: {
|
|
1814
|
+
operation: context.operation,
|
|
1815
|
+
parser: context.parser,
|
|
1816
|
+
reason: "mixed_list_markers",
|
|
1817
|
+
inputLength: input.length
|
|
1818
|
+
}
|
|
1819
|
+
});
|
|
1820
|
+
}
|
|
1821
|
+
return {
|
|
1822
|
+
lines: hasMarked ? lines.map((line) => line.replace(LIST_MARKER_PATTERN, "").trim()) : lines,
|
|
1823
|
+
marked: hasMarked
|
|
1824
|
+
};
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1827
|
+
// src/parser/parsers/ListToJsonParser.ts
|
|
1828
|
+
var ListToJsonParser = class extends BaseParserWithJson {
|
|
1829
|
+
constructor(options = {}) {
|
|
1830
|
+
super("listToJson", options);
|
|
1831
|
+
__publicField(this, "keyTransform");
|
|
1832
|
+
__publicField(this, "shouldValidateSchema");
|
|
1833
|
+
this.keyTransform = options.keyTransform ?? "camelCase";
|
|
1834
|
+
this.shouldValidateSchema = !!options.schema && options.validateSchema !== false;
|
|
1835
|
+
}
|
|
1836
|
+
/**
|
|
1837
|
+
* v3 parser contract:
|
|
1838
|
+
* Category: converter
|
|
1839
|
+
* Mode: line-oriented format conversion
|
|
1840
|
+
*
|
|
1841
|
+
* Uses the shared list boundary. Parses normalized lines as key/value pairs
|
|
1842
|
+
* split at the first colon. Duplicate keys throw because object output would
|
|
1843
|
+
* overwrite data.
|
|
1844
|
+
*
|
|
1845
|
+
*/
|
|
1846
|
+
parse(text) {
|
|
1847
|
+
if (typeof text !== "string") {
|
|
1848
|
+
throw new LlmExeError(
|
|
1849
|
+
`Invalid input. Expected string. Received ${text === null ? "null" : Array.isArray(text) ? "array" : typeof text}.`,
|
|
1850
|
+
{
|
|
1851
|
+
code: "parser.invalid_input",
|
|
1852
|
+
context: {
|
|
1853
|
+
operation: "ListToJsonParser.parse",
|
|
1854
|
+
parser: "listToJson",
|
|
1855
|
+
reason: "invalid_input_type",
|
|
1856
|
+
expected: "string",
|
|
1857
|
+
received: text === null ? "null" : Array.isArray(text) ? "array" : typeof text
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
);
|
|
1861
|
+
}
|
|
1862
|
+
const { lines } = normalizeListLines(text, {
|
|
1863
|
+
operation: "ListToJsonParser.parse",
|
|
1864
|
+
parser: "listToJson"
|
|
1865
|
+
});
|
|
1866
|
+
const output = {};
|
|
1867
|
+
lines.forEach((line) => {
|
|
1868
|
+
const colonIndex = line.indexOf(":");
|
|
1869
|
+
if (colonIndex === -1) {
|
|
1870
|
+
throw new LlmExeError(`Malformed key/value line.`, {
|
|
1871
|
+
code: "parser.parse_failed",
|
|
1872
|
+
context: {
|
|
1873
|
+
operation: "ListToJsonParser.parse",
|
|
1874
|
+
parser: "listToJson",
|
|
1875
|
+
reason: "malformed_line",
|
|
1876
|
+
inputLength: text.length
|
|
1877
|
+
}
|
|
1878
|
+
});
|
|
1879
|
+
}
|
|
1880
|
+
const key = line.slice(0, colonIndex).trim();
|
|
1881
|
+
if (!key) {
|
|
1882
|
+
throw new LlmExeError(`Empty key in key/value line.`, {
|
|
1883
|
+
code: "parser.parse_failed",
|
|
1884
|
+
context: {
|
|
1885
|
+
operation: "ListToJsonParser.parse",
|
|
1886
|
+
parser: "listToJson",
|
|
1887
|
+
reason: "empty_key",
|
|
1888
|
+
inputLength: text.length
|
|
1889
|
+
}
|
|
1890
|
+
});
|
|
1891
|
+
}
|
|
1892
|
+
const transformedKey = this.keyTransform === "preserve" ? key : camelCase(key);
|
|
1893
|
+
if (Object.prototype.hasOwnProperty.call(output, transformedKey)) {
|
|
1894
|
+
throw new LlmExeError(`Duplicate key in key/value input.`, {
|
|
1895
|
+
code: "parser.parse_failed",
|
|
1896
|
+
context: {
|
|
1897
|
+
operation: "ListToJsonParser.parse",
|
|
1898
|
+
parser: "listToJson",
|
|
1899
|
+
reason: "duplicate_key",
|
|
1900
|
+
inputLength: text.length
|
|
1901
|
+
}
|
|
1902
|
+
});
|
|
1903
|
+
}
|
|
1904
|
+
output[transformedKey] = line.slice(colonIndex + 1).trim();
|
|
1905
|
+
});
|
|
1906
|
+
if (this.schema) {
|
|
1907
|
+
const coerced = coerceParserSchemaValues(this.schema, output);
|
|
1908
|
+
if (this.shouldValidateSchema) {
|
|
1909
|
+
const valid = validateParserSchema(this.schema, coerced);
|
|
1910
|
+
if (valid && valid.length) {
|
|
1911
|
+
throw new LlmExeError(valid[0].message, {
|
|
1912
|
+
code: "parser.schema_validation_failed",
|
|
1913
|
+
context: {
|
|
1914
|
+
operation: "ListToJsonParser.parse",
|
|
1915
|
+
parser: "listToJson",
|
|
1916
|
+
schemaErrors: valid.map((error) => error.message)
|
|
1917
|
+
}
|
|
1918
|
+
});
|
|
1919
|
+
}
|
|
1920
|
+
}
|
|
1921
|
+
return applyParserSchemaDefaultsAndFilter(this.schema, coerced);
|
|
1922
|
+
}
|
|
1923
|
+
return output;
|
|
1924
|
+
}
|
|
1925
|
+
};
|
|
1926
|
+
|
|
1927
|
+
// src/parser/parsers/ListToKeyValueParser.ts
|
|
1928
|
+
var ListToKeyValueParser = class extends BaseParser {
|
|
1929
|
+
constructor(options) {
|
|
1930
|
+
super("listToKeyValue");
|
|
1931
|
+
__publicField(this, "keyTransform");
|
|
1932
|
+
this.keyTransform = options?.keyTransform ?? "preserve";
|
|
1933
|
+
}
|
|
1934
|
+
/**
|
|
1935
|
+
* v3 parser contract:
|
|
1936
|
+
* Category: converter
|
|
1937
|
+
* Mode: line-oriented collector
|
|
1938
|
+
*
|
|
1939
|
+
* Uses the shared list boundary. Parses normalized lines as key/value pairs
|
|
1940
|
+
* split at the first colon. Preserves duplicate keys because output is an
|
|
1941
|
+
* ordered array. Keys are returned as written by default; pass
|
|
1942
|
+
* keyTransform: "camelCase" to match listToJson's key normalization.
|
|
1943
|
+
*
|
|
1944
|
+
*/
|
|
1945
|
+
parse(text, _attributes) {
|
|
1946
|
+
if (typeof text !== "string") {
|
|
1947
|
+
throw new LlmExeError(
|
|
1948
|
+
`Invalid input. Expected string. Received ${text === null ? "null" : Array.isArray(text) ? "array" : typeof text}.`,
|
|
1949
|
+
{
|
|
1950
|
+
code: "parser.invalid_input",
|
|
1951
|
+
context: {
|
|
1952
|
+
operation: "ListToKeyValueParser.parse",
|
|
1953
|
+
parser: "listToKeyValue",
|
|
1954
|
+
reason: "invalid_input_type",
|
|
1955
|
+
expected: "string",
|
|
1956
|
+
received: text === null ? "null" : Array.isArray(text) ? "array" : typeof text
|
|
1957
|
+
}
|
|
1958
|
+
}
|
|
1959
|
+
);
|
|
1960
|
+
}
|
|
1961
|
+
const { lines } = normalizeListLines(text, {
|
|
1962
|
+
operation: "ListToKeyValueParser.parse",
|
|
1963
|
+
parser: "listToKeyValue"
|
|
1964
|
+
});
|
|
1965
|
+
let res = [];
|
|
1966
|
+
for (const line of lines) {
|
|
1967
|
+
const colonIndex = line.indexOf(":");
|
|
1968
|
+
if (colonIndex === -1) {
|
|
1969
|
+
throw new LlmExeError(`Malformed key/value line.`, {
|
|
1970
|
+
code: "parser.parse_failed",
|
|
1971
|
+
context: {
|
|
1972
|
+
operation: "ListToKeyValueParser.parse",
|
|
1973
|
+
parser: "listToKeyValue",
|
|
1974
|
+
reason: "malformed_line",
|
|
1975
|
+
inputLength: text.length
|
|
1976
|
+
}
|
|
1977
|
+
});
|
|
1978
|
+
}
|
|
1979
|
+
const rawKey = line.slice(0, colonIndex).trim();
|
|
1980
|
+
if (!rawKey) {
|
|
1981
|
+
throw new LlmExeError(`Empty key in key/value line.`, {
|
|
1982
|
+
code: "parser.parse_failed",
|
|
1983
|
+
context: {
|
|
1984
|
+
operation: "ListToKeyValueParser.parse",
|
|
1985
|
+
parser: "listToKeyValue",
|
|
1986
|
+
reason: "empty_key",
|
|
1987
|
+
inputLength: text.length
|
|
1988
|
+
}
|
|
1989
|
+
});
|
|
1990
|
+
}
|
|
1991
|
+
const key = this.keyTransform === "camelCase" ? camelCase(rawKey) : rawKey;
|
|
1992
|
+
res.push({ key, value: line.slice(colonIndex + 1).trim() });
|
|
1993
|
+
}
|
|
1994
|
+
return res;
|
|
1995
|
+
}
|
|
1996
|
+
};
|
|
1997
|
+
|
|
1998
|
+
// src/parser/parsers/CustomParser.ts
|
|
1999
|
+
var CustomParser = class extends BaseParser {
|
|
2000
|
+
constructor(name, parserFn) {
|
|
2001
|
+
super(name);
|
|
2002
|
+
__publicField(this, "parserFn");
|
|
2003
|
+
this.parserFn = parserFn;
|
|
2004
|
+
}
|
|
2005
|
+
parse(text, context) {
|
|
2006
|
+
return this.parserFn.call(this, text, context);
|
|
2007
|
+
}
|
|
2008
|
+
};
|
|
2009
|
+
|
|
2010
|
+
// src/parser/parsers/ListToArrayParser.ts
|
|
2011
|
+
var ListToArrayParser = class extends BaseParser {
|
|
2012
|
+
constructor() {
|
|
2013
|
+
super("listToArray");
|
|
2014
|
+
}
|
|
2015
|
+
parse(text, _attributes) {
|
|
2016
|
+
if (typeof text !== "string") {
|
|
2017
|
+
throw new LlmExeError(
|
|
2018
|
+
`Invalid input. Expected string. Received ${text === null ? "null" : Array.isArray(text) ? "array" : typeof text}.`,
|
|
2019
|
+
{
|
|
2020
|
+
code: "parser.invalid_input",
|
|
2021
|
+
context: {
|
|
2022
|
+
operation: "ListToArrayParser.parse",
|
|
2023
|
+
parser: "listToArray",
|
|
2024
|
+
reason: "invalid_input_type",
|
|
2025
|
+
expected: "string",
|
|
2026
|
+
received: text === null ? "null" : Array.isArray(text) ? "array" : typeof text
|
|
2027
|
+
}
|
|
2028
|
+
}
|
|
2029
|
+
);
|
|
2030
|
+
}
|
|
2031
|
+
const normalized = normalizeListLines(text, {
|
|
2032
|
+
operation: "ListToArrayParser.parse",
|
|
2033
|
+
parser: "listToArray"
|
|
2034
|
+
});
|
|
2035
|
+
if (!normalized.marked && normalized.lines.length === 1) {
|
|
2036
|
+
throw new LlmExeError(`Input is not list-like.`, {
|
|
2037
|
+
code: "parser.parse_failed",
|
|
2038
|
+
context: {
|
|
2039
|
+
operation: "ListToArrayParser.parse",
|
|
2040
|
+
parser: "listToArray",
|
|
2041
|
+
reason: "not_list_like",
|
|
2042
|
+
inputLength: text.length
|
|
2043
|
+
}
|
|
2044
|
+
});
|
|
2045
|
+
}
|
|
2046
|
+
return normalized.lines;
|
|
2047
|
+
}
|
|
2048
|
+
};
|
|
2049
|
+
|
|
2050
|
+
// src/utils/modules/handlebars/hbs.ts
|
|
2051
|
+
var import_handlebars = __toESM(require("handlebars"));
|
|
2052
|
+
|
|
2053
|
+
// src/utils/modules/handlebars/utils/registerHelpers.ts
|
|
2054
|
+
function _registerHelpers(helpers, instance) {
|
|
2055
|
+
if (helpers && Array.isArray(helpers)) {
|
|
2056
|
+
for (const helper of helpers) {
|
|
2057
|
+
if (helper.name && typeof helper.name === "string" && typeof helper.handler === "function") {
|
|
2058
|
+
if (instance) {
|
|
2059
|
+
instance.registerHelper(helper.name, helper.handler);
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
}
|
|
2063
|
+
}
|
|
2064
|
+
}
|
|
2065
|
+
|
|
2066
|
+
// src/utils/modules/handlebars/templates/index.ts
|
|
2067
|
+
var MarkdownCode = `{{#if code}}\`\`\`{{#if language}}{{language}}{{/if}}
|
|
2068
|
+
{{{code}}}
|
|
2069
|
+
\`\`\`{{/if}}`;
|
|
2070
|
+
var ThoughtActionResult = `
|
|
2071
|
+
{{#if title}}{{#if attributes.stepsTaken.length}}{{title}}
|
|
2072
|
+
{{/if}}{{/if}}
|
|
2073
|
+
{{#each attributes.stepsTaken as | step |}}
|
|
2074
|
+
{{#if step.thought}}Thought: {{step.result}}{{/if}}
|
|
2075
|
+
{{#if step.result}}Action: {{step.action}}{{/if}}
|
|
2076
|
+
{{#if step.result}}Result: {{step.result}}{{/if}}
|
|
2077
|
+
{{/each}}`;
|
|
2078
|
+
var ChatConversationHistory = `{{~#if title}}{{~#if chat_history.length}}{{title}}
|
|
2079
|
+
{{~/if}}{{~/if}}
|
|
2080
|
+
{{#each chat_history as | item |}}
|
|
2081
|
+
{{~#eq item.role 'user'}}{{#if @last}}{{../mostRecentRolePrefix}}{{../userName}}{{../mostRecentRoleSuffix}}{{else}}{{../userName}}{{/if}}: {{#if @last}}{{../mostRecentMessagePrefix}}{{/if}}{{{item.content}}}{{#if @last}}{{../mostRecentMessageSuffix}}{{/if}}
|
|
2082
|
+
{{/eq}}
|
|
2083
|
+
{{~#eq item.role 'assistant'}}{{#if @last}}{{../mostRecentRolePrefix}}{{../assistantName}}{{../mostRecentRoleSuffix}}{{else}}{{../assistantName}}{{/if}}: {{#if @last}}{{../mostRecentMessagePrefix}}{{/if}}{{{item.content}}}{{#if @last}}{{../mostRecentMessageSuffix}}{{/if}}
|
|
2084
|
+
{{/eq}}
|
|
2085
|
+
{{~#eq item.role 'system'}}{{../systemName}}: {{{item.content}}}
|
|
2086
|
+
{{/eq}}
|
|
2087
|
+
{{~/each}}`;
|
|
2088
|
+
var DialogueHistory = `{{>ChatConversationHistory title=title chat_history=(getKeyOr key []) assistantName=(getOr assistant 'Assistant') userName=(getOr user 'User') systemName=(getOr system 'System') mostRecentRolePrefix=mostRecentRolePrefix mostRecentRoleSuffix=mostRecentRoleSuffix mostRecentMessagePrefix=mostRecentMessagePrefix mostRecentMessageSuffix=mostRecentMessageSuffix}}`;
|
|
2089
|
+
var SingleChatMessage = `{{~#eq role 'user'}}{{getOr name 'User'}}: {{{content}}}{{~/eq}}
|
|
2090
|
+
{{~#eq role 'assistant'}}{{getOr assistant 'Assistant'}}: {{{content}}}{{~/eq}}
|
|
2091
|
+
{{~#eq role 'system'}}{{getOr system 'System'}}: {{{content}}}{{~/eq}}`;
|
|
2092
|
+
var ThoughtsAndObservations = `{{~#each thoughts as | step |}}
|
|
2093
|
+
{{~#if step.thought}}Thought: {{{step.thought}}}
|
|
2094
|
+
{{/if}}
|
|
2095
|
+
{{~#if step.observation}}Observation: {{{step.observation}}}
|
|
2096
|
+
{{/if}}
|
|
2097
|
+
{{~/each}}`;
|
|
2098
|
+
var JsonSchema = `{{#if (getKeyOr key false)}}
|
|
2099
|
+
\`\`\`json
|
|
2100
|
+
{{{indentJson (getKeyOr key) collapse}}}
|
|
2101
|
+
\`\`\`
|
|
2102
|
+
{{~/if}}`;
|
|
2103
|
+
var JsonSchemaExampleJson = `{{#if (getOr key false)}}
|
|
2104
|
+
\`\`\`json
|
|
2105
|
+
{{{jsonSchemaExample key (getOr property '') collapse}}}
|
|
2106
|
+
\`\`\`
|
|
2107
|
+
{{~/if}}`;
|
|
2108
|
+
var partials = {
|
|
2109
|
+
JsonSchema,
|
|
2110
|
+
JsonSchemaExampleJson,
|
|
797
2111
|
MarkdownCode,
|
|
798
2112
|
DialogueHistory,
|
|
799
2113
|
SingleChatMessage,
|
|
@@ -1110,7 +2424,15 @@ function isEmpty(value) {
|
|
|
1110
2424
|
// src/utils/modules/handlebars/helpers/async/with.ts
|
|
1111
2425
|
async function withFnAsync(context, options) {
|
|
1112
2426
|
if (arguments.length !== 2) {
|
|
1113
|
-
throw new
|
|
2427
|
+
throw new LlmExeError("#with requires exactly one argument", {
|
|
2428
|
+
code: "template.invalid_helper_arguments",
|
|
2429
|
+
context: {
|
|
2430
|
+
operation: "handlebars.asyncHelper.with",
|
|
2431
|
+
helper: "with",
|
|
2432
|
+
expected: 1,
|
|
2433
|
+
received: arguments.length
|
|
2434
|
+
}
|
|
2435
|
+
});
|
|
1114
2436
|
}
|
|
1115
2437
|
if (isPromise(context)) {
|
|
1116
2438
|
context = await context;
|
|
@@ -1138,7 +2460,15 @@ async function withFnAsync(context, options) {
|
|
|
1138
2460
|
// src/utils/modules/handlebars/helpers/async/if.ts
|
|
1139
2461
|
async function ifFnAsync(conditional, options) {
|
|
1140
2462
|
if (arguments.length !== 2) {
|
|
1141
|
-
throw new
|
|
2463
|
+
throw new LlmExeError("#if requires exactly one argument", {
|
|
2464
|
+
code: "template.invalid_helper_arguments",
|
|
2465
|
+
context: {
|
|
2466
|
+
operation: "handlebars.asyncHelper.if",
|
|
2467
|
+
helper: "if",
|
|
2468
|
+
expected: 1,
|
|
2469
|
+
received: arguments.length
|
|
2470
|
+
}
|
|
2471
|
+
});
|
|
1142
2472
|
}
|
|
1143
2473
|
if (isPromise(conditional)) {
|
|
1144
2474
|
conditional = await conditional;
|
|
@@ -1160,7 +2490,15 @@ function isReadableStream(obj) {
|
|
|
1160
2490
|
// src/utils/modules/handlebars/helpers/async/each.ts
|
|
1161
2491
|
async function eachFnAsync(arg1, options) {
|
|
1162
2492
|
if (!options) {
|
|
1163
|
-
throw new
|
|
2493
|
+
throw new LlmExeError("Must pass iterator to #each", {
|
|
2494
|
+
code: "template.invalid_helper_arguments",
|
|
2495
|
+
context: {
|
|
2496
|
+
operation: "handlebars.asyncHelper.each",
|
|
2497
|
+
helper: "each",
|
|
2498
|
+
expected: "an iterator",
|
|
2499
|
+
received: typeof options
|
|
2500
|
+
}
|
|
2501
|
+
});
|
|
1164
2502
|
}
|
|
1165
2503
|
const { fn } = options;
|
|
1166
2504
|
const { inverse } = options;
|
|
@@ -1256,7 +2594,15 @@ async function eachFnAsync(arg1, options) {
|
|
|
1256
2594
|
// src/utils/modules/handlebars/helpers/async/unless.ts
|
|
1257
2595
|
async function unlessFnAsync(conditional, options) {
|
|
1258
2596
|
if (arguments.length !== 2) {
|
|
1259
|
-
throw new
|
|
2597
|
+
throw new LlmExeError("#unless requires exactly one argument", {
|
|
2598
|
+
code: "template.invalid_helper_arguments",
|
|
2599
|
+
context: {
|
|
2600
|
+
operation: "handlebars.asyncHelper.unless",
|
|
2601
|
+
helper: "unless",
|
|
2602
|
+
expected: 1,
|
|
2603
|
+
received: arguments.length
|
|
2604
|
+
}
|
|
2605
|
+
});
|
|
1260
2606
|
}
|
|
1261
2607
|
return ifFnAsync.call(this, conditional, {
|
|
1262
2608
|
fn: options.inverse,
|
|
@@ -1450,434 +2796,609 @@ function replaceTemplateString(templateString, substitutions = {}, configuration
|
|
|
1450
2796
|
return res;
|
|
1451
2797
|
}
|
|
1452
2798
|
|
|
1453
|
-
// src/
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
}) {
|
|
1458
|
-
if (!templateString) return Promise.resolve(templateString || "");
|
|
1459
|
-
const tempHelpers = [];
|
|
1460
|
-
const tempPartials = [];
|
|
1461
|
-
if (Array.isArray(configuration.helpers)) {
|
|
1462
|
-
hbsAsync.registerHelpers(configuration.helpers);
|
|
1463
|
-
tempHelpers.push(...configuration.helpers.map((a) => a.name));
|
|
1464
|
-
}
|
|
1465
|
-
if (Array.isArray(configuration.partials)) {
|
|
1466
|
-
hbsAsync.registerPartials(configuration.partials);
|
|
1467
|
-
tempPartials.push(...configuration.partials.map((a) => a.name));
|
|
2799
|
+
// src/parser/parsers/ReplaceStringTemplateParser.ts
|
|
2800
|
+
var ReplaceStringTemplateParser = class extends BaseParser {
|
|
2801
|
+
constructor() {
|
|
2802
|
+
super("replaceStringTemplate");
|
|
1468
2803
|
}
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
}
|
|
1483
|
-
|
|
1484
|
-
// src/utils/modules/asyncCallWithTimeout.ts
|
|
1485
|
-
var asyncCallWithTimeout = async (asyncPromise, timeLimit = 1e4) => {
|
|
1486
|
-
let timeoutHandle;
|
|
1487
|
-
const timeoutPromise = new Promise((_resolve, reject) => {
|
|
1488
|
-
timeoutHandle = setTimeout(() => {
|
|
1489
|
-
return reject(
|
|
1490
|
-
new Error(`LLM call timed out after ${timeLimit}ms`)
|
|
2804
|
+
parse(text, attributes) {
|
|
2805
|
+
if (typeof text !== "string") {
|
|
2806
|
+
throw new LlmExeError(
|
|
2807
|
+
`Invalid input. Expected string. Received ${text === null ? "null" : Array.isArray(text) ? "array" : typeof text}.`,
|
|
2808
|
+
{
|
|
2809
|
+
code: "parser.invalid_input",
|
|
2810
|
+
context: {
|
|
2811
|
+
operation: "ReplaceStringTemplateParser.parse",
|
|
2812
|
+
parser: "replaceStringTemplate",
|
|
2813
|
+
reason: "invalid_input_type",
|
|
2814
|
+
expected: "string",
|
|
2815
|
+
received: text === null ? "null" : Array.isArray(text) ? "array" : typeof text
|
|
2816
|
+
}
|
|
2817
|
+
}
|
|
1491
2818
|
);
|
|
1492
|
-
}
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
if (model.startsWith("gpt-") || model.startsWith("chatgpt-")) {
|
|
1503
|
-
return true;
|
|
1504
|
-
}
|
|
1505
|
-
if (model === "o1" || model.startsWith("o1-")) {
|
|
1506
|
-
return true;
|
|
1507
|
-
}
|
|
1508
|
-
if (model === "o3-mini") {
|
|
1509
|
-
return true;
|
|
1510
|
-
}
|
|
1511
|
-
return false;
|
|
1512
|
-
}
|
|
1513
|
-
function isModelKnownAnthropic(payload) {
|
|
1514
|
-
const model = payload.model.toLowerCase();
|
|
1515
|
-
if (model.startsWith("claude-")) {
|
|
1516
|
-
return true;
|
|
1517
|
-
}
|
|
1518
|
-
return false;
|
|
1519
|
-
}
|
|
1520
|
-
function isModelKnownXai(payload) {
|
|
1521
|
-
const model = payload.model.toLowerCase();
|
|
1522
|
-
if (model.startsWith("grok-")) {
|
|
1523
|
-
return true;
|
|
1524
|
-
}
|
|
1525
|
-
return false;
|
|
1526
|
-
}
|
|
1527
|
-
function isModelKnownBedrockAnthropic(payload) {
|
|
1528
|
-
const model = payload.model.toLowerCase();
|
|
1529
|
-
if (model.startsWith("anthropic.claude-")) {
|
|
1530
|
-
return true;
|
|
1531
|
-
}
|
|
1532
|
-
return false;
|
|
1533
|
-
}
|
|
1534
|
-
function guessProviderFromModel(payload) {
|
|
1535
|
-
switch (true) {
|
|
1536
|
-
case isModelKnownOpenAi(payload):
|
|
1537
|
-
return "openai";
|
|
1538
|
-
case isModelKnownXai(payload):
|
|
1539
|
-
return "xai";
|
|
1540
|
-
case isModelKnownBedrockAnthropic(payload):
|
|
1541
|
-
return "bedrock:anthropic";
|
|
1542
|
-
case isModelKnownAnthropic(payload):
|
|
1543
|
-
return "anthropic";
|
|
1544
|
-
default:
|
|
1545
|
-
throw new Error("Unsupported model");
|
|
1546
|
-
}
|
|
1547
|
-
}
|
|
1548
|
-
|
|
1549
|
-
// src/utils/modules/index.ts
|
|
1550
|
-
function registerHelpers(helpers) {
|
|
1551
|
-
hbs.registerHelpers(helpers);
|
|
1552
|
-
hbsAsync.registerHelpers(helpers);
|
|
1553
|
-
}
|
|
1554
|
-
function registerPartials(partials2) {
|
|
1555
|
-
hbs.registerPartials(partials2);
|
|
1556
|
-
hbsAsync.registerPartials(partials2);
|
|
1557
|
-
}
|
|
1558
|
-
|
|
1559
|
-
// src/parser/_utils.ts
|
|
1560
|
-
var import_jsonschema = require("jsonschema");
|
|
1561
|
-
function enforceParserSchema(schema, parsed) {
|
|
1562
|
-
if (!schema || !parsed || typeof parsed !== "object") {
|
|
1563
|
-
return parsed;
|
|
1564
|
-
}
|
|
1565
|
-
return filterObjectOnSchema(schema, parsed);
|
|
1566
|
-
}
|
|
1567
|
-
function validateParserSchema(schema, parsed) {
|
|
1568
|
-
if (!schema || !parsed || typeof parsed !== "object") {
|
|
1569
|
-
return null;
|
|
1570
|
-
}
|
|
1571
|
-
const validate = (0, import_jsonschema.validate)(parsed, schema);
|
|
1572
|
-
if (validate.errors.length) {
|
|
1573
|
-
return validate.errors;
|
|
1574
|
-
}
|
|
1575
|
-
return null;
|
|
1576
|
-
}
|
|
1577
|
-
|
|
1578
|
-
// src/parser/parsers/JsonParser.ts
|
|
1579
|
-
var JsonParser = class extends BaseParserWithJson {
|
|
1580
|
-
constructor(options = {}) {
|
|
1581
|
-
super("json", options);
|
|
1582
|
-
}
|
|
1583
|
-
parse(text, _attributes) {
|
|
1584
|
-
const parsed = maybeParseJSON(helpJsonMarkup(text));
|
|
1585
|
-
if (this.schema) {
|
|
1586
|
-
const enforce = enforceParserSchema(this.schema, parsed);
|
|
1587
|
-
if (this.validateSchema) {
|
|
1588
|
-
const valid = validateParserSchema(this.schema, enforce);
|
|
1589
|
-
if (valid && valid.length) {
|
|
1590
|
-
throw new LlmExeError(valid[0].message, "parser", {
|
|
1591
|
-
parser: "json",
|
|
1592
|
-
output: parsed,
|
|
1593
|
-
error: valid[0].message
|
|
1594
|
-
});
|
|
2819
|
+
}
|
|
2820
|
+
if (attributes !== void 0 && (attributes === null || typeof attributes !== "object" || Array.isArray(attributes))) {
|
|
2821
|
+
throw new LlmExeError(`Invalid attributes. Expected object.`, {
|
|
2822
|
+
code: "parser.invalid_input",
|
|
2823
|
+
context: {
|
|
2824
|
+
operation: "ReplaceStringTemplateParser.parse",
|
|
2825
|
+
parser: "replaceStringTemplate",
|
|
2826
|
+
reason: "invalid_attributes",
|
|
2827
|
+
expected: "object",
|
|
2828
|
+
received: attributes === null ? "null" : Array.isArray(attributes) ? "array" : typeof attributes
|
|
1595
2829
|
}
|
|
2830
|
+
});
|
|
2831
|
+
}
|
|
2832
|
+
try {
|
|
2833
|
+
return replaceTemplateString(text, attributes);
|
|
2834
|
+
} catch (cause) {
|
|
2835
|
+
let received = typeof cause;
|
|
2836
|
+
if (cause instanceof Error) {
|
|
2837
|
+
received = cause.name;
|
|
1596
2838
|
}
|
|
1597
|
-
|
|
2839
|
+
throw new LlmExeError(`Template replacement failed.`, {
|
|
2840
|
+
code: "parser.parse_failed",
|
|
2841
|
+
context: {
|
|
2842
|
+
operation: "ReplaceStringTemplateParser.parse",
|
|
2843
|
+
parser: "replaceStringTemplate",
|
|
2844
|
+
reason: "template_replacement_failed",
|
|
2845
|
+
inputLength: text.length,
|
|
2846
|
+
received
|
|
2847
|
+
},
|
|
2848
|
+
cause
|
|
2849
|
+
});
|
|
1598
2850
|
}
|
|
1599
|
-
return parsed;
|
|
1600
2851
|
}
|
|
1601
2852
|
};
|
|
1602
2853
|
|
|
1603
|
-
// src/
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
const words = input.split(/\s+|_/);
|
|
1608
|
-
return words.map((word, index) => {
|
|
1609
|
-
if (index === 0) {
|
|
1610
|
-
return word.toLowerCase();
|
|
1611
|
-
} else {
|
|
1612
|
-
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
|
1613
|
-
}
|
|
1614
|
-
}).join("");
|
|
1615
|
-
}
|
|
1616
|
-
|
|
1617
|
-
// src/parser/parsers/ListToJsonParser.ts
|
|
1618
|
-
var ListToJsonParser = class extends BaseParserWithJson {
|
|
1619
|
-
constructor(options = {}) {
|
|
1620
|
-
super("listToJson", options);
|
|
1621
|
-
__publicField(this, "keyTransform");
|
|
1622
|
-
this.keyTransform = options.keyTransform ?? "camelCase";
|
|
2854
|
+
// src/parser/parsers/MarkdownCodeBlocks.ts
|
|
2855
|
+
var MarkdownCodeBlocksParser = class extends BaseParser {
|
|
2856
|
+
constructor() {
|
|
2857
|
+
super("markdownCodeBlocks");
|
|
1623
2858
|
}
|
|
1624
|
-
parse(
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
2859
|
+
parse(input, _attributes) {
|
|
2860
|
+
if (typeof input !== "string") {
|
|
2861
|
+
throw new LlmExeError(
|
|
2862
|
+
`Invalid input. Expected string. Received ${input === null ? "null" : Array.isArray(input) ? "array" : typeof input}.`,
|
|
2863
|
+
{
|
|
2864
|
+
code: "parser.invalid_input",
|
|
2865
|
+
context: {
|
|
2866
|
+
operation: "MarkdownCodeBlocksParser.parse",
|
|
2867
|
+
parser: "markdownCodeBlocks",
|
|
2868
|
+
reason: "invalid_input_type",
|
|
2869
|
+
expected: "string",
|
|
2870
|
+
received: input === null ? "null" : Array.isArray(input) ? "array" : typeof input
|
|
2871
|
+
}
|
|
1635
2872
|
}
|
|
1636
|
-
|
|
1637
|
-
}
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
2873
|
+
);
|
|
2874
|
+
}
|
|
2875
|
+
const out = [];
|
|
2876
|
+
const fenceCount = input.match(/```/g)?.length ?? 0;
|
|
2877
|
+
if (fenceCount % 2 !== 0) {
|
|
2878
|
+
throw new LlmExeError(`Malformed markdown code block.`, {
|
|
2879
|
+
code: "parser.parse_failed",
|
|
2880
|
+
context: {
|
|
2881
|
+
operation: "MarkdownCodeBlocksParser.parse",
|
|
2882
|
+
parser: "markdownCodeBlocks",
|
|
2883
|
+
reason: "malformed_code_block",
|
|
2884
|
+
inputLength: input.length
|
|
1648
2885
|
}
|
|
2886
|
+
});
|
|
2887
|
+
}
|
|
2888
|
+
const regex = input.matchAll(new RegExp(/```(\w*)\n([\s\S]*?)```/, "g"));
|
|
2889
|
+
for (const iterator of regex) {
|
|
2890
|
+
if (iterator) {
|
|
2891
|
+
const [_input, language, code] = iterator;
|
|
2892
|
+
out.push({
|
|
2893
|
+
language,
|
|
2894
|
+
code
|
|
2895
|
+
});
|
|
1649
2896
|
}
|
|
1650
|
-
return parsed;
|
|
1651
2897
|
}
|
|
1652
|
-
return
|
|
2898
|
+
return out;
|
|
1653
2899
|
}
|
|
1654
2900
|
};
|
|
1655
2901
|
|
|
1656
|
-
// src/parser/parsers/
|
|
1657
|
-
var
|
|
1658
|
-
constructor(
|
|
1659
|
-
super("
|
|
2902
|
+
// src/parser/parsers/MarkdownCodeBlock.ts
|
|
2903
|
+
var MarkdownCodeBlockParser = class extends BaseParser {
|
|
2904
|
+
constructor() {
|
|
2905
|
+
super("markdownCodeBlock");
|
|
1660
2906
|
}
|
|
1661
|
-
parse(
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
2907
|
+
parse(input, _attributes) {
|
|
2908
|
+
if (typeof input !== "string") {
|
|
2909
|
+
throw new LlmExeError(
|
|
2910
|
+
`Invalid input. Expected string. Received ${input === null ? "null" : Array.isArray(input) ? "array" : typeof input}.`,
|
|
2911
|
+
{
|
|
2912
|
+
code: "parser.invalid_input",
|
|
2913
|
+
context: {
|
|
2914
|
+
operation: "MarkdownCodeBlockParser.parse",
|
|
2915
|
+
parser: "markdownCodeBlock",
|
|
2916
|
+
reason: "invalid_input_type",
|
|
2917
|
+
expected: "string",
|
|
2918
|
+
received: input === null ? "null" : Array.isArray(input) ? "array" : typeof input
|
|
2919
|
+
}
|
|
2920
|
+
}
|
|
2921
|
+
);
|
|
1669
2922
|
}
|
|
1670
|
-
|
|
2923
|
+
if (input.trim() === "") {
|
|
2924
|
+
throw new LlmExeError(`No markdown code block found.`, {
|
|
2925
|
+
code: "parser.parse_failed",
|
|
2926
|
+
context: {
|
|
2927
|
+
operation: "MarkdownCodeBlockParser.parse",
|
|
2928
|
+
parser: "markdownCodeBlock",
|
|
2929
|
+
reason: "empty_input",
|
|
2930
|
+
inputLength: input.length
|
|
2931
|
+
}
|
|
2932
|
+
});
|
|
2933
|
+
}
|
|
2934
|
+
const blocks = new MarkdownCodeBlocksParser().parse(input);
|
|
2935
|
+
if (blocks.length === 0) {
|
|
2936
|
+
throw new LlmExeError(`No markdown code block found.`, {
|
|
2937
|
+
code: "parser.parse_failed",
|
|
2938
|
+
context: {
|
|
2939
|
+
operation: "MarkdownCodeBlockParser.parse",
|
|
2940
|
+
parser: "markdownCodeBlock",
|
|
2941
|
+
reason: "no_code_block",
|
|
2942
|
+
inputLength: input.length
|
|
2943
|
+
}
|
|
2944
|
+
});
|
|
2945
|
+
}
|
|
2946
|
+
if (blocks.length > 1) {
|
|
2947
|
+
throw new LlmExeError(`Multiple markdown code blocks found.`, {
|
|
2948
|
+
code: "parser.parse_failed",
|
|
2949
|
+
context: {
|
|
2950
|
+
operation: "MarkdownCodeBlockParser.parse",
|
|
2951
|
+
parser: "markdownCodeBlock",
|
|
2952
|
+
reason: "multiple_code_blocks",
|
|
2953
|
+
inputLength: input.length,
|
|
2954
|
+
matchCount: blocks.length
|
|
2955
|
+
}
|
|
2956
|
+
});
|
|
2957
|
+
}
|
|
2958
|
+
return blocks[0];
|
|
1671
2959
|
}
|
|
1672
2960
|
};
|
|
1673
2961
|
|
|
1674
|
-
// src/parser/parsers/
|
|
1675
|
-
var
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
this
|
|
2962
|
+
// src/parser/parsers/StringExtractParser.ts
|
|
2963
|
+
var REGEX_METACHAR = /[.*+?^${}()|[\]\\]/g;
|
|
2964
|
+
var WORD_CHAR = "[\\p{L}\\p{N}]";
|
|
2965
|
+
function escapeRegex(value) {
|
|
2966
|
+
return value.replace(REGEX_METACHAR, "\\$&");
|
|
2967
|
+
}
|
|
2968
|
+
function describeType(value) {
|
|
2969
|
+
if (value === null) return "null";
|
|
2970
|
+
if (Array.isArray(value)) return "array";
|
|
2971
|
+
return typeof value;
|
|
2972
|
+
}
|
|
2973
|
+
var StringExtractParser = class extends BaseParser {
|
|
2974
|
+
constructor(options) {
|
|
2975
|
+
super("stringExtract");
|
|
2976
|
+
__publicField(this, "enum", []);
|
|
2977
|
+
__publicField(this, "ignoreCase");
|
|
2978
|
+
__publicField(this, "match");
|
|
2979
|
+
if (options?.enum) {
|
|
2980
|
+
this.enum.push(...options.enum);
|
|
2981
|
+
}
|
|
2982
|
+
this.ignoreCase = options?.ignoreCase ?? true;
|
|
2983
|
+
this.match = options?.match ?? "word";
|
|
1689
2984
|
}
|
|
1690
2985
|
/**
|
|
1691
|
-
*
|
|
1692
|
-
*
|
|
1693
|
-
*
|
|
1694
|
-
*
|
|
2986
|
+
* v3 parser contract:
|
|
2987
|
+
* Category: extractor
|
|
2988
|
+
* Mode: configured value extraction
|
|
2989
|
+
*
|
|
2990
|
+
* Returns the single configured enum value found in input. Matching is
|
|
2991
|
+
* word-bounded by default; pass match: "whole" to require exact input or
|
|
2992
|
+
* match: "substring" for legacy contains() behavior. Case-insensitive by
|
|
2993
|
+
* default.
|
|
2994
|
+
*
|
|
1695
2995
|
*/
|
|
1696
|
-
parse(text,
|
|
1697
|
-
|
|
2996
|
+
parse(text, _attributes) {
|
|
2997
|
+
if (typeof text !== "string") {
|
|
2998
|
+
const received = describeType(text);
|
|
2999
|
+
throw new LlmExeError(
|
|
3000
|
+
`Invalid input. Expected string. Received ${received}.`,
|
|
3001
|
+
{
|
|
3002
|
+
code: "parser.invalid_input",
|
|
3003
|
+
context: {
|
|
3004
|
+
operation: "StringExtractParser.parse",
|
|
3005
|
+
parser: "stringExtract",
|
|
3006
|
+
reason: "invalid_input_type",
|
|
3007
|
+
expected: "string",
|
|
3008
|
+
received
|
|
3009
|
+
}
|
|
3010
|
+
}
|
|
3011
|
+
);
|
|
3012
|
+
}
|
|
3013
|
+
if (this.enum.length === 0) {
|
|
3014
|
+
throw new LlmExeError(`No enum values configured.`, {
|
|
3015
|
+
code: "parser.parse_failed",
|
|
3016
|
+
context: {
|
|
3017
|
+
operation: "StringExtractParser.parse",
|
|
3018
|
+
parser: "stringExtract",
|
|
3019
|
+
reason: "no_enum_values",
|
|
3020
|
+
expected: "non-empty enum",
|
|
3021
|
+
inputLength: text.length
|
|
3022
|
+
}
|
|
3023
|
+
});
|
|
3024
|
+
}
|
|
3025
|
+
if (text.length === 0) {
|
|
3026
|
+
if (this.enum.includes("")) {
|
|
3027
|
+
return "";
|
|
3028
|
+
}
|
|
3029
|
+
throw new LlmExeError(`No matching enum value found in input.`, {
|
|
3030
|
+
code: "parser.parse_failed",
|
|
3031
|
+
context: {
|
|
3032
|
+
operation: "StringExtractParser.parse",
|
|
3033
|
+
parser: "stringExtract",
|
|
3034
|
+
reason: "empty_input",
|
|
3035
|
+
expected: this.enum,
|
|
3036
|
+
inputLength: text.length
|
|
3037
|
+
}
|
|
3038
|
+
});
|
|
3039
|
+
}
|
|
3040
|
+
const matches = this.findMatches(text);
|
|
3041
|
+
const uniqueMatches = Array.from(new Set(matches));
|
|
3042
|
+
if (uniqueMatches.length === 1) {
|
|
3043
|
+
return uniqueMatches[0];
|
|
3044
|
+
}
|
|
3045
|
+
if (uniqueMatches.length > 1) {
|
|
3046
|
+
throw new LlmExeError(`Multiple enum values found in input.`, {
|
|
3047
|
+
code: "parser.parse_failed",
|
|
3048
|
+
context: {
|
|
3049
|
+
operation: "StringExtractParser.parse",
|
|
3050
|
+
parser: "stringExtract",
|
|
3051
|
+
reason: "ambiguous_enum_match",
|
|
3052
|
+
expected: this.enum,
|
|
3053
|
+
match: this.match,
|
|
3054
|
+
inputLength: text.length,
|
|
3055
|
+
matchCount: uniqueMatches.length
|
|
3056
|
+
}
|
|
3057
|
+
});
|
|
3058
|
+
}
|
|
3059
|
+
throw new LlmExeError(`No matching enum value found in input.`, {
|
|
3060
|
+
code: "parser.parse_failed",
|
|
3061
|
+
context: {
|
|
3062
|
+
operation: "StringExtractParser.parse",
|
|
3063
|
+
parser: "stringExtract",
|
|
3064
|
+
reason: "no_enum_match",
|
|
3065
|
+
expected: this.enum,
|
|
3066
|
+
match: this.match,
|
|
3067
|
+
inputLength: text.length
|
|
3068
|
+
}
|
|
3069
|
+
});
|
|
1698
3070
|
}
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
3071
|
+
findMatches(text) {
|
|
3072
|
+
switch (this.match) {
|
|
3073
|
+
case "whole":
|
|
3074
|
+
return this.matchWhole(text);
|
|
3075
|
+
case "substring":
|
|
3076
|
+
return this.matchSubstring(text);
|
|
3077
|
+
case "word":
|
|
3078
|
+
default:
|
|
3079
|
+
return this.matchWord(text);
|
|
3080
|
+
}
|
|
3081
|
+
}
|
|
3082
|
+
matchWhole(text) {
|
|
3083
|
+
const candidate = this.ignoreCase ? text.trim().toLowerCase() : text.trim();
|
|
3084
|
+
return this.enum.filter((option) => {
|
|
3085
|
+
if (option === "") return false;
|
|
3086
|
+
const normalized = this.ignoreCase ? option.toLowerCase() : option;
|
|
3087
|
+
return candidate === normalized;
|
|
3088
|
+
});
|
|
1705
3089
|
}
|
|
1706
|
-
|
|
1707
|
-
const
|
|
1708
|
-
return
|
|
3090
|
+
matchSubstring(text) {
|
|
3091
|
+
const haystack = this.ignoreCase ? text.toLowerCase() : text;
|
|
3092
|
+
return this.enum.filter((option) => {
|
|
3093
|
+
if (option === "") return false;
|
|
3094
|
+
const needle = this.ignoreCase ? option.toLowerCase() : option;
|
|
3095
|
+
return haystack.includes(needle);
|
|
3096
|
+
});
|
|
3097
|
+
}
|
|
3098
|
+
matchWord(text) {
|
|
3099
|
+
const flags = this.ignoreCase ? "iu" : "u";
|
|
3100
|
+
return this.enum.filter((option) => {
|
|
3101
|
+
if (option === "") return false;
|
|
3102
|
+
const pattern = new RegExp(
|
|
3103
|
+
`(?<!${WORD_CHAR})${escapeRegex(option)}(?!${WORD_CHAR})`,
|
|
3104
|
+
flags
|
|
3105
|
+
);
|
|
3106
|
+
return pattern.test(text);
|
|
3107
|
+
});
|
|
1709
3108
|
}
|
|
1710
3109
|
};
|
|
1711
3110
|
|
|
1712
|
-
// src/parser/
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
3111
|
+
// src/parser/_functions.ts
|
|
3112
|
+
function createParser(...args) {
|
|
3113
|
+
const [type, options] = args;
|
|
3114
|
+
switch (type) {
|
|
3115
|
+
case "json":
|
|
3116
|
+
return new JsonParser(options);
|
|
3117
|
+
case "listToJson":
|
|
3118
|
+
return new ListToJsonParser(options);
|
|
3119
|
+
case "stringExtract":
|
|
3120
|
+
return new StringExtractParser(options);
|
|
3121
|
+
case "markdownCodeBlocks":
|
|
3122
|
+
return new MarkdownCodeBlocksParser();
|
|
3123
|
+
case "markdownCodeBlock":
|
|
3124
|
+
return new MarkdownCodeBlockParser();
|
|
3125
|
+
case "listToArray":
|
|
3126
|
+
return new ListToArrayParser();
|
|
3127
|
+
case "listToKeyValue":
|
|
3128
|
+
return new ListToKeyValueParser(options);
|
|
3129
|
+
case "replaceStringTemplate":
|
|
3130
|
+
return new ReplaceStringTemplateParser();
|
|
3131
|
+
case "boolean":
|
|
3132
|
+
return new BooleanParser();
|
|
3133
|
+
case "number":
|
|
3134
|
+
return new NumberParser(options);
|
|
3135
|
+
case "string":
|
|
3136
|
+
return new StringParser();
|
|
3137
|
+
default:
|
|
3138
|
+
throw new LlmExeError(
|
|
3139
|
+
`Invalid parser type: "${type}"`,
|
|
3140
|
+
{
|
|
3141
|
+
code: "parser.invalid_type",
|
|
3142
|
+
context: {
|
|
3143
|
+
operation: "createParser",
|
|
3144
|
+
parser: type,
|
|
3145
|
+
availableParsers: [
|
|
3146
|
+
"json",
|
|
3147
|
+
"string",
|
|
3148
|
+
"boolean",
|
|
3149
|
+
"number",
|
|
3150
|
+
"stringExtract",
|
|
3151
|
+
"listToArray",
|
|
3152
|
+
"listToJson",
|
|
3153
|
+
"listToKeyValue",
|
|
3154
|
+
"replaceStringTemplate",
|
|
3155
|
+
"markdownCodeBlock",
|
|
3156
|
+
"markdownCodeBlocks"
|
|
3157
|
+
],
|
|
3158
|
+
resolution: "Use a registered parser type, or define a custom parser."
|
|
3159
|
+
}
|
|
3160
|
+
}
|
|
3161
|
+
);
|
|
1716
3162
|
}
|
|
1717
|
-
|
|
1718
|
-
|
|
3163
|
+
}
|
|
3164
|
+
function createCustomParser(name, parserFn) {
|
|
3165
|
+
return new CustomParser(name, parserFn);
|
|
3166
|
+
}
|
|
3167
|
+
|
|
3168
|
+
// src/utils/index.ts
|
|
3169
|
+
var utils_exports = {};
|
|
3170
|
+
__export(utils_exports, {
|
|
3171
|
+
LLM_EXE_ERROR_SYMBOL: () => LLM_EXE_ERROR_SYMBOL,
|
|
3172
|
+
LlmExeError: () => LlmExeError,
|
|
3173
|
+
assert: () => assert,
|
|
3174
|
+
asyncCallWithTimeout: () => asyncCallWithTimeout,
|
|
3175
|
+
defineSchema: () => defineSchema,
|
|
3176
|
+
filterObjectOnSchema: () => filterObjectOnSchema,
|
|
3177
|
+
guessProviderFromModel: () => guessProviderFromModel,
|
|
3178
|
+
importHelpers: () => importHelpers,
|
|
3179
|
+
importPartials: () => importPartials,
|
|
3180
|
+
isLlmExeError: () => isLlmExeError,
|
|
3181
|
+
isObjectStringified: () => isObjectStringified,
|
|
3182
|
+
maybeParseJSON: () => maybeParseJSON,
|
|
3183
|
+
maybeStringifyJSON: () => maybeStringifyJSON,
|
|
3184
|
+
registerHelpers: () => registerHelpers,
|
|
3185
|
+
registerPartials: () => registerPartials,
|
|
3186
|
+
replaceTemplateString: () => replaceTemplateString,
|
|
3187
|
+
replaceTemplateStringAsync: () => replaceTemplateStringAsync
|
|
3188
|
+
});
|
|
3189
|
+
|
|
3190
|
+
// src/utils/modules/assert.ts
|
|
3191
|
+
function assert(condition, message) {
|
|
3192
|
+
if (condition === void 0 || condition === null || condition === false) {
|
|
3193
|
+
if (typeof message === "string") {
|
|
3194
|
+
throw new Error(message);
|
|
3195
|
+
} else if (message instanceof Error) {
|
|
3196
|
+
throw message;
|
|
3197
|
+
} else {
|
|
3198
|
+
throw new Error(`Assertion error`);
|
|
3199
|
+
}
|
|
1719
3200
|
}
|
|
1720
|
-
}
|
|
3201
|
+
}
|
|
1721
3202
|
|
|
1722
|
-
// src/
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
3203
|
+
// src/utils/modules/defineSchema.ts
|
|
3204
|
+
var import_json_schema_to_ts = require("json-schema-to-ts");
|
|
3205
|
+
function defineSchema(obj) {
|
|
3206
|
+
obj.additionalProperties = false;
|
|
3207
|
+
return (0, import_json_schema_to_ts.asConst)(obj);
|
|
3208
|
+
}
|
|
3209
|
+
|
|
3210
|
+
// src/utils/modules/handlebars/utils/importPartials.ts
|
|
3211
|
+
function importPartials(_partials) {
|
|
3212
|
+
let partials2 = [];
|
|
3213
|
+
if (_partials) {
|
|
3214
|
+
const externalPartialKeys = Object.keys(
|
|
3215
|
+
_partials
|
|
3216
|
+
);
|
|
3217
|
+
for (const externalPartialKey of externalPartialKeys) {
|
|
3218
|
+
if (typeof externalPartialKey === "string") {
|
|
3219
|
+
partials2.push({
|
|
3220
|
+
name: externalPartialKey,
|
|
3221
|
+
template: _partials[externalPartialKey]
|
|
3222
|
+
});
|
|
1735
3223
|
}
|
|
1736
3224
|
}
|
|
1737
|
-
} catch {
|
|
1738
3225
|
}
|
|
1739
|
-
return
|
|
3226
|
+
return partials2;
|
|
1740
3227
|
}
|
|
1741
3228
|
|
|
1742
|
-
// src/
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
if (iterator) {
|
|
1755
|
-
const [_input, language, code] = iterator;
|
|
1756
|
-
out.push({
|
|
1757
|
-
language,
|
|
1758
|
-
code
|
|
3229
|
+
// src/utils/modules/handlebars/utils/importHelpers.ts
|
|
3230
|
+
function importHelpers(_helpers) {
|
|
3231
|
+
let helpers = [];
|
|
3232
|
+
if (_helpers) {
|
|
3233
|
+
const externalHelperKeys = Object.keys(
|
|
3234
|
+
_helpers
|
|
3235
|
+
);
|
|
3236
|
+
for (const externalHelperKey of externalHelperKeys) {
|
|
3237
|
+
if (typeof externalHelperKey === "string") {
|
|
3238
|
+
helpers.push({
|
|
3239
|
+
name: externalHelperKey,
|
|
3240
|
+
handler: _helpers[externalHelperKey]
|
|
1759
3241
|
});
|
|
1760
3242
|
}
|
|
1761
3243
|
}
|
|
1762
|
-
return out;
|
|
1763
3244
|
}
|
|
1764
|
-
|
|
3245
|
+
return helpers;
|
|
3246
|
+
}
|
|
1765
3247
|
|
|
1766
|
-
// src/
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
3248
|
+
// src/utils/modules/replaceTemplateStringAsync.ts
|
|
3249
|
+
async function replaceTemplateStringAsync(templateString, substitutions = {}, configuration = {
|
|
3250
|
+
helpers: [],
|
|
3251
|
+
partials: []
|
|
3252
|
+
}) {
|
|
3253
|
+
if (!templateString) return Promise.resolve(templateString || "");
|
|
3254
|
+
const tempHelpers = [];
|
|
3255
|
+
const tempPartials = [];
|
|
3256
|
+
if (Array.isArray(configuration.helpers)) {
|
|
3257
|
+
hbsAsync.registerHelpers(configuration.helpers);
|
|
3258
|
+
tempHelpers.push(...configuration.helpers.map((a) => a.name));
|
|
1770
3259
|
}
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
return {
|
|
1775
|
-
code: "",
|
|
1776
|
-
language: ""
|
|
1777
|
-
};
|
|
1778
|
-
}
|
|
1779
|
-
return block;
|
|
3260
|
+
if (Array.isArray(configuration.partials)) {
|
|
3261
|
+
hbsAsync.registerPartials(configuration.partials);
|
|
3262
|
+
tempPartials.push(...configuration.partials.map((a) => a.name));
|
|
1780
3263
|
}
|
|
3264
|
+
const template = hbsAsync.handlebars.compile(templateString);
|
|
3265
|
+
const res = await template(substitutions, {
|
|
3266
|
+
allowedProtoMethods: {
|
|
3267
|
+
substring: true
|
|
3268
|
+
}
|
|
3269
|
+
});
|
|
3270
|
+
tempHelpers.forEach(function(n) {
|
|
3271
|
+
hbsAsync.handlebars.unregisterHelper(n);
|
|
3272
|
+
});
|
|
3273
|
+
tempPartials.forEach(function(n) {
|
|
3274
|
+
hbsAsync.handlebars.unregisterPartial(n);
|
|
3275
|
+
});
|
|
3276
|
+
return res;
|
|
3277
|
+
}
|
|
3278
|
+
|
|
3279
|
+
// src/utils/modules/asyncCallWithTimeout.ts
|
|
3280
|
+
var asyncCallWithTimeout = async (asyncPromise, timeLimit = 1e4) => {
|
|
3281
|
+
let timeoutHandle;
|
|
3282
|
+
const timeoutPromise = new Promise((_resolve, reject) => {
|
|
3283
|
+
timeoutHandle = setTimeout(() => {
|
|
3284
|
+
return reject(
|
|
3285
|
+
new Error(`LLM call timed out after ${timeLimit}ms`)
|
|
3286
|
+
);
|
|
3287
|
+
}, timeLimit);
|
|
3288
|
+
});
|
|
3289
|
+
return Promise.race([asyncPromise, timeoutPromise]).finally(() => {
|
|
3290
|
+
clearTimeout(timeoutHandle);
|
|
3291
|
+
});
|
|
1781
3292
|
};
|
|
1782
3293
|
|
|
1783
|
-
// src/
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
__publicField(this, "ignoreCase");
|
|
1789
|
-
if (options?.enum) {
|
|
1790
|
-
this.enum.push(...options.enum);
|
|
1791
|
-
}
|
|
1792
|
-
if (options?.ignoreCase) {
|
|
1793
|
-
this.ignoreCase = true;
|
|
1794
|
-
}
|
|
3294
|
+
// src/utils/modules/guessProviderFromModel.ts
|
|
3295
|
+
function isModelKnownOpenAi(payload) {
|
|
3296
|
+
const model = payload.model.toLowerCase();
|
|
3297
|
+
if (model.startsWith("gpt-") || model.startsWith("chatgpt-")) {
|
|
3298
|
+
return true;
|
|
1795
3299
|
}
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
typeof text === "string",
|
|
1799
|
-
`Invalid input. Expected string. Received ${typeof text}.`
|
|
1800
|
-
);
|
|
1801
|
-
for (const option of this.enum) {
|
|
1802
|
-
const regex = this.ignoreCase ? new RegExp(option.toLowerCase(), "i") : new RegExp(option);
|
|
1803
|
-
if (regex.test(text)) {
|
|
1804
|
-
return option;
|
|
1805
|
-
}
|
|
1806
|
-
}
|
|
1807
|
-
throw new LlmExeError(
|
|
1808
|
-
`No matching enum value found in input.`,
|
|
1809
|
-
"parser",
|
|
1810
|
-
{
|
|
1811
|
-
parser: "stringExtract",
|
|
1812
|
-
output: text,
|
|
1813
|
-
error: `No matching enum value found in input. Expected one of: ${this.enum.join(", ")}`
|
|
1814
|
-
}
|
|
1815
|
-
);
|
|
3300
|
+
if (model === "o1" || model.startsWith("o1-")) {
|
|
3301
|
+
return true;
|
|
1816
3302
|
}
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
3303
|
+
if (model === "o3-mini") {
|
|
3304
|
+
return true;
|
|
3305
|
+
}
|
|
3306
|
+
return false;
|
|
3307
|
+
}
|
|
3308
|
+
function isModelKnownAnthropic(payload) {
|
|
3309
|
+
const model = payload.model.toLowerCase();
|
|
3310
|
+
if (model.startsWith("claude-")) {
|
|
3311
|
+
return true;
|
|
3312
|
+
}
|
|
3313
|
+
return false;
|
|
3314
|
+
}
|
|
3315
|
+
function isModelKnownXai(payload) {
|
|
3316
|
+
const model = payload.model.toLowerCase();
|
|
3317
|
+
if (model.startsWith("grok-")) {
|
|
3318
|
+
return true;
|
|
3319
|
+
}
|
|
3320
|
+
return false;
|
|
3321
|
+
}
|
|
3322
|
+
function isModelKnownBedrockAnthropic(payload) {
|
|
3323
|
+
const model = payload.model.toLowerCase();
|
|
3324
|
+
if (model.startsWith("anthropic.claude-")) {
|
|
3325
|
+
return true;
|
|
3326
|
+
}
|
|
3327
|
+
return false;
|
|
3328
|
+
}
|
|
3329
|
+
function guessProviderFromModel(payload) {
|
|
3330
|
+
switch (true) {
|
|
3331
|
+
case isModelKnownOpenAi(payload):
|
|
3332
|
+
return "openai";
|
|
3333
|
+
case isModelKnownXai(payload):
|
|
3334
|
+
return "xai";
|
|
3335
|
+
case isModelKnownBedrockAnthropic(payload):
|
|
3336
|
+
return "bedrock:anthropic";
|
|
3337
|
+
case isModelKnownAnthropic(payload):
|
|
3338
|
+
return "anthropic";
|
|
1844
3339
|
default:
|
|
1845
|
-
throw new
|
|
1846
|
-
|
|
1847
|
-
|
|
3340
|
+
throw new LlmExeError("Unsupported model", {
|
|
3341
|
+
code: "configuration.invalid_provider",
|
|
3342
|
+
context: {
|
|
3343
|
+
operation: "guessProviderFromModel",
|
|
3344
|
+
model: payload.model,
|
|
3345
|
+
// Mirrors the switch above. Keep these in sync when adding a new
|
|
3346
|
+
// isModelKnown* case.
|
|
3347
|
+
availableProviders: [
|
|
3348
|
+
"openai",
|
|
3349
|
+
"xai",
|
|
3350
|
+
"bedrock:anthropic",
|
|
3351
|
+
"anthropic"
|
|
3352
|
+
],
|
|
3353
|
+
resolution: "Pass a known model prefix (gpt-, chatgpt-, o1, o3-mini, claude-, grok-, anthropic.claude-) or specify the provider explicitly."
|
|
3354
|
+
}
|
|
3355
|
+
});
|
|
1848
3356
|
}
|
|
1849
3357
|
}
|
|
1850
|
-
|
|
1851
|
-
|
|
3358
|
+
|
|
3359
|
+
// src/utils/modules/index.ts
|
|
3360
|
+
function registerHelpers(helpers) {
|
|
3361
|
+
hbs.registerHelpers(helpers);
|
|
3362
|
+
hbsAsync.registerHelpers(helpers);
|
|
3363
|
+
}
|
|
3364
|
+
function registerPartials(partials2) {
|
|
3365
|
+
hbs.registerPartials(partials2);
|
|
3366
|
+
hbsAsync.registerPartials(partials2);
|
|
1852
3367
|
}
|
|
1853
3368
|
|
|
1854
3369
|
// src/parser/parsers/LlmNativeFunctionParser.ts
|
|
1855
3370
|
var LlmFunctionParser = class extends BaseParser {
|
|
1856
3371
|
constructor(options) {
|
|
1857
|
-
super("functionCall",
|
|
3372
|
+
super("functionCall", "function_call");
|
|
1858
3373
|
__publicField(this, "parser");
|
|
1859
3374
|
this.parser = options.parser;
|
|
1860
3375
|
}
|
|
1861
3376
|
parse(text, _options) {
|
|
1862
3377
|
if (typeof text === "string") {
|
|
1863
|
-
return this.parser.parse(text);
|
|
3378
|
+
return this.parser.parse(text, _options);
|
|
1864
3379
|
}
|
|
1865
3380
|
const { content } = text;
|
|
1866
3381
|
const functionUses = content?.filter((a) => a.type === "function_use") || [];
|
|
1867
3382
|
if (functionUses.length === 0) {
|
|
1868
3383
|
const [item] = content;
|
|
1869
|
-
return this.parser.parse(item.text);
|
|
3384
|
+
return this.parser.parse(item.text, _options);
|
|
1870
3385
|
}
|
|
1871
3386
|
return content;
|
|
1872
3387
|
}
|
|
1873
3388
|
};
|
|
1874
3389
|
var LlmNativeFunctionParser = class extends BaseParser {
|
|
1875
3390
|
constructor(options) {
|
|
1876
|
-
super("openAiFunction",
|
|
3391
|
+
super("openAiFunction", "function_call");
|
|
1877
3392
|
__publicField(this, "parser");
|
|
1878
3393
|
this.parser = options.parser;
|
|
1879
3394
|
}
|
|
1880
3395
|
parse(text, _options) {
|
|
3396
|
+
if (typeof text === "string") {
|
|
3397
|
+
return this.parser.parse(text, _options);
|
|
3398
|
+
}
|
|
3399
|
+
if (typeof text?.text === "string") {
|
|
3400
|
+
return this.parser.parse(text.text, _options);
|
|
3401
|
+
}
|
|
1881
3402
|
const { content } = text;
|
|
1882
3403
|
const functionUse = content?.find((a) => a.type === "function_use");
|
|
1883
3404
|
if (functionUse && "name" in functionUse && "input" in functionUse) {
|
|
@@ -1886,7 +3407,10 @@ var LlmNativeFunctionParser = class extends BaseParser {
|
|
|
1886
3407
|
arguments: maybeParseJSON(functionUse.input)
|
|
1887
3408
|
};
|
|
1888
3409
|
}
|
|
1889
|
-
|
|
3410
|
+
const textContent = content?.find(
|
|
3411
|
+
(item) => item.type === "text" && typeof item.text === "string"
|
|
3412
|
+
);
|
|
3413
|
+
return this.parser.parse(textContent?.text, _options);
|
|
1890
3414
|
}
|
|
1891
3415
|
};
|
|
1892
3416
|
var OpenAiFunctionParser = LlmNativeFunctionParser;
|
|
@@ -1913,17 +3437,29 @@ var LlmExecutor = class extends BaseExecutor {
|
|
|
1913
3437
|
this.promptFn = null;
|
|
1914
3438
|
}
|
|
1915
3439
|
}
|
|
3440
|
+
/**
|
|
3441
|
+
* Runs the executor against the configured LLM and prompt.
|
|
3442
|
+
*
|
|
3443
|
+
* `null` and `undefined` are rejected with a `TypeError`: the declared
|
|
3444
|
+
* input type requires an object, and silently coercing missing input hides a
|
|
3445
|
+
* clear contract violation. Use `{}` for prompts that declare no template
|
|
3446
|
+
* variables. See issue #410.
|
|
3447
|
+
*/
|
|
1916
3448
|
async execute(_input, _options) {
|
|
1917
|
-
|
|
3449
|
+
if (_input === null || typeof _input === "undefined") {
|
|
3450
|
+
throw new TypeError(
|
|
3451
|
+
`[llm-exe] Executor "${this.name}" received null or undefined as input. execute() expects an object matching the prompt's input type.`
|
|
3452
|
+
);
|
|
3453
|
+
}
|
|
1918
3454
|
if (this?.parser instanceof JsonParser && this.parser.schema) {
|
|
1919
3455
|
_options = Object.assign(_options || {}, {
|
|
1920
3456
|
jsonSchema: this.parser.schema
|
|
1921
3457
|
});
|
|
1922
3458
|
}
|
|
1923
|
-
return super.execute(
|
|
3459
|
+
return super.execute(_input, _options);
|
|
1924
3460
|
}
|
|
1925
|
-
async handler(_input,
|
|
1926
|
-
const call = await this.llm.call(_input,
|
|
3461
|
+
async handler(_input, _options, _context) {
|
|
3462
|
+
const call = await this.llm.call(_input, _options, _context);
|
|
1927
3463
|
return call;
|
|
1928
3464
|
}
|
|
1929
3465
|
async getHandlerInput(_input) {
|
|
@@ -1942,15 +3478,26 @@ var LlmExecutor = class extends BaseExecutor {
|
|
|
1942
3478
|
return prompt.format(_input);
|
|
1943
3479
|
}
|
|
1944
3480
|
}
|
|
1945
|
-
throw new
|
|
3481
|
+
throw new LlmExeError("Missing prompt", {
|
|
3482
|
+
code: "executor.missing_prompt",
|
|
3483
|
+
context: {
|
|
3484
|
+
operation: "LlmExecutor.getHandlerInput",
|
|
3485
|
+
executorName: this.name,
|
|
3486
|
+
executorType: this.type,
|
|
3487
|
+
traceId: this.getTraceId() ?? void 0,
|
|
3488
|
+
resolution: "Provide a prompt (or prompt factory) when constructing the LLM executor."
|
|
3489
|
+
}
|
|
3490
|
+
});
|
|
1946
3491
|
}
|
|
1947
|
-
getHandlerOutput(out, _metadata) {
|
|
3492
|
+
getHandlerOutput(out, _metadata, _options, _context) {
|
|
3493
|
+
const parse = this.parser.parse.bind(this.parser);
|
|
3494
|
+
const parserArg = _context ?? _metadata;
|
|
1948
3495
|
if (this.parser.target === "function_call") {
|
|
1949
3496
|
const outToStr = out.getResult();
|
|
1950
|
-
return
|
|
3497
|
+
return parse(outToStr, parserArg);
|
|
1951
3498
|
} else {
|
|
1952
3499
|
const outToStr = out.getResultText();
|
|
1953
|
-
return
|
|
3500
|
+
return parse(outToStr, parserArg);
|
|
1954
3501
|
}
|
|
1955
3502
|
}
|
|
1956
3503
|
metadata() {
|
|
@@ -2052,7 +3599,17 @@ var CallableExecutor = class {
|
|
|
2052
3599
|
} else if (typeof options.handler === "function") {
|
|
2053
3600
|
this._handler = createCoreExecutor(options.handler);
|
|
2054
3601
|
} else {
|
|
2055
|
-
throw new
|
|
3602
|
+
throw new LlmExeError("Invalid handler", {
|
|
3603
|
+
code: "callable.invalid_handler",
|
|
3604
|
+
context: {
|
|
3605
|
+
operation: "CallableExecutor.constructor",
|
|
3606
|
+
functionName: options.name,
|
|
3607
|
+
key: options?.key || options.name,
|
|
3608
|
+
expected: "function or BaseExecutor",
|
|
3609
|
+
received: typeof options.handler,
|
|
3610
|
+
resolution: "Pass a function or a BaseExecutor instance as the handler."
|
|
3611
|
+
}
|
|
3612
|
+
});
|
|
2056
3613
|
}
|
|
2057
3614
|
}
|
|
2058
3615
|
async execute(input) {
|
|
@@ -2070,7 +3627,16 @@ var CallableExecutor = class {
|
|
|
2070
3627
|
}
|
|
2071
3628
|
return { result: true, attributes: {} };
|
|
2072
3629
|
} catch (error) {
|
|
2073
|
-
|
|
3630
|
+
const wrapped = error instanceof LlmExeError ? error : new LlmExeError(error?.message ?? String(error), {
|
|
3631
|
+
code: "callable.validation_failed",
|
|
3632
|
+
context: {
|
|
3633
|
+
operation: "CallableExecutor.validateInput",
|
|
3634
|
+
functionName: this.name,
|
|
3635
|
+
key: this.key
|
|
3636
|
+
},
|
|
3637
|
+
cause: error
|
|
3638
|
+
});
|
|
3639
|
+
return { result: false, attributes: { error: wrapped.message } };
|
|
2074
3640
|
}
|
|
2075
3641
|
}
|
|
2076
3642
|
visibilityHandler(input, attributes) {
|
|
@@ -2107,10 +3673,19 @@ var UseExecutorsBase = class {
|
|
|
2107
3673
|
async callFunction(name, input) {
|
|
2108
3674
|
try {
|
|
2109
3675
|
const handler = this.getFunction(name);
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
3676
|
+
if (!handler) {
|
|
3677
|
+
throw new LlmExeError(
|
|
3678
|
+
`[invalid handler] The handler (${name}) does not exist.`,
|
|
3679
|
+
{
|
|
3680
|
+
code: "callable.handler_not_found",
|
|
3681
|
+
context: {
|
|
3682
|
+
operation: "UseExecutorsBase.callFunction",
|
|
3683
|
+
functionName: name,
|
|
3684
|
+
availableFunctions: this.handlers.map((h) => h.name)
|
|
3685
|
+
}
|
|
3686
|
+
}
|
|
3687
|
+
);
|
|
3688
|
+
}
|
|
2114
3689
|
const result = await handler.execute(ensureInputIsObject(input));
|
|
2115
3690
|
return result;
|
|
2116
3691
|
} catch (error) {
|
|
@@ -2120,10 +3695,19 @@ var UseExecutorsBase = class {
|
|
|
2120
3695
|
async validateFunctionInput(name, input) {
|
|
2121
3696
|
try {
|
|
2122
3697
|
const handler = this.getFunction(name);
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
3698
|
+
if (!handler) {
|
|
3699
|
+
throw new LlmExeError(
|
|
3700
|
+
`[invalid handler] The handler (${name}) does not exist.`,
|
|
3701
|
+
{
|
|
3702
|
+
code: "callable.handler_not_found",
|
|
3703
|
+
context: {
|
|
3704
|
+
operation: "UseExecutorsBase.validateFunctionInput",
|
|
3705
|
+
functionName: name,
|
|
3706
|
+
availableFunctions: this.handlers.map((h) => h.name)
|
|
3707
|
+
}
|
|
3708
|
+
}
|
|
3709
|
+
);
|
|
3710
|
+
}
|
|
2127
3711
|
const result = await handler.validateInput(
|
|
2128
3712
|
ensureInputIsObject(input)
|
|
2129
3713
|
);
|
|
@@ -2138,18 +3722,59 @@ var UseExecutorsBase = class {
|
|
|
2138
3722
|
function createCallableExecutor(options) {
|
|
2139
3723
|
return new CallableExecutor(options);
|
|
2140
3724
|
}
|
|
2141
|
-
var UseExecutors = class extends UseExecutorsBase {
|
|
2142
|
-
constructor(handlers) {
|
|
2143
|
-
super(handlers);
|
|
2144
|
-
}
|
|
2145
|
-
};
|
|
2146
|
-
function useExecutors(executors) {
|
|
2147
|
-
return new UseExecutors(
|
|
2148
|
-
executors.map((e) => {
|
|
2149
|
-
if (e instanceof CallableExecutor) return e;
|
|
2150
|
-
return createCallableExecutor(e);
|
|
2151
|
-
})
|
|
2152
|
-
);
|
|
3725
|
+
var UseExecutors = class extends UseExecutorsBase {
|
|
3726
|
+
constructor(handlers) {
|
|
3727
|
+
super(handlers);
|
|
3728
|
+
}
|
|
3729
|
+
};
|
|
3730
|
+
function useExecutors(executors) {
|
|
3731
|
+
return new UseExecutors(
|
|
3732
|
+
executors.map((e) => {
|
|
3733
|
+
if (e instanceof CallableExecutor) return e;
|
|
3734
|
+
return createCallableExecutor(e);
|
|
3735
|
+
})
|
|
3736
|
+
);
|
|
3737
|
+
}
|
|
3738
|
+
|
|
3739
|
+
// src/utils/guards.ts
|
|
3740
|
+
var guards_exports = {};
|
|
3741
|
+
__export(guards_exports, {
|
|
3742
|
+
hasFunctionCall: () => hasFunctionCall,
|
|
3743
|
+
hasToolCall: () => hasToolCall,
|
|
3744
|
+
isAssistantMessage: () => isAssistantMessage,
|
|
3745
|
+
isFunctionCall: () => isFunctionCall,
|
|
3746
|
+
isOutputResult: () => isOutputResult,
|
|
3747
|
+
isOutputResultContentText: () => isOutputResultContentText,
|
|
3748
|
+
isSystemMessage: () => isSystemMessage,
|
|
3749
|
+
isToolCall: () => isToolCall,
|
|
3750
|
+
isUserMessage: () => isUserMessage
|
|
3751
|
+
});
|
|
3752
|
+
function isOutputResult(obj) {
|
|
3753
|
+
return !!(obj && typeof obj === "object" && "id" in obj && "stopReason" in obj && "content" in obj && Array.isArray(obj.content));
|
|
3754
|
+
}
|
|
3755
|
+
function isOutputResultContentText(obj) {
|
|
3756
|
+
return !!(obj && typeof obj === "object" && "text" in obj && "type" in obj && obj.type === "text" && typeof obj.text === "string");
|
|
3757
|
+
}
|
|
3758
|
+
function isFunctionCall(result) {
|
|
3759
|
+
return !!(result && typeof result === "object" && "functionId" in result && "type" in result && result.type === "function_use");
|
|
3760
|
+
}
|
|
3761
|
+
function isToolCall(result) {
|
|
3762
|
+
return isFunctionCall(result);
|
|
3763
|
+
}
|
|
3764
|
+
function hasFunctionCall(results) {
|
|
3765
|
+
return !!(results && Array.isArray(results) && results.some(isToolCall));
|
|
3766
|
+
}
|
|
3767
|
+
function hasToolCall(results) {
|
|
3768
|
+
return hasFunctionCall(results);
|
|
3769
|
+
}
|
|
3770
|
+
function isUserMessage(message) {
|
|
3771
|
+
return message.role === "user";
|
|
3772
|
+
}
|
|
3773
|
+
function isAssistantMessage(message) {
|
|
3774
|
+
return message.role === "assistant" || message.role === "model";
|
|
3775
|
+
}
|
|
3776
|
+
function isSystemMessage(message) {
|
|
3777
|
+
return message.role === "system";
|
|
2153
3778
|
}
|
|
2154
3779
|
|
|
2155
3780
|
// src/utils/modules/deepClone.ts
|
|
@@ -2194,13 +3819,38 @@ function withDefaultModel(obj1, model) {
|
|
|
2194
3819
|
return copy;
|
|
2195
3820
|
}
|
|
2196
3821
|
|
|
2197
|
-
// src/
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
return
|
|
3822
|
+
// src/llm/_utils.deprecationWarning.ts
|
|
3823
|
+
var warned = /* @__PURE__ */ new Set();
|
|
3824
|
+
function emitDeprecationWarning(config, context) {
|
|
3825
|
+
if (!config.deprecated) return;
|
|
3826
|
+
if (typeof process !== "object" || typeof process?.emitWarning !== "function") {
|
|
3827
|
+
return;
|
|
2203
3828
|
}
|
|
3829
|
+
const { shorthand, message } = config.deprecated;
|
|
3830
|
+
if (warned.has(shorthand)) return;
|
|
3831
|
+
warned.add(shorthand);
|
|
3832
|
+
const detail = JSON.stringify({
|
|
3833
|
+
shorthand,
|
|
3834
|
+
model: config.options?.model?.default,
|
|
3835
|
+
provider: config.provider,
|
|
3836
|
+
executorName: context?.executorName,
|
|
3837
|
+
traceId: context?.traceId
|
|
3838
|
+
});
|
|
3839
|
+
process.emitWarning(message, {
|
|
3840
|
+
type: "DeprecationWarning",
|
|
3841
|
+
code: "LLM_EXE_DEPRECATED",
|
|
3842
|
+
detail
|
|
3843
|
+
});
|
|
3844
|
+
}
|
|
3845
|
+
function deprecateShorthand(shorthand, args) {
|
|
3846
|
+
const entry = {
|
|
3847
|
+
...args.config,
|
|
3848
|
+
deprecated: Object.freeze({
|
|
3849
|
+
shorthand,
|
|
3850
|
+
message: args.message
|
|
3851
|
+
})
|
|
3852
|
+
};
|
|
3853
|
+
return { [shorthand]: entry };
|
|
2204
3854
|
}
|
|
2205
3855
|
|
|
2206
3856
|
// src/llm/output/_util.ts
|
|
@@ -2482,7 +4132,10 @@ var openai = {
|
|
|
2482
4132
|
"openai.gpt-4o": withDefaultModel(openAiChatV1, "gpt-4o"),
|
|
2483
4133
|
"openai.gpt-4o-mini": withDefaultModel(openAiChatV1, "gpt-4o-mini"),
|
|
2484
4134
|
// Deprecated
|
|
2485
|
-
"openai.o4-mini"
|
|
4135
|
+
...deprecateShorthand("openai.o4-mini", {
|
|
4136
|
+
config: withDefaultModel(openAiChatV1, "o4-mini"),
|
|
4137
|
+
message: 'Shorthand "openai.o4-mini" is deprecated and may be removed in a future release.'
|
|
4138
|
+
})
|
|
2486
4139
|
};
|
|
2487
4140
|
|
|
2488
4141
|
// src/llm/config/anthropic/promptSanitizeMessageCallback.ts
|
|
@@ -2851,38 +4504,38 @@ var anthropic = {
|
|
|
2851
4504
|
"claude-sonnet-4-5"
|
|
2852
4505
|
),
|
|
2853
4506
|
// Deprecated
|
|
2854
|
-
"anthropic.claude-opus-4-6"
|
|
2855
|
-
anthropicChatV1,
|
|
2856
|
-
"claude-opus-4-6"
|
|
2857
|
-
),
|
|
2858
|
-
"anthropic.claude-opus-4-1"
|
|
2859
|
-
anthropicChatV1,
|
|
2860
|
-
"claude-opus-4-1
|
|
2861
|
-
),
|
|
2862
|
-
"anthropic.claude-sonnet-4"
|
|
2863
|
-
anthropicChatV1,
|
|
2864
|
-
"claude-sonnet-4
|
|
2865
|
-
),
|
|
2866
|
-
"anthropic.claude-opus-4"
|
|
2867
|
-
anthropicChatV1,
|
|
2868
|
-
"claude-opus-4
|
|
2869
|
-
),
|
|
2870
|
-
"anthropic.claude-3-7-sonnet"
|
|
2871
|
-
anthropicChatV1,
|
|
2872
|
-
"claude-3-7-sonnet
|
|
2873
|
-
),
|
|
2874
|
-
"anthropic.claude-3-5-sonnet"
|
|
2875
|
-
anthropicChatV1,
|
|
2876
|
-
"claude-3-5-sonnet
|
|
2877
|
-
),
|
|
2878
|
-
"anthropic.claude-3-5-haiku"
|
|
2879
|
-
anthropicChatV1,
|
|
2880
|
-
"claude-3-5-haiku
|
|
2881
|
-
),
|
|
2882
|
-
"anthropic.claude-3-opus"
|
|
2883
|
-
anthropicChatV1,
|
|
2884
|
-
"claude-3-opus
|
|
2885
|
-
)
|
|
4507
|
+
...deprecateShorthand("anthropic.claude-opus-4-6", {
|
|
4508
|
+
config: withDefaultModel(anthropicChatV1, "claude-opus-4-6"),
|
|
4509
|
+
message: 'Shorthand "anthropic.claude-opus-4-6" is deprecated and may be removed in a future release.'
|
|
4510
|
+
}),
|
|
4511
|
+
...deprecateShorthand("anthropic.claude-opus-4-1", {
|
|
4512
|
+
config: withDefaultModel(anthropicChatV1, "claude-opus-4-1-20250805"),
|
|
4513
|
+
message: 'Shorthand "anthropic.claude-opus-4-1" is deprecated and may be removed in a future release.'
|
|
4514
|
+
}),
|
|
4515
|
+
...deprecateShorthand("anthropic.claude-sonnet-4", {
|
|
4516
|
+
config: withDefaultModel(anthropicChatV1, "claude-sonnet-4-0"),
|
|
4517
|
+
message: 'Shorthand "anthropic.claude-sonnet-4" is deprecated and may be removed in a future release.'
|
|
4518
|
+
}),
|
|
4519
|
+
...deprecateShorthand("anthropic.claude-opus-4", {
|
|
4520
|
+
config: withDefaultModel(anthropicChatV1, "claude-opus-4-0"),
|
|
4521
|
+
message: 'Shorthand "anthropic.claude-opus-4" is deprecated and may be removed in a future release.'
|
|
4522
|
+
}),
|
|
4523
|
+
...deprecateShorthand("anthropic.claude-3-7-sonnet", {
|
|
4524
|
+
config: withDefaultModel(anthropicChatV1, "claude-3-7-sonnet-20250219"),
|
|
4525
|
+
message: 'Shorthand "anthropic.claude-3-7-sonnet" is deprecated and may be removed in a future release.'
|
|
4526
|
+
}),
|
|
4527
|
+
...deprecateShorthand("anthropic.claude-3-5-sonnet", {
|
|
4528
|
+
config: withDefaultModel(anthropicChatV1, "claude-3-5-sonnet-latest"),
|
|
4529
|
+
message: 'Shorthand "anthropic.claude-3-5-sonnet" is deprecated and may be removed in a future release.'
|
|
4530
|
+
}),
|
|
4531
|
+
...deprecateShorthand("anthropic.claude-3-5-haiku", {
|
|
4532
|
+
config: withDefaultModel(anthropicChatV1, "claude-3-5-haiku-latest"),
|
|
4533
|
+
message: 'Shorthand "anthropic.claude-3-5-haiku" is deprecated and may be removed in a future release.'
|
|
4534
|
+
}),
|
|
4535
|
+
...deprecateShorthand("anthropic.claude-3-opus", {
|
|
4536
|
+
config: withDefaultModel(anthropicChatV1, "claude-3-opus-20240229"),
|
|
4537
|
+
message: 'Shorthand "anthropic.claude-3-opus" is deprecated and may be removed in a future release.'
|
|
4538
|
+
})
|
|
2886
4539
|
};
|
|
2887
4540
|
|
|
2888
4541
|
// src/llm/config/x/index.ts
|
|
@@ -2901,20 +4554,41 @@ var xai = {
|
|
|
2901
4554
|
"xai.grok-4": withDefaultModel(xaiChatV1, "grok-4"),
|
|
2902
4555
|
"xai.grok-4-fast": withDefaultModel(xaiChatV1, "grok-4-fast-non-reasoning"),
|
|
2903
4556
|
"xai.grok-4-1-fast": withDefaultModel(xaiChatV1, "grok-4-1-fast-non-reasoning"),
|
|
2904
|
-
"xai.grok-4.3": withDefaultModel(xaiChatV1, "grok-4.3")
|
|
4557
|
+
"xai.grok-4.3": withDefaultModel(xaiChatV1, "grok-4.3"),
|
|
4558
|
+
"xai.grok-4.20": withDefaultModel(xaiChatV1, "grok-4.20-0309-non-reasoning"),
|
|
4559
|
+
"xai.grok-4.20-reasoning": withDefaultModel(
|
|
4560
|
+
xaiChatV1,
|
|
4561
|
+
"grok-4.20-0309-reasoning"
|
|
4562
|
+
)
|
|
2905
4563
|
};
|
|
2906
4564
|
|
|
2907
4565
|
// src/llm/output/_utils/combineJsonl.ts
|
|
2908
4566
|
function combineJsonl(jsonl) {
|
|
2909
|
-
const
|
|
4567
|
+
const rawLines = jsonl.trim().split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
|
|
4568
|
+
const lines = rawLines.map((line, idx) => {
|
|
2910
4569
|
try {
|
|
2911
4570
|
return JSON.parse(line);
|
|
2912
4571
|
} catch (e) {
|
|
2913
|
-
throw new
|
|
4572
|
+
throw new LlmExeError(`Invalid JSON: ${line}`, {
|
|
4573
|
+
code: "llm.invalid_jsonl_response",
|
|
4574
|
+
context: {
|
|
4575
|
+
operation: "combineJsonl",
|
|
4576
|
+
lineNumber: idx + 1,
|
|
4577
|
+
lineExcerpt: line
|
|
4578
|
+
},
|
|
4579
|
+
cause: e
|
|
4580
|
+
});
|
|
2914
4581
|
}
|
|
2915
4582
|
});
|
|
2916
4583
|
if (lines.length === 0) {
|
|
2917
|
-
throw new
|
|
4584
|
+
throw new LlmExeError("No JSON lines provided.", {
|
|
4585
|
+
code: "llm.invalid_jsonl_response",
|
|
4586
|
+
context: {
|
|
4587
|
+
operation: "combineJsonl",
|
|
4588
|
+
received: 0,
|
|
4589
|
+
expected: "at least one JSONL line"
|
|
4590
|
+
}
|
|
4591
|
+
});
|
|
2918
4592
|
}
|
|
2919
4593
|
lines.sort(
|
|
2920
4594
|
(a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime()
|
|
@@ -2923,7 +4597,14 @@ function combineJsonl(jsonl) {
|
|
|
2923
4597
|
combinedContent = combinedContent.replace(/\\u003c/g, "<").replace(/\\u003e/g, ">");
|
|
2924
4598
|
const finalLine = lines.find((line) => line.done === true);
|
|
2925
4599
|
if (!finalLine) {
|
|
2926
|
-
throw new
|
|
4600
|
+
throw new LlmExeError("No line found where done = true.", {
|
|
4601
|
+
code: "llm.invalid_jsonl_response",
|
|
4602
|
+
context: {
|
|
4603
|
+
operation: "combineJsonl",
|
|
4604
|
+
lineCount: lines.length,
|
|
4605
|
+
expected: "a final line with done = true"
|
|
4606
|
+
}
|
|
4607
|
+
});
|
|
2927
4608
|
}
|
|
2928
4609
|
const result = {
|
|
2929
4610
|
model: finalLine.model,
|
|
@@ -3012,7 +4693,10 @@ var ollama = {
|
|
|
3012
4693
|
"ollama.gemma3": withDefaultModel(ollamaChatV1, "gemma3"),
|
|
3013
4694
|
"ollama.mistral": withDefaultModel(ollamaChatV1, "mistral"),
|
|
3014
4695
|
"ollama.qwen2.5": withDefaultModel(ollamaChatV1, "qwen2.5"),
|
|
3015
|
-
"ollama.qwen3": withDefaultModel(ollamaChatV1, "qwen3")
|
|
4696
|
+
"ollama.qwen3": withDefaultModel(ollamaChatV1, "qwen3"),
|
|
4697
|
+
"ollama.qwen3.5": withDefaultModel(ollamaChatV1, "qwen3.5"),
|
|
4698
|
+
"ollama.gemma4": withDefaultModel(ollamaChatV1, "gemma4"),
|
|
4699
|
+
"ollama.gpt-oss": withDefaultModel(ollamaChatV1, "gpt-oss")
|
|
3016
4700
|
};
|
|
3017
4701
|
|
|
3018
4702
|
// src/llm/config/google/promptSanitizeMessageCallback.ts
|
|
@@ -3085,7 +4769,16 @@ function googleGeminiPromptSanitize(_messages, _inputBodyObj, _outputObj) {
|
|
|
3085
4769
|
}
|
|
3086
4770
|
if (Array.isArray(_messages)) {
|
|
3087
4771
|
if (_messages.length === 0) {
|
|
3088
|
-
throw new
|
|
4772
|
+
throw new LlmExeError("Empty messages array", {
|
|
4773
|
+
code: "prompt.invalid_messages",
|
|
4774
|
+
context: {
|
|
4775
|
+
operation: "googleGeminiPromptSanitize",
|
|
4776
|
+
provider: "google",
|
|
4777
|
+
received: "empty array",
|
|
4778
|
+
expected: "a non-empty messages array",
|
|
4779
|
+
resolution: "Pass at least one message to the prompt."
|
|
4780
|
+
}
|
|
4781
|
+
});
|
|
3089
4782
|
}
|
|
3090
4783
|
if (_messages.length === 1 && _messages[0].role === "system") {
|
|
3091
4784
|
return [{ role: "user", parts: [{ text: _messages[0].content }] }];
|
|
@@ -3113,7 +4806,16 @@ function googleGeminiPromptSanitize(_messages, _inputBodyObj, _outputObj) {
|
|
|
3113
4806
|
const result = _messages.map(googleGeminiPromptMessageCallback);
|
|
3114
4807
|
return mergeConsecutiveSameRole2(result);
|
|
3115
4808
|
}
|
|
3116
|
-
throw new
|
|
4809
|
+
throw new LlmExeError("Invalid messages format", {
|
|
4810
|
+
code: "prompt.invalid_messages",
|
|
4811
|
+
context: {
|
|
4812
|
+
operation: "googleGeminiPromptSanitize",
|
|
4813
|
+
provider: "google",
|
|
4814
|
+
received: typeof _messages,
|
|
4815
|
+
expected: "string or messages array",
|
|
4816
|
+
resolution: "Pass a string or an array of chat messages."
|
|
4817
|
+
}
|
|
4818
|
+
});
|
|
3117
4819
|
}
|
|
3118
4820
|
|
|
3119
4821
|
// src/llm/output/google.gemini/formatResult.ts
|
|
@@ -3229,23 +4931,27 @@ var googleGeminiChatV1 = {
|
|
|
3229
4931
|
};
|
|
3230
4932
|
var google = {
|
|
3231
4933
|
"google.chat.v1": googleGeminiChatV1,
|
|
3232
|
-
"google.gemini-2.5-flash": withDefaultModel(
|
|
3233
|
-
googleGeminiChatV1,
|
|
3234
|
-
"gemini-2.5-flash"
|
|
3235
|
-
),
|
|
3236
|
-
"google.gemini-2.5-flash-lite": withDefaultModel(
|
|
3237
|
-
googleGeminiChatV1,
|
|
3238
|
-
"gemini-2.5-flash-lite"
|
|
3239
|
-
),
|
|
3240
|
-
"google.gemini-2.5-pro": withDefaultModel(
|
|
3241
|
-
googleGeminiChatV1,
|
|
3242
|
-
"gemini-2.5-pro"
|
|
3243
|
-
),
|
|
3244
4934
|
"google.gemini-3.1-flash-lite": withDefaultModel(
|
|
3245
4935
|
googleGeminiChatV1,
|
|
3246
4936
|
"gemini-3.1-flash-lite"
|
|
3247
4937
|
),
|
|
4938
|
+
"google.gemini-3.5-flash": withDefaultModel(
|
|
4939
|
+
googleGeminiChatV1,
|
|
4940
|
+
"gemini-3.5-flash"
|
|
4941
|
+
),
|
|
3248
4942
|
// Deprecated
|
|
4943
|
+
...deprecateShorthand("google.gemini-2.5-flash", {
|
|
4944
|
+
config: withDefaultModel(googleGeminiChatV1, "gemini-2.5-flash"),
|
|
4945
|
+
message: 'Model "google.gemini-2.5-flash" is deprecated and will shut down on 2026-06-17.'
|
|
4946
|
+
}),
|
|
4947
|
+
...deprecateShorthand("google.gemini-2.5-flash-lite", {
|
|
4948
|
+
config: withDefaultModel(googleGeminiChatV1, "gemini-2.5-flash-lite"),
|
|
4949
|
+
message: 'Model "google.gemini-2.5-flash-lite" is deprecated and will shut down on 2026-07-22.'
|
|
4950
|
+
}),
|
|
4951
|
+
...deprecateShorthand("google.gemini-2.5-pro", {
|
|
4952
|
+
config: withDefaultModel(googleGeminiChatV1, "gemini-2.5-pro"),
|
|
4953
|
+
message: 'Model "google.gemini-2.5-pro" is deprecated and will shut down on 2026-06-17.'
|
|
4954
|
+
}),
|
|
3249
4955
|
"google.gemini-2.0-flash": withDefaultModel(
|
|
3250
4956
|
googleGeminiChatV1,
|
|
3251
4957
|
"gemini-2.0-flash"
|
|
@@ -3286,81 +4992,28 @@ var configs = {
|
|
|
3286
4992
|
};
|
|
3287
4993
|
function getLlmConfig(provider) {
|
|
3288
4994
|
if (!provider) {
|
|
3289
|
-
throw new LlmExeError(`Missing provider`,
|
|
3290
|
-
|
|
3291
|
-
|
|
4995
|
+
throw new LlmExeError(`Missing provider`, {
|
|
4996
|
+
code: "configuration.missing_provider",
|
|
4997
|
+
context: {
|
|
4998
|
+
operation: "getLlmConfig",
|
|
4999
|
+
availableProviders: Object.keys(configs),
|
|
5000
|
+
resolution: "Provide a valid provider"
|
|
5001
|
+
}
|
|
3292
5002
|
});
|
|
3293
5003
|
}
|
|
3294
5004
|
const pick2 = configs[provider];
|
|
3295
5005
|
if (pick2) {
|
|
3296
5006
|
return pick2;
|
|
3297
5007
|
}
|
|
3298
|
-
throw new LlmExeError(`Invalid provider: ${provider}`,
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
// src/utils/modules/maskApiKeysInDebug.ts
|
|
3306
|
-
function maskApiKeys(log) {
|
|
3307
|
-
return log.replace(
|
|
3308
|
-
/\b(Bearer\s+[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+|Bearer\s+[A-Za-z0-9\-_]{20,}|sk-[A-Za-z0-9]{20,}|AKIA[A-Z0-9]{16}|[A-Za-z0-9]{32,})\b/g,
|
|
3309
|
-
(match) => {
|
|
3310
|
-
if (match.length <= 8) return match;
|
|
3311
|
-
const prefix = match.substring(0, 4);
|
|
3312
|
-
const suffix = match.substring(match.length - 4);
|
|
3313
|
-
const maskLength = match.length - 8;
|
|
3314
|
-
return `${prefix}${"*".repeat(maskLength)}${suffix}`;
|
|
3315
|
-
}
|
|
3316
|
-
);
|
|
3317
|
-
}
|
|
3318
|
-
|
|
3319
|
-
// src/utils/modules/debug.ts
|
|
3320
|
-
function debug(...args) {
|
|
3321
|
-
const debugValue = getEnvironmentVariable("LLM_EXE_DEBUG");
|
|
3322
|
-
const logs = [];
|
|
3323
|
-
for (const arg of args) {
|
|
3324
|
-
if (arg && typeof arg === "object") {
|
|
3325
|
-
if (arg instanceof Error) {
|
|
3326
|
-
} else if (arg instanceof Array) {
|
|
3327
|
-
logs.push(arg.map((item) => JSON.stringify(item, null, 2)));
|
|
3328
|
-
} else if (arg instanceof Map) {
|
|
3329
|
-
logs.push(
|
|
3330
|
-
Array.from(arg.entries()).map(
|
|
3331
|
-
([key, value]) => `${key}: ${JSON.stringify(value, null, 2)}`
|
|
3332
|
-
)
|
|
3333
|
-
);
|
|
3334
|
-
} else if (arg instanceof Set) {
|
|
3335
|
-
logs.push(Array.from(arg).map((item) => JSON.stringify(item, null, 2)));
|
|
3336
|
-
} else if (arg instanceof Date) {
|
|
3337
|
-
logs.push(arg.toISOString());
|
|
3338
|
-
} else if (arg instanceof RegExp) {
|
|
3339
|
-
logs.push(arg.toString());
|
|
3340
|
-
} else {
|
|
3341
|
-
try {
|
|
3342
|
-
let shouldMask = false;
|
|
3343
|
-
if (arg.headers && arg.headers.Authorization) {
|
|
3344
|
-
shouldMask = true;
|
|
3345
|
-
}
|
|
3346
|
-
let str = JSON.stringify(arg, null, 2);
|
|
3347
|
-
if (shouldMask) {
|
|
3348
|
-
str = maskApiKeys(str);
|
|
3349
|
-
}
|
|
3350
|
-
logs.push(str);
|
|
3351
|
-
} catch (error) {
|
|
3352
|
-
console.error("Error parsing object:", error);
|
|
3353
|
-
}
|
|
3354
|
-
}
|
|
3355
|
-
} else if (typeof arg === "string") {
|
|
3356
|
-
logs.push(arg);
|
|
3357
|
-
} else {
|
|
3358
|
-
logs.push(arg);
|
|
5008
|
+
throw new LlmExeError(`Invalid provider: ${provider}`, {
|
|
5009
|
+
code: "configuration.invalid_provider",
|
|
5010
|
+
context: {
|
|
5011
|
+
operation: "getLlmConfig",
|
|
5012
|
+
provider,
|
|
5013
|
+
availableProviders: Object.keys(configs),
|
|
5014
|
+
resolution: "Provide a valid provider"
|
|
3359
5015
|
}
|
|
3360
|
-
}
|
|
3361
|
-
if (typeof debugValue === "string" && debugValue !== "" && debugValue.toLowerCase() !== "undefined" && debugValue.toLowerCase() !== "null") {
|
|
3362
|
-
console.debug(...logs);
|
|
3363
|
-
}
|
|
5016
|
+
});
|
|
3364
5017
|
}
|
|
3365
5018
|
|
|
3366
5019
|
// src/utils/modules/isValidUrl.ts
|
|
@@ -3378,41 +5031,93 @@ async function apiRequest(url, options) {
|
|
|
3378
5031
|
const finalOptions = {
|
|
3379
5032
|
...options
|
|
3380
5033
|
};
|
|
5034
|
+
debug(url, finalOptions);
|
|
5035
|
+
if (!url || !isValidUrl(url)) {
|
|
5036
|
+
const safeUrl = safeRequestUrl(url);
|
|
5037
|
+
throw new LlmExeError("Invalid URL", {
|
|
5038
|
+
code: "request.invalid_url",
|
|
5039
|
+
context: {
|
|
5040
|
+
operation: "apiRequest",
|
|
5041
|
+
url: safeUrl,
|
|
5042
|
+
expected: "valid URL"
|
|
5043
|
+
}
|
|
5044
|
+
});
|
|
5045
|
+
}
|
|
5046
|
+
let response;
|
|
3381
5047
|
try {
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
5048
|
+
response = await fetch(url, finalOptions);
|
|
5049
|
+
} catch (fetchError) {
|
|
5050
|
+
const innerMsg = fetchError instanceof Error ? fetchError.message : "Error";
|
|
5051
|
+
const safeUrl = safeRequestUrl(url);
|
|
5052
|
+
throw new LlmExeError(`Request to ${safeUrl} failed: ${innerMsg}`, {
|
|
5053
|
+
code: "request.http_error",
|
|
5054
|
+
context: {
|
|
5055
|
+
operation: "apiRequest",
|
|
5056
|
+
url: safeUrl
|
|
5057
|
+
},
|
|
5058
|
+
cause: fetchError
|
|
5059
|
+
});
|
|
5060
|
+
}
|
|
5061
|
+
if (!response.ok) {
|
|
5062
|
+
let bodyText = "";
|
|
5063
|
+
let bodyJson = void 0;
|
|
5064
|
+
let bodyReadError = void 0;
|
|
5065
|
+
try {
|
|
5066
|
+
bodyText = await response.text();
|
|
5067
|
+
if (bodyText) {
|
|
5068
|
+
try {
|
|
5069
|
+
bodyJson = JSON.parse(bodyText);
|
|
5070
|
+
} catch {
|
|
3400
5071
|
}
|
|
3401
|
-
} catch {
|
|
3402
5072
|
}
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
5073
|
+
} catch (e) {
|
|
5074
|
+
bodyReadError = e;
|
|
5075
|
+
}
|
|
5076
|
+
let message;
|
|
5077
|
+
if (bodyText) {
|
|
5078
|
+
let detail = bodyText;
|
|
5079
|
+
if (bodyJson) {
|
|
5080
|
+
const b = bodyJson;
|
|
5081
|
+
detail = b.error?.message || b.error || b.message || bodyText;
|
|
5082
|
+
if (typeof detail !== "string") detail = JSON.stringify(detail);
|
|
5083
|
+
}
|
|
5084
|
+
const safeDetail = safeProviderString(detail) ?? "";
|
|
5085
|
+
message = `HTTP error. Status Code: ${response.status}. Error Message: ${safeDetail}`;
|
|
3409
5086
|
} else {
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
const
|
|
3415
|
-
|
|
5087
|
+
message = `HTTP error. Status: ${response.status}. Error Message: ${response.statusText || "Unknown error."}`;
|
|
5088
|
+
}
|
|
5089
|
+
const safeUrl = safeRequestUrl(url);
|
|
5090
|
+
const wrappedMessage = `Request to ${safeUrl} failed: ${message}`;
|
|
5091
|
+
const safeHeaders = safeResponseHeaders(response.headers);
|
|
5092
|
+
const providerError = parseProviderErrorGeneric({
|
|
5093
|
+
status: response.status,
|
|
5094
|
+
statusText: response.statusText,
|
|
5095
|
+
headers: safeHeaders,
|
|
5096
|
+
bodyJson,
|
|
5097
|
+
bodyText
|
|
5098
|
+
});
|
|
5099
|
+
throw new LlmExeError(wrappedMessage, {
|
|
5100
|
+
code: "request.http_error",
|
|
5101
|
+
context: {
|
|
5102
|
+
operation: "apiRequest",
|
|
5103
|
+
url: safeUrl,
|
|
5104
|
+
status: response.status,
|
|
5105
|
+
statusText: response.statusText,
|
|
5106
|
+
responseHeaders: safeHeaders,
|
|
5107
|
+
providerError,
|
|
5108
|
+
providerErrorBody: bodyJson !== void 0 ? safeProviderErrorBody(bodyJson) : void 0,
|
|
5109
|
+
providerErrorRaw: bodyText ? safeProviderErrorBody(bodyText) : void 0
|
|
5110
|
+
},
|
|
5111
|
+
cause: bodyReadError
|
|
5112
|
+
});
|
|
5113
|
+
}
|
|
5114
|
+
const contentType = response.headers.get("content-type");
|
|
5115
|
+
if (contentType?.includes("application/json")) {
|
|
5116
|
+
const responseData = await response.json();
|
|
5117
|
+
return responseData;
|
|
5118
|
+
} else {
|
|
5119
|
+
const responseData = await response.text();
|
|
5120
|
+
return responseData;
|
|
3416
5121
|
}
|
|
3417
5122
|
}
|
|
3418
5123
|
|
|
@@ -3533,7 +5238,19 @@ async function runWithTemporaryEnv(env, handler) {
|
|
|
3533
5238
|
// src/utils/modules/getAwsAuthorizationHeaders.ts
|
|
3534
5239
|
async function getAwsAuthorizationHeaders(req, props) {
|
|
3535
5240
|
if (!props.url || !props.regionName) {
|
|
3536
|
-
throw new
|
|
5241
|
+
throw new LlmExeError(
|
|
5242
|
+
"URL and region name are required for AWS authorization",
|
|
5243
|
+
{
|
|
5244
|
+
code: "auth.aws_signing_input_missing",
|
|
5245
|
+
context: {
|
|
5246
|
+
operation: "getAwsAuthorizationHeaders",
|
|
5247
|
+
url: props.url,
|
|
5248
|
+
regionName: props.regionName,
|
|
5249
|
+
expected: "both url and regionName to be set",
|
|
5250
|
+
resolution: "Set AWS_REGION as an environment variable (or pass regionName) and provide a valid request URL."
|
|
5251
|
+
}
|
|
5252
|
+
}
|
|
5253
|
+
);
|
|
3537
5254
|
}
|
|
3538
5255
|
const providerChain = (0, import_credential_providers.fromNodeProviderChain)();
|
|
3539
5256
|
const credentials = await runWithTemporaryEnv(
|
|
@@ -3572,6 +5289,12 @@ async function getAwsAuthorizationHeaders(req, props) {
|
|
|
3572
5289
|
}
|
|
3573
5290
|
|
|
3574
5291
|
// src/llm/_utils.parseHeaders.ts
|
|
5292
|
+
var REPLACED_HEADERS_EXCERPT_MAX = 500;
|
|
5293
|
+
function safeReplacedHeaders(value) {
|
|
5294
|
+
if (!value) return "";
|
|
5295
|
+
const truncated = value.length > REPLACED_HEADERS_EXCERPT_MAX ? value.slice(0, REPLACED_HEADERS_EXCERPT_MAX) + "\u2026(truncated)" : value;
|
|
5296
|
+
return redactSecrets(truncated);
|
|
5297
|
+
}
|
|
3575
5298
|
async function parseHeaders(config, replacements, payload) {
|
|
3576
5299
|
const replace = replaceTemplateStringSimple(config.headers, replacements);
|
|
3577
5300
|
let parsedHeaders = {};
|
|
@@ -3583,8 +5306,21 @@ async function parseHeaders(config, replacements, payload) {
|
|
|
3583
5306
|
}
|
|
3584
5307
|
} catch (error) {
|
|
3585
5308
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
3586
|
-
|
|
3587
|
-
|
|
5309
|
+
const safeReplaced = safeReplacedHeaders(replace);
|
|
5310
|
+
throw new LlmExeError(
|
|
5311
|
+
`Failed to parse headers configuration: ${errorMessage}. Headers template: "${config.headers}". After replacement: "${safeReplaced}"`,
|
|
5312
|
+
{
|
|
5313
|
+
code: "configuration.invalid_headers",
|
|
5314
|
+
context: {
|
|
5315
|
+
operation: "parseHeaders",
|
|
5316
|
+
provider: config.provider,
|
|
5317
|
+
key: config.key,
|
|
5318
|
+
headerTemplate: config.headers,
|
|
5319
|
+
replacedHeadersExcerpt: safeReplaced,
|
|
5320
|
+
resolution: "Fix the headers template so replacement produces a JSON object."
|
|
5321
|
+
},
|
|
5322
|
+
cause: error
|
|
5323
|
+
}
|
|
3588
5324
|
);
|
|
3589
5325
|
}
|
|
3590
5326
|
}
|
|
@@ -3738,29 +5474,47 @@ async function useLlm_call(state, messages, _options) {
|
|
|
3738
5474
|
headers: {},
|
|
3739
5475
|
body
|
|
3740
5476
|
});
|
|
3741
|
-
const response = config.provider === "openai.chat-mock" ? {
|
|
3742
|
-
id: "0123-45-6789",
|
|
3743
|
-
model: "model",
|
|
3744
|
-
created: (/* @__PURE__ */ new Date()).getTime(),
|
|
3745
|
-
usage: { completion_tokens: 0, prompt_tokens: 0, total_tokens: 0 },
|
|
3746
|
-
choices: [
|
|
3747
|
-
{
|
|
3748
|
-
message: {
|
|
3749
|
-
role: "assistant",
|
|
3750
|
-
content: `Hello world from LLM! The input was ${JSON.stringify(
|
|
3751
|
-
messages
|
|
3752
|
-
)}`
|
|
3753
|
-
}
|
|
3754
|
-
}
|
|
3755
|
-
]
|
|
3756
|
-
} : await apiRequest(url, {
|
|
3757
|
-
method: config.method,
|
|
3758
|
-
body,
|
|
3759
|
-
headers
|
|
3760
|
-
});
|
|
3761
5477
|
const { transformResponse = OutputDefault } = config;
|
|
3762
|
-
|
|
3763
|
-
|
|
5478
|
+
if (config.provider === "openai.chat-mock") {
|
|
5479
|
+
const mockResponse = {
|
|
5480
|
+
id: "0123-45-6789",
|
|
5481
|
+
model: "model",
|
|
5482
|
+
created: (/* @__PURE__ */ new Date()).getTime(),
|
|
5483
|
+
usage: { completion_tokens: 0, prompt_tokens: 0, total_tokens: 0 },
|
|
5484
|
+
choices: [
|
|
5485
|
+
{
|
|
5486
|
+
message: {
|
|
5487
|
+
role: "assistant",
|
|
5488
|
+
content: `Hello world from LLM! The input was ${JSON.stringify(messages)}`
|
|
5489
|
+
}
|
|
5490
|
+
}
|
|
5491
|
+
]
|
|
5492
|
+
};
|
|
5493
|
+
return BaseLlmOutput(transformResponse(mockResponse, config));
|
|
5494
|
+
}
|
|
5495
|
+
try {
|
|
5496
|
+
const response = await apiRequest(url, {
|
|
5497
|
+
method: config.method,
|
|
5498
|
+
body,
|
|
5499
|
+
headers
|
|
5500
|
+
});
|
|
5501
|
+
return BaseLlmOutput(transformResponse(response, config));
|
|
5502
|
+
} catch (e) {
|
|
5503
|
+
if (!isLlmExeError(e, "request.http_error")) throw e;
|
|
5504
|
+
const ctx = e.context ?? {};
|
|
5505
|
+
const status = typeof ctx.status === "number" ? ctx.status : void 0;
|
|
5506
|
+
const code = status ? statusToLlmProviderCode(status) : "llm.provider_http_error";
|
|
5507
|
+
throw new LlmExeError(e.message, {
|
|
5508
|
+
code,
|
|
5509
|
+
context: {
|
|
5510
|
+
...ctx,
|
|
5511
|
+
operation: "useLlm_call",
|
|
5512
|
+
provider: state.provider,
|
|
5513
|
+
model: state.model
|
|
5514
|
+
},
|
|
5515
|
+
cause: e
|
|
5516
|
+
});
|
|
5517
|
+
}
|
|
3764
5518
|
}
|
|
3765
5519
|
|
|
3766
5520
|
// src/llm/_utils.stateFromOptions.ts
|
|
@@ -3784,7 +5538,16 @@ function stateFromOptions(options, config) {
|
|
|
3784
5538
|
if (Array.isArray(thisConfig?.required)) {
|
|
3785
5539
|
const [required, message = `Error: [${key}] is required`] = thisConfig.required;
|
|
3786
5540
|
if (required && typeof value === "undefined") {
|
|
3787
|
-
throw new
|
|
5541
|
+
throw new LlmExeError(message, {
|
|
5542
|
+
code: "configuration.missing_option",
|
|
5543
|
+
context: {
|
|
5544
|
+
operation: "stateFromOptions",
|
|
5545
|
+
provider: config.provider,
|
|
5546
|
+
key: config.key,
|
|
5547
|
+
option: String(key),
|
|
5548
|
+
resolution: `Provide a value for "${String(key)}" via options or environment.`
|
|
5549
|
+
}
|
|
5550
|
+
});
|
|
3788
5551
|
}
|
|
3789
5552
|
}
|
|
3790
5553
|
}
|
|
@@ -3831,8 +5594,12 @@ function apiRequestWrapper(config, options, handler, doNotRetryErrorMessages = [
|
|
|
3831
5594
|
const numOfAttempts = options.numOfAttempts || 2;
|
|
3832
5595
|
const jitter = options.jitter || "none";
|
|
3833
5596
|
let traceId = options?.traceId || null;
|
|
3834
|
-
async function call(messages, options2) {
|
|
5597
|
+
async function call(messages, options2, context) {
|
|
3835
5598
|
try {
|
|
5599
|
+
emitDeprecationWarning(config, {
|
|
5600
|
+
executorName: context?.executor?.name,
|
|
5601
|
+
traceId: context?.traceId ?? getTraceId() ?? void 0
|
|
5602
|
+
});
|
|
3836
5603
|
metrics.total_calls++;
|
|
3837
5604
|
const result = await (0, import_exponential_backoff.backOff)(
|
|
3838
5605
|
() => asyncCallWithTimeout(
|
|
@@ -4010,8 +5777,19 @@ var embeddingConfigs = {
|
|
|
4010
5777
|
const isV3 = /embed-(english|multilingual)-v3/.test(model);
|
|
4011
5778
|
if (isV3) {
|
|
4012
5779
|
if (value === 1024) return void 0;
|
|
4013
|
-
throw new
|
|
4014
|
-
`Cohere Embed v3 only supports 1024-dimensional output (model: "${model}", requested: ${value}). Use cohere.embed-v4:0 for configurable dimensions
|
|
5780
|
+
throw new LlmExeError(
|
|
5781
|
+
`Cohere Embed v3 only supports 1024-dimensional output (model: "${model}", requested: ${value}). Use cohere.embed-v4:0 for configurable dimensions.`,
|
|
5782
|
+
{
|
|
5783
|
+
code: "embedding.unsupported_dimensions",
|
|
5784
|
+
context: {
|
|
5785
|
+
operation: "embedding.dimensionTransform",
|
|
5786
|
+
provider: "amazon:cohere.embedding",
|
|
5787
|
+
model,
|
|
5788
|
+
dimensions: value,
|
|
5789
|
+
expected: 1024,
|
|
5790
|
+
resolution: "Use cohere.embed-v4:0 for configurable dimensions."
|
|
5791
|
+
}
|
|
5792
|
+
}
|
|
4015
5793
|
);
|
|
4016
5794
|
}
|
|
4017
5795
|
return value;
|
|
@@ -4022,13 +5800,28 @@ var embeddingConfigs = {
|
|
|
4022
5800
|
};
|
|
4023
5801
|
function getEmbeddingConfig(provider) {
|
|
4024
5802
|
if (!provider) {
|
|
4025
|
-
throw new
|
|
5803
|
+
throw new LlmExeError(`Missing provider`, {
|
|
5804
|
+
code: "embedding.missing_provider",
|
|
5805
|
+
context: {
|
|
5806
|
+
operation: "getEmbeddingConfig",
|
|
5807
|
+
availableProviders: Object.keys(embeddingConfigs),
|
|
5808
|
+
resolution: "Provide a valid embedding provider key."
|
|
5809
|
+
}
|
|
5810
|
+
});
|
|
4026
5811
|
}
|
|
4027
5812
|
const pick2 = embeddingConfigs[provider];
|
|
4028
5813
|
if (pick2) {
|
|
4029
5814
|
return pick2;
|
|
4030
5815
|
}
|
|
4031
|
-
throw new
|
|
5816
|
+
throw new LlmExeError(`Invalid provider: ${provider}`, {
|
|
5817
|
+
code: "embedding.invalid_provider",
|
|
5818
|
+
context: {
|
|
5819
|
+
operation: "getEmbeddingConfig",
|
|
5820
|
+
provider,
|
|
5821
|
+
availableProviders: Object.keys(embeddingConfigs),
|
|
5822
|
+
resolution: "Provide a valid embedding provider key."
|
|
5823
|
+
}
|
|
5824
|
+
});
|
|
4032
5825
|
}
|
|
4033
5826
|
|
|
4034
5827
|
// src/embedding/output/BaseEmbeddingOutput.ts
|
|
@@ -4132,7 +5925,16 @@ function getEmbeddingOutputParser(config, response) {
|
|
|
4132
5925
|
case "amazon:cohere.embedding.v1":
|
|
4133
5926
|
return CohereBedrockEmbedding(response, config);
|
|
4134
5927
|
default:
|
|
4135
|
-
throw new
|
|
5928
|
+
throw new LlmExeError("Unsupported provider", {
|
|
5929
|
+
code: "embedding.invalid_response_shape",
|
|
5930
|
+
context: {
|
|
5931
|
+
operation: "getEmbeddingOutputParser",
|
|
5932
|
+
provider: config.key,
|
|
5933
|
+
model: config.model,
|
|
5934
|
+
availableProviders: Object.keys(embeddingConfigs),
|
|
5935
|
+
resolution: "Use a supported embedding provider key."
|
|
5936
|
+
}
|
|
5937
|
+
});
|
|
4136
5938
|
}
|
|
4137
5939
|
}
|
|
4138
5940
|
|
|
@@ -4152,12 +5954,29 @@ async function createEmbedding_call(state, _input, _options) {
|
|
|
4152
5954
|
headers: {},
|
|
4153
5955
|
body
|
|
4154
5956
|
});
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
5957
|
+
try {
|
|
5958
|
+
const request = await apiRequest(url, {
|
|
5959
|
+
method: config.method,
|
|
5960
|
+
body,
|
|
5961
|
+
headers
|
|
5962
|
+
});
|
|
5963
|
+
return getEmbeddingOutputParser(state, request);
|
|
5964
|
+
} catch (e) {
|
|
5965
|
+
if (!isLlmExeError(e, "request.http_error")) throw e;
|
|
5966
|
+
const ctx = e.context ?? {};
|
|
5967
|
+
const status = typeof ctx.status === "number" ? ctx.status : void 0;
|
|
5968
|
+
const code = status ? statusToEmbeddingProviderCode(status) : "embedding.provider_http_error";
|
|
5969
|
+
throw new LlmExeError(e.message, {
|
|
5970
|
+
code,
|
|
5971
|
+
context: {
|
|
5972
|
+
...ctx,
|
|
5973
|
+
operation: "createEmbedding_call",
|
|
5974
|
+
provider: state.provider,
|
|
5975
|
+
model: state.model
|
|
5976
|
+
},
|
|
5977
|
+
cause: e
|
|
5978
|
+
});
|
|
5979
|
+
}
|
|
4161
5980
|
}
|
|
4162
5981
|
|
|
4163
5982
|
// src/embedding/embedding.ts
|
|
@@ -4166,6 +5985,245 @@ function createEmbedding(provider, options) {
|
|
|
4166
5985
|
return apiRequestWrapper(config, options, createEmbedding_call);
|
|
4167
5986
|
}
|
|
4168
5987
|
|
|
5988
|
+
// src/prompt/_templateValidation.ts
|
|
5989
|
+
var BUILT_IN_HELPERS = /* @__PURE__ */ new Set([
|
|
5990
|
+
"if",
|
|
5991
|
+
"unless",
|
|
5992
|
+
"each",
|
|
5993
|
+
"with",
|
|
5994
|
+
"lookup",
|
|
5995
|
+
"log",
|
|
5996
|
+
"blockHelperMissing",
|
|
5997
|
+
"helperMissing"
|
|
5998
|
+
]);
|
|
5999
|
+
function isKnownHelper(name, customHelpers) {
|
|
6000
|
+
if (BUILT_IN_HELPERS.has(name)) return true;
|
|
6001
|
+
if (customHelpers && Object.prototype.hasOwnProperty.call(customHelpers, name)) {
|
|
6002
|
+
return true;
|
|
6003
|
+
}
|
|
6004
|
+
return false;
|
|
6005
|
+
}
|
|
6006
|
+
function pathRootSegment(path) {
|
|
6007
|
+
if (path.depth > 0) return null;
|
|
6008
|
+
if (path.data) return null;
|
|
6009
|
+
if (path.parts.length === 0) return null;
|
|
6010
|
+
return path.parts[0];
|
|
6011
|
+
}
|
|
6012
|
+
function pathToCollectedString(path) {
|
|
6013
|
+
const parts = path.parts.slice();
|
|
6014
|
+
return parts.join(".");
|
|
6015
|
+
}
|
|
6016
|
+
function collectFromPath(path, source, locals, options, references, seen) {
|
|
6017
|
+
const root = pathRootSegment(path);
|
|
6018
|
+
if (!root) return;
|
|
6019
|
+
if (locals.has(root)) return;
|
|
6020
|
+
const collected = pathToCollectedString(path);
|
|
6021
|
+
const dedupKey = `${source}::${collected}`;
|
|
6022
|
+
if (seen.has(dedupKey)) return;
|
|
6023
|
+
seen.add(dedupKey);
|
|
6024
|
+
references.push({
|
|
6025
|
+
path: collected,
|
|
6026
|
+
source,
|
|
6027
|
+
location: options.location
|
|
6028
|
+
});
|
|
6029
|
+
}
|
|
6030
|
+
function collectFromExpression(expr, source, locals, options, references, missingHelpers, seen) {
|
|
6031
|
+
if (expr.type === "PathExpression") {
|
|
6032
|
+
collectFromPath(expr, source, locals, options, references, seen);
|
|
6033
|
+
return;
|
|
6034
|
+
}
|
|
6035
|
+
if (expr.type === "SubExpression") {
|
|
6036
|
+
walkCall(
|
|
6037
|
+
expr.path,
|
|
6038
|
+
expr.params,
|
|
6039
|
+
expr.hash,
|
|
6040
|
+
locals,
|
|
6041
|
+
options,
|
|
6042
|
+
references,
|
|
6043
|
+
missingHelpers,
|
|
6044
|
+
seen
|
|
6045
|
+
);
|
|
6046
|
+
return;
|
|
6047
|
+
}
|
|
6048
|
+
}
|
|
6049
|
+
function walkHash(hash, locals, options, references, missingHelpers, seen) {
|
|
6050
|
+
if (!hash || !hash.pairs) return;
|
|
6051
|
+
for (const pair of hash.pairs) {
|
|
6052
|
+
collectFromExpression(
|
|
6053
|
+
pair.value,
|
|
6054
|
+
"hash",
|
|
6055
|
+
locals,
|
|
6056
|
+
options,
|
|
6057
|
+
references,
|
|
6058
|
+
missingHelpers,
|
|
6059
|
+
seen
|
|
6060
|
+
);
|
|
6061
|
+
}
|
|
6062
|
+
}
|
|
6063
|
+
function walkCall(path, params, hash, locals, options, references, missingHelpers, seen) {
|
|
6064
|
+
const root = pathRootSegment(path);
|
|
6065
|
+
const hasArgs = params.length > 0 || hash !== void 0 && hash.pairs.length > 0;
|
|
6066
|
+
if (hasArgs) {
|
|
6067
|
+
if (root) {
|
|
6068
|
+
if (!isKnownHelper(path.original, options.helpers) && !locals.has(root)) {
|
|
6069
|
+
missingHelpers.add(path.original);
|
|
6070
|
+
}
|
|
6071
|
+
}
|
|
6072
|
+
for (const param of params) {
|
|
6073
|
+
collectFromExpression(
|
|
6074
|
+
param,
|
|
6075
|
+
"helper-param",
|
|
6076
|
+
locals,
|
|
6077
|
+
options,
|
|
6078
|
+
references,
|
|
6079
|
+
missingHelpers,
|
|
6080
|
+
seen
|
|
6081
|
+
);
|
|
6082
|
+
}
|
|
6083
|
+
walkHash(hash, locals, options, references, missingHelpers, seen);
|
|
6084
|
+
return;
|
|
6085
|
+
}
|
|
6086
|
+
if (root && isKnownHelper(path.original, options.helpers)) {
|
|
6087
|
+
return;
|
|
6088
|
+
}
|
|
6089
|
+
collectFromPath(path, "mustache", locals, options, references, seen);
|
|
6090
|
+
}
|
|
6091
|
+
function walkProgram(program, parentLocals, options, references, missingHelpers, seen) {
|
|
6092
|
+
if (!program) return;
|
|
6093
|
+
const locals = new Set(parentLocals);
|
|
6094
|
+
if (program.blockParams) {
|
|
6095
|
+
for (const bp of program.blockParams) {
|
|
6096
|
+
locals.add(bp);
|
|
6097
|
+
}
|
|
6098
|
+
}
|
|
6099
|
+
for (const node of program.body) {
|
|
6100
|
+
walkStatement(node, locals, options, references, missingHelpers, seen);
|
|
6101
|
+
}
|
|
6102
|
+
}
|
|
6103
|
+
function walkStatement(node, locals, options, references, missingHelpers, seen) {
|
|
6104
|
+
switch (node.type) {
|
|
6105
|
+
case "MustacheStatement": {
|
|
6106
|
+
const m = node;
|
|
6107
|
+
if (m.path.type === "PathExpression") {
|
|
6108
|
+
walkCall(
|
|
6109
|
+
m.path,
|
|
6110
|
+
m.params,
|
|
6111
|
+
m.hash,
|
|
6112
|
+
locals,
|
|
6113
|
+
options,
|
|
6114
|
+
references,
|
|
6115
|
+
missingHelpers,
|
|
6116
|
+
seen
|
|
6117
|
+
);
|
|
6118
|
+
}
|
|
6119
|
+
return;
|
|
6120
|
+
}
|
|
6121
|
+
case "BlockStatement": {
|
|
6122
|
+
const b = node;
|
|
6123
|
+
const root = pathRootSegment(b.path);
|
|
6124
|
+
if (root && !isKnownHelper(b.path.original, options.helpers) && !locals.has(root)) {
|
|
6125
|
+
missingHelpers.add(b.path.original);
|
|
6126
|
+
}
|
|
6127
|
+
for (const param of b.params) {
|
|
6128
|
+
collectFromExpression(
|
|
6129
|
+
param,
|
|
6130
|
+
"block-param",
|
|
6131
|
+
locals,
|
|
6132
|
+
options,
|
|
6133
|
+
references,
|
|
6134
|
+
missingHelpers,
|
|
6135
|
+
seen
|
|
6136
|
+
);
|
|
6137
|
+
}
|
|
6138
|
+
walkHash(b.hash, locals, options, references, missingHelpers, seen);
|
|
6139
|
+
const isEach = b.path.original === "each";
|
|
6140
|
+
const hasBlockParams = b.program?.blockParams && b.program.blockParams.length > 0 || b.inverse?.blockParams && b.inverse.blockParams.length > 0;
|
|
6141
|
+
if (isEach && !hasBlockParams) {
|
|
6142
|
+
return;
|
|
6143
|
+
}
|
|
6144
|
+
walkProgram(b.program, locals, options, references, missingHelpers, seen);
|
|
6145
|
+
walkProgram(b.inverse, locals, options, references, missingHelpers, seen);
|
|
6146
|
+
return;
|
|
6147
|
+
}
|
|
6148
|
+
case "PartialStatement": {
|
|
6149
|
+
const p = node;
|
|
6150
|
+
for (const param of p.params) {
|
|
6151
|
+
collectFromExpression(
|
|
6152
|
+
param,
|
|
6153
|
+
"helper-param",
|
|
6154
|
+
locals,
|
|
6155
|
+
options,
|
|
6156
|
+
references,
|
|
6157
|
+
missingHelpers,
|
|
6158
|
+
seen
|
|
6159
|
+
);
|
|
6160
|
+
}
|
|
6161
|
+
walkHash(p.hash, locals, options, references, missingHelpers, seen);
|
|
6162
|
+
return;
|
|
6163
|
+
}
|
|
6164
|
+
}
|
|
6165
|
+
}
|
|
6166
|
+
function collectAll(template, options) {
|
|
6167
|
+
const references = [];
|
|
6168
|
+
const missingHelpers = /* @__PURE__ */ new Set();
|
|
6169
|
+
let ast;
|
|
6170
|
+
try {
|
|
6171
|
+
ast = hbs.handlebars.parse(template);
|
|
6172
|
+
} catch {
|
|
6173
|
+
return { references, missingHelpers: [] };
|
|
6174
|
+
}
|
|
6175
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6176
|
+
walkProgram(ast, /* @__PURE__ */ new Set(), options, references, missingHelpers, seen);
|
|
6177
|
+
return { references, missingHelpers: Array.from(missingHelpers) };
|
|
6178
|
+
}
|
|
6179
|
+
function hasInputPath(input, path) {
|
|
6180
|
+
if (!input || typeof input !== "object") return false;
|
|
6181
|
+
let current = input;
|
|
6182
|
+
for (const part of path.split(".")) {
|
|
6183
|
+
if (!current || typeof current !== "object") return false;
|
|
6184
|
+
if (!Object.prototype.hasOwnProperty.call(current, part)) return false;
|
|
6185
|
+
current = current[part];
|
|
6186
|
+
}
|
|
6187
|
+
return current !== void 0;
|
|
6188
|
+
}
|
|
6189
|
+
function validateTemplateInputReferences(template, input, options = {}) {
|
|
6190
|
+
const { references, missingHelpers } = collectAll(template, options);
|
|
6191
|
+
const missingVariables = [];
|
|
6192
|
+
const seenMissing = /* @__PURE__ */ new Set();
|
|
6193
|
+
for (const ref of references) {
|
|
6194
|
+
if (hasInputPath(input, ref.path)) continue;
|
|
6195
|
+
const key = ref.path;
|
|
6196
|
+
if (seenMissing.has(key)) continue;
|
|
6197
|
+
seenMissing.add(key);
|
|
6198
|
+
missingVariables.push(ref);
|
|
6199
|
+
}
|
|
6200
|
+
return { references, missingVariables, missingHelpers };
|
|
6201
|
+
}
|
|
6202
|
+
|
|
6203
|
+
// src/prompt/errors.ts
|
|
6204
|
+
function buildMessage(context) {
|
|
6205
|
+
const { missingVariables, missingHelpers } = context;
|
|
6206
|
+
const vars = missingVariables.length ? `Missing variables: ${formatErrorList(missingVariables)}.` : "";
|
|
6207
|
+
const helpers = missingHelpers.length ? `Missing helpers: ${formatErrorList(missingHelpers)}.` : "";
|
|
6208
|
+
if (vars && helpers) {
|
|
6209
|
+
return `Prompt template has unresolved references. ${vars} ${helpers}`;
|
|
6210
|
+
}
|
|
6211
|
+
if (vars) {
|
|
6212
|
+
return `Prompt template references variables not provided. ${vars}`;
|
|
6213
|
+
}
|
|
6214
|
+
return `Prompt template references helpers not registered. ${helpers}`;
|
|
6215
|
+
}
|
|
6216
|
+
function missingTemplateReferencesError(context) {
|
|
6217
|
+
return createLlmExeError(
|
|
6218
|
+
{
|
|
6219
|
+
code: "prompt.missing_template_variable",
|
|
6220
|
+
message: buildMessage,
|
|
6221
|
+
resolution: "Pass every variable referenced by the prompt template, or register any custom helpers used."
|
|
6222
|
+
},
|
|
6223
|
+
context
|
|
6224
|
+
);
|
|
6225
|
+
}
|
|
6226
|
+
|
|
4169
6227
|
// src/prompt/_base.ts
|
|
4170
6228
|
var BasePrompt = class {
|
|
4171
6229
|
/**
|
|
@@ -4177,6 +6235,7 @@ var BasePrompt = class {
|
|
|
4177
6235
|
__publicField(this, "messages", []);
|
|
4178
6236
|
__publicField(this, "partials", []);
|
|
4179
6237
|
__publicField(this, "helpers", []);
|
|
6238
|
+
__publicField(this, "validateInput", false);
|
|
4180
6239
|
__publicField(this, "replaceTemplateString", replaceTemplateString);
|
|
4181
6240
|
__publicField(this, "replaceTemplateStringAsync", replaceTemplateStringAsync);
|
|
4182
6241
|
__publicField(this, "filters", {
|
|
@@ -4202,6 +6261,9 @@ var BasePrompt = class {
|
|
|
4202
6261
|
if (options.replaceTemplateString) {
|
|
4203
6262
|
this.replaceTemplateString = options.replaceTemplateString;
|
|
4204
6263
|
}
|
|
6264
|
+
if (options.validateInput !== void 0) {
|
|
6265
|
+
this.validateInput = options.validateInput;
|
|
6266
|
+
}
|
|
4205
6267
|
}
|
|
4206
6268
|
}
|
|
4207
6269
|
/**
|
|
@@ -4253,6 +6315,40 @@ var BasePrompt = class {
|
|
|
4253
6315
|
this.helpers.push(...helpers);
|
|
4254
6316
|
return this;
|
|
4255
6317
|
}
|
|
6318
|
+
/**
|
|
6319
|
+
* Returns the Handlebars-bearing strings that should be validated, along
|
|
6320
|
+
* with a location label used for error context. Subclasses with structured
|
|
6321
|
+
* message content (e.g. ChatPrompt) should override.
|
|
6322
|
+
*/
|
|
6323
|
+
getTemplateContents() {
|
|
6324
|
+
return this.messages.map((message, index) => {
|
|
6325
|
+
if (!message.content || Array.isArray(message.content)) {
|
|
6326
|
+
return null;
|
|
6327
|
+
}
|
|
6328
|
+
return {
|
|
6329
|
+
content: message.content,
|
|
6330
|
+
location: `messages[${index}].content`
|
|
6331
|
+
};
|
|
6332
|
+
}).filter(
|
|
6333
|
+
(entry) => entry !== null
|
|
6334
|
+
);
|
|
6335
|
+
}
|
|
6336
|
+
preflightValidate(values) {
|
|
6337
|
+
if (this.validateInput === false || !this.validateInput) {
|
|
6338
|
+
return;
|
|
6339
|
+
}
|
|
6340
|
+
try {
|
|
6341
|
+
this.validate(values);
|
|
6342
|
+
} catch (error) {
|
|
6343
|
+
if (this.validateInput === "warn" && isLlmExeError(error, "prompt.missing_template_variable")) {
|
|
6344
|
+
if (typeof process === "object" && typeof process?.emitWarning === "function") {
|
|
6345
|
+
process.emitWarning(error);
|
|
6346
|
+
}
|
|
6347
|
+
return;
|
|
6348
|
+
}
|
|
6349
|
+
throw error;
|
|
6350
|
+
}
|
|
6351
|
+
}
|
|
4256
6352
|
/**
|
|
4257
6353
|
* format description
|
|
4258
6354
|
* @param values The message content
|
|
@@ -4260,6 +6356,7 @@ var BasePrompt = class {
|
|
|
4260
6356
|
* @return returns messages formatted with template replacement
|
|
4261
6357
|
*/
|
|
4262
6358
|
format(values, separator = "\n\n") {
|
|
6359
|
+
this.preflightValidate(values);
|
|
4263
6360
|
const replacements = this.getReplacements(values);
|
|
4264
6361
|
const messages = this.messages.map((message) => {
|
|
4265
6362
|
return message.content && !Array.isArray(message.content) ? this.replaceTemplateString(
|
|
@@ -4280,6 +6377,7 @@ var BasePrompt = class {
|
|
|
4280
6377
|
* @return returns messages formatted with template replacement
|
|
4281
6378
|
*/
|
|
4282
6379
|
async formatAsync(values, separator = "\n\n") {
|
|
6380
|
+
this.preflightValidate(values);
|
|
4283
6381
|
const replacements = this.getReplacements(values);
|
|
4284
6382
|
const _messages = await Promise.all(this.messages.map((message) => {
|
|
4285
6383
|
return message.content && !Array.isArray(message.content) ? this.replaceTemplateStringAsync(
|
|
@@ -4303,8 +6401,18 @@ var BasePrompt = class {
|
|
|
4303
6401
|
}
|
|
4304
6402
|
getReplacements(values) {
|
|
4305
6403
|
if (values === void 0 || values === null) {
|
|
4306
|
-
throw new
|
|
4307
|
-
"format() requires an input object. Did you forget to pass arguments?"
|
|
6404
|
+
throw new LlmExeError(
|
|
6405
|
+
"format() requires an input object. Did you forget to pass arguments?",
|
|
6406
|
+
{
|
|
6407
|
+
code: "prompt.missing_input",
|
|
6408
|
+
context: {
|
|
6409
|
+
operation: "BasePrompt.getReplacements",
|
|
6410
|
+
promptType: this.type,
|
|
6411
|
+
expected: "object",
|
|
6412
|
+
received: values === null ? "null" : "undefined",
|
|
6413
|
+
resolution: "Pass an object of template values to format()."
|
|
6414
|
+
}
|
|
6415
|
+
}
|
|
4308
6416
|
);
|
|
4309
6417
|
}
|
|
4310
6418
|
const { input = "", ...restOfValues } = values;
|
|
@@ -4319,11 +6427,52 @@ var BasePrompt = class {
|
|
|
4319
6427
|
return replacements;
|
|
4320
6428
|
}
|
|
4321
6429
|
/**
|
|
4322
|
-
* Validates
|
|
4323
|
-
*
|
|
6430
|
+
* Validates that `input` provides every variable referenced by this prompt's
|
|
6431
|
+
* templates, and that every identifiable helper call is registered.
|
|
6432
|
+
*
|
|
6433
|
+
* @breaking v3: previously returned `this.messages.length > 0` with no
|
|
6434
|
+
* `input` parameter. For the old behavior, read `prompt.messages.length > 0`
|
|
6435
|
+
* directly.
|
|
6436
|
+
*
|
|
6437
|
+
* @throws LlmExeError with code `"prompt.missing_template_variable"` listing
|
|
6438
|
+
* all missing variables and helpers.
|
|
4324
6439
|
*/
|
|
4325
|
-
validate() {
|
|
4326
|
-
|
|
6440
|
+
validate(input) {
|
|
6441
|
+
const allMissingVariables = [];
|
|
6442
|
+
const allMissingHelpers = /* @__PURE__ */ new Set();
|
|
6443
|
+
const registeredHelpers = this.helpers.reduce(
|
|
6444
|
+
(acc, h) => {
|
|
6445
|
+
acc[h.name] = h.handler;
|
|
6446
|
+
return acc;
|
|
6447
|
+
},
|
|
6448
|
+
{}
|
|
6449
|
+
);
|
|
6450
|
+
const knownHelpers = {
|
|
6451
|
+
...hbs.handlebars.helpers,
|
|
6452
|
+
...registeredHelpers
|
|
6453
|
+
};
|
|
6454
|
+
for (const template of this.getTemplateContents()) {
|
|
6455
|
+
const result = validateTemplateInputReferences(template.content, input, {
|
|
6456
|
+
helpers: knownHelpers,
|
|
6457
|
+
location: template.location
|
|
6458
|
+
});
|
|
6459
|
+
allMissingVariables.push(...result.missingVariables);
|
|
6460
|
+
for (const helper of result.missingHelpers) {
|
|
6461
|
+
allMissingHelpers.add(helper);
|
|
6462
|
+
}
|
|
6463
|
+
}
|
|
6464
|
+
if (allMissingVariables.length === 0 && allMissingHelpers.size === 0) {
|
|
6465
|
+
return;
|
|
6466
|
+
}
|
|
6467
|
+
const dedupedVariables = Array.from(
|
|
6468
|
+
new Set(allMissingVariables.map((r) => r.path))
|
|
6469
|
+
);
|
|
6470
|
+
throw missingTemplateReferencesError({
|
|
6471
|
+
operation: "Prompt.validate",
|
|
6472
|
+
promptType: this.type,
|
|
6473
|
+
missingVariables: dedupedVariables,
|
|
6474
|
+
missingHelpers: Array.from(allMissingHelpers)
|
|
6475
|
+
});
|
|
4327
6476
|
}
|
|
4328
6477
|
};
|
|
4329
6478
|
|
|
@@ -4625,6 +6774,7 @@ var ChatPrompt = class extends BasePrompt {
|
|
|
4625
6774
|
* @return formatted prompt.
|
|
4626
6775
|
*/
|
|
4627
6776
|
format(values) {
|
|
6777
|
+
this.preflightValidate(values);
|
|
4628
6778
|
const messagesOut = [];
|
|
4629
6779
|
const replacements = this.getReplacements(values);
|
|
4630
6780
|
const safeToParseTemplate = ["assistant", "system"];
|
|
@@ -4750,6 +6900,7 @@ var ChatPrompt = class extends BasePrompt {
|
|
|
4750
6900
|
* @return formatted prompt.
|
|
4751
6901
|
*/
|
|
4752
6902
|
async formatAsync(values) {
|
|
6903
|
+
this.preflightValidate(values);
|
|
4753
6904
|
const messagesOut = [];
|
|
4754
6905
|
const replacements = this.getReplacements(values);
|
|
4755
6906
|
const safeToParseTemplate = ["assistant", "system"];
|
|
@@ -5052,16 +7203,26 @@ var Dialogue = class extends BaseStateItem {
|
|
|
5052
7203
|
}
|
|
5053
7204
|
setFunctionCallMessage(input) {
|
|
5054
7205
|
if (!input || typeof input !== "object") {
|
|
5055
|
-
throw new LlmExeError(`Invalid arguments`,
|
|
5056
|
-
|
|
5057
|
-
|
|
7206
|
+
throw new LlmExeError(`Invalid arguments`, {
|
|
7207
|
+
code: "state.invalid_arguments",
|
|
7208
|
+
context: {
|
|
7209
|
+
operation: "Dialogue.setFunctionCallMessage",
|
|
7210
|
+
module: "dialogue",
|
|
7211
|
+
expected: "object",
|
|
7212
|
+
received: typeof input
|
|
7213
|
+
}
|
|
5058
7214
|
});
|
|
5059
7215
|
}
|
|
5060
7216
|
if ("function_call" in input) {
|
|
5061
7217
|
if (!input.function_call || typeof input.function_call !== "object") {
|
|
5062
|
-
throw new LlmExeError(`Invalid arguments`,
|
|
5063
|
-
|
|
5064
|
-
|
|
7218
|
+
throw new LlmExeError(`Invalid arguments`, {
|
|
7219
|
+
code: "state.invalid_arguments",
|
|
7220
|
+
context: {
|
|
7221
|
+
operation: "Dialogue.setFunctionCallMessage",
|
|
7222
|
+
module: "dialogue",
|
|
7223
|
+
expected: "object",
|
|
7224
|
+
received: typeof input.function_call
|
|
7225
|
+
}
|
|
5065
7226
|
});
|
|
5066
7227
|
}
|
|
5067
7228
|
this.value.push({
|
|
@@ -5297,6 +7458,8 @@ function createStateItem(name, defaultValue) {
|
|
|
5297
7458
|
CustomParser,
|
|
5298
7459
|
DefaultState,
|
|
5299
7460
|
DefaultStateItem,
|
|
7461
|
+
LLM_EXE_ERROR_SYMBOL,
|
|
7462
|
+
LlmExeError,
|
|
5300
7463
|
LlmExecutorOpenAiFunctions,
|
|
5301
7464
|
LlmExecutorWithFunctions,
|
|
5302
7465
|
LlmNativeFunctionParser,
|
|
@@ -5317,6 +7480,7 @@ function createStateItem(name, defaultValue) {
|
|
|
5317
7480
|
createStateItem,
|
|
5318
7481
|
defineSchema,
|
|
5319
7482
|
guards,
|
|
7483
|
+
isLlmExeError,
|
|
5320
7484
|
registerHelpers,
|
|
5321
7485
|
registerPartials,
|
|
5322
7486
|
useExecutors,
|