llm-exe 2.3.11 → 3.0.0-beta.2

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.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(input, _options);
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.runHook("onSuccess", _metadata.asPlainObject());
948
+ this.collectHookErrors(
949
+ this.runHook("onSuccess", _metadata.asPlainObject()),
950
+ _metadata
951
+ );
255
952
  return output;
256
953
  } catch (error) {
257
- _metadata.setItem({ error, errorMessage: error.message });
258
- this.runHook("onError", _metadata.asPlainObject());
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
- console.warn(
287
- `[llm-exe] Error in "${String(hook)}" hook:`,
288
- error
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 Error(
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 Error(
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
- fn(...args);
343
- this.off(eventName, onceWrapper);
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 options - options
1162
+ * @param target - Whether the parser consumes text or function-call output.
424
1163
  */
425
- constructor(name, options = {}, target = "text") {
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,93 +1181,185 @@ 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`);
1184
+ // src/parser/parsers/StringParser.ts
1185
+ var StringParser = class extends BaseParser {
1186
+ constructor() {
1187
+ super("string");
1188
+ }
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
+ );
463
1204
  }
1205
+ return text;
464
1206
  }
465
- }
1207
+ };
466
1208
 
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";
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;
1215
+ }
506
1216
  }
507
1217
 
508
- // src/parser/parsers/StringParser.ts
509
- var StringParser = class extends BaseParser {
510
- constructor(options) {
511
- super("string", options);
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";
1222
+ }
1223
+ function debug(...args) {
1224
+ if (!isDebugEnabled()) {
1225
+ return;
512
1226
  }
513
- parse(text, _options) {
514
- if (isOutputResult(text)) {
515
- return text.content?.[0]?.text ?? "";
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
+ }
1252
+ }
1253
+ } else if (typeof arg === "string") {
1254
+ logs.push(safeRequestUrl(arg));
1255
+ } else {
1256
+ logs.push(arg);
516
1257
  }
517
- assert(
518
- typeof text === "string",
519
- `Invalid input. Expected string. Received ${typeof text}.`
520
- );
521
- const parsed = text.toString();
522
- return parsed;
523
1258
  }
524
- };
1259
+ if (isDebugEnabled()) {
1260
+ console.debug(...logs);
1261
+ }
1262
+ }
525
1263
 
526
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 BOOLEAN_TOKEN_PATTERN = /(?<![\p{L}\p{N}])(?:true|false|yes|no|y|n|1|0)(?![\p{L}\p{N}])/giu;
527
1270
  var BooleanParser = class extends BaseParser {
528
1271
  constructor(options) {
529
- super("boolean", options);
1272
+ super("boolean");
1273
+ __publicField(this, "match");
1274
+ this.match = options?.match ?? "exact";
530
1275
  }
531
- parse(text) {
532
- assert(
533
- typeof text === "string",
534
- `Invalid input. Expected string. Received ${typeof text}.`
535
- );
1276
+ getInputErrorContext(text) {
1277
+ const context = {
1278
+ inputLength: text.length
1279
+ };
1280
+ if (isDebugEnabled()) {
1281
+ const truncated = text.length > MAX_ERROR_INPUT_EXCERPT_LENGTH;
1282
+ context.inputExcerpt = truncated ? text.slice(0, MAX_ERROR_INPUT_EXCERPT_LENGTH) : text;
1283
+ context.inputExcerptTruncated = truncated;
1284
+ }
1285
+ return context;
1286
+ }
1287
+ parse(text, _attributes) {
1288
+ if (typeof text !== "string") {
1289
+ throw new LlmExeError(
1290
+ `Invalid input. Expected string. Received ${text === null ? "null" : typeof text}.`,
1291
+ {
1292
+ code: "parser.invalid_input",
1293
+ context: {
1294
+ operation: "BooleanParser.parse",
1295
+ parser: "boolean",
1296
+ reason: "invalid_input_type",
1297
+ expected: "string",
1298
+ received: text === null ? "null" : typeof text
1299
+ }
1300
+ }
1301
+ );
1302
+ }
536
1303
  const clean = text.toLowerCase().trim();
537
- if (clean === "true" || clean === "yes" || clean === "y" || clean === "1") {
1304
+ if (!clean) {
1305
+ throw new LlmExeError(`No boolean value found in input.`, {
1306
+ code: "parser.parse_failed",
1307
+ context: {
1308
+ operation: "BooleanParser.parse",
1309
+ parser: "boolean",
1310
+ reason: "empty_input",
1311
+ expected: BOOLEAN_VALUES,
1312
+ ...this.getInputErrorContext(text)
1313
+ }
1314
+ });
1315
+ }
1316
+ if (TRUTHY_VALUES.has(clean)) {
538
1317
  return true;
539
1318
  }
540
- return false;
1319
+ if (FALSY_VALUES.has(clean)) {
1320
+ return false;
1321
+ }
1322
+ if (this.match === "extract") {
1323
+ const matches = Array.from(
1324
+ text.toLowerCase().matchAll(BOOLEAN_TOKEN_PATTERN)
1325
+ ).map((match) => match[0]);
1326
+ const values = Array.from(
1327
+ new Set(
1328
+ matches.map((match) => {
1329
+ if (TRUTHY_VALUES.has(match)) return true;
1330
+ return false;
1331
+ })
1332
+ )
1333
+ );
1334
+ if (values.length === 1) {
1335
+ return values[0];
1336
+ }
1337
+ if (values.length > 1) {
1338
+ throw new LlmExeError(`Multiple boolean values found in input.`, {
1339
+ code: "parser.parse_failed",
1340
+ context: {
1341
+ operation: "BooleanParser.parse",
1342
+ parser: "boolean",
1343
+ reason: "ambiguous_boolean",
1344
+ expected: "one boolean value",
1345
+ match: this.match,
1346
+ matchCount: values.length,
1347
+ ...this.getInputErrorContext(text)
1348
+ }
1349
+ });
1350
+ }
1351
+ }
1352
+ throw new LlmExeError(`No boolean value found in input.`, {
1353
+ code: "parser.parse_failed",
1354
+ context: {
1355
+ operation: "BooleanParser.parse",
1356
+ parser: "boolean",
1357
+ reason: "unrecognized_boolean",
1358
+ expected: BOOLEAN_VALUES,
1359
+ match: this.match,
1360
+ ...this.getInputErrorContext(text)
1361
+ }
1362
+ });
541
1363
  }
542
1364
  };
543
1365
 
@@ -557,106 +1379,121 @@ function toNumber(value) {
557
1379
  return NaN;
558
1380
  }
559
1381
 
560
- // src/utils/modules/errors.ts
561
- var LlmExeError = class extends Error {
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
1382
  // src/parser/parsers/NumberParser.ts
1383
+ var NUMERIC_TOKEN_PATTERN = /(^|[^\w.,])([+-]?(?:(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d+)?|\.\d+)(?:[eE][+-]?\d+)?)(?![\w,])/g;
1384
+ var EXACT_NUMERIC_PATTERN = /^[+-]?(?:(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d+)?|\.\d+)(?:[eE][+-]?\d+)?$/;
576
1385
  var NumberParser = class extends BaseParser {
577
1386
  constructor(options) {
578
- super("number", options);
1387
+ super("number");
1388
+ __publicField(this, "match");
1389
+ this.match = options?.match ?? "extract";
579
1390
  }
580
- parse(text) {
581
- const match = text.match(/-?\d+(\.\d+)?/);
582
- if (match && isFinite(toNumber(match[0]))) {
583
- return toNumber(match[0]);
1391
+ parse(text, _attributes) {
1392
+ if (typeof text !== "string") {
1393
+ throw new LlmExeError(
1394
+ `Invalid input. Expected string. Received ${text === null ? "null" : Array.isArray(text) ? "array" : typeof text}.`,
1395
+ {
1396
+ code: "parser.invalid_input",
1397
+ context: {
1398
+ operation: "NumberParser.parse",
1399
+ parser: "number",
1400
+ reason: "invalid_input_type",
1401
+ expected: "string",
1402
+ received: text === null ? "null" : Array.isArray(text) ? "array" : typeof text
1403
+ }
1404
+ }
1405
+ );
584
1406
  }
585
- throw new LlmExeError(
586
- `No numeric value found in input.`,
587
- "parser",
588
- {
589
- parser: "number",
590
- output: text,
591
- error: `No numeric value found in input.`
1407
+ if (text.trim() === "") {
1408
+ throw new LlmExeError(`No numeric value found in input.`, {
1409
+ code: "parser.parse_failed",
1410
+ context: {
1411
+ operation: "NumberParser.parse",
1412
+ parser: "number",
1413
+ reason: "empty_input",
1414
+ expected: "number",
1415
+ inputLength: text.length
1416
+ }
1417
+ });
1418
+ }
1419
+ if (this.match === "exact") {
1420
+ const trimmed = text.trim();
1421
+ if (!EXACT_NUMERIC_PATTERN.test(trimmed)) {
1422
+ throw new LlmExeError(`Input is not an exact numeric value.`, {
1423
+ code: "parser.parse_failed",
1424
+ context: {
1425
+ operation: "NumberParser.parse",
1426
+ parser: "number",
1427
+ reason: "no_numeric_value",
1428
+ expected: "exact number",
1429
+ match: this.match,
1430
+ inputLength: text.length
1431
+ }
1432
+ });
592
1433
  }
593
- );
594
- }
595
- };
596
-
597
- // src/utils/index.ts
598
- var utils_exports = {};
599
- __export(utils_exports, {
600
- assert: () => assert,
601
- asyncCallWithTimeout: () => asyncCallWithTimeout,
602
- defineSchema: () => defineSchema,
603
- filterObjectOnSchema: () => filterObjectOnSchema,
604
- guessProviderFromModel: () => guessProviderFromModel,
605
- importHelpers: () => importHelpers,
606
- importPartials: () => importPartials,
607
- isObjectStringified: () => isObjectStringified,
608
- maybeParseJSON: () => maybeParseJSON,
609
- maybeStringifyJSON: () => maybeStringifyJSON,
610
- registerHelpers: () => registerHelpers,
611
- registerPartials: () => registerPartials,
612
- replaceTemplateString: () => replaceTemplateString,
613
- replaceTemplateStringAsync: () => replaceTemplateStringAsync
614
- });
615
-
616
- // src/utils/modules/defineSchema.ts
617
- var import_json_schema_to_ts = require("json-schema-to-ts");
618
- function defineSchema(obj) {
619
- obj.additionalProperties = false;
620
- return (0, import_json_schema_to_ts.asConst)(obj);
621
- }
622
-
623
- // src/utils/modules/handlebars/utils/importPartials.ts
624
- function importPartials(_partials) {
625
- let partials2 = [];
626
- if (_partials) {
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]
1434
+ const value2 = toNumber(trimmed.replace(/,/g, ""));
1435
+ if (!isFinite(value2)) {
1436
+ throw new LlmExeError(`Invalid numeric value found in input.`, {
1437
+ code: "parser.parse_failed",
1438
+ context: {
1439
+ operation: "NumberParser.parse",
1440
+ parser: "number",
1441
+ reason: "invalid_number",
1442
+ expected: "finite number",
1443
+ match: this.match,
1444
+ inputLength: text.length
1445
+ }
635
1446
  });
636
1447
  }
1448
+ return value2;
637
1449
  }
638
- }
639
- return partials2;
640
- }
641
-
642
- // src/utils/modules/handlebars/utils/importHelpers.ts
643
- function importHelpers(_helpers) {
644
- let helpers = [];
645
- if (_helpers) {
646
- const externalHelperKeys = Object.keys(
647
- _helpers
1450
+ const matches = Array.from(text.matchAll(NUMERIC_TOKEN_PATTERN)).map(
1451
+ (match) => match[2]
648
1452
  );
649
- for (const externalHelperKey of externalHelperKeys) {
650
- if (typeof externalHelperKey === "string") {
651
- helpers.push({
652
- name: externalHelperKey,
653
- handler: _helpers[externalHelperKey]
654
- });
655
- }
1453
+ if (matches.length === 0) {
1454
+ throw new LlmExeError(`No numeric value found in input.`, {
1455
+ code: "parser.parse_failed",
1456
+ context: {
1457
+ operation: "NumberParser.parse",
1458
+ parser: "number",
1459
+ reason: "no_numeric_value",
1460
+ expected: "number",
1461
+ match: this.match,
1462
+ inputLength: text.length
1463
+ }
1464
+ });
1465
+ }
1466
+ if (matches.length > 1) {
1467
+ throw new LlmExeError(`Multiple numeric values found in input.`, {
1468
+ code: "parser.parse_failed",
1469
+ context: {
1470
+ operation: "NumberParser.parse",
1471
+ parser: "number",
1472
+ reason: "ambiguous_number",
1473
+ expected: "one numeric value",
1474
+ match: this.match,
1475
+ inputLength: text.length,
1476
+ matchCount: matches.length
1477
+ }
1478
+ });
656
1479
  }
1480
+ const value = toNumber(matches[0].replace(/,/g, ""));
1481
+ if (!isFinite(value)) {
1482
+ throw new LlmExeError(`Invalid numeric value found in input.`, {
1483
+ code: "parser.parse_failed",
1484
+ context: {
1485
+ operation: "NumberParser.parse",
1486
+ parser: "number",
1487
+ reason: "invalid_number",
1488
+ expected: "finite number",
1489
+ match: this.match,
1490
+ inputLength: text.length
1491
+ }
1492
+ });
1493
+ }
1494
+ return value;
657
1495
  }
658
- return helpers;
659
- }
1496
+ };
660
1497
 
661
1498
  // src/utils/modules/get.ts
662
1499
  function get(obj, path, defaultValue) {
@@ -710,10 +1547,22 @@ function filterObjectOnSchema(schema, doc, detach, property) {
710
1547
  return;
711
1548
  }
712
1549
  } else {
713
- if (sp.type === "integer" || sp.type === "number") {
1550
+ var childType = getType(sp.type);
1551
+ if (childType === "integer" || childType === "number") {
714
1552
  result[key] = toNumber(filteredChild);
715
- } else if (sp.type === "boolean") {
716
- result[key] = !!filteredChild;
1553
+ } else if (childType === "boolean") {
1554
+ if (typeof filteredChild === "string") {
1555
+ const normalized = filteredChild.trim().toLowerCase();
1556
+ if (normalized === "true") {
1557
+ result[key] = true;
1558
+ } else if (normalized === "false") {
1559
+ result[key] = false;
1560
+ } else {
1561
+ result[key] = filteredChild;
1562
+ }
1563
+ } else {
1564
+ result[key] = filteredChild;
1565
+ }
717
1566
  } else {
718
1567
  result[key] = filteredChild;
719
1568
  }
@@ -733,122 +1582,719 @@ function filterObjectOnSchema(schema, doc, detach, property) {
733
1582
  return result;
734
1583
  }
735
1584
 
736
- // src/utils/modules/handlebars/hbs.ts
737
- var import_handlebars = __toESM(require("handlebars"));
738
-
739
- // src/utils/modules/handlebars/utils/registerHelpers.ts
740
- function _registerHelpers(helpers, instance) {
741
- if (helpers && Array.isArray(helpers)) {
742
- for (const helper of helpers) {
743
- if (helper.name && typeof helper.name === "string" && typeof helper.handler === "function") {
744
- if (instance) {
745
- instance.registerHelper(helper.name, helper.handler);
746
- }
747
- }
748
- }
1585
+ // src/parser/_utils.ts
1586
+ var import_jsonschema = require("jsonschema");
1587
+ function isPlainObject(value) {
1588
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1589
+ return false;
749
1590
  }
1591
+ const proto = Object.getPrototypeOf(value);
1592
+ return proto === Object.prototype || proto === null;
750
1593
  }
751
-
752
- // src/utils/modules/handlebars/templates/index.ts
753
- var MarkdownCode = `{{#if code}}\`\`\`{{#if language}}{{language}}{{/if}}
754
- {{{code}}}
755
- \`\`\`{{/if}}`;
756
- var ThoughtActionResult = `
757
- {{#if title}}{{#if attributes.stepsTaken.length}}{{title}}
758
- {{/if}}{{/if}}
759
- {{#each attributes.stepsTaken as | step |}}
760
- {{#if step.thought}}Thought: {{step.result}}{{/if}}
761
- {{#if step.result}}Action: {{step.action}}{{/if}}
762
- {{#if step.result}}Result: {{step.result}}{{/if}}
763
- {{/each}}`;
764
- var ChatConversationHistory = `{{~#if title}}{{~#if chat_history.length}}{{title}}
765
- {{~/if}}{{~/if}}
766
- {{#each chat_history as | item |}}
767
- {{~#eq item.role 'user'}}{{#if @last}}{{../mostRecentRolePrefix}}{{../userName}}{{../mostRecentRoleSuffix}}{{else}}{{../userName}}{{/if}}: {{#if @last}}{{../mostRecentMessagePrefix}}{{/if}}{{{item.content}}}{{#if @last}}{{../mostRecentMessageSuffix}}{{/if}}
768
- {{/eq}}
769
- {{~#eq item.role 'assistant'}}{{#if @last}}{{../mostRecentRolePrefix}}{{../assistantName}}{{../mostRecentRoleSuffix}}{{else}}{{../assistantName}}{{/if}}: {{#if @last}}{{../mostRecentMessagePrefix}}{{/if}}{{{item.content}}}{{#if @last}}{{../mostRecentMessageSuffix}}{{/if}}
770
- {{/eq}}
771
- {{~#eq item.role 'system'}}{{../systemName}}: {{{item.content}}}
772
- {{/eq}}
773
- {{~/each}}`;
774
- 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}}`;
775
- var SingleChatMessage = `{{~#eq role 'user'}}{{getOr name 'User'}}: {{{content}}}{{~/eq}}
776
- {{~#eq role 'assistant'}}{{getOr assistant 'Assistant'}}: {{{content}}}{{~/eq}}
777
- {{~#eq role 'system'}}{{getOr system 'System'}}: {{{content}}}{{~/eq}}`;
778
- var ThoughtsAndObservations = `{{~#each thoughts as | step |}}
779
- {{~#if step.thought}}Thought: {{{step.thought}}}
780
- {{/if}}
781
- {{~#if step.observation}}Observation: {{{step.observation}}}
782
- {{/if}}
783
- {{~/each}}`;
784
- var JsonSchema = `{{#if (getKeyOr key false)}}
785
- \`\`\`json
786
- {{{indentJson (getKeyOr key) collapse}}}
787
- \`\`\`
788
- {{~/if}}`;
789
- var JsonSchemaExampleJson = `{{#if (getOr key false)}}
790
- \`\`\`json
791
- {{{jsonSchemaExample key (getOr property '') collapse}}}
792
- \`\`\`
793
- {{~/if}}`;
794
- var partials = {
795
- JsonSchema,
796
- JsonSchemaExampleJson,
797
- MarkdownCode,
798
- DialogueHistory,
799
- SingleChatMessage,
800
- ChatConversationHistory,
801
- ThoughtsAndObservations,
802
- ThoughtActionResult
803
- };
804
-
805
- // src/utils/modules/handlebars/helpers/index.ts
806
- var helpers_exports = {};
807
- __export(helpers_exports, {
808
- cut: () => cutFn,
809
- eq: () => eq,
810
- getKeyOr: () => getKeyOr,
811
- getOr: () => getOr,
812
- ifCond: () => ifCond,
813
- indentJson: () => indentJson,
814
- join: () => join,
815
- jsonSchemaExample: () => jsonSchemaExample,
816
- neq: () => neq,
817
- objectToList: () => objectToList,
818
- pluralize: () => pluralize,
819
- substring: () => substringFn,
820
- with: () => withFn
821
- });
822
-
823
- // src/utils/modules/json.ts
824
- var maybeStringifyJSON = (objOrMaybeString) => {
825
- if (!objOrMaybeString || typeof objOrMaybeString !== "object") {
826
- return objOrMaybeString;
1594
+ function getSchemaType(schemaType) {
1595
+ if (!Array.isArray(schemaType)) {
1596
+ return schemaType;
827
1597
  }
828
- try {
829
- const result = JSON.stringify(objOrMaybeString);
830
- return result;
831
- } catch (error) {
1598
+ return schemaType.find((type) => type !== "null");
1599
+ }
1600
+ function enforceParserSchema(schema, parsed) {
1601
+ if (!schema || !parsed || typeof parsed !== "object") {
1602
+ return parsed;
832
1603
  }
833
- return "";
834
- };
835
- var maybeParseJSON = (objOrMaybeJSON) => {
836
- if (!objOrMaybeJSON) return {};
837
- if (typeof objOrMaybeJSON === "string") {
838
- try {
839
- const cleanMarkdown = helpJsonMarkup(objOrMaybeJSON);
840
- const result = JSON.parse(cleanMarkdown);
841
- if (typeof result === "object" && result !== null) {
842
- return result;
1604
+ return filterObjectOnSchema(schema, parsed);
1605
+ }
1606
+ function validateParserSchema(schema, parsed) {
1607
+ if (!schema || !parsed || typeof parsed !== "object") {
1608
+ return null;
1609
+ }
1610
+ const validate = (0, import_jsonschema.validate)(parsed, schema);
1611
+ if (validate.errors.length) {
1612
+ return validate.errors;
1613
+ }
1614
+ return null;
1615
+ }
1616
+ function coerceParserSchemaValues(schema, parsed) {
1617
+ if (!schema || parsed === null || typeof parsed === "undefined") {
1618
+ return parsed;
1619
+ }
1620
+ const type = getSchemaType(schema.type);
1621
+ if (type === "object" && isPlainObject(parsed)) {
1622
+ const properties = schema.properties || {};
1623
+ return Object.keys(parsed).reduce((output, key) => {
1624
+ const propertySchema = properties[key];
1625
+ output[key] = propertySchema ? coerceParserSchemaValues(propertySchema, parsed[key]) : parsed[key];
1626
+ return output;
1627
+ }, {});
1628
+ }
1629
+ if (type === "array" && Array.isArray(parsed) && schema.items) {
1630
+ return parsed.map(
1631
+ (item) => coerceParserSchemaValues(schema.items, item)
1632
+ );
1633
+ }
1634
+ if ((type === "number" || type === "integer") && typeof parsed === "string") {
1635
+ const trimmed = parsed.trim();
1636
+ if (trimmed !== "") {
1637
+ const value = Number(trimmed);
1638
+ if (Number.isFinite(value)) {
1639
+ return value;
843
1640
  }
844
- } catch (error) {
845
1641
  }
846
1642
  }
847
- if (typeof objOrMaybeJSON === "object" && objOrMaybeJSON !== null) {
848
- return objOrMaybeJSON;
1643
+ if (type === "boolean" && typeof parsed === "string") {
1644
+ const normalized = parsed.trim().toLowerCase();
1645
+ if (normalized === "true") {
1646
+ return true;
1647
+ }
1648
+ if (normalized === "false") {
1649
+ return false;
1650
+ }
849
1651
  }
850
- return {};
851
- };
1652
+ return parsed;
1653
+ }
1654
+ function applyParserSchemaDefaultsAndFilter(schema, parsed) {
1655
+ if (!schema || parsed === null || typeof parsed === "undefined") {
1656
+ return parsed;
1657
+ }
1658
+ const type = getSchemaType(schema.type);
1659
+ if (type === "object" && isPlainObject(parsed)) {
1660
+ const properties = schema.properties;
1661
+ if (!properties) {
1662
+ return parsed;
1663
+ }
1664
+ const keepAdditionalProperties = schema.additionalProperties !== false;
1665
+ const initialOutput = keepAdditionalProperties ? { ...parsed } : {};
1666
+ return Object.keys(properties).reduce((output, key) => {
1667
+ const propertySchema = properties[key];
1668
+ const value = parsed[key];
1669
+ if (typeof value === "undefined") {
1670
+ if (typeof propertySchema?.default !== "undefined") {
1671
+ output[key] = propertySchema.default;
1672
+ }
1673
+ return output;
1674
+ }
1675
+ output[key] = applyParserSchemaDefaultsAndFilter(propertySchema, value);
1676
+ return output;
1677
+ }, initialOutput);
1678
+ }
1679
+ if (type === "array" && Array.isArray(parsed) && schema.items) {
1680
+ return parsed.map(
1681
+ (item) => applyParserSchemaDefaultsAndFilter(schema.items, item)
1682
+ );
1683
+ }
1684
+ return parsed;
1685
+ }
1686
+
1687
+ // src/parser/parsers/JsonParser.ts
1688
+ function isPlainObject2(value) {
1689
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1690
+ return false;
1691
+ }
1692
+ const proto = Object.getPrototypeOf(value);
1693
+ return proto === Object.prototype || proto === null;
1694
+ }
1695
+ function normalizeExactResponseJsonText(input) {
1696
+ const trimmed = input.trim();
1697
+ const fenceMatch = trimmed.match(
1698
+ /^```([a-zA-Z]*)[^\S\r\n]*\r?\n([\s\S]*)```$/
1699
+ );
1700
+ if (!fenceMatch) {
1701
+ return trimmed;
1702
+ }
1703
+ const [, language, body] = fenceMatch;
1704
+ if (language && language.toLowerCase() !== "json") {
1705
+ return trimmed;
1706
+ }
1707
+ return body.trim();
1708
+ }
1709
+ function findBalancedJsonEnd(input, start) {
1710
+ const first = input[start];
1711
+ const stack = first === "{" ? ["}"] : first === "[" ? ["]"] : [];
1712
+ let inString = false;
1713
+ let escaping = false;
1714
+ for (let index = start + 1; index < input.length; index += 1) {
1715
+ const char = input[index];
1716
+ if (inString) {
1717
+ if (escaping) {
1718
+ escaping = false;
1719
+ } else if (char === "\\") {
1720
+ escaping = true;
1721
+ } else if (char === '"') {
1722
+ inString = false;
1723
+ }
1724
+ continue;
1725
+ }
1726
+ if (char === '"') {
1727
+ inString = true;
1728
+ continue;
1729
+ }
1730
+ if (char === "{" || char === "[") {
1731
+ stack.push(char === "{" ? "}" : "]");
1732
+ continue;
1733
+ }
1734
+ if (char !== "}" && char !== "]") {
1735
+ continue;
1736
+ }
1737
+ if (stack[stack.length - 1] !== char) {
1738
+ return void 0;
1739
+ }
1740
+ stack.pop();
1741
+ if (stack.length === 0) {
1742
+ return index;
1743
+ }
1744
+ }
1745
+ return void 0;
1746
+ }
1747
+ function extractJsonCandidates(input) {
1748
+ const candidates = [];
1749
+ for (let index = 0; index < input.length; index += 1) {
1750
+ const char = input[index];
1751
+ if (char !== "{" && char !== "[") {
1752
+ continue;
1753
+ }
1754
+ const end = findBalancedJsonEnd(input, index);
1755
+ if (end === void 0) {
1756
+ continue;
1757
+ }
1758
+ const candidate = input.slice(index, end + 1);
1759
+ try {
1760
+ candidates.push({
1761
+ parsed: JSON.parse(candidate)
1762
+ });
1763
+ index = end;
1764
+ } catch {
1765
+ }
1766
+ }
1767
+ return candidates;
1768
+ }
1769
+ var JsonParser = class extends BaseParserWithJson {
1770
+ constructor(options = {}) {
1771
+ super("json", options);
1772
+ __publicField(this, "shouldValidateSchema");
1773
+ __publicField(this, "match");
1774
+ this.match = options.match ?? "exact";
1775
+ this.shouldValidateSchema = !!options.schema && options.validateSchema !== false;
1776
+ }
1777
+ /**
1778
+ * v3 parser contract:
1779
+ * Category: strict
1780
+ * Mode: exact
1781
+ *
1782
+ * Parses strict JSON object/array output by default. Pass match: "extract"
1783
+ * to extract one JSON object or array from surrounding text. Invalid JSON,
1784
+ * empty input, JSON primitives, and non-plain runtime objects throw typed parser errors.
1785
+ * Schema validation is on by default when a schema is provided unless
1786
+ * validateSchema: false is explicitly set.
1787
+ *
1788
+ */
1789
+ parse(text, _attributes) {
1790
+ let parsed;
1791
+ let inputLength;
1792
+ if (typeof text === "string") {
1793
+ inputLength = text.length;
1794
+ if (text.trim() === "") {
1795
+ throw new LlmExeError(`No JSON value found in input.`, {
1796
+ code: "parser.parse_failed",
1797
+ context: {
1798
+ operation: "JsonParser.parse",
1799
+ parser: "json",
1800
+ reason: "empty_input",
1801
+ expected: "JSON object or array",
1802
+ inputLength
1803
+ }
1804
+ });
1805
+ }
1806
+ try {
1807
+ parsed = JSON.parse(normalizeExactResponseJsonText(text));
1808
+ } catch (cause) {
1809
+ if (this.match === "extract") {
1810
+ const candidates = extractJsonCandidates(text);
1811
+ if (candidates.length === 1) {
1812
+ parsed = candidates[0].parsed;
1813
+ } else if (candidates.length > 1) {
1814
+ throw new LlmExeError(`Multiple JSON values found in input.`, {
1815
+ code: "parser.parse_failed",
1816
+ context: {
1817
+ operation: "JsonParser.parse",
1818
+ parser: "json",
1819
+ reason: "ambiguous_json_match",
1820
+ expected: "one JSON object or array",
1821
+ match: this.match,
1822
+ inputLength,
1823
+ matchCount: candidates.length
1824
+ }
1825
+ });
1826
+ } else {
1827
+ throw new LlmExeError(`No JSON value found in input.`, {
1828
+ code: "parser.parse_failed",
1829
+ context: {
1830
+ operation: "JsonParser.parse",
1831
+ parser: "json",
1832
+ reason: "no_json_value",
1833
+ expected: "JSON object or array",
1834
+ match: this.match,
1835
+ inputLength
1836
+ },
1837
+ cause
1838
+ });
1839
+ }
1840
+ } else {
1841
+ throw new LlmExeError(`Invalid JSON input.`, {
1842
+ code: "parser.parse_failed",
1843
+ context: {
1844
+ operation: "JsonParser.parse",
1845
+ parser: "json",
1846
+ reason: "invalid_json",
1847
+ expected: "JSON object or array",
1848
+ inputLength
1849
+ },
1850
+ cause
1851
+ });
1852
+ }
1853
+ }
1854
+ } else if (Array.isArray(text) || isPlainObject2(text)) {
1855
+ parsed = text;
1856
+ } else {
1857
+ throw new LlmExeError(
1858
+ `Invalid input. Expected JSON string, plain object, or array. Received ${text === null ? "null" : typeof text}.`,
1859
+ {
1860
+ code: "parser.invalid_input",
1861
+ context: {
1862
+ operation: "JsonParser.parse",
1863
+ parser: "json",
1864
+ reason: "invalid_input_type",
1865
+ expected: "JSON string, plain object, or array",
1866
+ received: text === null ? "null" : typeof text
1867
+ }
1868
+ }
1869
+ );
1870
+ }
1871
+ if (!Array.isArray(parsed) && !isPlainObject2(parsed)) {
1872
+ throw new LlmExeError(`Invalid JSON root type.`, {
1873
+ code: "parser.parse_failed",
1874
+ context: {
1875
+ operation: "JsonParser.parse",
1876
+ parser: "json",
1877
+ reason: "invalid_json_root_type",
1878
+ expected: "JSON object or array",
1879
+ received: parsed === null ? "null" : typeof parsed,
1880
+ inputLength
1881
+ }
1882
+ });
1883
+ }
1884
+ if (this.schema) {
1885
+ if (this.shouldValidateSchema) {
1886
+ const valid = validateParserSchema(this.schema, parsed);
1887
+ if (valid && valid.length) {
1888
+ throw new LlmExeError(valid[0].message, {
1889
+ code: "parser.schema_validation_failed",
1890
+ context: {
1891
+ operation: "JsonParser.parse",
1892
+ parser: "json",
1893
+ schemaErrors: valid.map((error) => error.message)
1894
+ }
1895
+ });
1896
+ }
1897
+ }
1898
+ if (this.shouldValidateSchema) {
1899
+ return applyParserSchemaDefaultsAndFilter(
1900
+ this.schema,
1901
+ parsed
1902
+ );
1903
+ }
1904
+ return enforceParserSchema(this.schema, parsed);
1905
+ }
1906
+ return parsed;
1907
+ }
1908
+ };
1909
+
1910
+ // src/utils/modules/camelCase.ts
1911
+ function camelCase(input) {
1912
+ if (!input) return input;
1913
+ input = input.replace(/[^a-zA-Z0-9_]+/g, " ").trim();
1914
+ const words = input.split(/\s+|_/);
1915
+ return words.map((word, index) => {
1916
+ if (index === 0) {
1917
+ return word.toLowerCase();
1918
+ } else {
1919
+ return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
1920
+ }
1921
+ }).join("");
1922
+ }
1923
+
1924
+ // src/parser/_listBoundary.ts
1925
+ var LIST_MARKER_PATTERN = /^(?:[-*]\s+|\d+\.\s+|•\s*)/;
1926
+ function normalizeListLines(input, context) {
1927
+ const lines = input.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
1928
+ if (lines.length === 0) {
1929
+ throw new LlmExeError(`No list items found in input.`, {
1930
+ code: "parser.parse_failed",
1931
+ context: {
1932
+ operation: context.operation,
1933
+ parser: context.parser,
1934
+ reason: "empty_input",
1935
+ inputLength: input.length
1936
+ }
1937
+ });
1938
+ }
1939
+ const markedStates = lines.map((line) => LIST_MARKER_PATTERN.test(line));
1940
+ const hasMarked = markedStates.some(Boolean);
1941
+ const hasUnmarked = markedStates.some((marked) => !marked);
1942
+ if (hasMarked && hasUnmarked) {
1943
+ throw new LlmExeError(`Mixed marked and unmarked list items found.`, {
1944
+ code: "parser.parse_failed",
1945
+ context: {
1946
+ operation: context.operation,
1947
+ parser: context.parser,
1948
+ reason: "mixed_list_markers",
1949
+ inputLength: input.length
1950
+ }
1951
+ });
1952
+ }
1953
+ return {
1954
+ lines: hasMarked ? lines.map((line) => line.replace(LIST_MARKER_PATTERN, "").trim()) : lines,
1955
+ marked: hasMarked
1956
+ };
1957
+ }
1958
+
1959
+ // src/parser/parsers/ListToJsonParser.ts
1960
+ var ListToJsonParser = class extends BaseParserWithJson {
1961
+ constructor(options = {}) {
1962
+ super("listToJson", options);
1963
+ __publicField(this, "keyTransform");
1964
+ __publicField(this, "shouldValidateSchema");
1965
+ this.keyTransform = options.keyTransform ?? "camelCase";
1966
+ this.shouldValidateSchema = !!options.schema && options.validateSchema !== false;
1967
+ }
1968
+ /**
1969
+ * v3 parser contract:
1970
+ * Category: converter
1971
+ * Mode: line-oriented format conversion
1972
+ *
1973
+ * Uses the shared list boundary. Parses normalized lines as key/value pairs
1974
+ * split at the first colon. Duplicate keys throw because object output would
1975
+ * overwrite data.
1976
+ *
1977
+ */
1978
+ parse(text) {
1979
+ if (typeof text !== "string") {
1980
+ throw new LlmExeError(
1981
+ `Invalid input. Expected string. Received ${text === null ? "null" : Array.isArray(text) ? "array" : typeof text}.`,
1982
+ {
1983
+ code: "parser.invalid_input",
1984
+ context: {
1985
+ operation: "ListToJsonParser.parse",
1986
+ parser: "listToJson",
1987
+ reason: "invalid_input_type",
1988
+ expected: "string",
1989
+ received: text === null ? "null" : Array.isArray(text) ? "array" : typeof text
1990
+ }
1991
+ }
1992
+ );
1993
+ }
1994
+ const { lines } = normalizeListLines(text, {
1995
+ operation: "ListToJsonParser.parse",
1996
+ parser: "listToJson"
1997
+ });
1998
+ const output = {};
1999
+ lines.forEach((line) => {
2000
+ const colonIndex = line.indexOf(":");
2001
+ if (colonIndex === -1) {
2002
+ throw new LlmExeError(`Malformed key/value line.`, {
2003
+ code: "parser.parse_failed",
2004
+ context: {
2005
+ operation: "ListToJsonParser.parse",
2006
+ parser: "listToJson",
2007
+ reason: "malformed_line",
2008
+ inputLength: text.length
2009
+ }
2010
+ });
2011
+ }
2012
+ const key = line.slice(0, colonIndex).trim();
2013
+ if (!key) {
2014
+ throw new LlmExeError(`Empty key in key/value line.`, {
2015
+ code: "parser.parse_failed",
2016
+ context: {
2017
+ operation: "ListToJsonParser.parse",
2018
+ parser: "listToJson",
2019
+ reason: "empty_key",
2020
+ inputLength: text.length
2021
+ }
2022
+ });
2023
+ }
2024
+ const transformedKey = this.keyTransform === "preserve" ? key : camelCase(key);
2025
+ if (Object.prototype.hasOwnProperty.call(output, transformedKey)) {
2026
+ throw new LlmExeError(`Duplicate key in key/value input.`, {
2027
+ code: "parser.parse_failed",
2028
+ context: {
2029
+ operation: "ListToJsonParser.parse",
2030
+ parser: "listToJson",
2031
+ reason: "duplicate_key",
2032
+ inputLength: text.length
2033
+ }
2034
+ });
2035
+ }
2036
+ output[transformedKey] = line.slice(colonIndex + 1).trim();
2037
+ });
2038
+ if (this.schema) {
2039
+ const coerced = coerceParserSchemaValues(this.schema, output);
2040
+ if (this.shouldValidateSchema) {
2041
+ const valid = validateParserSchema(this.schema, coerced);
2042
+ if (valid && valid.length) {
2043
+ throw new LlmExeError(valid[0].message, {
2044
+ code: "parser.schema_validation_failed",
2045
+ context: {
2046
+ operation: "ListToJsonParser.parse",
2047
+ parser: "listToJson",
2048
+ schemaErrors: valid.map((error) => error.message)
2049
+ }
2050
+ });
2051
+ }
2052
+ }
2053
+ return applyParserSchemaDefaultsAndFilter(this.schema, coerced);
2054
+ }
2055
+ return output;
2056
+ }
2057
+ };
2058
+
2059
+ // src/parser/parsers/ListToKeyValueParser.ts
2060
+ var ListToKeyValueParser = class extends BaseParser {
2061
+ constructor(options) {
2062
+ super("listToKeyValue");
2063
+ __publicField(this, "keyTransform");
2064
+ this.keyTransform = options?.keyTransform ?? "preserve";
2065
+ }
2066
+ /**
2067
+ * v3 parser contract:
2068
+ * Category: converter
2069
+ * Mode: line-oriented collector
2070
+ *
2071
+ * Uses the shared list boundary. Parses normalized lines as key/value pairs
2072
+ * split at the first colon. Preserves duplicate keys because output is an
2073
+ * ordered array. Keys are returned as written by default; pass
2074
+ * keyTransform: "camelCase" to match listToJson's key normalization.
2075
+ *
2076
+ */
2077
+ parse(text, _attributes) {
2078
+ if (typeof text !== "string") {
2079
+ throw new LlmExeError(
2080
+ `Invalid input. Expected string. Received ${text === null ? "null" : Array.isArray(text) ? "array" : typeof text}.`,
2081
+ {
2082
+ code: "parser.invalid_input",
2083
+ context: {
2084
+ operation: "ListToKeyValueParser.parse",
2085
+ parser: "listToKeyValue",
2086
+ reason: "invalid_input_type",
2087
+ expected: "string",
2088
+ received: text === null ? "null" : Array.isArray(text) ? "array" : typeof text
2089
+ }
2090
+ }
2091
+ );
2092
+ }
2093
+ const { lines } = normalizeListLines(text, {
2094
+ operation: "ListToKeyValueParser.parse",
2095
+ parser: "listToKeyValue"
2096
+ });
2097
+ let res = [];
2098
+ for (const line of lines) {
2099
+ const colonIndex = line.indexOf(":");
2100
+ if (colonIndex === -1) {
2101
+ throw new LlmExeError(`Malformed key/value line.`, {
2102
+ code: "parser.parse_failed",
2103
+ context: {
2104
+ operation: "ListToKeyValueParser.parse",
2105
+ parser: "listToKeyValue",
2106
+ reason: "malformed_line",
2107
+ inputLength: text.length
2108
+ }
2109
+ });
2110
+ }
2111
+ const rawKey = line.slice(0, colonIndex).trim();
2112
+ if (!rawKey) {
2113
+ throw new LlmExeError(`Empty key in key/value line.`, {
2114
+ code: "parser.parse_failed",
2115
+ context: {
2116
+ operation: "ListToKeyValueParser.parse",
2117
+ parser: "listToKeyValue",
2118
+ reason: "empty_key",
2119
+ inputLength: text.length
2120
+ }
2121
+ });
2122
+ }
2123
+ const key = this.keyTransform === "camelCase" ? camelCase(rawKey) : rawKey;
2124
+ res.push({ key, value: line.slice(colonIndex + 1).trim() });
2125
+ }
2126
+ return res;
2127
+ }
2128
+ };
2129
+
2130
+ // src/parser/parsers/CustomParser.ts
2131
+ var CustomParser = class extends BaseParser {
2132
+ constructor(name, parserFn) {
2133
+ super(name);
2134
+ __publicField(this, "parserFn");
2135
+ this.parserFn = parserFn;
2136
+ }
2137
+ parse(text, context) {
2138
+ return this.parserFn.call(this, text, context);
2139
+ }
2140
+ };
2141
+
2142
+ // src/parser/parsers/ListToArrayParser.ts
2143
+ var ListToArrayParser = class extends BaseParser {
2144
+ constructor() {
2145
+ super("listToArray");
2146
+ }
2147
+ parse(text, _attributes) {
2148
+ if (typeof text !== "string") {
2149
+ throw new LlmExeError(
2150
+ `Invalid input. Expected string. Received ${text === null ? "null" : Array.isArray(text) ? "array" : typeof text}.`,
2151
+ {
2152
+ code: "parser.invalid_input",
2153
+ context: {
2154
+ operation: "ListToArrayParser.parse",
2155
+ parser: "listToArray",
2156
+ reason: "invalid_input_type",
2157
+ expected: "string",
2158
+ received: text === null ? "null" : Array.isArray(text) ? "array" : typeof text
2159
+ }
2160
+ }
2161
+ );
2162
+ }
2163
+ const normalized = normalizeListLines(text, {
2164
+ operation: "ListToArrayParser.parse",
2165
+ parser: "listToArray"
2166
+ });
2167
+ if (!normalized.marked && normalized.lines.length === 1) {
2168
+ throw new LlmExeError(`Input is not list-like.`, {
2169
+ code: "parser.parse_failed",
2170
+ context: {
2171
+ operation: "ListToArrayParser.parse",
2172
+ parser: "listToArray",
2173
+ reason: "not_list_like",
2174
+ inputLength: text.length
2175
+ }
2176
+ });
2177
+ }
2178
+ return normalized.lines;
2179
+ }
2180
+ };
2181
+
2182
+ // src/utils/modules/handlebars/hbs.ts
2183
+ var import_handlebars = __toESM(require("handlebars"));
2184
+
2185
+ // src/utils/modules/handlebars/utils/registerHelpers.ts
2186
+ function _registerHelpers(helpers, instance) {
2187
+ if (helpers && Array.isArray(helpers)) {
2188
+ for (const helper of helpers) {
2189
+ if (helper.name && typeof helper.name === "string" && typeof helper.handler === "function") {
2190
+ if (instance) {
2191
+ instance.registerHelper(helper.name, helper.handler);
2192
+ }
2193
+ }
2194
+ }
2195
+ }
2196
+ }
2197
+
2198
+ // src/utils/modules/handlebars/templates/index.ts
2199
+ var MarkdownCode = `{{#if code}}\`\`\`{{#if language}}{{language}}{{/if}}
2200
+ {{{code}}}
2201
+ \`\`\`{{/if}}`;
2202
+ var ThoughtActionResult = `
2203
+ {{#if title}}{{#if attributes.stepsTaken.length}}{{title}}
2204
+ {{/if}}{{/if}}
2205
+ {{#each attributes.stepsTaken as | step |}}
2206
+ {{#if step.thought}}Thought: {{step.result}}{{/if}}
2207
+ {{#if step.result}}Action: {{step.action}}{{/if}}
2208
+ {{#if step.result}}Result: {{step.result}}{{/if}}
2209
+ {{/each}}`;
2210
+ var ChatConversationHistory = `{{~#if title}}{{~#if chat_history.length}}{{title}}
2211
+ {{~/if}}{{~/if}}
2212
+ {{#each chat_history as | item |}}
2213
+ {{~#eq item.role 'user'}}{{#if @last}}{{../mostRecentRolePrefix}}{{../userName}}{{../mostRecentRoleSuffix}}{{else}}{{../userName}}{{/if}}: {{#if @last}}{{../mostRecentMessagePrefix}}{{/if}}{{{item.content}}}{{#if @last}}{{../mostRecentMessageSuffix}}{{/if}}
2214
+ {{/eq}}
2215
+ {{~#eq item.role 'assistant'}}{{#if @last}}{{../mostRecentRolePrefix}}{{../assistantName}}{{../mostRecentRoleSuffix}}{{else}}{{../assistantName}}{{/if}}: {{#if @last}}{{../mostRecentMessagePrefix}}{{/if}}{{{item.content}}}{{#if @last}}{{../mostRecentMessageSuffix}}{{/if}}
2216
+ {{/eq}}
2217
+ {{~#eq item.role 'system'}}{{../systemName}}: {{{item.content}}}
2218
+ {{/eq}}
2219
+ {{~/each}}`;
2220
+ 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}}`;
2221
+ var SingleChatMessage = `{{~#eq role 'user'}}{{getOr name 'User'}}: {{{content}}}{{~/eq}}
2222
+ {{~#eq role 'assistant'}}{{getOr assistant 'Assistant'}}: {{{content}}}{{~/eq}}
2223
+ {{~#eq role 'system'}}{{getOr system 'System'}}: {{{content}}}{{~/eq}}`;
2224
+ var ThoughtsAndObservations = `{{~#each thoughts as | step |}}
2225
+ {{~#if step.thought}}Thought: {{{step.thought}}}
2226
+ {{/if}}
2227
+ {{~#if step.observation}}Observation: {{{step.observation}}}
2228
+ {{/if}}
2229
+ {{~/each}}`;
2230
+ var JsonSchema = `{{#if (getKeyOr key false)}}
2231
+ \`\`\`json
2232
+ {{{indentJson (getKeyOr key) collapse}}}
2233
+ \`\`\`
2234
+ {{~/if}}`;
2235
+ var JsonSchemaExampleJson = `{{#if (getOr key false)}}
2236
+ \`\`\`json
2237
+ {{{jsonSchemaExample key (getOr property '') collapse}}}
2238
+ \`\`\`
2239
+ {{~/if}}`;
2240
+ var partials = {
2241
+ JsonSchema,
2242
+ JsonSchemaExampleJson,
2243
+ MarkdownCode,
2244
+ DialogueHistory,
2245
+ SingleChatMessage,
2246
+ ChatConversationHistory,
2247
+ ThoughtsAndObservations,
2248
+ ThoughtActionResult
2249
+ };
2250
+
2251
+ // src/utils/modules/handlebars/helpers/index.ts
2252
+ var helpers_exports = {};
2253
+ __export(helpers_exports, {
2254
+ cut: () => cutFn,
2255
+ eq: () => eq,
2256
+ getKeyOr: () => getKeyOr,
2257
+ getOr: () => getOr,
2258
+ ifCond: () => ifCond,
2259
+ indentJson: () => indentJson,
2260
+ join: () => join,
2261
+ jsonSchemaExample: () => jsonSchemaExample,
2262
+ neq: () => neq,
2263
+ objectToList: () => objectToList,
2264
+ pluralize: () => pluralize,
2265
+ substring: () => substringFn,
2266
+ with: () => withFn
2267
+ });
2268
+
2269
+ // src/utils/modules/json.ts
2270
+ var maybeStringifyJSON = (objOrMaybeString) => {
2271
+ if (!objOrMaybeString || typeof objOrMaybeString !== "object") {
2272
+ return objOrMaybeString;
2273
+ }
2274
+ try {
2275
+ const result = JSON.stringify(objOrMaybeString);
2276
+ return result;
2277
+ } catch (error) {
2278
+ }
2279
+ return "";
2280
+ };
2281
+ var maybeParseJSON = (objOrMaybeJSON) => {
2282
+ if (!objOrMaybeJSON) return {};
2283
+ if (typeof objOrMaybeJSON === "string") {
2284
+ try {
2285
+ const cleanMarkdown = helpJsonMarkup(objOrMaybeJSON);
2286
+ const result = JSON.parse(cleanMarkdown);
2287
+ if (typeof result === "object" && result !== null) {
2288
+ return result;
2289
+ }
2290
+ } catch (error) {
2291
+ }
2292
+ }
2293
+ if (typeof objOrMaybeJSON === "object" && objOrMaybeJSON !== null) {
2294
+ return objOrMaybeJSON;
2295
+ }
2296
+ return {};
2297
+ };
852
2298
  function isObjectStringified(maybeObject) {
853
2299
  if (typeof maybeObject !== "string") return false;
854
2300
  const trimmed = maybeObject.trim();
@@ -1110,7 +2556,15 @@ function isEmpty(value) {
1110
2556
  // src/utils/modules/handlebars/helpers/async/with.ts
1111
2557
  async function withFnAsync(context, options) {
1112
2558
  if (arguments.length !== 2) {
1113
- throw new Error("#with requires exactly one argument");
2559
+ throw new LlmExeError("#with requires exactly one argument", {
2560
+ code: "template.invalid_helper_arguments",
2561
+ context: {
2562
+ operation: "handlebars.asyncHelper.with",
2563
+ helper: "with",
2564
+ expected: 1,
2565
+ received: arguments.length
2566
+ }
2567
+ });
1114
2568
  }
1115
2569
  if (isPromise(context)) {
1116
2570
  context = await context;
@@ -1138,7 +2592,15 @@ async function withFnAsync(context, options) {
1138
2592
  // src/utils/modules/handlebars/helpers/async/if.ts
1139
2593
  async function ifFnAsync(conditional, options) {
1140
2594
  if (arguments.length !== 2) {
1141
- throw new Error("#if requires exactly one argument");
2595
+ throw new LlmExeError("#if requires exactly one argument", {
2596
+ code: "template.invalid_helper_arguments",
2597
+ context: {
2598
+ operation: "handlebars.asyncHelper.if",
2599
+ helper: "if",
2600
+ expected: 1,
2601
+ received: arguments.length
2602
+ }
2603
+ });
1142
2604
  }
1143
2605
  if (isPromise(conditional)) {
1144
2606
  conditional = await conditional;
@@ -1160,7 +2622,15 @@ function isReadableStream(obj) {
1160
2622
  // src/utils/modules/handlebars/helpers/async/each.ts
1161
2623
  async function eachFnAsync(arg1, options) {
1162
2624
  if (!options) {
1163
- throw new Error("Must pass iterator to #each");
2625
+ throw new LlmExeError("Must pass iterator to #each", {
2626
+ code: "template.invalid_helper_arguments",
2627
+ context: {
2628
+ operation: "handlebars.asyncHelper.each",
2629
+ helper: "each",
2630
+ expected: "an iterator",
2631
+ received: typeof options
2632
+ }
2633
+ });
1164
2634
  }
1165
2635
  const { fn } = options;
1166
2636
  const { inverse } = options;
@@ -1256,7 +2726,15 @@ async function eachFnAsync(arg1, options) {
1256
2726
  // src/utils/modules/handlebars/helpers/async/unless.ts
1257
2727
  async function unlessFnAsync(conditional, options) {
1258
2728
  if (arguments.length !== 2) {
1259
- throw new Error("#unless requires exactly one argument");
2729
+ throw new LlmExeError("#unless requires exactly one argument", {
2730
+ code: "template.invalid_helper_arguments",
2731
+ context: {
2732
+ operation: "handlebars.asyncHelper.unless",
2733
+ helper: "unless",
2734
+ expected: 1,
2735
+ received: arguments.length
2736
+ }
2737
+ });
1260
2738
  }
1261
2739
  return ifFnAsync.call(this, conditional, {
1262
2740
  fn: options.inverse,
@@ -1429,455 +2907,627 @@ function replaceTemplateString(templateString, substitutions = {}, configuration
1429
2907
  const tempPartials = [];
1430
2908
  if (Array.isArray(configuration.helpers)) {
1431
2909
  hbs.registerHelpers(configuration.helpers);
1432
- tempHelpers.push(...configuration.helpers.map((a) => a.name));
1433
- }
1434
- if (Array.isArray(configuration.partials)) {
1435
- hbs.registerPartials(configuration.partials);
1436
- tempPartials.push(...configuration.partials.map((a) => a.name));
1437
- }
1438
- const template = hbs.handlebars.compile(templateString);
1439
- const res = template(substitutions, {
1440
- allowedProtoMethods: {
1441
- substring: true
1442
- }
1443
- });
1444
- tempHelpers.forEach(function(n) {
1445
- hbs.handlebars.unregisterHelper(n);
1446
- });
1447
- tempPartials.forEach(function(n) {
1448
- hbs.handlebars.unregisterPartial(n);
1449
- });
1450
- return res;
1451
- }
1452
-
1453
- // src/utils/modules/replaceTemplateStringAsync.ts
1454
- async function replaceTemplateStringAsync(templateString, substitutions = {}, configuration = {
1455
- helpers: [],
1456
- partials: []
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));
1468
- }
1469
- const template = hbsAsync.handlebars.compile(templateString);
1470
- const res = await template(substitutions, {
1471
- allowedProtoMethods: {
1472
- substring: true
1473
- }
1474
- });
1475
- tempHelpers.forEach(function(n) {
1476
- hbsAsync.handlebars.unregisterHelper(n);
1477
- });
1478
- tempPartials.forEach(function(n) {
1479
- hbsAsync.handlebars.unregisterPartial(n);
1480
- });
1481
- return res;
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`)
1491
- );
1492
- }, timeLimit);
1493
- });
1494
- return Promise.race([asyncPromise, timeoutPromise]).finally(() => {
1495
- clearTimeout(timeoutHandle);
1496
- });
1497
- };
1498
-
1499
- // src/utils/modules/guessProviderFromModel.ts
1500
- function isModelKnownOpenAi(payload) {
1501
- const model = payload.model.toLowerCase();
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;
2910
+ tempHelpers.push(...configuration.helpers.map((a) => a.name));
1574
2911
  }
1575
- return null;
2912
+ if (Array.isArray(configuration.partials)) {
2913
+ hbs.registerPartials(configuration.partials);
2914
+ tempPartials.push(...configuration.partials.map((a) => a.name));
2915
+ }
2916
+ const template = hbs.handlebars.compile(templateString);
2917
+ const res = template(substitutions, {
2918
+ allowedProtoMethods: {
2919
+ substring: true
2920
+ }
2921
+ });
2922
+ tempHelpers.forEach(function(n) {
2923
+ hbs.handlebars.unregisterHelper(n);
2924
+ });
2925
+ tempPartials.forEach(function(n) {
2926
+ hbs.handlebars.unregisterPartial(n);
2927
+ });
2928
+ return res;
1576
2929
  }
1577
2930
 
1578
- // src/parser/parsers/JsonParser.ts
1579
- var JsonParser = class extends BaseParserWithJson {
1580
- constructor(options = {}) {
1581
- super("json", options);
2931
+ // src/parser/parsers/ReplaceStringTemplateParser.ts
2932
+ var ReplaceStringTemplateParser = class extends BaseParser {
2933
+ constructor() {
2934
+ super("replaceStringTemplate");
1582
2935
  }
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
- });
2936
+ parse(text, attributes) {
2937
+ if (typeof text !== "string") {
2938
+ throw new LlmExeError(
2939
+ `Invalid input. Expected string. Received ${text === null ? "null" : Array.isArray(text) ? "array" : typeof text}.`,
2940
+ {
2941
+ code: "parser.invalid_input",
2942
+ context: {
2943
+ operation: "ReplaceStringTemplateParser.parse",
2944
+ parser: "replaceStringTemplate",
2945
+ reason: "invalid_input_type",
2946
+ expected: "string",
2947
+ received: text === null ? "null" : Array.isArray(text) ? "array" : typeof text
2948
+ }
2949
+ }
2950
+ );
2951
+ }
2952
+ if (attributes !== void 0 && (attributes === null || typeof attributes !== "object" || Array.isArray(attributes))) {
2953
+ throw new LlmExeError(`Invalid attributes. Expected object.`, {
2954
+ code: "parser.invalid_input",
2955
+ context: {
2956
+ operation: "ReplaceStringTemplateParser.parse",
2957
+ parser: "replaceStringTemplate",
2958
+ reason: "invalid_attributes",
2959
+ expected: "object",
2960
+ received: attributes === null ? "null" : Array.isArray(attributes) ? "array" : typeof attributes
1595
2961
  }
2962
+ });
2963
+ }
2964
+ try {
2965
+ return replaceTemplateString(text, attributes);
2966
+ } catch (cause) {
2967
+ let received = typeof cause;
2968
+ if (cause instanceof Error) {
2969
+ received = cause.name;
1596
2970
  }
1597
- return enforce;
2971
+ throw new LlmExeError(`Template replacement failed.`, {
2972
+ code: "parser.parse_failed",
2973
+ context: {
2974
+ operation: "ReplaceStringTemplateParser.parse",
2975
+ parser: "replaceStringTemplate",
2976
+ reason: "template_replacement_failed",
2977
+ inputLength: text.length,
2978
+ received
2979
+ },
2980
+ cause
2981
+ });
1598
2982
  }
1599
- return parsed;
1600
2983
  }
1601
2984
  };
1602
2985
 
1603
- // src/utils/modules/camelCase.ts
1604
- function camelCase(input) {
1605
- if (!input) return input;
1606
- input = input.replace(/[^a-zA-Z0-9_]+/g, " ").trim();
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";
2986
+ // src/parser/parsers/MarkdownCodeBlocks.ts
2987
+ var MarkdownCodeBlocksParser = class extends BaseParser {
2988
+ constructor() {
2989
+ super("markdownCodeBlocks");
1623
2990
  }
1624
- parse(text) {
1625
- const lines = text.split("\n");
1626
- const output = {};
1627
- lines.forEach((line) => {
1628
- const colonIndex = line.indexOf(":");
1629
- if (colonIndex !== -1) {
1630
- const key = line.slice(0, colonIndex);
1631
- const value = line.slice(colonIndex + 1).trim();
1632
- if (value) {
1633
- const transformedKey = this.keyTransform === "preserve" ? key.trim() : camelCase(key);
1634
- output[transformedKey] = value;
2991
+ parse(input, _attributes) {
2992
+ if (typeof input !== "string") {
2993
+ throw new LlmExeError(
2994
+ `Invalid input. Expected string. Received ${input === null ? "null" : Array.isArray(input) ? "array" : typeof input}.`,
2995
+ {
2996
+ code: "parser.invalid_input",
2997
+ context: {
2998
+ operation: "MarkdownCodeBlocksParser.parse",
2999
+ parser: "markdownCodeBlocks",
3000
+ reason: "invalid_input_type",
3001
+ expected: "string",
3002
+ received: input === null ? "null" : Array.isArray(input) ? "array" : typeof input
3003
+ }
1635
3004
  }
1636
- }
1637
- });
1638
- if (this.schema) {
1639
- const parsed = enforceParserSchema(this.schema, output);
1640
- if (this?.validateSchema) {
1641
- const valid = validateParserSchema(this.schema, parsed);
1642
- if (valid && valid.length) {
1643
- throw new LlmExeError(valid[0].message, "parser", {
1644
- parser: "json",
1645
- output: parsed,
1646
- error: valid[0].message
1647
- });
3005
+ );
3006
+ }
3007
+ const out = [];
3008
+ const fenceCount = input.match(/```/g)?.length ?? 0;
3009
+ if (fenceCount % 2 !== 0) {
3010
+ throw new LlmExeError(`Malformed markdown code block.`, {
3011
+ code: "parser.parse_failed",
3012
+ context: {
3013
+ operation: "MarkdownCodeBlocksParser.parse",
3014
+ parser: "markdownCodeBlocks",
3015
+ reason: "malformed_code_block",
3016
+ inputLength: input.length
1648
3017
  }
3018
+ });
3019
+ }
3020
+ const regex = input.matchAll(new RegExp(/```(\w*)\n([\s\S]*?)```/, "g"));
3021
+ for (const iterator of regex) {
3022
+ if (iterator) {
3023
+ const [_input, language, code] = iterator;
3024
+ out.push({
3025
+ language,
3026
+ code
3027
+ });
1649
3028
  }
1650
- return parsed;
1651
3029
  }
1652
- return output;
3030
+ return out;
1653
3031
  }
1654
3032
  };
1655
3033
 
1656
- // src/parser/parsers/ListToKeyValueParser.ts
1657
- var ListToKeyValueParser = class extends BaseParser {
1658
- constructor(options) {
1659
- super("listToKeyValue", options);
3034
+ // src/parser/parsers/MarkdownCodeBlock.ts
3035
+ var MarkdownCodeBlockParser = class extends BaseParser {
3036
+ constructor() {
3037
+ super("markdownCodeBlock");
1660
3038
  }
1661
- parse(text) {
1662
- const lines = text.split("\n").map((s) => s.replace("- ", "").replace(/'/g, "'"));
1663
- let res = [];
1664
- for (const line of lines) {
1665
- const [key, value] = line.split(":");
1666
- if (key && value) {
1667
- res.push({ key: key?.trim(), value: value?.trim() });
1668
- }
3039
+ parse(input, _attributes) {
3040
+ if (typeof input !== "string") {
3041
+ throw new LlmExeError(
3042
+ `Invalid input. Expected string. Received ${input === null ? "null" : Array.isArray(input) ? "array" : typeof input}.`,
3043
+ {
3044
+ code: "parser.invalid_input",
3045
+ context: {
3046
+ operation: "MarkdownCodeBlockParser.parse",
3047
+ parser: "markdownCodeBlock",
3048
+ reason: "invalid_input_type",
3049
+ expected: "string",
3050
+ received: input === null ? "null" : Array.isArray(input) ? "array" : typeof input
3051
+ }
3052
+ }
3053
+ );
1669
3054
  }
1670
- return res;
3055
+ if (input.trim() === "") {
3056
+ throw new LlmExeError(`No markdown code block found.`, {
3057
+ code: "parser.parse_failed",
3058
+ context: {
3059
+ operation: "MarkdownCodeBlockParser.parse",
3060
+ parser: "markdownCodeBlock",
3061
+ reason: "empty_input",
3062
+ inputLength: input.length
3063
+ }
3064
+ });
3065
+ }
3066
+ const blocks = new MarkdownCodeBlocksParser().parse(input);
3067
+ if (blocks.length === 0) {
3068
+ throw new LlmExeError(`No markdown code block found.`, {
3069
+ code: "parser.parse_failed",
3070
+ context: {
3071
+ operation: "MarkdownCodeBlockParser.parse",
3072
+ parser: "markdownCodeBlock",
3073
+ reason: "no_code_block",
3074
+ inputLength: input.length
3075
+ }
3076
+ });
3077
+ }
3078
+ if (blocks.length > 1) {
3079
+ throw new LlmExeError(`Multiple markdown code blocks found.`, {
3080
+ code: "parser.parse_failed",
3081
+ context: {
3082
+ operation: "MarkdownCodeBlockParser.parse",
3083
+ parser: "markdownCodeBlock",
3084
+ reason: "multiple_code_blocks",
3085
+ inputLength: input.length,
3086
+ matchCount: blocks.length
3087
+ }
3088
+ });
3089
+ }
3090
+ return blocks[0];
1671
3091
  }
1672
3092
  };
1673
3093
 
1674
- // src/parser/parsers/CustomParser.ts
1675
- var CustomParser = class extends BaseParser {
1676
- /**
1677
- * Creates a new CustomParser instance.
1678
- * @param {string} name The name of the parser.
1679
- * @param {any} parserFn The custom parsing function.
1680
- */
1681
- constructor(name, parserFn) {
1682
- super(name);
1683
- /**
1684
- * Custom parsing function.
1685
- * @type {any}
1686
- */
1687
- __publicField(this, "parserFn");
1688
- this.parserFn = parserFn;
3094
+ // src/parser/parsers/StringExtractParser.ts
3095
+ var REGEX_METACHAR = /[.*+?^${}()|[\]\\]/g;
3096
+ var WORD_CHAR = "[\\p{L}\\p{N}]";
3097
+ function escapeRegex(value) {
3098
+ return value.replace(REGEX_METACHAR, "\\$&");
3099
+ }
3100
+ function describeType(value) {
3101
+ if (value === null) return "null";
3102
+ if (Array.isArray(value)) return "array";
3103
+ return typeof value;
3104
+ }
3105
+ var StringExtractParser = class extends BaseParser {
3106
+ constructor(options) {
3107
+ super("stringExtract");
3108
+ __publicField(this, "enum", []);
3109
+ __publicField(this, "ignoreCase");
3110
+ __publicField(this, "match");
3111
+ if (options?.enum) {
3112
+ this.enum.push(...options.enum);
3113
+ }
3114
+ this.ignoreCase = options?.ignoreCase ?? true;
3115
+ this.match = options?.match ?? "word";
1689
3116
  }
1690
3117
  /**
1691
- * Parses the text using the custom parsing function.
1692
- * @param {string} text The text to be parsed.
1693
- * @param {any} inputValues Additional input values for the parser function.
1694
- * @returns {O} The parsed value.
3118
+ * v3 parser contract:
3119
+ * Category: extractor
3120
+ * Mode: configured value extraction
3121
+ *
3122
+ * Returns the single configured enum value found in input. Matching is
3123
+ * word-bounded by default; pass match: "exact" to require exact input or
3124
+ * match: "substring" for legacy contains() behavior. Case-insensitive by
3125
+ * default.
3126
+ *
1695
3127
  */
1696
- parse(text, inputValues) {
1697
- return this.parserFn.call(this, text, inputValues);
3128
+ parse(text, _attributes) {
3129
+ if (typeof text !== "string") {
3130
+ const received = describeType(text);
3131
+ throw new LlmExeError(
3132
+ `Invalid input. Expected string. Received ${received}.`,
3133
+ {
3134
+ code: "parser.invalid_input",
3135
+ context: {
3136
+ operation: "StringExtractParser.parse",
3137
+ parser: "stringExtract",
3138
+ reason: "invalid_input_type",
3139
+ expected: "string",
3140
+ received
3141
+ }
3142
+ }
3143
+ );
3144
+ }
3145
+ if (this.enum.length === 0) {
3146
+ throw new LlmExeError(`No enum values configured.`, {
3147
+ code: "parser.parse_failed",
3148
+ context: {
3149
+ operation: "StringExtractParser.parse",
3150
+ parser: "stringExtract",
3151
+ reason: "no_enum_values",
3152
+ expected: "non-empty enum",
3153
+ inputLength: text.length
3154
+ }
3155
+ });
3156
+ }
3157
+ if (text.length === 0) {
3158
+ if (this.enum.includes("")) {
3159
+ return "";
3160
+ }
3161
+ throw new LlmExeError(`No matching enum value found in input.`, {
3162
+ code: "parser.parse_failed",
3163
+ context: {
3164
+ operation: "StringExtractParser.parse",
3165
+ parser: "stringExtract",
3166
+ reason: "empty_input",
3167
+ expected: this.enum,
3168
+ inputLength: text.length
3169
+ }
3170
+ });
3171
+ }
3172
+ const matches = this.findMatches(text);
3173
+ const uniqueMatches = Array.from(new Set(matches));
3174
+ if (uniqueMatches.length === 1) {
3175
+ return uniqueMatches[0];
3176
+ }
3177
+ if (uniqueMatches.length > 1) {
3178
+ throw new LlmExeError(`Multiple enum values found in input.`, {
3179
+ code: "parser.parse_failed",
3180
+ context: {
3181
+ operation: "StringExtractParser.parse",
3182
+ parser: "stringExtract",
3183
+ reason: "ambiguous_enum_match",
3184
+ expected: this.enum,
3185
+ match: this.match,
3186
+ inputLength: text.length,
3187
+ matchCount: uniqueMatches.length
3188
+ }
3189
+ });
3190
+ }
3191
+ throw new LlmExeError(`No matching enum value found in input.`, {
3192
+ code: "parser.parse_failed",
3193
+ context: {
3194
+ operation: "StringExtractParser.parse",
3195
+ parser: "stringExtract",
3196
+ reason: "no_enum_match",
3197
+ expected: this.enum,
3198
+ match: this.match,
3199
+ inputLength: text.length
3200
+ }
3201
+ });
1698
3202
  }
1699
- };
1700
-
1701
- // src/parser/parsers/ListToArrayParser.ts
1702
- var ListToArrayParser = class extends BaseParser {
1703
- constructor() {
1704
- super("listToArray");
3203
+ findMatches(text) {
3204
+ switch (this.match) {
3205
+ case "exact":
3206
+ return this.matchExact(text);
3207
+ case "substring":
3208
+ return this.matchSubstring(text);
3209
+ case "word":
3210
+ default:
3211
+ return this.matchWord(text);
3212
+ }
3213
+ }
3214
+ matchExact(text) {
3215
+ const candidate = this.ignoreCase ? text.trim().toLowerCase() : text.trim();
3216
+ return this.enum.filter((option) => {
3217
+ if (option === "") return false;
3218
+ const normalized = this.ignoreCase ? option.toLowerCase() : option;
3219
+ return candidate === normalized;
3220
+ });
1705
3221
  }
1706
- parse(text) {
1707
- const lines = text.split("\n").map((s) => s.replace(/^(?:[-*] |\d+\. )/, "").replace(/'/g, "\u2019").trim());
1708
- return lines;
3222
+ matchSubstring(text) {
3223
+ const haystack = this.ignoreCase ? text.toLowerCase() : text;
3224
+ return this.enum.filter((option) => {
3225
+ if (option === "") return false;
3226
+ const needle = this.ignoreCase ? option.toLowerCase() : option;
3227
+ return haystack.includes(needle);
3228
+ });
3229
+ }
3230
+ matchWord(text) {
3231
+ const flags = this.ignoreCase ? "iu" : "u";
3232
+ return this.enum.filter((option) => {
3233
+ if (option === "") return false;
3234
+ const pattern = new RegExp(
3235
+ `(?<!${WORD_CHAR})${escapeRegex(option)}(?!${WORD_CHAR})`,
3236
+ flags
3237
+ );
3238
+ return pattern.test(text);
3239
+ });
1709
3240
  }
1710
3241
  };
1711
3242
 
1712
- // src/parser/parsers/ReplaceStringTemplateParser.ts
1713
- var ReplaceStringTemplateParser = class extends BaseParser {
1714
- constructor(options) {
1715
- super("replaceStringTemplate", options);
3243
+ // src/parser/_functions.ts
3244
+ function createParser(...args) {
3245
+ const [type, options] = args;
3246
+ switch (type) {
3247
+ case "json":
3248
+ return new JsonParser(options);
3249
+ case "listToJson":
3250
+ return new ListToJsonParser(options);
3251
+ case "stringExtract":
3252
+ return new StringExtractParser(options);
3253
+ case "markdownCodeBlocks":
3254
+ return new MarkdownCodeBlocksParser();
3255
+ case "markdownCodeBlock":
3256
+ return new MarkdownCodeBlockParser();
3257
+ case "listToArray":
3258
+ return new ListToArrayParser();
3259
+ case "listToKeyValue":
3260
+ return new ListToKeyValueParser(options);
3261
+ case "replaceStringTemplate":
3262
+ return new ReplaceStringTemplateParser();
3263
+ case "boolean":
3264
+ return new BooleanParser(options);
3265
+ case "number":
3266
+ return new NumberParser(options);
3267
+ case "string":
3268
+ return new StringParser();
3269
+ default:
3270
+ throw new LlmExeError(`Invalid parser type: "${type}"`, {
3271
+ code: "parser.invalid_type",
3272
+ context: {
3273
+ operation: "createParser",
3274
+ parser: type,
3275
+ availableParsers: [
3276
+ "json",
3277
+ "string",
3278
+ "boolean",
3279
+ "number",
3280
+ "stringExtract",
3281
+ "listToArray",
3282
+ "listToJson",
3283
+ "listToKeyValue",
3284
+ "replaceStringTemplate",
3285
+ "markdownCodeBlock",
3286
+ "markdownCodeBlocks"
3287
+ ],
3288
+ resolution: "Use a registered parser type, or define a custom parser."
3289
+ }
3290
+ });
1716
3291
  }
1717
- parse(text, attributes) {
1718
- return replaceTemplateString(text, attributes);
3292
+ }
3293
+ function createCustomParser(name, parserFn) {
3294
+ return new CustomParser(name, parserFn);
3295
+ }
3296
+
3297
+ // src/utils/index.ts
3298
+ var utils_exports = {};
3299
+ __export(utils_exports, {
3300
+ LLM_EXE_ERROR_SYMBOL: () => LLM_EXE_ERROR_SYMBOL,
3301
+ LlmExeError: () => LlmExeError,
3302
+ assert: () => assert,
3303
+ asyncCallWithTimeout: () => asyncCallWithTimeout,
3304
+ defineSchema: () => defineSchema,
3305
+ filterObjectOnSchema: () => filterObjectOnSchema,
3306
+ guessProviderFromModel: () => guessProviderFromModel,
3307
+ importHelpers: () => importHelpers,
3308
+ importPartials: () => importPartials,
3309
+ isLlmExeError: () => isLlmExeError,
3310
+ isObjectStringified: () => isObjectStringified,
3311
+ maybeParseJSON: () => maybeParseJSON,
3312
+ maybeStringifyJSON: () => maybeStringifyJSON,
3313
+ registerHelpers: () => registerHelpers,
3314
+ registerPartials: () => registerPartials,
3315
+ replaceTemplateString: () => replaceTemplateString,
3316
+ replaceTemplateStringAsync: () => replaceTemplateStringAsync
3317
+ });
3318
+
3319
+ // src/utils/modules/assert.ts
3320
+ function assert(condition, message) {
3321
+ if (condition === void 0 || condition === null || condition === false) {
3322
+ if (typeof message === "string") {
3323
+ throw new Error(message);
3324
+ } else if (message instanceof Error) {
3325
+ throw message;
3326
+ } else {
3327
+ throw new Error(`Assertion error`);
3328
+ }
1719
3329
  }
1720
- };
3330
+ }
1721
3331
 
1722
- // src/parser/singleKeyObjectToString.ts
1723
- function singleKeyObjectToString(input) {
1724
- try {
1725
- const parsed = JSON.parse(input);
1726
- if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
1727
- const keys = Object.keys(parsed);
1728
- if (keys.length === 1) {
1729
- const value = parsed[keys[0]];
1730
- if (typeof value === "string") {
1731
- return value;
1732
- } else {
1733
- return input;
1734
- }
3332
+ // src/utils/modules/defineSchema.ts
3333
+ var import_json_schema_to_ts = require("json-schema-to-ts");
3334
+ function defineSchema(obj) {
3335
+ obj.additionalProperties = false;
3336
+ return (0, import_json_schema_to_ts.asConst)(obj);
3337
+ }
3338
+
3339
+ // src/utils/modules/handlebars/utils/importPartials.ts
3340
+ function importPartials(_partials) {
3341
+ let partials2 = [];
3342
+ if (_partials) {
3343
+ const externalPartialKeys = Object.keys(
3344
+ _partials
3345
+ );
3346
+ for (const externalPartialKey of externalPartialKeys) {
3347
+ if (typeof externalPartialKey === "string") {
3348
+ partials2.push({
3349
+ name: externalPartialKey,
3350
+ template: _partials[externalPartialKey]
3351
+ });
1735
3352
  }
1736
3353
  }
1737
- } catch {
1738
3354
  }
1739
- return input;
3355
+ return partials2;
1740
3356
  }
1741
3357
 
1742
- // src/parser/parsers/MarkdownCodeBlocks.ts
1743
- var MarkdownCodeBlocksParser = class extends BaseParser {
1744
- constructor(options) {
1745
- super("markdownCodeBlocks", options);
1746
- }
1747
- parse(input) {
1748
- const out = [];
1749
- if (isObjectStringified(input)) {
1750
- input = singleKeyObjectToString(input);
1751
- }
1752
- const regex = input.matchAll(new RegExp(/```(\w*)\n([\s\S]*?)```/, "g"));
1753
- for (const iterator of regex) {
1754
- if (iterator) {
1755
- const [_input, language, code] = iterator;
1756
- out.push({
1757
- language,
1758
- code
3358
+ // src/utils/modules/handlebars/utils/importHelpers.ts
3359
+ function importHelpers(_helpers) {
3360
+ let helpers = [];
3361
+ if (_helpers) {
3362
+ const externalHelperKeys = Object.keys(
3363
+ _helpers
3364
+ );
3365
+ for (const externalHelperKey of externalHelperKeys) {
3366
+ if (typeof externalHelperKey === "string") {
3367
+ helpers.push({
3368
+ name: externalHelperKey,
3369
+ handler: _helpers[externalHelperKey]
1759
3370
  });
1760
3371
  }
1761
3372
  }
1762
- return out;
1763
3373
  }
1764
- };
3374
+ return helpers;
3375
+ }
1765
3376
 
1766
- // src/parser/parsers/MarkdownCodeBlock.ts
1767
- var MarkdownCodeBlockParser = class extends BaseParser {
1768
- constructor(options) {
1769
- super("markdownCodeBlock", options);
3377
+ // src/utils/modules/replaceTemplateStringAsync.ts
3378
+ async function replaceTemplateStringAsync(templateString, substitutions = {}, configuration = {
3379
+ helpers: [],
3380
+ partials: []
3381
+ }) {
3382
+ if (!templateString) return Promise.resolve(templateString || "");
3383
+ const tempHelpers = [];
3384
+ const tempPartials = [];
3385
+ if (Array.isArray(configuration.helpers)) {
3386
+ hbsAsync.registerHelpers(configuration.helpers);
3387
+ tempHelpers.push(...configuration.helpers.map((a) => a.name));
1770
3388
  }
1771
- parse(input) {
1772
- const [block] = new MarkdownCodeBlocksParser().parse(input);
1773
- if (!block) {
1774
- return {
1775
- code: "",
1776
- language: ""
1777
- };
1778
- }
1779
- return block;
3389
+ if (Array.isArray(configuration.partials)) {
3390
+ hbsAsync.registerPartials(configuration.partials);
3391
+ tempPartials.push(...configuration.partials.map((a) => a.name));
1780
3392
  }
3393
+ const template = hbsAsync.handlebars.compile(templateString);
3394
+ const res = await template(substitutions, {
3395
+ allowedProtoMethods: {
3396
+ substring: true
3397
+ }
3398
+ });
3399
+ tempHelpers.forEach(function(n) {
3400
+ hbsAsync.handlebars.unregisterHelper(n);
3401
+ });
3402
+ tempPartials.forEach(function(n) {
3403
+ hbsAsync.handlebars.unregisterPartial(n);
3404
+ });
3405
+ return res;
3406
+ }
3407
+
3408
+ // src/utils/modules/asyncCallWithTimeout.ts
3409
+ var asyncCallWithTimeout = async (asyncPromise, timeLimit = 1e4) => {
3410
+ let timeoutHandle;
3411
+ const timeoutPromise = new Promise((_resolve, reject) => {
3412
+ timeoutHandle = setTimeout(() => {
3413
+ return reject(
3414
+ new Error(`LLM call timed out after ${timeLimit}ms`)
3415
+ );
3416
+ }, timeLimit);
3417
+ });
3418
+ return Promise.race([asyncPromise, timeoutPromise]).finally(() => {
3419
+ clearTimeout(timeoutHandle);
3420
+ });
1781
3421
  };
1782
3422
 
1783
- // src/parser/parsers/StringExtractParser.ts
1784
- var StringExtractParser = class extends BaseParser {
1785
- constructor(options) {
1786
- super("stringExtract", options);
1787
- __publicField(this, "enum", []);
1788
- __publicField(this, "ignoreCase");
1789
- if (options?.enum) {
1790
- this.enum.push(...options.enum);
1791
- }
1792
- if (options?.ignoreCase) {
1793
- this.ignoreCase = true;
1794
- }
3423
+ // src/utils/modules/guessProviderFromModel.ts
3424
+ function isModelKnownOpenAi(payload) {
3425
+ const model = payload.model.toLowerCase();
3426
+ if (model.startsWith("gpt-") || model.startsWith("chatgpt-")) {
3427
+ return true;
1795
3428
  }
1796
- parse(text) {
1797
- assert(
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
- );
3429
+ if (model === "o1" || model.startsWith("o1-")) {
3430
+ return true;
1816
3431
  }
1817
- };
1818
-
1819
- // src/parser/_functions.ts
1820
- function createParser(type, options = {}) {
1821
- switch (type) {
1822
- case "json":
1823
- return new JsonParser(options);
1824
- case "markdownCodeBlocks":
1825
- return new MarkdownCodeBlocksParser();
1826
- case "markdownCodeBlock":
1827
- return new MarkdownCodeBlockParser();
1828
- case "listToArray":
1829
- return new ListToArrayParser();
1830
- case "listToJson":
1831
- return new ListToJsonParser(options);
1832
- case "listToKeyValue":
1833
- return new ListToKeyValueParser();
1834
- case "replaceStringTemplate":
1835
- return new ReplaceStringTemplateParser();
1836
- case "boolean":
1837
- return new BooleanParser();
1838
- case "number":
1839
- return new NumberParser();
1840
- case "stringExtract":
1841
- return new StringExtractParser(options);
1842
- case "string":
1843
- return new StringParser();
3432
+ if (model === "o3-mini") {
3433
+ return true;
3434
+ }
3435
+ return false;
3436
+ }
3437
+ function isModelKnownAnthropic(payload) {
3438
+ const model = payload.model.toLowerCase();
3439
+ if (model.startsWith("claude-")) {
3440
+ return true;
3441
+ }
3442
+ return false;
3443
+ }
3444
+ function isModelKnownXai(payload) {
3445
+ const model = payload.model.toLowerCase();
3446
+ if (model.startsWith("grok-")) {
3447
+ return true;
3448
+ }
3449
+ return false;
3450
+ }
3451
+ function isModelKnownBedrockAnthropic(payload) {
3452
+ const model = payload.model.toLowerCase();
3453
+ if (model.startsWith("anthropic.claude-")) {
3454
+ return true;
3455
+ }
3456
+ return false;
3457
+ }
3458
+ function guessProviderFromModel(payload) {
3459
+ switch (true) {
3460
+ case isModelKnownOpenAi(payload):
3461
+ return "openai";
3462
+ case isModelKnownXai(payload):
3463
+ return "xai";
3464
+ case isModelKnownBedrockAnthropic(payload):
3465
+ return "bedrock:anthropic";
3466
+ case isModelKnownAnthropic(payload):
3467
+ return "anthropic";
1844
3468
  default:
1845
- throw new Error(
1846
- `Invalid parser type: "${type}". Valid types are: json, string, boolean, number, stringExtract, listToArray, listToJson, listToKeyValue, replaceStringTemplate, markdownCodeBlock, markdownCodeBlocks`
1847
- );
3469
+ throw new LlmExeError("Unsupported model", {
3470
+ code: "configuration.invalid_provider",
3471
+ context: {
3472
+ operation: "guessProviderFromModel",
3473
+ model: payload.model,
3474
+ // Mirrors the switch above. Keep these in sync when adding a new
3475
+ // isModelKnown* case.
3476
+ availableProviders: [
3477
+ "openai",
3478
+ "xai",
3479
+ "bedrock:anthropic",
3480
+ "anthropic"
3481
+ ],
3482
+ resolution: "Pass a known model prefix (gpt-, chatgpt-, o1, o3-mini, claude-, grok-, anthropic.claude-) or specify the provider explicitly."
3483
+ }
3484
+ });
1848
3485
  }
1849
3486
  }
1850
- function createCustomParser(name, parserFn) {
1851
- return new CustomParser(name, parserFn);
3487
+
3488
+ // src/utils/modules/index.ts
3489
+ function registerHelpers(helpers) {
3490
+ hbs.registerHelpers(helpers);
3491
+ hbsAsync.registerHelpers(helpers);
3492
+ }
3493
+ function registerPartials(partials2) {
3494
+ hbs.registerPartials(partials2);
3495
+ hbsAsync.registerPartials(partials2);
1852
3496
  }
1853
3497
 
1854
3498
  // src/parser/parsers/LlmNativeFunctionParser.ts
1855
3499
  var LlmFunctionParser = class extends BaseParser {
1856
3500
  constructor(options) {
1857
- super("functionCall", options, "function_call");
3501
+ super("functionCall", "function_call");
1858
3502
  __publicField(this, "parser");
1859
3503
  this.parser = options.parser;
1860
3504
  }
1861
3505
  parse(text, _options) {
1862
3506
  if (typeof text === "string") {
1863
- return this.parser.parse(text);
3507
+ return this.parser.parse(text, _options);
1864
3508
  }
1865
3509
  const { content } = text;
1866
3510
  const functionUses = content?.filter((a) => a.type === "function_use") || [];
1867
3511
  if (functionUses.length === 0) {
1868
3512
  const [item] = content;
1869
- return this.parser.parse(item.text);
3513
+ return this.parser.parse(item.text, _options);
1870
3514
  }
1871
3515
  return content;
1872
3516
  }
1873
3517
  };
1874
3518
  var LlmNativeFunctionParser = class extends BaseParser {
1875
3519
  constructor(options) {
1876
- super("openAiFunction", options, "function_call");
3520
+ super("openAiFunction", "function_call");
1877
3521
  __publicField(this, "parser");
1878
3522
  this.parser = options.parser;
1879
3523
  }
1880
3524
  parse(text, _options) {
3525
+ if (typeof text === "string") {
3526
+ return this.parser.parse(text, _options);
3527
+ }
3528
+ if (typeof text?.text === "string") {
3529
+ return this.parser.parse(text.text, _options);
3530
+ }
1881
3531
  const { content } = text;
1882
3532
  const functionUse = content?.find((a) => a.type === "function_use");
1883
3533
  if (functionUse && "name" in functionUse && "input" in functionUse) {
@@ -1886,7 +3536,10 @@ var LlmNativeFunctionParser = class extends BaseParser {
1886
3536
  arguments: maybeParseJSON(functionUse.input)
1887
3537
  };
1888
3538
  }
1889
- return this.parser.parse(text?.text ?? text);
3539
+ const textContent = content?.find(
3540
+ (item) => item.type === "text" && typeof item.text === "string"
3541
+ );
3542
+ return this.parser.parse(textContent?.text, _options);
1890
3543
  }
1891
3544
  };
1892
3545
  var OpenAiFunctionParser = LlmNativeFunctionParser;
@@ -1913,17 +3566,29 @@ var LlmExecutor = class extends BaseExecutor {
1913
3566
  this.promptFn = null;
1914
3567
  }
1915
3568
  }
3569
+ /**
3570
+ * Runs the executor against the configured LLM and prompt.
3571
+ *
3572
+ * `null` and `undefined` are rejected with a `TypeError`: the declared
3573
+ * input type requires an object, and silently coercing missing input hides a
3574
+ * clear contract violation. Use `{}` for prompts that declare no template
3575
+ * variables. See issue #410.
3576
+ */
1916
3577
  async execute(_input, _options) {
1917
- const input = _input ?? {};
3578
+ if (_input === null || typeof _input === "undefined") {
3579
+ throw new TypeError(
3580
+ `[llm-exe] Executor "${this.name}" received null or undefined as input. execute() expects an object matching the prompt's input type.`
3581
+ );
3582
+ }
1918
3583
  if (this?.parser instanceof JsonParser && this.parser.schema) {
1919
3584
  _options = Object.assign(_options || {}, {
1920
3585
  jsonSchema: this.parser.schema
1921
3586
  });
1922
3587
  }
1923
- return super.execute(input, _options);
3588
+ return super.execute(_input, _options);
1924
3589
  }
1925
- async handler(_input, ..._args) {
1926
- const call = await this.llm.call(_input, ..._args);
3590
+ async handler(_input, _options, _context) {
3591
+ const call = await this.llm.call(_input, _options, _context);
1927
3592
  return call;
1928
3593
  }
1929
3594
  async getHandlerInput(_input) {
@@ -1942,15 +3607,26 @@ var LlmExecutor = class extends BaseExecutor {
1942
3607
  return prompt.format(_input);
1943
3608
  }
1944
3609
  }
1945
- throw new Error("Missing prompt");
3610
+ throw new LlmExeError("Missing prompt", {
3611
+ code: "executor.missing_prompt",
3612
+ context: {
3613
+ operation: "LlmExecutor.getHandlerInput",
3614
+ executorName: this.name,
3615
+ executorType: this.type,
3616
+ traceId: this.getTraceId() ?? void 0,
3617
+ resolution: "Provide a prompt (or prompt factory) when constructing the LLM executor."
3618
+ }
3619
+ });
1946
3620
  }
1947
- getHandlerOutput(out, _metadata) {
3621
+ getHandlerOutput(out, _metadata, _options, _context) {
3622
+ const parse = this.parser.parse.bind(this.parser);
3623
+ const parserArg = _context ?? _metadata;
1948
3624
  if (this.parser.target === "function_call") {
1949
3625
  const outToStr = out.getResult();
1950
- return this.parser.parse(outToStr, _metadata);
3626
+ return parse(outToStr, parserArg);
1951
3627
  } else {
1952
3628
  const outToStr = out.getResultText();
1953
- return this.parser.parse(outToStr, _metadata);
3629
+ return parse(outToStr, parserArg);
1954
3630
  }
1955
3631
  }
1956
3632
  metadata() {
@@ -2052,7 +3728,17 @@ var CallableExecutor = class {
2052
3728
  } else if (typeof options.handler === "function") {
2053
3729
  this._handler = createCoreExecutor(options.handler);
2054
3730
  } else {
2055
- throw new Error("Invalid handler");
3731
+ throw new LlmExeError("Invalid handler", {
3732
+ code: "callable.invalid_handler",
3733
+ context: {
3734
+ operation: "CallableExecutor.constructor",
3735
+ functionName: options.name,
3736
+ key: options?.key || options.name,
3737
+ expected: "function or BaseExecutor",
3738
+ received: typeof options.handler,
3739
+ resolution: "Pass a function or a BaseExecutor instance as the handler."
3740
+ }
3741
+ });
2056
3742
  }
2057
3743
  }
2058
3744
  async execute(input) {
@@ -2070,7 +3756,16 @@ var CallableExecutor = class {
2070
3756
  }
2071
3757
  return { result: true, attributes: {} };
2072
3758
  } catch (error) {
2073
- return { result: false, attributes: { error: error.message } };
3759
+ const wrapped = error instanceof LlmExeError ? error : new LlmExeError(error?.message ?? String(error), {
3760
+ code: "callable.validation_failed",
3761
+ context: {
3762
+ operation: "CallableExecutor.validateInput",
3763
+ functionName: this.name,
3764
+ key: this.key
3765
+ },
3766
+ cause: error
3767
+ });
3768
+ return { result: false, attributes: { error: wrapped.message } };
2074
3769
  }
2075
3770
  }
2076
3771
  visibilityHandler(input, attributes) {
@@ -2107,10 +3802,19 @@ var UseExecutorsBase = class {
2107
3802
  async callFunction(name, input) {
2108
3803
  try {
2109
3804
  const handler = this.getFunction(name);
2110
- assert(
2111
- handler,
2112
- `[invalid handler] The handler (${name}) does not exist.`
2113
- );
3805
+ if (!handler) {
3806
+ throw new LlmExeError(
3807
+ `[invalid handler] The handler (${name}) does not exist.`,
3808
+ {
3809
+ code: "callable.handler_not_found",
3810
+ context: {
3811
+ operation: "UseExecutorsBase.callFunction",
3812
+ functionName: name,
3813
+ availableFunctions: this.handlers.map((h) => h.name)
3814
+ }
3815
+ }
3816
+ );
3817
+ }
2114
3818
  const result = await handler.execute(ensureInputIsObject(input));
2115
3819
  return result;
2116
3820
  } catch (error) {
@@ -2120,10 +3824,19 @@ var UseExecutorsBase = class {
2120
3824
  async validateFunctionInput(name, input) {
2121
3825
  try {
2122
3826
  const handler = this.getFunction(name);
2123
- assert(
2124
- handler,
2125
- `[invalid handler] The handler (${name}) does not exist.`
2126
- );
3827
+ if (!handler) {
3828
+ throw new LlmExeError(
3829
+ `[invalid handler] The handler (${name}) does not exist.`,
3830
+ {
3831
+ code: "callable.handler_not_found",
3832
+ context: {
3833
+ operation: "UseExecutorsBase.validateFunctionInput",
3834
+ functionName: name,
3835
+ availableFunctions: this.handlers.map((h) => h.name)
3836
+ }
3837
+ }
3838
+ );
3839
+ }
2127
3840
  const result = await handler.validateInput(
2128
3841
  ensureInputIsObject(input)
2129
3842
  );
@@ -2138,18 +3851,59 @@ var UseExecutorsBase = class {
2138
3851
  function createCallableExecutor(options) {
2139
3852
  return new CallableExecutor(options);
2140
3853
  }
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
- );
3854
+ var UseExecutors = class extends UseExecutorsBase {
3855
+ constructor(handlers) {
3856
+ super(handlers);
3857
+ }
3858
+ };
3859
+ function useExecutors(executors) {
3860
+ return new UseExecutors(
3861
+ executors.map((e) => {
3862
+ if (e instanceof CallableExecutor) return e;
3863
+ return createCallableExecutor(e);
3864
+ })
3865
+ );
3866
+ }
3867
+
3868
+ // src/utils/guards.ts
3869
+ var guards_exports = {};
3870
+ __export(guards_exports, {
3871
+ hasFunctionCall: () => hasFunctionCall,
3872
+ hasToolCall: () => hasToolCall,
3873
+ isAssistantMessage: () => isAssistantMessage,
3874
+ isFunctionCall: () => isFunctionCall,
3875
+ isOutputResult: () => isOutputResult,
3876
+ isOutputResultContentText: () => isOutputResultContentText,
3877
+ isSystemMessage: () => isSystemMessage,
3878
+ isToolCall: () => isToolCall,
3879
+ isUserMessage: () => isUserMessage
3880
+ });
3881
+ function isOutputResult(obj) {
3882
+ return !!(obj && typeof obj === "object" && "id" in obj && "stopReason" in obj && "content" in obj && Array.isArray(obj.content));
3883
+ }
3884
+ function isOutputResultContentText(obj) {
3885
+ return !!(obj && typeof obj === "object" && "text" in obj && "type" in obj && obj.type === "text" && typeof obj.text === "string");
3886
+ }
3887
+ function isFunctionCall(result) {
3888
+ return !!(result && typeof result === "object" && "functionId" in result && "type" in result && result.type === "function_use");
3889
+ }
3890
+ function isToolCall(result) {
3891
+ return isFunctionCall(result);
3892
+ }
3893
+ function hasFunctionCall(results) {
3894
+ return !!(results && Array.isArray(results) && results.some(isToolCall));
3895
+ }
3896
+ function hasToolCall(results) {
3897
+ return hasFunctionCall(results);
3898
+ }
3899
+ function isUserMessage(message) {
3900
+ return message.role === "user";
3901
+ }
3902
+ function isAssistantMessage(message) {
3903
+ return message.role === "assistant" || message.role === "model";
3904
+ }
3905
+ function isSystemMessage(message) {
3906
+ return message.role === "system";
2153
3907
  }
2154
3908
 
2155
3909
  // src/utils/modules/deepClone.ts
@@ -2194,13 +3948,38 @@ function withDefaultModel(obj1, model) {
2194
3948
  return copy;
2195
3949
  }
2196
3950
 
2197
- // src/utils/modules/getEnvironmentVariable.ts
2198
- function getEnvironmentVariable(name) {
2199
- if (typeof process === "object" && process?.env) {
2200
- return process.env[name];
2201
- } else {
2202
- return void 0;
3951
+ // src/llm/_utils.deprecationWarning.ts
3952
+ var warned = /* @__PURE__ */ new Set();
3953
+ function emitDeprecationWarning(config, context) {
3954
+ if (!config.deprecated) return;
3955
+ if (typeof process !== "object" || typeof process?.emitWarning !== "function") {
3956
+ return;
2203
3957
  }
3958
+ const { shorthand, message } = config.deprecated;
3959
+ if (warned.has(shorthand)) return;
3960
+ warned.add(shorthand);
3961
+ const detail = JSON.stringify({
3962
+ shorthand,
3963
+ model: config.options?.model?.default,
3964
+ provider: config.provider,
3965
+ executorName: context?.executorName,
3966
+ traceId: context?.traceId
3967
+ });
3968
+ process.emitWarning(message, {
3969
+ type: "DeprecationWarning",
3970
+ code: "LLM_EXE_DEPRECATED",
3971
+ detail
3972
+ });
3973
+ }
3974
+ function deprecateShorthand(shorthand, args) {
3975
+ const entry = {
3976
+ ...args.config,
3977
+ deprecated: Object.freeze({
3978
+ shorthand,
3979
+ message: args.message
3980
+ })
3981
+ };
3982
+ return { [shorthand]: entry };
2204
3983
  }
2205
3984
 
2206
3985
  // src/llm/output/_util.ts
@@ -2482,7 +4261,10 @@ var openai = {
2482
4261
  "openai.gpt-4o": withDefaultModel(openAiChatV1, "gpt-4o"),
2483
4262
  "openai.gpt-4o-mini": withDefaultModel(openAiChatV1, "gpt-4o-mini"),
2484
4263
  // Deprecated
2485
- "openai.o4-mini": withDefaultModel(openAiChatV1, "o4-mini")
4264
+ ...deprecateShorthand("openai.o4-mini", {
4265
+ config: withDefaultModel(openAiChatV1, "o4-mini"),
4266
+ message: 'Shorthand "openai.o4-mini" is deprecated and may be removed in a future release.'
4267
+ })
2486
4268
  };
2487
4269
 
2488
4270
  // src/llm/config/anthropic/promptSanitizeMessageCallback.ts
@@ -2851,38 +4633,38 @@ var anthropic = {
2851
4633
  "claude-sonnet-4-5"
2852
4634
  ),
2853
4635
  // Deprecated
2854
- "anthropic.claude-opus-4-6": withDefaultModel(
2855
- anthropicChatV1,
2856
- "claude-opus-4-6"
2857
- ),
2858
- "anthropic.claude-opus-4-1": withDefaultModel(
2859
- anthropicChatV1,
2860
- "claude-opus-4-1-20250805"
2861
- ),
2862
- "anthropic.claude-sonnet-4": withDefaultModel(
2863
- anthropicChatV1,
2864
- "claude-sonnet-4-0"
2865
- ),
2866
- "anthropic.claude-opus-4": withDefaultModel(
2867
- anthropicChatV1,
2868
- "claude-opus-4-0"
2869
- ),
2870
- "anthropic.claude-3-7-sonnet": withDefaultModel(
2871
- anthropicChatV1,
2872
- "claude-3-7-sonnet-20250219"
2873
- ),
2874
- "anthropic.claude-3-5-sonnet": withDefaultModel(
2875
- anthropicChatV1,
2876
- "claude-3-5-sonnet-latest"
2877
- ),
2878
- "anthropic.claude-3-5-haiku": withDefaultModel(
2879
- anthropicChatV1,
2880
- "claude-3-5-haiku-latest"
2881
- ),
2882
- "anthropic.claude-3-opus": withDefaultModel(
2883
- anthropicChatV1,
2884
- "claude-3-opus-20240229"
2885
- )
4636
+ ...deprecateShorthand("anthropic.claude-opus-4-6", {
4637
+ config: withDefaultModel(anthropicChatV1, "claude-opus-4-6"),
4638
+ message: 'Shorthand "anthropic.claude-opus-4-6" is deprecated and may be removed in a future release.'
4639
+ }),
4640
+ ...deprecateShorthand("anthropic.claude-opus-4-1", {
4641
+ config: withDefaultModel(anthropicChatV1, "claude-opus-4-1-20250805"),
4642
+ message: 'Shorthand "anthropic.claude-opus-4-1" is deprecated and may be removed in a future release.'
4643
+ }),
4644
+ ...deprecateShorthand("anthropic.claude-sonnet-4", {
4645
+ config: withDefaultModel(anthropicChatV1, "claude-sonnet-4-0"),
4646
+ message: 'Shorthand "anthropic.claude-sonnet-4" is deprecated and may be removed in a future release.'
4647
+ }),
4648
+ ...deprecateShorthand("anthropic.claude-opus-4", {
4649
+ config: withDefaultModel(anthropicChatV1, "claude-opus-4-0"),
4650
+ message: 'Shorthand "anthropic.claude-opus-4" is deprecated and may be removed in a future release.'
4651
+ }),
4652
+ ...deprecateShorthand("anthropic.claude-3-7-sonnet", {
4653
+ config: withDefaultModel(anthropicChatV1, "claude-3-7-sonnet-20250219"),
4654
+ message: 'Shorthand "anthropic.claude-3-7-sonnet" is deprecated and may be removed in a future release.'
4655
+ }),
4656
+ ...deprecateShorthand("anthropic.claude-3-5-sonnet", {
4657
+ config: withDefaultModel(anthropicChatV1, "claude-3-5-sonnet-latest"),
4658
+ message: 'Shorthand "anthropic.claude-3-5-sonnet" is deprecated and may be removed in a future release.'
4659
+ }),
4660
+ ...deprecateShorthand("anthropic.claude-3-5-haiku", {
4661
+ config: withDefaultModel(anthropicChatV1, "claude-3-5-haiku-latest"),
4662
+ message: 'Shorthand "anthropic.claude-3-5-haiku" is deprecated and may be removed in a future release.'
4663
+ }),
4664
+ ...deprecateShorthand("anthropic.claude-3-opus", {
4665
+ config: withDefaultModel(anthropicChatV1, "claude-3-opus-20240229"),
4666
+ message: 'Shorthand "anthropic.claude-3-opus" is deprecated and may be removed in a future release.'
4667
+ })
2886
4668
  };
2887
4669
 
2888
4670
  // src/llm/config/x/index.ts
@@ -2911,15 +4693,31 @@ var xai = {
2911
4693
 
2912
4694
  // src/llm/output/_utils/combineJsonl.ts
2913
4695
  function combineJsonl(jsonl) {
2914
- const lines = jsonl.trim().split("\n").map((line) => line.trim()).filter((line) => line.length > 0).map((line) => {
4696
+ const rawLines = jsonl.trim().split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
4697
+ const lines = rawLines.map((line, idx) => {
2915
4698
  try {
2916
4699
  return JSON.parse(line);
2917
4700
  } catch (e) {
2918
- throw new Error(`Invalid JSON: ${line}`);
4701
+ throw new LlmExeError(`Invalid JSON: ${line}`, {
4702
+ code: "llm.invalid_jsonl_response",
4703
+ context: {
4704
+ operation: "combineJsonl",
4705
+ lineNumber: idx + 1,
4706
+ lineExcerpt: line
4707
+ },
4708
+ cause: e
4709
+ });
2919
4710
  }
2920
4711
  });
2921
4712
  if (lines.length === 0) {
2922
- throw new Error("No JSON lines provided.");
4713
+ throw new LlmExeError("No JSON lines provided.", {
4714
+ code: "llm.invalid_jsonl_response",
4715
+ context: {
4716
+ operation: "combineJsonl",
4717
+ received: 0,
4718
+ expected: "at least one JSONL line"
4719
+ }
4720
+ });
2923
4721
  }
2924
4722
  lines.sort(
2925
4723
  (a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime()
@@ -2928,7 +4726,14 @@ function combineJsonl(jsonl) {
2928
4726
  combinedContent = combinedContent.replace(/\\u003c/g, "<").replace(/\\u003e/g, ">");
2929
4727
  const finalLine = lines.find((line) => line.done === true);
2930
4728
  if (!finalLine) {
2931
- throw new Error("No line found where done = true.");
4729
+ throw new LlmExeError("No line found where done = true.", {
4730
+ code: "llm.invalid_jsonl_response",
4731
+ context: {
4732
+ operation: "combineJsonl",
4733
+ lineCount: lines.length,
4734
+ expected: "a final line with done = true"
4735
+ }
4736
+ });
2932
4737
  }
2933
4738
  const result = {
2934
4739
  model: finalLine.model,
@@ -3093,7 +4898,16 @@ function googleGeminiPromptSanitize(_messages, _inputBodyObj, _outputObj) {
3093
4898
  }
3094
4899
  if (Array.isArray(_messages)) {
3095
4900
  if (_messages.length === 0) {
3096
- throw new Error("Empty messages array");
4901
+ throw new LlmExeError("Empty messages array", {
4902
+ code: "prompt.invalid_messages",
4903
+ context: {
4904
+ operation: "googleGeminiPromptSanitize",
4905
+ provider: "google",
4906
+ received: "empty array",
4907
+ expected: "a non-empty messages array",
4908
+ resolution: "Pass at least one message to the prompt."
4909
+ }
4910
+ });
3097
4911
  }
3098
4912
  if (_messages.length === 1 && _messages[0].role === "system") {
3099
4913
  return [{ role: "user", parts: [{ text: _messages[0].content }] }];
@@ -3121,7 +4935,16 @@ function googleGeminiPromptSanitize(_messages, _inputBodyObj, _outputObj) {
3121
4935
  const result = _messages.map(googleGeminiPromptMessageCallback);
3122
4936
  return mergeConsecutiveSameRole2(result);
3123
4937
  }
3124
- throw new Error("Invalid messages format");
4938
+ throw new LlmExeError("Invalid messages format", {
4939
+ code: "prompt.invalid_messages",
4940
+ context: {
4941
+ operation: "googleGeminiPromptSanitize",
4942
+ provider: "google",
4943
+ received: typeof _messages,
4944
+ expected: "string or messages array",
4945
+ resolution: "Pass a string or an array of chat messages."
4946
+ }
4947
+ });
3125
4948
  }
3126
4949
 
3127
4950
  // src/llm/output/google.gemini/formatResult.ts
@@ -3237,18 +5060,6 @@ var googleGeminiChatV1 = {
3237
5060
  };
3238
5061
  var google = {
3239
5062
  "google.chat.v1": googleGeminiChatV1,
3240
- "google.gemini-2.5-flash": withDefaultModel(
3241
- googleGeminiChatV1,
3242
- "gemini-2.5-flash"
3243
- ),
3244
- "google.gemini-2.5-flash-lite": withDefaultModel(
3245
- googleGeminiChatV1,
3246
- "gemini-2.5-flash-lite"
3247
- ),
3248
- "google.gemini-2.5-pro": withDefaultModel(
3249
- googleGeminiChatV1,
3250
- "gemini-2.5-pro"
3251
- ),
3252
5063
  "google.gemini-3.1-flash-lite": withDefaultModel(
3253
5064
  googleGeminiChatV1,
3254
5065
  "gemini-3.1-flash-lite"
@@ -3258,6 +5069,18 @@ var google = {
3258
5069
  "gemini-3.5-flash"
3259
5070
  ),
3260
5071
  // Deprecated
5072
+ ...deprecateShorthand("google.gemini-2.5-flash", {
5073
+ config: withDefaultModel(googleGeminiChatV1, "gemini-2.5-flash"),
5074
+ message: 'Model "google.gemini-2.5-flash" is deprecated and will shut down on 2026-06-17.'
5075
+ }),
5076
+ ...deprecateShorthand("google.gemini-2.5-flash-lite", {
5077
+ config: withDefaultModel(googleGeminiChatV1, "gemini-2.5-flash-lite"),
5078
+ message: 'Model "google.gemini-2.5-flash-lite" is deprecated and will shut down on 2026-07-22.'
5079
+ }),
5080
+ ...deprecateShorthand("google.gemini-2.5-pro", {
5081
+ config: withDefaultModel(googleGeminiChatV1, "gemini-2.5-pro"),
5082
+ message: 'Model "google.gemini-2.5-pro" is deprecated and will shut down on 2026-06-17.'
5083
+ }),
3261
5084
  "google.gemini-2.0-flash": withDefaultModel(
3262
5085
  googleGeminiChatV1,
3263
5086
  "gemini-2.0-flash"
@@ -3298,81 +5121,28 @@ var configs = {
3298
5121
  };
3299
5122
  function getLlmConfig(provider) {
3300
5123
  if (!provider) {
3301
- throw new LlmExeError(`Missing provider`, "unknown", {
3302
- error: "Missing provider",
3303
- resolution: "Provide a valid provider"
5124
+ throw new LlmExeError(`Missing provider`, {
5125
+ code: "configuration.missing_provider",
5126
+ context: {
5127
+ operation: "getLlmConfig",
5128
+ availableProviders: Object.keys(configs),
5129
+ resolution: "Provide a valid provider"
5130
+ }
3304
5131
  });
3305
5132
  }
3306
5133
  const pick2 = configs[provider];
3307
5134
  if (pick2) {
3308
5135
  return pick2;
3309
5136
  }
3310
- throw new LlmExeError(`Invalid provider: ${provider}`, "unknown", {
3311
- provider,
3312
- error: `Invalid provider: ${provider}`,
3313
- resolution: "Provide a valid provider"
3314
- });
3315
- }
3316
-
3317
- // src/utils/modules/maskApiKeysInDebug.ts
3318
- function maskApiKeys(log) {
3319
- return log.replace(
3320
- /\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,
3321
- (match) => {
3322
- if (match.length <= 8) return match;
3323
- const prefix = match.substring(0, 4);
3324
- const suffix = match.substring(match.length - 4);
3325
- const maskLength = match.length - 8;
3326
- return `${prefix}${"*".repeat(maskLength)}${suffix}`;
3327
- }
3328
- );
3329
- }
3330
-
3331
- // src/utils/modules/debug.ts
3332
- function debug(...args) {
3333
- const debugValue = getEnvironmentVariable("LLM_EXE_DEBUG");
3334
- const logs = [];
3335
- for (const arg of args) {
3336
- if (arg && typeof arg === "object") {
3337
- if (arg instanceof Error) {
3338
- } else if (arg instanceof Array) {
3339
- logs.push(arg.map((item) => JSON.stringify(item, null, 2)));
3340
- } else if (arg instanceof Map) {
3341
- logs.push(
3342
- Array.from(arg.entries()).map(
3343
- ([key, value]) => `${key}: ${JSON.stringify(value, null, 2)}`
3344
- )
3345
- );
3346
- } else if (arg instanceof Set) {
3347
- logs.push(Array.from(arg).map((item) => JSON.stringify(item, null, 2)));
3348
- } else if (arg instanceof Date) {
3349
- logs.push(arg.toISOString());
3350
- } else if (arg instanceof RegExp) {
3351
- logs.push(arg.toString());
3352
- } else {
3353
- try {
3354
- let shouldMask = false;
3355
- if (arg.headers && arg.headers.Authorization) {
3356
- shouldMask = true;
3357
- }
3358
- let str = JSON.stringify(arg, null, 2);
3359
- if (shouldMask) {
3360
- str = maskApiKeys(str);
3361
- }
3362
- logs.push(str);
3363
- } catch (error) {
3364
- console.error("Error parsing object:", error);
3365
- }
3366
- }
3367
- } else if (typeof arg === "string") {
3368
- logs.push(arg);
3369
- } else {
3370
- logs.push(arg);
5137
+ throw new LlmExeError(`Invalid provider: ${provider}`, {
5138
+ code: "configuration.invalid_provider",
5139
+ context: {
5140
+ operation: "getLlmConfig",
5141
+ provider,
5142
+ availableProviders: Object.keys(configs),
5143
+ resolution: "Provide a valid provider"
3371
5144
  }
3372
- }
3373
- if (typeof debugValue === "string" && debugValue !== "" && debugValue.toLowerCase() !== "undefined" && debugValue.toLowerCase() !== "null") {
3374
- console.debug(...logs);
3375
- }
5145
+ });
3376
5146
  }
3377
5147
 
3378
5148
  // src/utils/modules/isValidUrl.ts
@@ -3390,41 +5160,93 @@ async function apiRequest(url, options) {
3390
5160
  const finalOptions = {
3391
5161
  ...options
3392
5162
  };
5163
+ debug(url, finalOptions);
5164
+ if (!url || !isValidUrl(url)) {
5165
+ const safeUrl = safeRequestUrl(url);
5166
+ throw new LlmExeError("Invalid URL", {
5167
+ code: "request.invalid_url",
5168
+ context: {
5169
+ operation: "apiRequest",
5170
+ url: safeUrl,
5171
+ expected: "valid URL"
5172
+ }
5173
+ });
5174
+ }
5175
+ let response;
3393
5176
  try {
3394
- debug(url, finalOptions);
3395
- if (!url || !isValidUrl(url)) {
3396
- throw new Error("Invalid URL");
3397
- }
3398
- const response = await fetch(url, finalOptions);
3399
- if (!response.ok) {
3400
- let message = `HTTP error. Status: ${response.status}. Error Message: ${response?.statusText || "Unknown error."}`;
3401
- try {
3402
- const text = await response.text();
3403
- if (text) {
3404
- let detail = text;
3405
- try {
3406
- const body = JSON.parse(text);
3407
- detail = body?.error?.message || body?.error || body?.message || text;
3408
- if (typeof detail !== "string") detail = JSON.stringify(detail);
3409
- } catch {
3410
- }
3411
- message = `HTTP error. Status Code: ${response.status}. Error Message: ${detail}`;
5177
+ response = await fetch(url, finalOptions);
5178
+ } catch (fetchError) {
5179
+ const innerMsg = fetchError instanceof Error ? fetchError.message : "Error";
5180
+ const safeUrl = safeRequestUrl(url);
5181
+ throw new LlmExeError(`Request to ${safeUrl} failed: ${innerMsg}`, {
5182
+ code: "request.http_error",
5183
+ context: {
5184
+ operation: "apiRequest",
5185
+ url: safeUrl
5186
+ },
5187
+ cause: fetchError
5188
+ });
5189
+ }
5190
+ if (!response.ok) {
5191
+ let bodyText = "";
5192
+ let bodyJson = void 0;
5193
+ let bodyReadError = void 0;
5194
+ try {
5195
+ bodyText = await response.text();
5196
+ if (bodyText) {
5197
+ try {
5198
+ bodyJson = JSON.parse(bodyText);
5199
+ } catch {
3412
5200
  }
3413
- } catch {
3414
5201
  }
3415
- throw new Error(message);
3416
- }
3417
- const contentType = response.headers.get("content-type");
3418
- if (contentType?.includes("application/json")) {
3419
- const responseData = await response.json();
3420
- return responseData;
5202
+ } catch (e) {
5203
+ bodyReadError = e;
5204
+ }
5205
+ let message;
5206
+ if (bodyText) {
5207
+ let detail = bodyText;
5208
+ if (bodyJson) {
5209
+ const b = bodyJson;
5210
+ detail = b.error?.message || b.error || b.message || bodyText;
5211
+ if (typeof detail !== "string") detail = JSON.stringify(detail);
5212
+ }
5213
+ const safeDetail = safeProviderString(detail) ?? "";
5214
+ message = `HTTP error. Status Code: ${response.status}. Error Message: ${safeDetail}`;
3421
5215
  } else {
3422
- const responseData = await response.text();
3423
- return responseData;
3424
- }
3425
- } catch (error) {
3426
- const message = error instanceof Error ? error.message : "Error";
3427
- throw new Error(`Request to ${url} failed: ${message}`);
5216
+ message = `HTTP error. Status: ${response.status}. Error Message: ${response.statusText || "Unknown error."}`;
5217
+ }
5218
+ const safeUrl = safeRequestUrl(url);
5219
+ const wrappedMessage = `Request to ${safeUrl} failed: ${message}`;
5220
+ const safeHeaders = safeResponseHeaders(response.headers);
5221
+ const providerError = parseProviderErrorGeneric({
5222
+ status: response.status,
5223
+ statusText: response.statusText,
5224
+ headers: safeHeaders,
5225
+ bodyJson,
5226
+ bodyText
5227
+ });
5228
+ throw new LlmExeError(wrappedMessage, {
5229
+ code: "request.http_error",
5230
+ context: {
5231
+ operation: "apiRequest",
5232
+ url: safeUrl,
5233
+ status: response.status,
5234
+ statusText: response.statusText,
5235
+ responseHeaders: safeHeaders,
5236
+ providerError,
5237
+ providerErrorBody: bodyJson !== void 0 ? safeProviderErrorBody(bodyJson) : void 0,
5238
+ providerErrorRaw: bodyText ? safeProviderErrorBody(bodyText) : void 0
5239
+ },
5240
+ cause: bodyReadError
5241
+ });
5242
+ }
5243
+ const contentType = response.headers.get("content-type");
5244
+ if (contentType?.includes("application/json")) {
5245
+ const responseData = await response.json();
5246
+ return responseData;
5247
+ } else {
5248
+ const responseData = await response.text();
5249
+ return responseData;
3428
5250
  }
3429
5251
  }
3430
5252
 
@@ -3545,7 +5367,19 @@ async function runWithTemporaryEnv(env, handler) {
3545
5367
  // src/utils/modules/getAwsAuthorizationHeaders.ts
3546
5368
  async function getAwsAuthorizationHeaders(req, props) {
3547
5369
  if (!props.url || !props.regionName) {
3548
- throw new Error("URL and region name are required for AWS authorization");
5370
+ throw new LlmExeError(
5371
+ "URL and region name are required for AWS authorization",
5372
+ {
5373
+ code: "auth.aws_signing_input_missing",
5374
+ context: {
5375
+ operation: "getAwsAuthorizationHeaders",
5376
+ url: props.url,
5377
+ regionName: props.regionName,
5378
+ expected: "both url and regionName to be set",
5379
+ resolution: "Set AWS_REGION as an environment variable (or pass regionName) and provide a valid request URL."
5380
+ }
5381
+ }
5382
+ );
3549
5383
  }
3550
5384
  const providerChain = (0, import_credential_providers.fromNodeProviderChain)();
3551
5385
  const credentials = await runWithTemporaryEnv(
@@ -3584,6 +5418,12 @@ async function getAwsAuthorizationHeaders(req, props) {
3584
5418
  }
3585
5419
 
3586
5420
  // src/llm/_utils.parseHeaders.ts
5421
+ var REPLACED_HEADERS_EXCERPT_MAX = 500;
5422
+ function safeReplacedHeaders(value) {
5423
+ if (!value) return "";
5424
+ const truncated = value.length > REPLACED_HEADERS_EXCERPT_MAX ? value.slice(0, REPLACED_HEADERS_EXCERPT_MAX) + "\u2026(truncated)" : value;
5425
+ return redactSecrets(truncated);
5426
+ }
3587
5427
  async function parseHeaders(config, replacements, payload) {
3588
5428
  const replace = replaceTemplateStringSimple(config.headers, replacements);
3589
5429
  let parsedHeaders = {};
@@ -3595,8 +5435,21 @@ async function parseHeaders(config, replacements, payload) {
3595
5435
  }
3596
5436
  } catch (error) {
3597
5437
  const errorMessage = error instanceof Error ? error.message : "Unknown error";
3598
- throw new Error(
3599
- `Failed to parse headers configuration: ${errorMessage}. Headers template: "${config.headers}". After replacement: "${replace}"`
5438
+ const safeReplaced = safeReplacedHeaders(replace);
5439
+ throw new LlmExeError(
5440
+ `Failed to parse headers configuration: ${errorMessage}. Headers template: "${config.headers}". After replacement: "${safeReplaced}"`,
5441
+ {
5442
+ code: "configuration.invalid_headers",
5443
+ context: {
5444
+ operation: "parseHeaders",
5445
+ provider: config.provider,
5446
+ key: config.key,
5447
+ headerTemplate: config.headers,
5448
+ replacedHeadersExcerpt: safeReplaced,
5449
+ resolution: "Fix the headers template so replacement produces a JSON object."
5450
+ },
5451
+ cause: error
5452
+ }
3600
5453
  );
3601
5454
  }
3602
5455
  }
@@ -3750,29 +5603,47 @@ async function useLlm_call(state, messages, _options) {
3750
5603
  headers: {},
3751
5604
  body
3752
5605
  });
3753
- const response = config.provider === "openai.chat-mock" ? {
3754
- id: "0123-45-6789",
3755
- model: "model",
3756
- created: (/* @__PURE__ */ new Date()).getTime(),
3757
- usage: { completion_tokens: 0, prompt_tokens: 0, total_tokens: 0 },
3758
- choices: [
3759
- {
3760
- message: {
3761
- role: "assistant",
3762
- content: `Hello world from LLM! The input was ${JSON.stringify(
3763
- messages
3764
- )}`
3765
- }
3766
- }
3767
- ]
3768
- } : await apiRequest(url, {
3769
- method: config.method,
3770
- body,
3771
- headers
3772
- });
3773
5606
  const { transformResponse = OutputDefault } = config;
3774
- const normalized = transformResponse(response, config);
3775
- return BaseLlmOutput(normalized);
5607
+ if (config.provider === "openai.chat-mock") {
5608
+ const mockResponse = {
5609
+ id: "0123-45-6789",
5610
+ model: "model",
5611
+ created: (/* @__PURE__ */ new Date()).getTime(),
5612
+ usage: { completion_tokens: 0, prompt_tokens: 0, total_tokens: 0 },
5613
+ choices: [
5614
+ {
5615
+ message: {
5616
+ role: "assistant",
5617
+ content: `Hello world from LLM! The input was ${JSON.stringify(messages)}`
5618
+ }
5619
+ }
5620
+ ]
5621
+ };
5622
+ return BaseLlmOutput(transformResponse(mockResponse, config));
5623
+ }
5624
+ try {
5625
+ const response = await apiRequest(url, {
5626
+ method: config.method,
5627
+ body,
5628
+ headers
5629
+ });
5630
+ return BaseLlmOutput(transformResponse(response, config));
5631
+ } catch (e) {
5632
+ if (!isLlmExeError(e, "request.http_error")) throw e;
5633
+ const ctx = e.context ?? {};
5634
+ const status = typeof ctx.status === "number" ? ctx.status : void 0;
5635
+ const code = status ? statusToLlmProviderCode(status) : "llm.provider_http_error";
5636
+ throw new LlmExeError(e.message, {
5637
+ code,
5638
+ context: {
5639
+ ...ctx,
5640
+ operation: "useLlm_call",
5641
+ provider: state.provider,
5642
+ model: state.model
5643
+ },
5644
+ cause: e
5645
+ });
5646
+ }
3776
5647
  }
3777
5648
 
3778
5649
  // src/llm/_utils.stateFromOptions.ts
@@ -3796,7 +5667,16 @@ function stateFromOptions(options, config) {
3796
5667
  if (Array.isArray(thisConfig?.required)) {
3797
5668
  const [required, message = `Error: [${key}] is required`] = thisConfig.required;
3798
5669
  if (required && typeof value === "undefined") {
3799
- throw new Error(message);
5670
+ throw new LlmExeError(message, {
5671
+ code: "configuration.missing_option",
5672
+ context: {
5673
+ operation: "stateFromOptions",
5674
+ provider: config.provider,
5675
+ key: config.key,
5676
+ option: String(key),
5677
+ resolution: `Provide a value for "${String(key)}" via options or environment.`
5678
+ }
5679
+ });
3800
5680
  }
3801
5681
  }
3802
5682
  }
@@ -3843,8 +5723,12 @@ function apiRequestWrapper(config, options, handler, doNotRetryErrorMessages = [
3843
5723
  const numOfAttempts = options.numOfAttempts || 2;
3844
5724
  const jitter = options.jitter || "none";
3845
5725
  let traceId = options?.traceId || null;
3846
- async function call(messages, options2) {
5726
+ async function call(messages, options2, context) {
3847
5727
  try {
5728
+ emitDeprecationWarning(config, {
5729
+ executorName: context?.executor?.name,
5730
+ traceId: context?.traceId ?? getTraceId() ?? void 0
5731
+ });
3848
5732
  metrics.total_calls++;
3849
5733
  const result = await (0, import_exponential_backoff.backOff)(
3850
5734
  () => asyncCallWithTimeout(
@@ -4022,8 +5906,19 @@ var embeddingConfigs = {
4022
5906
  const isV3 = /embed-(english|multilingual)-v3/.test(model);
4023
5907
  if (isV3) {
4024
5908
  if (value === 1024) return void 0;
4025
- throw new Error(
4026
- `Cohere Embed v3 only supports 1024-dimensional output (model: "${model}", requested: ${value}). Use cohere.embed-v4:0 for configurable dimensions.`
5909
+ throw new LlmExeError(
5910
+ `Cohere Embed v3 only supports 1024-dimensional output (model: "${model}", requested: ${value}). Use cohere.embed-v4:0 for configurable dimensions.`,
5911
+ {
5912
+ code: "embedding.unsupported_dimensions",
5913
+ context: {
5914
+ operation: "embedding.dimensionTransform",
5915
+ provider: "amazon:cohere.embedding",
5916
+ model,
5917
+ dimensions: value,
5918
+ expected: 1024,
5919
+ resolution: "Use cohere.embed-v4:0 for configurable dimensions."
5920
+ }
5921
+ }
4027
5922
  );
4028
5923
  }
4029
5924
  return value;
@@ -4034,13 +5929,28 @@ var embeddingConfigs = {
4034
5929
  };
4035
5930
  function getEmbeddingConfig(provider) {
4036
5931
  if (!provider) {
4037
- throw new Error(`Missing provider`);
5932
+ throw new LlmExeError(`Missing provider`, {
5933
+ code: "embedding.missing_provider",
5934
+ context: {
5935
+ operation: "getEmbeddingConfig",
5936
+ availableProviders: Object.keys(embeddingConfigs),
5937
+ resolution: "Provide a valid embedding provider key."
5938
+ }
5939
+ });
4038
5940
  }
4039
5941
  const pick2 = embeddingConfigs[provider];
4040
5942
  if (pick2) {
4041
5943
  return pick2;
4042
5944
  }
4043
- throw new Error(`Invalid provider: ${provider}`);
5945
+ throw new LlmExeError(`Invalid provider: ${provider}`, {
5946
+ code: "embedding.invalid_provider",
5947
+ context: {
5948
+ operation: "getEmbeddingConfig",
5949
+ provider,
5950
+ availableProviders: Object.keys(embeddingConfigs),
5951
+ resolution: "Provide a valid embedding provider key."
5952
+ }
5953
+ });
4044
5954
  }
4045
5955
 
4046
5956
  // src/embedding/output/BaseEmbeddingOutput.ts
@@ -4144,7 +6054,16 @@ function getEmbeddingOutputParser(config, response) {
4144
6054
  case "amazon:cohere.embedding.v1":
4145
6055
  return CohereBedrockEmbedding(response, config);
4146
6056
  default:
4147
- throw new Error("Unsupported provider");
6057
+ throw new LlmExeError("Unsupported provider", {
6058
+ code: "embedding.invalid_response_shape",
6059
+ context: {
6060
+ operation: "getEmbeddingOutputParser",
6061
+ provider: config.key,
6062
+ model: config.model,
6063
+ availableProviders: Object.keys(embeddingConfigs),
6064
+ resolution: "Use a supported embedding provider key."
6065
+ }
6066
+ });
4148
6067
  }
4149
6068
  }
4150
6069
 
@@ -4164,12 +6083,29 @@ async function createEmbedding_call(state, _input, _options) {
4164
6083
  headers: {},
4165
6084
  body
4166
6085
  });
4167
- const request = await apiRequest(url, {
4168
- method: config.method,
4169
- body,
4170
- headers
4171
- });
4172
- return getEmbeddingOutputParser(state, request);
6086
+ try {
6087
+ const request = await apiRequest(url, {
6088
+ method: config.method,
6089
+ body,
6090
+ headers
6091
+ });
6092
+ return getEmbeddingOutputParser(state, request);
6093
+ } catch (e) {
6094
+ if (!isLlmExeError(e, "request.http_error")) throw e;
6095
+ const ctx = e.context ?? {};
6096
+ const status = typeof ctx.status === "number" ? ctx.status : void 0;
6097
+ const code = status ? statusToEmbeddingProviderCode(status) : "embedding.provider_http_error";
6098
+ throw new LlmExeError(e.message, {
6099
+ code,
6100
+ context: {
6101
+ ...ctx,
6102
+ operation: "createEmbedding_call",
6103
+ provider: state.provider,
6104
+ model: state.model
6105
+ },
6106
+ cause: e
6107
+ });
6108
+ }
4173
6109
  }
4174
6110
 
4175
6111
  // src/embedding/embedding.ts
@@ -4178,6 +6114,245 @@ function createEmbedding(provider, options) {
4178
6114
  return apiRequestWrapper(config, options, createEmbedding_call);
4179
6115
  }
4180
6116
 
6117
+ // src/prompt/_templateValidation.ts
6118
+ var BUILT_IN_HELPERS = /* @__PURE__ */ new Set([
6119
+ "if",
6120
+ "unless",
6121
+ "each",
6122
+ "with",
6123
+ "lookup",
6124
+ "log",
6125
+ "blockHelperMissing",
6126
+ "helperMissing"
6127
+ ]);
6128
+ function isKnownHelper(name, customHelpers) {
6129
+ if (BUILT_IN_HELPERS.has(name)) return true;
6130
+ if (customHelpers && Object.prototype.hasOwnProperty.call(customHelpers, name)) {
6131
+ return true;
6132
+ }
6133
+ return false;
6134
+ }
6135
+ function pathRootSegment(path) {
6136
+ if (path.depth > 0) return null;
6137
+ if (path.data) return null;
6138
+ if (path.parts.length === 0) return null;
6139
+ return path.parts[0];
6140
+ }
6141
+ function pathToCollectedString(path) {
6142
+ const parts = path.parts.slice();
6143
+ return parts.join(".");
6144
+ }
6145
+ function collectFromPath(path, source, locals, options, references, seen) {
6146
+ const root = pathRootSegment(path);
6147
+ if (!root) return;
6148
+ if (locals.has(root)) return;
6149
+ const collected = pathToCollectedString(path);
6150
+ const dedupKey = `${source}::${collected}`;
6151
+ if (seen.has(dedupKey)) return;
6152
+ seen.add(dedupKey);
6153
+ references.push({
6154
+ path: collected,
6155
+ source,
6156
+ location: options.location
6157
+ });
6158
+ }
6159
+ function collectFromExpression(expr, source, locals, options, references, missingHelpers, seen) {
6160
+ if (expr.type === "PathExpression") {
6161
+ collectFromPath(expr, source, locals, options, references, seen);
6162
+ return;
6163
+ }
6164
+ if (expr.type === "SubExpression") {
6165
+ walkCall(
6166
+ expr.path,
6167
+ expr.params,
6168
+ expr.hash,
6169
+ locals,
6170
+ options,
6171
+ references,
6172
+ missingHelpers,
6173
+ seen
6174
+ );
6175
+ return;
6176
+ }
6177
+ }
6178
+ function walkHash(hash, locals, options, references, missingHelpers, seen) {
6179
+ if (!hash || !hash.pairs) return;
6180
+ for (const pair of hash.pairs) {
6181
+ collectFromExpression(
6182
+ pair.value,
6183
+ "hash",
6184
+ locals,
6185
+ options,
6186
+ references,
6187
+ missingHelpers,
6188
+ seen
6189
+ );
6190
+ }
6191
+ }
6192
+ function walkCall(path, params, hash, locals, options, references, missingHelpers, seen) {
6193
+ const root = pathRootSegment(path);
6194
+ const hasArgs = params.length > 0 || hash !== void 0 && hash.pairs.length > 0;
6195
+ if (hasArgs) {
6196
+ if (root) {
6197
+ if (!isKnownHelper(path.original, options.helpers) && !locals.has(root)) {
6198
+ missingHelpers.add(path.original);
6199
+ }
6200
+ }
6201
+ for (const param of params) {
6202
+ collectFromExpression(
6203
+ param,
6204
+ "helper-param",
6205
+ locals,
6206
+ options,
6207
+ references,
6208
+ missingHelpers,
6209
+ seen
6210
+ );
6211
+ }
6212
+ walkHash(hash, locals, options, references, missingHelpers, seen);
6213
+ return;
6214
+ }
6215
+ if (root && isKnownHelper(path.original, options.helpers)) {
6216
+ return;
6217
+ }
6218
+ collectFromPath(path, "mustache", locals, options, references, seen);
6219
+ }
6220
+ function walkProgram(program, parentLocals, options, references, missingHelpers, seen) {
6221
+ if (!program) return;
6222
+ const locals = new Set(parentLocals);
6223
+ if (program.blockParams) {
6224
+ for (const bp of program.blockParams) {
6225
+ locals.add(bp);
6226
+ }
6227
+ }
6228
+ for (const node of program.body) {
6229
+ walkStatement(node, locals, options, references, missingHelpers, seen);
6230
+ }
6231
+ }
6232
+ function walkStatement(node, locals, options, references, missingHelpers, seen) {
6233
+ switch (node.type) {
6234
+ case "MustacheStatement": {
6235
+ const m = node;
6236
+ if (m.path.type === "PathExpression") {
6237
+ walkCall(
6238
+ m.path,
6239
+ m.params,
6240
+ m.hash,
6241
+ locals,
6242
+ options,
6243
+ references,
6244
+ missingHelpers,
6245
+ seen
6246
+ );
6247
+ }
6248
+ return;
6249
+ }
6250
+ case "BlockStatement": {
6251
+ const b = node;
6252
+ const root = pathRootSegment(b.path);
6253
+ if (root && !isKnownHelper(b.path.original, options.helpers) && !locals.has(root)) {
6254
+ missingHelpers.add(b.path.original);
6255
+ }
6256
+ for (const param of b.params) {
6257
+ collectFromExpression(
6258
+ param,
6259
+ "block-param",
6260
+ locals,
6261
+ options,
6262
+ references,
6263
+ missingHelpers,
6264
+ seen
6265
+ );
6266
+ }
6267
+ walkHash(b.hash, locals, options, references, missingHelpers, seen);
6268
+ const isEach = b.path.original === "each";
6269
+ const hasBlockParams = b.program?.blockParams && b.program.blockParams.length > 0 || b.inverse?.blockParams && b.inverse.blockParams.length > 0;
6270
+ if (isEach && !hasBlockParams) {
6271
+ return;
6272
+ }
6273
+ walkProgram(b.program, locals, options, references, missingHelpers, seen);
6274
+ walkProgram(b.inverse, locals, options, references, missingHelpers, seen);
6275
+ return;
6276
+ }
6277
+ case "PartialStatement": {
6278
+ const p = node;
6279
+ for (const param of p.params) {
6280
+ collectFromExpression(
6281
+ param,
6282
+ "helper-param",
6283
+ locals,
6284
+ options,
6285
+ references,
6286
+ missingHelpers,
6287
+ seen
6288
+ );
6289
+ }
6290
+ walkHash(p.hash, locals, options, references, missingHelpers, seen);
6291
+ return;
6292
+ }
6293
+ }
6294
+ }
6295
+ function collectAll(template, options) {
6296
+ const references = [];
6297
+ const missingHelpers = /* @__PURE__ */ new Set();
6298
+ let ast;
6299
+ try {
6300
+ ast = hbs.handlebars.parse(template);
6301
+ } catch {
6302
+ return { references, missingHelpers: [] };
6303
+ }
6304
+ const seen = /* @__PURE__ */ new Set();
6305
+ walkProgram(ast, /* @__PURE__ */ new Set(), options, references, missingHelpers, seen);
6306
+ return { references, missingHelpers: Array.from(missingHelpers) };
6307
+ }
6308
+ function hasInputPath(input, path) {
6309
+ if (!input || typeof input !== "object") return false;
6310
+ let current = input;
6311
+ for (const part of path.split(".")) {
6312
+ if (!current || typeof current !== "object") return false;
6313
+ if (!Object.prototype.hasOwnProperty.call(current, part)) return false;
6314
+ current = current[part];
6315
+ }
6316
+ return current !== void 0;
6317
+ }
6318
+ function validateTemplateInputReferences(template, input, options = {}) {
6319
+ const { references, missingHelpers } = collectAll(template, options);
6320
+ const missingVariables = [];
6321
+ const seenMissing = /* @__PURE__ */ new Set();
6322
+ for (const ref of references) {
6323
+ if (hasInputPath(input, ref.path)) continue;
6324
+ const key = ref.path;
6325
+ if (seenMissing.has(key)) continue;
6326
+ seenMissing.add(key);
6327
+ missingVariables.push(ref);
6328
+ }
6329
+ return { references, missingVariables, missingHelpers };
6330
+ }
6331
+
6332
+ // src/prompt/errors.ts
6333
+ function buildMessage(context) {
6334
+ const { missingVariables, missingHelpers } = context;
6335
+ const vars = missingVariables.length ? `Missing variables: ${formatErrorList(missingVariables)}.` : "";
6336
+ const helpers = missingHelpers.length ? `Missing helpers: ${formatErrorList(missingHelpers)}.` : "";
6337
+ if (vars && helpers) {
6338
+ return `Prompt template has unresolved references. ${vars} ${helpers}`;
6339
+ }
6340
+ if (vars) {
6341
+ return `Prompt template references variables not provided. ${vars}`;
6342
+ }
6343
+ return `Prompt template references helpers not registered. ${helpers}`;
6344
+ }
6345
+ function missingTemplateReferencesError(context) {
6346
+ return createLlmExeError(
6347
+ {
6348
+ code: "prompt.missing_template_variable",
6349
+ message: buildMessage,
6350
+ resolution: "Pass every variable referenced by the prompt template, or register any custom helpers used."
6351
+ },
6352
+ context
6353
+ );
6354
+ }
6355
+
4181
6356
  // src/prompt/_base.ts
4182
6357
  var BasePrompt = class {
4183
6358
  /**
@@ -4189,6 +6364,7 @@ var BasePrompt = class {
4189
6364
  __publicField(this, "messages", []);
4190
6365
  __publicField(this, "partials", []);
4191
6366
  __publicField(this, "helpers", []);
6367
+ __publicField(this, "validateInput", false);
4192
6368
  __publicField(this, "replaceTemplateString", replaceTemplateString);
4193
6369
  __publicField(this, "replaceTemplateStringAsync", replaceTemplateStringAsync);
4194
6370
  __publicField(this, "filters", {
@@ -4214,6 +6390,9 @@ var BasePrompt = class {
4214
6390
  if (options.replaceTemplateString) {
4215
6391
  this.replaceTemplateString = options.replaceTemplateString;
4216
6392
  }
6393
+ if (options.validateInput !== void 0) {
6394
+ this.validateInput = options.validateInput;
6395
+ }
4217
6396
  }
4218
6397
  }
4219
6398
  /**
@@ -4265,6 +6444,40 @@ var BasePrompt = class {
4265
6444
  this.helpers.push(...helpers);
4266
6445
  return this;
4267
6446
  }
6447
+ /**
6448
+ * Returns the Handlebars-bearing strings that should be validated, along
6449
+ * with a location label used for error context. Subclasses with structured
6450
+ * message content (e.g. ChatPrompt) should override.
6451
+ */
6452
+ getTemplateContents() {
6453
+ return this.messages.map((message, index) => {
6454
+ if (!message.content || Array.isArray(message.content)) {
6455
+ return null;
6456
+ }
6457
+ return {
6458
+ content: message.content,
6459
+ location: `messages[${index}].content`
6460
+ };
6461
+ }).filter(
6462
+ (entry) => entry !== null
6463
+ );
6464
+ }
6465
+ preflightValidate(values) {
6466
+ if (this.validateInput === false || !this.validateInput) {
6467
+ return;
6468
+ }
6469
+ try {
6470
+ this.validate(values);
6471
+ } catch (error) {
6472
+ if (this.validateInput === "warn" && isLlmExeError(error, "prompt.missing_template_variable")) {
6473
+ if (typeof process === "object" && typeof process?.emitWarning === "function") {
6474
+ process.emitWarning(error);
6475
+ }
6476
+ return;
6477
+ }
6478
+ throw error;
6479
+ }
6480
+ }
4268
6481
  /**
4269
6482
  * format description
4270
6483
  * @param values The message content
@@ -4272,6 +6485,7 @@ var BasePrompt = class {
4272
6485
  * @return returns messages formatted with template replacement
4273
6486
  */
4274
6487
  format(values, separator = "\n\n") {
6488
+ this.preflightValidate(values);
4275
6489
  const replacements = this.getReplacements(values);
4276
6490
  const messages = this.messages.map((message) => {
4277
6491
  return message.content && !Array.isArray(message.content) ? this.replaceTemplateString(
@@ -4292,6 +6506,7 @@ var BasePrompt = class {
4292
6506
  * @return returns messages formatted with template replacement
4293
6507
  */
4294
6508
  async formatAsync(values, separator = "\n\n") {
6509
+ this.preflightValidate(values);
4295
6510
  const replacements = this.getReplacements(values);
4296
6511
  const _messages = await Promise.all(this.messages.map((message) => {
4297
6512
  return message.content && !Array.isArray(message.content) ? this.replaceTemplateStringAsync(
@@ -4315,8 +6530,18 @@ var BasePrompt = class {
4315
6530
  }
4316
6531
  getReplacements(values) {
4317
6532
  if (values === void 0 || values === null) {
4318
- throw new Error(
4319
- "format() requires an input object. Did you forget to pass arguments?"
6533
+ throw new LlmExeError(
6534
+ "format() requires an input object. Did you forget to pass arguments?",
6535
+ {
6536
+ code: "prompt.missing_input",
6537
+ context: {
6538
+ operation: "BasePrompt.getReplacements",
6539
+ promptType: this.type,
6540
+ expected: "object",
6541
+ received: values === null ? "null" : "undefined",
6542
+ resolution: "Pass an object of template values to format()."
6543
+ }
6544
+ }
4320
6545
  );
4321
6546
  }
4322
6547
  const { input = "", ...restOfValues } = values;
@@ -4331,11 +6556,52 @@ var BasePrompt = class {
4331
6556
  return replacements;
4332
6557
  }
4333
6558
  /**
4334
- * Validates the prompt structure.
4335
- * @return {boolean} Returns false if the prompt has no messages defined.
6559
+ * Validates that `input` provides every variable referenced by this prompt's
6560
+ * templates, and that every identifiable helper call is registered.
6561
+ *
6562
+ * @breaking v3: previously returned `this.messages.length > 0` with no
6563
+ * `input` parameter. For the old behavior, read `prompt.messages.length > 0`
6564
+ * directly.
6565
+ *
6566
+ * @throws LlmExeError with code `"prompt.missing_template_variable"` listing
6567
+ * all missing variables and helpers.
4336
6568
  */
4337
- validate() {
4338
- return this.messages.length > 0;
6569
+ validate(input) {
6570
+ const allMissingVariables = [];
6571
+ const allMissingHelpers = /* @__PURE__ */ new Set();
6572
+ const registeredHelpers = this.helpers.reduce(
6573
+ (acc, h) => {
6574
+ acc[h.name] = h.handler;
6575
+ return acc;
6576
+ },
6577
+ {}
6578
+ );
6579
+ const knownHelpers = {
6580
+ ...hbs.handlebars.helpers,
6581
+ ...registeredHelpers
6582
+ };
6583
+ for (const template of this.getTemplateContents()) {
6584
+ const result = validateTemplateInputReferences(template.content, input, {
6585
+ helpers: knownHelpers,
6586
+ location: template.location
6587
+ });
6588
+ allMissingVariables.push(...result.missingVariables);
6589
+ for (const helper of result.missingHelpers) {
6590
+ allMissingHelpers.add(helper);
6591
+ }
6592
+ }
6593
+ if (allMissingVariables.length === 0 && allMissingHelpers.size === 0) {
6594
+ return;
6595
+ }
6596
+ const dedupedVariables = Array.from(
6597
+ new Set(allMissingVariables.map((r) => r.path))
6598
+ );
6599
+ throw missingTemplateReferencesError({
6600
+ operation: "Prompt.validate",
6601
+ promptType: this.type,
6602
+ missingVariables: dedupedVariables,
6603
+ missingHelpers: Array.from(allMissingHelpers)
6604
+ });
4339
6605
  }
4340
6606
  };
4341
6607
 
@@ -4637,6 +6903,7 @@ var ChatPrompt = class extends BasePrompt {
4637
6903
  * @return formatted prompt.
4638
6904
  */
4639
6905
  format(values) {
6906
+ this.preflightValidate(values);
4640
6907
  const messagesOut = [];
4641
6908
  const replacements = this.getReplacements(values);
4642
6909
  const safeToParseTemplate = ["assistant", "system"];
@@ -4762,6 +7029,7 @@ var ChatPrompt = class extends BasePrompt {
4762
7029
  * @return formatted prompt.
4763
7030
  */
4764
7031
  async formatAsync(values) {
7032
+ this.preflightValidate(values);
4765
7033
  const messagesOut = [];
4766
7034
  const replacements = this.getReplacements(values);
4767
7035
  const safeToParseTemplate = ["assistant", "system"];
@@ -5064,16 +7332,26 @@ var Dialogue = class extends BaseStateItem {
5064
7332
  }
5065
7333
  setFunctionCallMessage(input) {
5066
7334
  if (!input || typeof input !== "object") {
5067
- throw new LlmExeError(`Invalid arguments`, "state", {
5068
- error: `Invalid arguments: input must be an object`,
5069
- module: "dialogue"
7335
+ throw new LlmExeError(`Invalid arguments`, {
7336
+ code: "state.invalid_arguments",
7337
+ context: {
7338
+ operation: "Dialogue.setFunctionCallMessage",
7339
+ module: "dialogue",
7340
+ expected: "object",
7341
+ received: typeof input
7342
+ }
5070
7343
  });
5071
7344
  }
5072
7345
  if ("function_call" in input) {
5073
7346
  if (!input.function_call || typeof input.function_call !== "object") {
5074
- throw new LlmExeError(`Invalid arguments`, "state", {
5075
- error: `Invalid arguments: input must be an object`,
5076
- module: "dialogue"
7347
+ throw new LlmExeError(`Invalid arguments`, {
7348
+ code: "state.invalid_arguments",
7349
+ context: {
7350
+ operation: "Dialogue.setFunctionCallMessage",
7351
+ module: "dialogue",
7352
+ expected: "object",
7353
+ received: typeof input.function_call
7354
+ }
5077
7355
  });
5078
7356
  }
5079
7357
  this.value.push({
@@ -5309,6 +7587,8 @@ function createStateItem(name, defaultValue) {
5309
7587
  CustomParser,
5310
7588
  DefaultState,
5311
7589
  DefaultStateItem,
7590
+ LLM_EXE_ERROR_SYMBOL,
7591
+ LlmExeError,
5312
7592
  LlmExecutorOpenAiFunctions,
5313
7593
  LlmExecutorWithFunctions,
5314
7594
  LlmNativeFunctionParser,
@@ -5329,6 +7609,7 @@ function createStateItem(name, defaultValue) {
5329
7609
  createStateItem,
5330
7610
  defineSchema,
5331
7611
  guards,
7612
+ isLlmExeError,
5332
7613
  registerHelpers,
5333
7614
  registerPartials,
5334
7615
  useExecutors,