llm-exe 2.3.10 → 3.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +578 -185
- package/dist/index.d.ts +578 -185
- package/dist/index.js +3027 -863
- package/dist/index.mjs +3024 -863
- package/package.json +3 -4
- package/readme.md +2 -0
package/dist/index.mjs
CHANGED
|
@@ -55,6 +55,11 @@ var ExecutorExecutionMetadataState = class {
|
|
|
55
55
|
output: void 0,
|
|
56
56
|
errorMessage: void 0,
|
|
57
57
|
error: void 0,
|
|
58
|
+
errorCategory: void 0,
|
|
59
|
+
errorCode: void 0,
|
|
60
|
+
errorContext: void 0,
|
|
61
|
+
errorCause: void 0,
|
|
62
|
+
hookErrors: void 0,
|
|
58
63
|
metadata: null
|
|
59
64
|
});
|
|
60
65
|
if (items) {
|
|
@@ -82,6 +87,11 @@ var ExecutorExecutionMetadataState = class {
|
|
|
82
87
|
output: __privateGet(this, _state).output,
|
|
83
88
|
errorMessage: __privateGet(this, _state).errorMessage,
|
|
84
89
|
error: __privateGet(this, _state).error,
|
|
90
|
+
errorCategory: __privateGet(this, _state).errorCategory,
|
|
91
|
+
errorCode: __privateGet(this, _state).errorCode,
|
|
92
|
+
errorContext: __privateGet(this, _state).errorContext,
|
|
93
|
+
errorCause: __privateGet(this, _state).errorCause,
|
|
94
|
+
hookErrors: __privateGet(this, _state).hookErrors,
|
|
85
95
|
metadata: __privateGet(this, _state).metadata
|
|
86
96
|
});
|
|
87
97
|
}
|
|
@@ -96,6 +106,653 @@ var hookOnComplete = `onComplete`;
|
|
|
96
106
|
var hookOnError = `onError`;
|
|
97
107
|
var hookOnSuccess = `onSuccess`;
|
|
98
108
|
|
|
109
|
+
// src/errors/knownCodes.ts
|
|
110
|
+
var ALL_CODES = [
|
|
111
|
+
"configuration.missing_provider",
|
|
112
|
+
"configuration.invalid_provider",
|
|
113
|
+
"configuration.missing_env",
|
|
114
|
+
"configuration.missing_option",
|
|
115
|
+
"configuration.invalid_headers",
|
|
116
|
+
"parser.invalid_type",
|
|
117
|
+
"parser.invalid_input",
|
|
118
|
+
"parser.parse_failed",
|
|
119
|
+
"parser.schema_validation_failed",
|
|
120
|
+
"prompt.missing_input",
|
|
121
|
+
"prompt.invalid_messages",
|
|
122
|
+
"prompt.missing_template_variable",
|
|
123
|
+
"llm.provider_http_error",
|
|
124
|
+
"llm.provider_rate_limited",
|
|
125
|
+
"llm.provider_auth_failed",
|
|
126
|
+
"llm.provider_invalid_request",
|
|
127
|
+
"llm.provider_unavailable",
|
|
128
|
+
"llm.invalid_response_shape",
|
|
129
|
+
"llm.invalid_jsonl_response",
|
|
130
|
+
"embedding.provider_http_error",
|
|
131
|
+
"embedding.provider_rate_limited",
|
|
132
|
+
"embedding.provider_auth_failed",
|
|
133
|
+
"embedding.provider_invalid_request",
|
|
134
|
+
"embedding.provider_unavailable",
|
|
135
|
+
"embedding.missing_provider",
|
|
136
|
+
"embedding.invalid_provider",
|
|
137
|
+
"embedding.unsupported_dimensions",
|
|
138
|
+
"embedding.invalid_response_shape",
|
|
139
|
+
"executor.missing_prompt",
|
|
140
|
+
"executor.hook_limit_reached",
|
|
141
|
+
"executor.hook_failed",
|
|
142
|
+
"callable.invalid_handler",
|
|
143
|
+
"callable.handler_not_found",
|
|
144
|
+
"callable.validation_failed",
|
|
145
|
+
"template.invalid_helper_arguments",
|
|
146
|
+
"state.invalid_arguments",
|
|
147
|
+
"auth.aws_signing_input_missing",
|
|
148
|
+
"request.invalid_url",
|
|
149
|
+
"request.http_error",
|
|
150
|
+
"internal.invariant_failed",
|
|
151
|
+
"unknown.unclassified"
|
|
152
|
+
];
|
|
153
|
+
var KNOWN_ERROR_CODES = new Set(ALL_CODES);
|
|
154
|
+
|
|
155
|
+
// src/errors/serialize.ts
|
|
156
|
+
var MAX_VALUE_DEPTH = 5;
|
|
157
|
+
var MAX_CAUSE_DEPTH = 5;
|
|
158
|
+
var CIRCULAR = "[Circular]";
|
|
159
|
+
var SYMBOL = Symbol.for("llm-exe.error");
|
|
160
|
+
function isLlmExeErrorLike(value) {
|
|
161
|
+
if (!value || typeof value !== "object") return false;
|
|
162
|
+
return value[SYMBOL] === true || value.isLlmExeError === true;
|
|
163
|
+
}
|
|
164
|
+
function isErrorLike(value) {
|
|
165
|
+
if (value instanceof Error) return true;
|
|
166
|
+
if (!value || typeof value !== "object") return false;
|
|
167
|
+
const v = value;
|
|
168
|
+
return typeof v.message === "string" && typeof v.name === "string";
|
|
169
|
+
}
|
|
170
|
+
function isResponseLike(value) {
|
|
171
|
+
if (!value || typeof value !== "object") return false;
|
|
172
|
+
if (typeof Response !== "undefined" && value instanceof Response) return true;
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
function describeOpaque(value) {
|
|
176
|
+
const tag = Object.prototype.toString.call(value).slice(8, -1);
|
|
177
|
+
if (tag === "Object") return "[object Object]";
|
|
178
|
+
return `[object ${tag}]`;
|
|
179
|
+
}
|
|
180
|
+
function safeValue(value, seen, depth) {
|
|
181
|
+
if (value === null) return null;
|
|
182
|
+
if (value === void 0) return null;
|
|
183
|
+
const t = typeof value;
|
|
184
|
+
if (t === "string") return value;
|
|
185
|
+
if (t === "boolean") return value;
|
|
186
|
+
if (t === "number") {
|
|
187
|
+
const n = value;
|
|
188
|
+
return Number.isFinite(n) ? n : null;
|
|
189
|
+
}
|
|
190
|
+
if (t === "bigint") return value.toString();
|
|
191
|
+
if (t === "symbol") return String(value);
|
|
192
|
+
if (t === "function") {
|
|
193
|
+
const name = value.name;
|
|
194
|
+
return name ? `[Function ${name}]` : "[Function]";
|
|
195
|
+
}
|
|
196
|
+
if (depth >= MAX_VALUE_DEPTH) {
|
|
197
|
+
return describeOpaque(value);
|
|
198
|
+
}
|
|
199
|
+
if (seen.has(value)) return CIRCULAR;
|
|
200
|
+
seen.add(value);
|
|
201
|
+
try {
|
|
202
|
+
if (Array.isArray(value)) {
|
|
203
|
+
const arr = [];
|
|
204
|
+
for (let i = 0; i < value.length; i++) {
|
|
205
|
+
arr.push(safeValue(value[i], seen, depth + 1));
|
|
206
|
+
}
|
|
207
|
+
return arr;
|
|
208
|
+
}
|
|
209
|
+
if (value instanceof Date) {
|
|
210
|
+
const ts = value.getTime();
|
|
211
|
+
return Number.isFinite(ts) ? new Date(ts).toISOString() : null;
|
|
212
|
+
}
|
|
213
|
+
if (typeof Buffer !== "undefined" && Buffer.isBuffer && Buffer.isBuffer(value)) {
|
|
214
|
+
return `[Buffer length=${value.length}]`;
|
|
215
|
+
}
|
|
216
|
+
if (value instanceof Map || value instanceof Set || value instanceof WeakMap || value instanceof WeakSet) {
|
|
217
|
+
return describeOpaque(value);
|
|
218
|
+
}
|
|
219
|
+
if (isResponseLike(value)) {
|
|
220
|
+
return {
|
|
221
|
+
name: "Response",
|
|
222
|
+
status: value.status,
|
|
223
|
+
statusText: value.statusText ?? "",
|
|
224
|
+
url: value.url ?? ""
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
const proto = Object.getPrototypeOf(value);
|
|
228
|
+
if (proto !== null && proto !== Object.prototype) {
|
|
229
|
+
const ctor = value.constructor;
|
|
230
|
+
if (ctor && ctor.name && ctor.name !== "Object") {
|
|
231
|
+
const out2 = {};
|
|
232
|
+
for (const key of Object.keys(value)) {
|
|
233
|
+
const v = value[key];
|
|
234
|
+
if (v === void 0) continue;
|
|
235
|
+
out2[key] = safeValue(v, seen, depth + 1);
|
|
236
|
+
}
|
|
237
|
+
return Object.keys(out2).length > 0 ? out2 : describeOpaque(value);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
const out = {};
|
|
241
|
+
for (const key of Object.keys(value)) {
|
|
242
|
+
const v = value[key];
|
|
243
|
+
if (v === void 0) continue;
|
|
244
|
+
out[key] = safeValue(v, seen, depth + 1);
|
|
245
|
+
}
|
|
246
|
+
return out;
|
|
247
|
+
} finally {
|
|
248
|
+
seen.delete(value);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
function freshSafeValue(value) {
|
|
252
|
+
return safeValue(value, /* @__PURE__ */ new WeakSet(), 0);
|
|
253
|
+
}
|
|
254
|
+
function serializeOne(error, errorSeen, causeDepth, options) {
|
|
255
|
+
if (error === null || error === void 0) return null;
|
|
256
|
+
if (typeof error !== "object") return freshSafeValue(error);
|
|
257
|
+
if (errorSeen.has(error)) return CIRCULAR;
|
|
258
|
+
errorSeen.add(error);
|
|
259
|
+
try {
|
|
260
|
+
if (isLlmExeErrorLike(error)) {
|
|
261
|
+
const e = error;
|
|
262
|
+
const out = {
|
|
263
|
+
name: "LlmExeError",
|
|
264
|
+
message: typeof e.message === "string" ? e.message : "",
|
|
265
|
+
category: typeof e.category === "string" ? e.category : "unknown",
|
|
266
|
+
code: typeof e.code === "string" ? e.code : "unknown.unclassified"
|
|
267
|
+
};
|
|
268
|
+
if (e.context !== void 0) {
|
|
269
|
+
out.context = freshSafeValue(e.context);
|
|
270
|
+
}
|
|
271
|
+
if (options.includeStack && typeof e.stack === "string") {
|
|
272
|
+
out.stack = e.stack;
|
|
273
|
+
}
|
|
274
|
+
if (e.cause !== void 0) {
|
|
275
|
+
if (causeDepth + 1 >= MAX_CAUSE_DEPTH) {
|
|
276
|
+
out.cause = { truncated: true };
|
|
277
|
+
} else {
|
|
278
|
+
out.cause = serializeOne(e.cause, errorSeen, causeDepth + 1, options);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return out;
|
|
282
|
+
}
|
|
283
|
+
if (isResponseLike(error)) {
|
|
284
|
+
return {
|
|
285
|
+
name: "Response",
|
|
286
|
+
status: error.status,
|
|
287
|
+
statusText: error.statusText ?? "",
|
|
288
|
+
url: error.url ?? ""
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
if (isErrorLike(error)) {
|
|
292
|
+
const e = error;
|
|
293
|
+
const out = {
|
|
294
|
+
name: typeof e.name === "string" && e.name ? e.name : "Error",
|
|
295
|
+
message: typeof e.message === "string" ? e.message : ""
|
|
296
|
+
};
|
|
297
|
+
if (options.includeStack && typeof e.stack === "string") {
|
|
298
|
+
out.stack = e.stack;
|
|
299
|
+
}
|
|
300
|
+
if (e.cause !== void 0) {
|
|
301
|
+
if (causeDepth + 1 >= MAX_CAUSE_DEPTH) {
|
|
302
|
+
out.cause = { truncated: true };
|
|
303
|
+
} else {
|
|
304
|
+
out.cause = serializeOne(e.cause, errorSeen, causeDepth + 1, options);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return out;
|
|
308
|
+
}
|
|
309
|
+
return freshSafeValue(error);
|
|
310
|
+
} finally {
|
|
311
|
+
errorSeen.delete(error);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
function serializeLlmExeError(error, options) {
|
|
315
|
+
return serializeOne(error, /* @__PURE__ */ new WeakSet(), 0, options ?? {});
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// src/errors/LlmExeError.ts
|
|
319
|
+
var LLM_EXE_ERROR_SYMBOL = Symbol.for("llm-exe.error");
|
|
320
|
+
function deriveCategory(code) {
|
|
321
|
+
if (typeof code !== "string") return void 0;
|
|
322
|
+
if (!KNOWN_ERROR_CODES.has(code)) return void 0;
|
|
323
|
+
const dot = code.indexOf(".");
|
|
324
|
+
return code.slice(0, dot);
|
|
325
|
+
}
|
|
326
|
+
var LlmExeError = class _LlmExeError extends Error {
|
|
327
|
+
constructor(message, options) {
|
|
328
|
+
super(message);
|
|
329
|
+
__publicField(this, "category");
|
|
330
|
+
__publicField(this, "code");
|
|
331
|
+
__publicField(this, "context");
|
|
332
|
+
Object.defineProperties(this, {
|
|
333
|
+
name: {
|
|
334
|
+
value: "LlmExeError",
|
|
335
|
+
configurable: true,
|
|
336
|
+
writable: false,
|
|
337
|
+
enumerable: false
|
|
338
|
+
},
|
|
339
|
+
isLlmExeError: {
|
|
340
|
+
value: true,
|
|
341
|
+
configurable: false,
|
|
342
|
+
writable: false,
|
|
343
|
+
enumerable: false
|
|
344
|
+
},
|
|
345
|
+
[LLM_EXE_ERROR_SYMBOL]: {
|
|
346
|
+
value: true,
|
|
347
|
+
configurable: false,
|
|
348
|
+
writable: false,
|
|
349
|
+
enumerable: false
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
const providedCode = options ? options.code : void 0;
|
|
353
|
+
const category = deriveCategory(providedCode);
|
|
354
|
+
if (!category) {
|
|
355
|
+
this.code = "internal.invariant_failed";
|
|
356
|
+
this.category = "internal";
|
|
357
|
+
this.context = {
|
|
358
|
+
invariant: "invalid_error_code",
|
|
359
|
+
received: providedCode
|
|
360
|
+
};
|
|
361
|
+
} else {
|
|
362
|
+
this.code = providedCode;
|
|
363
|
+
this.category = category;
|
|
364
|
+
if (options.context !== void 0) {
|
|
365
|
+
this.context = options.context;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
if (options && options.cause !== void 0) {
|
|
369
|
+
Object.defineProperty(this, "cause", {
|
|
370
|
+
value: options.cause,
|
|
371
|
+
configurable: true,
|
|
372
|
+
writable: true,
|
|
373
|
+
enumerable: false
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
const capture = Error.captureStackTrace;
|
|
377
|
+
if (typeof capture === "function") {
|
|
378
|
+
capture(this, _LlmExeError);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
toJSON() {
|
|
382
|
+
return serializeLlmExeError(this);
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
Object.defineProperty(LlmExeError, "name", {
|
|
386
|
+
value: "LlmExeError",
|
|
387
|
+
configurable: true
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
// src/errors/isLlmExeError.ts
|
|
391
|
+
function isLlmExeError(error, code) {
|
|
392
|
+
if (!error || typeof error !== "object") return false;
|
|
393
|
+
const marked = error instanceof LlmExeError || error[LLM_EXE_ERROR_SYMBOL] === true || error.isLlmExeError === true;
|
|
394
|
+
if (!marked) return false;
|
|
395
|
+
if (code === void 0) return true;
|
|
396
|
+
const errorCode = error.code;
|
|
397
|
+
if (Array.isArray(code)) {
|
|
398
|
+
return code.includes(errorCode);
|
|
399
|
+
}
|
|
400
|
+
return errorCode === code;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// src/errors/format.ts
|
|
404
|
+
var DEFAULT_VALUE_MAX_LENGTH = 200;
|
|
405
|
+
var DEFAULT_LIST_MAX_ITEMS = 8;
|
|
406
|
+
function truncate(s, maxLength) {
|
|
407
|
+
if (s.length <= maxLength) return s;
|
|
408
|
+
return s.slice(0, Math.max(0, maxLength - 1)) + "\u2026";
|
|
409
|
+
}
|
|
410
|
+
function compactJson(value) {
|
|
411
|
+
try {
|
|
412
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
413
|
+
const replacer = (_key, val) => {
|
|
414
|
+
if (typeof val === "bigint") return val.toString();
|
|
415
|
+
if (typeof val === "function") return "[Function]";
|
|
416
|
+
if (typeof val === "symbol") return String(val);
|
|
417
|
+
if (val && typeof val === "object") {
|
|
418
|
+
if (seen.has(val)) return "[Circular]";
|
|
419
|
+
seen.add(val);
|
|
420
|
+
}
|
|
421
|
+
return val;
|
|
422
|
+
};
|
|
423
|
+
return JSON.stringify(value, replacer);
|
|
424
|
+
} catch {
|
|
425
|
+
return void 0;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
function formatErrorValue(value, options) {
|
|
429
|
+
const maxLength = options?.maxLength ?? DEFAULT_VALUE_MAX_LENGTH;
|
|
430
|
+
if (value === null) return "null";
|
|
431
|
+
if (value === void 0) return "undefined";
|
|
432
|
+
const t = typeof value;
|
|
433
|
+
if (t === "string") {
|
|
434
|
+
const s = value;
|
|
435
|
+
return `"${truncate(s, Math.max(2, maxLength - 2))}"`;
|
|
436
|
+
}
|
|
437
|
+
if (t === "number") {
|
|
438
|
+
const n = value;
|
|
439
|
+
return Number.isFinite(n) ? String(n) : "null";
|
|
440
|
+
}
|
|
441
|
+
if (t === "boolean") return value ? "true" : "false";
|
|
442
|
+
if (t === "bigint") return value.toString();
|
|
443
|
+
if (t === "symbol") return String(value);
|
|
444
|
+
if (t === "function") {
|
|
445
|
+
const name = value.name;
|
|
446
|
+
return name ? `[Function ${name}]` : "[Function]";
|
|
447
|
+
}
|
|
448
|
+
const json = compactJson(value);
|
|
449
|
+
if (json !== void 0) return truncate(json, maxLength);
|
|
450
|
+
const tag = Object.prototype.toString.call(value).slice(8, -1);
|
|
451
|
+
return `[object ${tag}]`;
|
|
452
|
+
}
|
|
453
|
+
function formatErrorList(values, options) {
|
|
454
|
+
const maxItems = options?.maxItems ?? DEFAULT_LIST_MAX_ITEMS;
|
|
455
|
+
const maxLength = options?.maxLength;
|
|
456
|
+
if (!values || values.length === 0) return "";
|
|
457
|
+
const limit = Math.min(values.length, maxItems);
|
|
458
|
+
const parts = [];
|
|
459
|
+
for (let i = 0; i < limit; i++) {
|
|
460
|
+
parts.push(formatErrorValue(values[i], maxLength ? { maxLength } : void 0));
|
|
461
|
+
}
|
|
462
|
+
if (values.length > limit) {
|
|
463
|
+
parts.push(`\u2026 (${values.length - limit} more)`);
|
|
464
|
+
}
|
|
465
|
+
return parts.join(", ");
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// src/errors/createLlmExeError.ts
|
|
469
|
+
var DOCS_BASE_URL = "https://llm-exe.com";
|
|
470
|
+
function resolveDefinitionValue(value, context) {
|
|
471
|
+
if (value === void 0) return void 0;
|
|
472
|
+
return typeof value === "function" ? value(context) : value;
|
|
473
|
+
}
|
|
474
|
+
function resolveDocsUrl(docsPath) {
|
|
475
|
+
if (/^https?:\/\//i.test(docsPath)) return docsPath;
|
|
476
|
+
return `${DOCS_BASE_URL}${docsPath.startsWith("/") ? "" : "/"}${docsPath}`;
|
|
477
|
+
}
|
|
478
|
+
function createLlmExeError(definition, context, options) {
|
|
479
|
+
const message = definition.message(context);
|
|
480
|
+
const resolution = resolveDefinitionValue(definition.resolution, context);
|
|
481
|
+
const docsPath = resolveDefinitionValue(definition.docsPath, context);
|
|
482
|
+
const docsUrl = docsPath ? resolveDocsUrl(docsPath) : void 0;
|
|
483
|
+
const mergedContext = {
|
|
484
|
+
...context,
|
|
485
|
+
...resolution !== void 0 ? { resolution } : null,
|
|
486
|
+
...docsPath !== void 0 ? { docsPath } : null,
|
|
487
|
+
...docsUrl !== void 0 ? { docsUrl } : null
|
|
488
|
+
};
|
|
489
|
+
return new LlmExeError(message, {
|
|
490
|
+
code: definition.code,
|
|
491
|
+
context: mergedContext,
|
|
492
|
+
cause: options?.cause
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// src/utils/modules/redactSecrets.ts
|
|
497
|
+
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;
|
|
498
|
+
var FULL_REDACTION_PATTERNS = [
|
|
499
|
+
// Alternate auth schemes.
|
|
500
|
+
[/\b(Basic|Digest|AWS4-HMAC-SHA256)\s+[A-Za-z0-9+/=._-]+/g, "$1 [redacted]"],
|
|
501
|
+
// Header- or query-style key/value pairs. Preserves the original separator
|
|
502
|
+
// ("Authorization: ..." stays colon, "?token=..." stays equals).
|
|
503
|
+
[
|
|
504
|
+
/(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,
|
|
505
|
+
"$1$2[redacted]"
|
|
506
|
+
],
|
|
507
|
+
// JSON-shaped fields.
|
|
508
|
+
[
|
|
509
|
+
/"(authorization|api[-_]?key|secret[-_]?key|access[-_]?key|secret|token|password|cookie|x-amz[a-z-]*)"\s*:\s*"[^"]*"/gi,
|
|
510
|
+
'"$1": "[redacted]"'
|
|
511
|
+
]
|
|
512
|
+
];
|
|
513
|
+
function maskToken(match) {
|
|
514
|
+
if (match.length <= 8) return match;
|
|
515
|
+
const prefix = match.substring(0, 4);
|
|
516
|
+
const suffix = match.substring(match.length - 4);
|
|
517
|
+
return `${prefix}${"*".repeat(match.length - 8)}${suffix}`;
|
|
518
|
+
}
|
|
519
|
+
function redactSecrets(input) {
|
|
520
|
+
let out = input.replace(TOKEN_MASK_REGEX, maskToken);
|
|
521
|
+
for (const [pattern, replacement] of FULL_REDACTION_PATTERNS) {
|
|
522
|
+
out = out.replace(pattern, replacement);
|
|
523
|
+
}
|
|
524
|
+
return out;
|
|
525
|
+
}
|
|
526
|
+
var maskApiKeys = redactSecrets;
|
|
527
|
+
var SECRET_URL_QUERY_KEYS = /* @__PURE__ */ new Set([
|
|
528
|
+
"key",
|
|
529
|
+
"api_key",
|
|
530
|
+
"apikey",
|
|
531
|
+
"token",
|
|
532
|
+
"access_token",
|
|
533
|
+
"refresh_token",
|
|
534
|
+
"id_token",
|
|
535
|
+
"secret",
|
|
536
|
+
"client_secret",
|
|
537
|
+
"password",
|
|
538
|
+
"x-amz-signature",
|
|
539
|
+
"x-amz-security-token",
|
|
540
|
+
"x-amz-credential",
|
|
541
|
+
"signature"
|
|
542
|
+
]);
|
|
543
|
+
function safeRequestUrl(url) {
|
|
544
|
+
if (typeof url !== "string" || !url) return url;
|
|
545
|
+
let working = url;
|
|
546
|
+
try {
|
|
547
|
+
const parsed = new URL(url);
|
|
548
|
+
for (const key of Array.from(parsed.searchParams.keys())) {
|
|
549
|
+
if (SECRET_URL_QUERY_KEYS.has(key.toLowerCase())) {
|
|
550
|
+
parsed.searchParams.set(key, "[redacted]");
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
working = parsed.toString();
|
|
554
|
+
} catch {
|
|
555
|
+
}
|
|
556
|
+
return redactSecrets(working);
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
// src/errors/providerErrors.ts
|
|
560
|
+
var PROVIDER_MESSAGE_MAX_LENGTH = 240;
|
|
561
|
+
function safeProviderString(value, maxLength = PROVIDER_MESSAGE_MAX_LENGTH) {
|
|
562
|
+
if (typeof value !== "string" || value.length === 0) return void 0;
|
|
563
|
+
const scrubbed = redactSecrets(value);
|
|
564
|
+
return scrubbed.length > maxLength ? scrubbed.slice(0, maxLength) + "\u2026(truncated)" : scrubbed;
|
|
565
|
+
}
|
|
566
|
+
var SECRET_KEY_REGEX = /authorization|api[-_]?key|secret|token|password|cookie|set-cookie|x-amz/i;
|
|
567
|
+
var REDACTED = "[redacted]";
|
|
568
|
+
var DEFAULT_MAX_BODY_BYTES = 8192;
|
|
569
|
+
var DEFAULT_MAX_STRING_LENGTH = 2e3;
|
|
570
|
+
var MAX_SCRUB_DEPTH = 8;
|
|
571
|
+
var ALLOWED_RESPONSE_HEADERS = /* @__PURE__ */ new Set([
|
|
572
|
+
// Generic diagnostic headers
|
|
573
|
+
"content-type",
|
|
574
|
+
"retry-after",
|
|
575
|
+
// Request/correlation IDs
|
|
576
|
+
"request-id",
|
|
577
|
+
"x-request-id",
|
|
578
|
+
"x-amzn-requestid",
|
|
579
|
+
"x-amz-request-id",
|
|
580
|
+
"x-goog-request-id",
|
|
581
|
+
// OpenAI-style rate-limit headers
|
|
582
|
+
"x-ratelimit-limit-requests",
|
|
583
|
+
"x-ratelimit-remaining-requests",
|
|
584
|
+
"x-ratelimit-reset-requests",
|
|
585
|
+
"x-ratelimit-limit-tokens",
|
|
586
|
+
"x-ratelimit-remaining-tokens",
|
|
587
|
+
"x-ratelimit-reset-tokens",
|
|
588
|
+
// Anthropic-style rate-limit headers
|
|
589
|
+
"anthropic-ratelimit-requests-limit",
|
|
590
|
+
"anthropic-ratelimit-requests-remaining",
|
|
591
|
+
"anthropic-ratelimit-requests-reset",
|
|
592
|
+
"anthropic-ratelimit-tokens-limit",
|
|
593
|
+
"anthropic-ratelimit-tokens-remaining",
|
|
594
|
+
"anthropic-ratelimit-tokens-reset"
|
|
595
|
+
]);
|
|
596
|
+
function truncateString(value, max) {
|
|
597
|
+
if (value.length <= max) return value;
|
|
598
|
+
return value.slice(0, max) + "\u2026(truncated)";
|
|
599
|
+
}
|
|
600
|
+
function scrub(value, seen, depth, maxStringLength) {
|
|
601
|
+
if (value === null || value === void 0) return value;
|
|
602
|
+
const t = typeof value;
|
|
603
|
+
if (t === "string")
|
|
604
|
+
return redactSecrets(truncateString(value, maxStringLength));
|
|
605
|
+
if (t === "number" || t === "boolean") return value;
|
|
606
|
+
if (t === "bigint") return value.toString();
|
|
607
|
+
if (t === "symbol") return String(value);
|
|
608
|
+
if (t === "function") return "[Function]";
|
|
609
|
+
if (depth >= MAX_SCRUB_DEPTH) return "[deep]";
|
|
610
|
+
if (seen.has(value)) return "[Circular]";
|
|
611
|
+
seen.add(value);
|
|
612
|
+
try {
|
|
613
|
+
if (Array.isArray(value)) {
|
|
614
|
+
const arr = [];
|
|
615
|
+
for (let i = 0; i < value.length; i++) {
|
|
616
|
+
arr.push(scrub(value[i], seen, depth + 1, maxStringLength));
|
|
617
|
+
}
|
|
618
|
+
return arr;
|
|
619
|
+
}
|
|
620
|
+
const out = {};
|
|
621
|
+
for (const key of Object.keys(value)) {
|
|
622
|
+
if (SECRET_KEY_REGEX.test(key)) {
|
|
623
|
+
out[key] = REDACTED;
|
|
624
|
+
continue;
|
|
625
|
+
}
|
|
626
|
+
const v = value[key];
|
|
627
|
+
out[key] = scrub(v, seen, depth + 1, maxStringLength);
|
|
628
|
+
}
|
|
629
|
+
return out;
|
|
630
|
+
} finally {
|
|
631
|
+
seen.delete(value);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
function safeProviderErrorBody(value, options) {
|
|
635
|
+
const maxStringLength = options?.maxStringLength ?? DEFAULT_MAX_STRING_LENGTH;
|
|
636
|
+
const maxBodyBytes = options?.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;
|
|
637
|
+
if (typeof value === "string") {
|
|
638
|
+
return redactSecrets(truncateString(value, maxBodyBytes));
|
|
639
|
+
}
|
|
640
|
+
return scrub(value, /* @__PURE__ */ new WeakSet(), 0, maxStringLength);
|
|
641
|
+
}
|
|
642
|
+
function safeResponseHeaders(headers) {
|
|
643
|
+
const out = {};
|
|
644
|
+
if (!headers) return out;
|
|
645
|
+
if (typeof headers.forEach === "function" && typeof headers.get === "function") {
|
|
646
|
+
headers.forEach((value, key) => {
|
|
647
|
+
const lower = key.toLowerCase();
|
|
648
|
+
if (ALLOWED_RESPONSE_HEADERS.has(lower) && typeof value === "string") {
|
|
649
|
+
out[lower] = value;
|
|
650
|
+
}
|
|
651
|
+
});
|
|
652
|
+
return out;
|
|
653
|
+
}
|
|
654
|
+
for (const key of Object.keys(headers)) {
|
|
655
|
+
const value = headers[key];
|
|
656
|
+
const lower = key.toLowerCase();
|
|
657
|
+
if (ALLOWED_RESPONSE_HEADERS.has(lower) && typeof value === "string") {
|
|
658
|
+
out[lower] = value;
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
return out;
|
|
662
|
+
}
|
|
663
|
+
function parseRetryAfter(value) {
|
|
664
|
+
if (!value) return void 0;
|
|
665
|
+
const trimmed = value.trim();
|
|
666
|
+
if (!trimmed) return void 0;
|
|
667
|
+
if (/^\d+(\.\d+)?$/.test(trimmed)) {
|
|
668
|
+
const seconds = Number(trimmed);
|
|
669
|
+
if (!Number.isFinite(seconds)) return void 0;
|
|
670
|
+
return Math.max(0, Math.round(seconds * 1e3));
|
|
671
|
+
}
|
|
672
|
+
const dateMs = Date.parse(trimmed);
|
|
673
|
+
if (Number.isFinite(dateMs)) {
|
|
674
|
+
return Math.max(0, dateMs - Date.now());
|
|
675
|
+
}
|
|
676
|
+
return void 0;
|
|
677
|
+
}
|
|
678
|
+
function readStringField(obj, key) {
|
|
679
|
+
if (!obj || typeof obj !== "object") return void 0;
|
|
680
|
+
const v = obj[key];
|
|
681
|
+
return typeof v === "string" ? v : void 0;
|
|
682
|
+
}
|
|
683
|
+
function readStringOrNumberField(obj, key) {
|
|
684
|
+
if (!obj || typeof obj !== "object") return void 0;
|
|
685
|
+
const v = obj[key];
|
|
686
|
+
if (typeof v === "string") return v;
|
|
687
|
+
if (typeof v === "number" && Number.isFinite(v)) return String(v);
|
|
688
|
+
return void 0;
|
|
689
|
+
}
|
|
690
|
+
var parseProviderErrorGeneric = (input) => {
|
|
691
|
+
const status = input.status ?? input.response?.status;
|
|
692
|
+
const statusText = input.statusText ?? input.response?.statusText;
|
|
693
|
+
const headers = input.headers ?? {};
|
|
694
|
+
let message;
|
|
695
|
+
let providerType;
|
|
696
|
+
let providerCode;
|
|
697
|
+
const body = input.bodyJson;
|
|
698
|
+
if (body && typeof body === "object") {
|
|
699
|
+
const root = body;
|
|
700
|
+
const errVal = root.error;
|
|
701
|
+
const errObj = errVal && typeof errVal === "object" ? errVal : void 0;
|
|
702
|
+
message = readStringField(errObj, "message") ?? readStringField(root, "message") ?? (typeof errVal === "string" ? errVal : void 0);
|
|
703
|
+
providerType = readStringField(errObj, "type") ?? readStringField(root, "type") ?? // Bedrock-style: top-level "__type" carries the exception class.
|
|
704
|
+
readStringField(root, "__type") ?? readStringField(errObj, "status");
|
|
705
|
+
providerCode = // Accept numeric codes too (Gemini emits error.code: 400 as a number).
|
|
706
|
+
readStringOrNumberField(errObj, "code") ?? readStringOrNumberField(root, "code") ?? readStringField(errObj, "status");
|
|
707
|
+
}
|
|
708
|
+
if (!message && typeof input.bodyText === "string" && input.bodyText.length > 0) {
|
|
709
|
+
message = input.bodyText;
|
|
710
|
+
}
|
|
711
|
+
const retryAfterRaw = headers["retry-after"] ?? headers["Retry-After"];
|
|
712
|
+
const retryAfterMs = parseRetryAfter(retryAfterRaw);
|
|
713
|
+
let retryable;
|
|
714
|
+
if (typeof status === "number") {
|
|
715
|
+
retryable = status === 408 || status === 429 || status >= 500 && status < 600;
|
|
716
|
+
}
|
|
717
|
+
return {
|
|
718
|
+
message: safeProviderString(message),
|
|
719
|
+
providerType: safeProviderString(providerType),
|
|
720
|
+
providerCode: safeProviderString(providerCode),
|
|
721
|
+
status,
|
|
722
|
+
statusText,
|
|
723
|
+
retryable,
|
|
724
|
+
retryAfterMs
|
|
725
|
+
};
|
|
726
|
+
};
|
|
727
|
+
function statusToLlmProviderCode(status) {
|
|
728
|
+
if (status === 429) return "llm.provider_rate_limited";
|
|
729
|
+
if (status === 401 || status === 403) return "llm.provider_auth_failed";
|
|
730
|
+
if (status === 400 || status === 422) return "llm.provider_invalid_request";
|
|
731
|
+
if (status === 408 || status >= 500 && status < 600)
|
|
732
|
+
return "llm.provider_unavailable";
|
|
733
|
+
return "llm.provider_http_error";
|
|
734
|
+
}
|
|
735
|
+
function statusToEmbeddingProviderCode(status) {
|
|
736
|
+
if (status === 429) return "embedding.provider_rate_limited";
|
|
737
|
+
if (status === 401 || status === 403) return "embedding.provider_auth_failed";
|
|
738
|
+
if (status === 400 || status === 422)
|
|
739
|
+
return "embedding.provider_invalid_request";
|
|
740
|
+
if (status === 408 || status >= 500 && status < 600)
|
|
741
|
+
return "embedding.provider_unavailable";
|
|
742
|
+
return "embedding.provider_http_error";
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// src/errors/getErrorMetadata.ts
|
|
746
|
+
function getErrorMetadata(error) {
|
|
747
|
+
if (!isLlmExeError(error)) return {};
|
|
748
|
+
return {
|
|
749
|
+
errorCategory: error.category,
|
|
750
|
+
errorCode: error.code,
|
|
751
|
+
errorContext: error.context,
|
|
752
|
+
errorCause: error.cause
|
|
753
|
+
};
|
|
754
|
+
}
|
|
755
|
+
|
|
99
756
|
// src/executor/_base.ts
|
|
100
757
|
var BaseExecutor = class {
|
|
101
758
|
constructor(name, type, options) {
|
|
@@ -144,12 +801,41 @@ var BaseExecutor = class {
|
|
|
144
801
|
}
|
|
145
802
|
}
|
|
146
803
|
/**
|
|
804
|
+
* Build a per-call execution context snapshot. Captures the current
|
|
805
|
+
* execution metadata so the snapshot reflects state at the time it was
|
|
806
|
+
* taken (e.g. `handlerInput` becomes available after `getHandlerInput`).
|
|
807
|
+
*/
|
|
808
|
+
snapshotContext(execution) {
|
|
809
|
+
return {
|
|
810
|
+
traceId: this.getTraceId() ?? void 0,
|
|
811
|
+
executor: this.getMetadata(),
|
|
812
|
+
execution,
|
|
813
|
+
attributes: {}
|
|
814
|
+
};
|
|
815
|
+
}
|
|
816
|
+
/**
|
|
817
|
+
*
|
|
818
|
+
* Used to filter the input of the handler.
|
|
819
|
+
*
|
|
820
|
+
* Throws a `TypeError` if `_input` is `null` or `undefined`. The declared
|
|
821
|
+
* input type is `I extends PlainObject`; omitting input or passing an
|
|
822
|
+
* explicit `null` is a contract violation with no valid coercion, so we
|
|
823
|
+
* surface it loudly rather than silently wrapping it.
|
|
824
|
+
*
|
|
825
|
+
* Non-object inputs (strings, numbers, arrays) are intentionally coerced
|
|
826
|
+
* to `{ input: value }` via {@link ensureInputIsObject}. This preserves the
|
|
827
|
+
* convenience pattern used by tool/function callables, which forward raw
|
|
828
|
+
* string arguments into an executor.
|
|
147
829
|
*
|
|
148
|
-
* Used to filter the input of the handler
|
|
149
830
|
* @param _input
|
|
150
831
|
* @returns original input formatted for handler
|
|
151
832
|
*/
|
|
152
833
|
async getHandlerInput(_input, _metadata, _options) {
|
|
834
|
+
if (_input === null || typeof _input === "undefined") {
|
|
835
|
+
throw new TypeError(
|
|
836
|
+
`[llm-exe] Executor "${this.name}" received null or undefined as input. execute() expects an object matching the prompt's input type.`
|
|
837
|
+
);
|
|
838
|
+
}
|
|
153
839
|
return ensureInputIsObject(_input);
|
|
154
840
|
}
|
|
155
841
|
/**
|
|
@@ -158,7 +844,7 @@ var BaseExecutor = class {
|
|
|
158
844
|
* @param _input
|
|
159
845
|
* @returns output O
|
|
160
846
|
*/
|
|
161
|
-
getHandlerOutput(out, _metadata, _options) {
|
|
847
|
+
getHandlerOutput(out, _metadata, _options, _context) {
|
|
162
848
|
return out;
|
|
163
849
|
}
|
|
164
850
|
/**
|
|
@@ -180,25 +866,45 @@ var BaseExecutor = class {
|
|
|
180
866
|
_options
|
|
181
867
|
);
|
|
182
868
|
_metadata.setItem({ handlerInput: input });
|
|
183
|
-
let result = await this.handler(
|
|
869
|
+
let result = await this.handler(
|
|
870
|
+
input,
|
|
871
|
+
_options,
|
|
872
|
+
this.snapshotContext(_metadata.asPlainObject())
|
|
873
|
+
);
|
|
184
874
|
_metadata.setItem({ handlerOutput: result });
|
|
185
875
|
const output = this.getHandlerOutput(
|
|
186
876
|
result,
|
|
187
877
|
_metadata.asPlainObject(),
|
|
188
|
-
_options
|
|
878
|
+
_options,
|
|
879
|
+
this.snapshotContext(_metadata.asPlainObject())
|
|
189
880
|
);
|
|
190
881
|
_metadata.setItem({ output });
|
|
191
|
-
this.
|
|
882
|
+
this.collectHookErrors(
|
|
883
|
+
this.runHook("onSuccess", _metadata.asPlainObject()),
|
|
884
|
+
_metadata
|
|
885
|
+
);
|
|
192
886
|
return output;
|
|
193
887
|
} catch (error) {
|
|
194
|
-
_metadata.setItem({
|
|
195
|
-
|
|
888
|
+
_metadata.setItem({
|
|
889
|
+
error,
|
|
890
|
+
errorMessage: error.message,
|
|
891
|
+
...getErrorMetadata(error)
|
|
892
|
+
});
|
|
893
|
+
this.collectHookErrors(
|
|
894
|
+
this.runHook("onError", _metadata.asPlainObject()),
|
|
895
|
+
_metadata
|
|
896
|
+
);
|
|
196
897
|
throw error;
|
|
197
898
|
} finally {
|
|
198
899
|
_metadata.setItem({ end: (/* @__PURE__ */ new Date()).getTime() });
|
|
199
900
|
this.runHook("onComplete", _metadata.asPlainObject());
|
|
200
901
|
}
|
|
201
902
|
}
|
|
903
|
+
collectHookErrors(fresh, state) {
|
|
904
|
+
if (fresh.length === 0) return;
|
|
905
|
+
const existing = state.asPlainObject().hookErrors ?? [];
|
|
906
|
+
state.setItem({ hookErrors: [...existing, ...fresh] });
|
|
907
|
+
}
|
|
202
908
|
metadata() {
|
|
203
909
|
return {};
|
|
204
910
|
}
|
|
@@ -215,18 +921,23 @@ var BaseExecutor = class {
|
|
|
215
921
|
}
|
|
216
922
|
runHook(hook, _metadata) {
|
|
217
923
|
const { [hook]: hooks = [] } = pick(this.hooks, this.allowedHooks);
|
|
924
|
+
const errors = [];
|
|
218
925
|
for (const hookFn of [...hooks]) {
|
|
219
926
|
if (typeof hookFn === "function") {
|
|
220
927
|
try {
|
|
221
928
|
hookFn(_metadata, this.getMetadata());
|
|
222
929
|
} catch (error) {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
930
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
931
|
+
errors.push({
|
|
932
|
+
hook: String(hook),
|
|
933
|
+
error,
|
|
934
|
+
errorMessage: message,
|
|
935
|
+
...getErrorMetadata(error)
|
|
936
|
+
});
|
|
227
937
|
}
|
|
228
938
|
}
|
|
229
939
|
}
|
|
940
|
+
return errors;
|
|
230
941
|
}
|
|
231
942
|
setHooks(hooks = {}) {
|
|
232
943
|
const hookKeys = Object.keys(hooks);
|
|
@@ -239,8 +950,19 @@ var BaseExecutor = class {
|
|
|
239
950
|
for (const hook of _hooks) {
|
|
240
951
|
if (hook && typeof hook === "function" && !this.hooks[hookKey].find((h) => h === hook)) {
|
|
241
952
|
if (this.hooks[hookKey].length >= this.maxHooksPerEvent) {
|
|
242
|
-
throw new
|
|
243
|
-
`Maximum number of hooks (${this.maxHooksPerEvent}) reached for event "${String(hookKey)}". Consider removing unused hooks or increasing the limit
|
|
953
|
+
throw new LlmExeError(
|
|
954
|
+
`Maximum number of hooks (${this.maxHooksPerEvent}) reached for event "${String(hookKey)}". Consider removing unused hooks or increasing the limit.`,
|
|
955
|
+
{
|
|
956
|
+
code: "executor.hook_limit_reached",
|
|
957
|
+
context: {
|
|
958
|
+
operation: "BaseExecutor.setHooks",
|
|
959
|
+
executorName: this.name,
|
|
960
|
+
executorType: this.type,
|
|
961
|
+
hook: String(hookKey),
|
|
962
|
+
hookCount: this.hooks[hookKey].length,
|
|
963
|
+
maxHooksPerEvent: this.maxHooksPerEvent
|
|
964
|
+
}
|
|
965
|
+
}
|
|
244
966
|
);
|
|
245
967
|
}
|
|
246
968
|
this.hooks[hookKey].push(hook);
|
|
@@ -271,13 +993,27 @@ var BaseExecutor = class {
|
|
|
271
993
|
once(eventName, fn) {
|
|
272
994
|
if (typeof fn !== "function") return this;
|
|
273
995
|
if (this.hooks[eventName] && this.hooks[eventName].length >= this.maxHooksPerEvent) {
|
|
274
|
-
throw new
|
|
275
|
-
`Maximum number of hooks (${this.maxHooksPerEvent}) reached for event "${String(eventName)}". Consider removing unused hooks or increasing the limit
|
|
996
|
+
throw new LlmExeError(
|
|
997
|
+
`Maximum number of hooks (${this.maxHooksPerEvent}) reached for event "${String(eventName)}". Consider removing unused hooks or increasing the limit.`,
|
|
998
|
+
{
|
|
999
|
+
code: "executor.hook_limit_reached",
|
|
1000
|
+
context: {
|
|
1001
|
+
operation: "BaseExecutor.once",
|
|
1002
|
+
executorName: this.name,
|
|
1003
|
+
executorType: this.type,
|
|
1004
|
+
hook: String(eventName),
|
|
1005
|
+
hookCount: this.hooks[eventName].length,
|
|
1006
|
+
maxHooksPerEvent: this.maxHooksPerEvent
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
276
1009
|
);
|
|
277
1010
|
}
|
|
278
1011
|
const onceWrapper = (...args) => {
|
|
279
|
-
|
|
280
|
-
|
|
1012
|
+
try {
|
|
1013
|
+
fn(...args);
|
|
1014
|
+
} finally {
|
|
1015
|
+
this.off(eventName, onceWrapper);
|
|
1016
|
+
}
|
|
281
1017
|
};
|
|
282
1018
|
if (!this.hooks[eventName]) {
|
|
283
1019
|
this.hooks[eventName] = [];
|
|
@@ -357,25 +1093,16 @@ var BaseParser = class {
|
|
|
357
1093
|
/**
|
|
358
1094
|
* Create a new BaseParser.
|
|
359
1095
|
* @param name - The name of the parser.
|
|
360
|
-
* @param
|
|
1096
|
+
* @param target - Whether the parser consumes text or function-call output.
|
|
361
1097
|
*/
|
|
362
|
-
constructor(name,
|
|
1098
|
+
constructor(name, target = "text") {
|
|
363
1099
|
__publicField(this, "name");
|
|
364
|
-
__publicField(this, "options");
|
|
365
1100
|
__publicField(this, "target", "text");
|
|
366
1101
|
this.name = name;
|
|
367
1102
|
this.target = target;
|
|
368
|
-
if (options) {
|
|
369
|
-
this.options = options;
|
|
370
|
-
}
|
|
371
1103
|
}
|
|
372
1104
|
};
|
|
373
1105
|
var BaseParserWithJson = class extends BaseParser {
|
|
374
|
-
/**
|
|
375
|
-
* Create a new BaseParser.
|
|
376
|
-
* @param name - The name of the parser.
|
|
377
|
-
* @param options - options
|
|
378
|
-
*/
|
|
379
1106
|
constructor(name, options) {
|
|
380
1107
|
super(name);
|
|
381
1108
|
__publicField(this, "schema");
|
|
@@ -388,212 +1115,285 @@ var BaseParserWithJson = class extends BaseParser {
|
|
|
388
1115
|
}
|
|
389
1116
|
};
|
|
390
1117
|
|
|
391
|
-
// src/utils/modules/assert.ts
|
|
392
|
-
function assert(condition, message) {
|
|
393
|
-
if (condition === void 0 || condition === null || condition === false) {
|
|
394
|
-
if (typeof message === "string") {
|
|
395
|
-
throw new Error(message);
|
|
396
|
-
} else if (message instanceof Error) {
|
|
397
|
-
throw message;
|
|
398
|
-
} else {
|
|
399
|
-
throw new Error(`Assertion error`);
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
// src/utils/guards.ts
|
|
405
|
-
var guards_exports = {};
|
|
406
|
-
__export(guards_exports, {
|
|
407
|
-
hasFunctionCall: () => hasFunctionCall,
|
|
408
|
-
hasToolCall: () => hasToolCall,
|
|
409
|
-
isAssistantMessage: () => isAssistantMessage,
|
|
410
|
-
isFunctionCall: () => isFunctionCall,
|
|
411
|
-
isOutputResult: () => isOutputResult,
|
|
412
|
-
isOutputResultContentText: () => isOutputResultContentText,
|
|
413
|
-
isSystemMessage: () => isSystemMessage,
|
|
414
|
-
isToolCall: () => isToolCall,
|
|
415
|
-
isUserMessage: () => isUserMessage
|
|
416
|
-
});
|
|
417
|
-
function isOutputResult(obj) {
|
|
418
|
-
return !!(obj && typeof obj === "object" && "id" in obj && "stopReason" in obj && "content" in obj && Array.isArray(obj.content));
|
|
419
|
-
}
|
|
420
|
-
function isOutputResultContentText(obj) {
|
|
421
|
-
return !!(obj && typeof obj === "object" && "text" in obj && "type" in obj && obj.type === "text" && typeof obj.text === "string");
|
|
422
|
-
}
|
|
423
|
-
function isFunctionCall(result) {
|
|
424
|
-
return !!(result && typeof result === "object" && "functionId" in result && "type" in result && result.type === "function_use");
|
|
425
|
-
}
|
|
426
|
-
function isToolCall(result) {
|
|
427
|
-
return isFunctionCall(result);
|
|
428
|
-
}
|
|
429
|
-
function hasFunctionCall(results) {
|
|
430
|
-
return !!(results && Array.isArray(results) && results.some(isToolCall));
|
|
431
|
-
}
|
|
432
|
-
function hasToolCall(results) {
|
|
433
|
-
return hasFunctionCall(results);
|
|
434
|
-
}
|
|
435
|
-
function isUserMessage(message) {
|
|
436
|
-
return message.role === "user";
|
|
437
|
-
}
|
|
438
|
-
function isAssistantMessage(message) {
|
|
439
|
-
return message.role === "assistant" || message.role === "model";
|
|
440
|
-
}
|
|
441
|
-
function isSystemMessage(message) {
|
|
442
|
-
return message.role === "system";
|
|
443
|
-
}
|
|
444
|
-
|
|
445
1118
|
// src/parser/parsers/StringParser.ts
|
|
446
1119
|
var StringParser = class extends BaseParser {
|
|
447
|
-
constructor(
|
|
448
|
-
super("string"
|
|
1120
|
+
constructor() {
|
|
1121
|
+
super("string");
|
|
449
1122
|
}
|
|
450
|
-
parse(text,
|
|
451
|
-
if (
|
|
452
|
-
|
|
1123
|
+
parse(text, _attributes) {
|
|
1124
|
+
if (typeof text !== "string") {
|
|
1125
|
+
throw new LlmExeError(
|
|
1126
|
+
`Invalid input. Expected string. Received ${text === null ? "null" : Array.isArray(text) ? "array" : typeof text}.`,
|
|
1127
|
+
{
|
|
1128
|
+
code: "parser.invalid_input",
|
|
1129
|
+
context: {
|
|
1130
|
+
operation: "StringParser.parse",
|
|
1131
|
+
parser: "string",
|
|
1132
|
+
reason: "invalid_input_type",
|
|
1133
|
+
expected: "string",
|
|
1134
|
+
received: text === null ? "null" : Array.isArray(text) ? "array" : typeof text
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
);
|
|
453
1138
|
}
|
|
454
|
-
|
|
455
|
-
typeof text === "string",
|
|
456
|
-
`Invalid input. Expected string. Received ${typeof text}.`
|
|
457
|
-
);
|
|
458
|
-
const parsed = text.toString();
|
|
459
|
-
return parsed;
|
|
1139
|
+
return text;
|
|
460
1140
|
}
|
|
461
1141
|
};
|
|
462
1142
|
|
|
463
|
-
// src/
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
assert(
|
|
470
|
-
typeof text === "string",
|
|
471
|
-
`Invalid input. Expected string. Received ${typeof text}.`
|
|
472
|
-
);
|
|
473
|
-
const clean = text.toLowerCase().trim();
|
|
474
|
-
if (clean === "true" || clean === "yes" || clean === "y" || clean === "1") {
|
|
475
|
-
return true;
|
|
476
|
-
}
|
|
477
|
-
return false;
|
|
1143
|
+
// src/utils/modules/getEnvironmentVariable.ts
|
|
1144
|
+
function getEnvironmentVariable(name) {
|
|
1145
|
+
if (typeof process === "object" && process?.env) {
|
|
1146
|
+
return process.env[name];
|
|
1147
|
+
} else {
|
|
1148
|
+
return void 0;
|
|
478
1149
|
}
|
|
479
|
-
};
|
|
480
|
-
|
|
481
|
-
// src/utils/modules/isFinite.ts
|
|
482
|
-
function isFinite(value) {
|
|
483
|
-
return typeof value === "number" && Number.isFinite(value);
|
|
484
1150
|
}
|
|
485
1151
|
|
|
486
|
-
// src/utils/modules/
|
|
487
|
-
function
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
}
|
|
491
|
-
if (typeof value === "string" && value.trim() !== "") {
|
|
492
|
-
return Number(value);
|
|
493
|
-
}
|
|
494
|
-
return NaN;
|
|
1152
|
+
// src/utils/modules/debug.ts
|
|
1153
|
+
function isDebugEnabled() {
|
|
1154
|
+
const debugValue = getEnvironmentVariable("LLM_EXE_DEBUG");
|
|
1155
|
+
return typeof debugValue === "string" && debugValue !== "" && debugValue.toLowerCase() !== "undefined" && debugValue.toLowerCase() !== "null";
|
|
495
1156
|
}
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
constructor(message, code, context) {
|
|
500
|
-
super(message ?? "");
|
|
501
|
-
__publicField(this, "code");
|
|
502
|
-
__publicField(this, "context");
|
|
503
|
-
this.name = this.constructor.name;
|
|
504
|
-
this.code = code ?? "unknown";
|
|
505
|
-
this.context = context;
|
|
506
|
-
if (Error.captureStackTrace) {
|
|
507
|
-
Error.captureStackTrace(this, this.constructor);
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
};
|
|
511
|
-
|
|
512
|
-
// src/parser/parsers/NumberParser.ts
|
|
513
|
-
var NumberParser = class extends BaseParser {
|
|
514
|
-
constructor(options) {
|
|
515
|
-
super("number", options);
|
|
1157
|
+
function debug(...args) {
|
|
1158
|
+
if (!isDebugEnabled()) {
|
|
1159
|
+
return;
|
|
516
1160
|
}
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
if (
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
1161
|
+
const logs = [];
|
|
1162
|
+
for (const arg of args) {
|
|
1163
|
+
if (arg && typeof arg === "object") {
|
|
1164
|
+
if (arg instanceof Error) {
|
|
1165
|
+
} else if (arg instanceof Array) {
|
|
1166
|
+
logs.push(arg.map((item) => JSON.stringify(item, null, 2)));
|
|
1167
|
+
} else if (arg instanceof Map) {
|
|
1168
|
+
logs.push(
|
|
1169
|
+
Array.from(arg.entries()).map(
|
|
1170
|
+
([key, value]) => `${key}: ${JSON.stringify(value, null, 2)}`
|
|
1171
|
+
)
|
|
1172
|
+
);
|
|
1173
|
+
} else if (arg instanceof Set) {
|
|
1174
|
+
logs.push(Array.from(arg).map((item) => JSON.stringify(item, null, 2)));
|
|
1175
|
+
} else if (arg instanceof Date) {
|
|
1176
|
+
logs.push(arg.toISOString());
|
|
1177
|
+
} else if (arg instanceof RegExp) {
|
|
1178
|
+
logs.push(arg.toString());
|
|
1179
|
+
} else {
|
|
1180
|
+
try {
|
|
1181
|
+
const str = maskApiKeys(JSON.stringify(arg, null, 2));
|
|
1182
|
+
logs.push(str);
|
|
1183
|
+
} catch (error) {
|
|
1184
|
+
console.error("Error parsing object:", error);
|
|
1185
|
+
}
|
|
529
1186
|
}
|
|
530
|
-
)
|
|
1187
|
+
} else if (typeof arg === "string") {
|
|
1188
|
+
logs.push(safeRequestUrl(arg));
|
|
1189
|
+
} else {
|
|
1190
|
+
logs.push(arg);
|
|
1191
|
+
}
|
|
531
1192
|
}
|
|
532
|
-
|
|
1193
|
+
if (isDebugEnabled()) {
|
|
1194
|
+
console.debug(...logs);
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
533
1197
|
|
|
534
|
-
// src/
|
|
535
|
-
var
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
}
|
|
1198
|
+
// src/parser/parsers/BooleanParser.ts
|
|
1199
|
+
var BOOLEAN_VALUES = ["true", "false", "yes", "no", "y", "n", "1", "0"];
|
|
1200
|
+
var TRUTHY_VALUES = /* @__PURE__ */ new Set(["true", "yes", "y", "1"]);
|
|
1201
|
+
var FALSY_VALUES = /* @__PURE__ */ new Set(["false", "no", "n", "0"]);
|
|
1202
|
+
var MAX_ERROR_INPUT_EXCERPT_LENGTH = 500;
|
|
1203
|
+
var BooleanParser = class extends BaseParser {
|
|
1204
|
+
constructor() {
|
|
1205
|
+
super("boolean");
|
|
1206
|
+
}
|
|
1207
|
+
getInputErrorContext(text) {
|
|
1208
|
+
const context = {
|
|
1209
|
+
inputLength: text.length
|
|
1210
|
+
};
|
|
1211
|
+
if (isDebugEnabled()) {
|
|
1212
|
+
const truncated = text.length > MAX_ERROR_INPUT_EXCERPT_LENGTH;
|
|
1213
|
+
context.inputExcerpt = truncated ? text.slice(0, MAX_ERROR_INPUT_EXCERPT_LENGTH) : text;
|
|
1214
|
+
context.inputExcerptTruncated = truncated;
|
|
1215
|
+
}
|
|
1216
|
+
return context;
|
|
1217
|
+
}
|
|
1218
|
+
parse(text, _attributes) {
|
|
1219
|
+
if (typeof text !== "string") {
|
|
1220
|
+
throw new LlmExeError(
|
|
1221
|
+
`Invalid input. Expected string. Received ${text === null ? "null" : typeof text}.`,
|
|
1222
|
+
{
|
|
1223
|
+
code: "parser.invalid_input",
|
|
1224
|
+
context: {
|
|
1225
|
+
operation: "BooleanParser.parse",
|
|
1226
|
+
parser: "boolean",
|
|
1227
|
+
reason: "invalid_input_type",
|
|
1228
|
+
expected: "string",
|
|
1229
|
+
received: text === null ? "null" : typeof text
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
);
|
|
1233
|
+
}
|
|
1234
|
+
const clean = text.toLowerCase().trim();
|
|
1235
|
+
if (!clean) {
|
|
1236
|
+
throw new LlmExeError(`No boolean value found in input.`, {
|
|
1237
|
+
code: "parser.parse_failed",
|
|
1238
|
+
context: {
|
|
1239
|
+
operation: "BooleanParser.parse",
|
|
1240
|
+
parser: "boolean",
|
|
1241
|
+
reason: "empty_input",
|
|
1242
|
+
expected: BOOLEAN_VALUES,
|
|
1243
|
+
...this.getInputErrorContext(text)
|
|
1244
|
+
}
|
|
1245
|
+
});
|
|
1246
|
+
}
|
|
1247
|
+
if (TRUTHY_VALUES.has(clean)) {
|
|
1248
|
+
return true;
|
|
1249
|
+
}
|
|
1250
|
+
if (FALSY_VALUES.has(clean)) {
|
|
1251
|
+
return false;
|
|
1252
|
+
}
|
|
1253
|
+
throw new LlmExeError(`No boolean value found in input.`, {
|
|
1254
|
+
code: "parser.parse_failed",
|
|
1255
|
+
context: {
|
|
1256
|
+
operation: "BooleanParser.parse",
|
|
1257
|
+
parser: "boolean",
|
|
1258
|
+
reason: "unrecognized_boolean",
|
|
1259
|
+
expected: BOOLEAN_VALUES,
|
|
1260
|
+
...this.getInputErrorContext(text)
|
|
1261
|
+
}
|
|
1262
|
+
});
|
|
1263
|
+
}
|
|
1264
|
+
};
|
|
552
1265
|
|
|
553
|
-
// src/utils/modules/
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
obj.additionalProperties = false;
|
|
557
|
-
return asConst(obj);
|
|
1266
|
+
// src/utils/modules/isFinite.ts
|
|
1267
|
+
function isFinite(value) {
|
|
1268
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
558
1269
|
}
|
|
559
1270
|
|
|
560
|
-
// src/utils/modules/
|
|
561
|
-
function
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
const externalPartialKeys = Object.keys(
|
|
565
|
-
_partials
|
|
566
|
-
);
|
|
567
|
-
for (const externalPartialKey of externalPartialKeys) {
|
|
568
|
-
if (typeof externalPartialKey === "string") {
|
|
569
|
-
partials2.push({
|
|
570
|
-
name: externalPartialKey,
|
|
571
|
-
template: _partials[externalPartialKey]
|
|
572
|
-
});
|
|
573
|
-
}
|
|
574
|
-
}
|
|
1271
|
+
// src/utils/modules/toNumber.ts
|
|
1272
|
+
function toNumber(value) {
|
|
1273
|
+
if (typeof value === "number") {
|
|
1274
|
+
return value;
|
|
575
1275
|
}
|
|
576
|
-
|
|
1276
|
+
if (typeof value === "string" && value.trim() !== "") {
|
|
1277
|
+
return Number(value);
|
|
1278
|
+
}
|
|
1279
|
+
return NaN;
|
|
577
1280
|
}
|
|
578
1281
|
|
|
579
|
-
// src/
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
);
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
1282
|
+
// src/parser/parsers/NumberParser.ts
|
|
1283
|
+
var NUMERIC_TOKEN_PATTERN = /(^|[^\w.,])([+-]?(?:(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d+)?|\.\d+)(?:[eE][+-]?\d+)?)(?![\w,])/g;
|
|
1284
|
+
var WHOLE_NUMERIC_PATTERN = /^[+-]?(?:(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d+)?|\.\d+)(?:[eE][+-]?\d+)?$/;
|
|
1285
|
+
var NumberParser = class extends BaseParser {
|
|
1286
|
+
constructor(options) {
|
|
1287
|
+
super("number");
|
|
1288
|
+
__publicField(this, "match");
|
|
1289
|
+
this.match = options?.match ?? "extract";
|
|
1290
|
+
}
|
|
1291
|
+
parse(text, _attributes) {
|
|
1292
|
+
if (typeof text !== "string") {
|
|
1293
|
+
throw new LlmExeError(
|
|
1294
|
+
`Invalid input. Expected string. Received ${text === null ? "null" : Array.isArray(text) ? "array" : typeof text}.`,
|
|
1295
|
+
{
|
|
1296
|
+
code: "parser.invalid_input",
|
|
1297
|
+
context: {
|
|
1298
|
+
operation: "NumberParser.parse",
|
|
1299
|
+
parser: "number",
|
|
1300
|
+
reason: "invalid_input_type",
|
|
1301
|
+
expected: "string",
|
|
1302
|
+
received: text === null ? "null" : Array.isArray(text) ? "array" : typeof text
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
);
|
|
1306
|
+
}
|
|
1307
|
+
if (text.trim() === "") {
|
|
1308
|
+
throw new LlmExeError(`No numeric value found in input.`, {
|
|
1309
|
+
code: "parser.parse_failed",
|
|
1310
|
+
context: {
|
|
1311
|
+
operation: "NumberParser.parse",
|
|
1312
|
+
parser: "number",
|
|
1313
|
+
reason: "empty_input",
|
|
1314
|
+
expected: "number",
|
|
1315
|
+
inputLength: text.length
|
|
1316
|
+
}
|
|
1317
|
+
});
|
|
1318
|
+
}
|
|
1319
|
+
if (this.match === "whole") {
|
|
1320
|
+
const trimmed = text.trim();
|
|
1321
|
+
if (!WHOLE_NUMERIC_PATTERN.test(trimmed)) {
|
|
1322
|
+
throw new LlmExeError(`Input is not a whole numeric value.`, {
|
|
1323
|
+
code: "parser.parse_failed",
|
|
1324
|
+
context: {
|
|
1325
|
+
operation: "NumberParser.parse",
|
|
1326
|
+
parser: "number",
|
|
1327
|
+
reason: "no_numeric_value",
|
|
1328
|
+
expected: "whole number",
|
|
1329
|
+
match: this.match,
|
|
1330
|
+
inputLength: text.length
|
|
1331
|
+
}
|
|
1332
|
+
});
|
|
1333
|
+
}
|
|
1334
|
+
const value2 = toNumber(trimmed.replace(/,/g, ""));
|
|
1335
|
+
if (!isFinite(value2)) {
|
|
1336
|
+
throw new LlmExeError(`Invalid numeric value found in input.`, {
|
|
1337
|
+
code: "parser.parse_failed",
|
|
1338
|
+
context: {
|
|
1339
|
+
operation: "NumberParser.parse",
|
|
1340
|
+
parser: "number",
|
|
1341
|
+
reason: "invalid_number",
|
|
1342
|
+
expected: "finite number",
|
|
1343
|
+
match: this.match,
|
|
1344
|
+
inputLength: text.length
|
|
1345
|
+
}
|
|
591
1346
|
});
|
|
592
1347
|
}
|
|
1348
|
+
return value2;
|
|
1349
|
+
}
|
|
1350
|
+
const matches = Array.from(text.matchAll(NUMERIC_TOKEN_PATTERN)).map(
|
|
1351
|
+
(match) => match[2]
|
|
1352
|
+
);
|
|
1353
|
+
if (matches.length === 0) {
|
|
1354
|
+
throw new LlmExeError(`No numeric value found in input.`, {
|
|
1355
|
+
code: "parser.parse_failed",
|
|
1356
|
+
context: {
|
|
1357
|
+
operation: "NumberParser.parse",
|
|
1358
|
+
parser: "number",
|
|
1359
|
+
reason: "no_numeric_value",
|
|
1360
|
+
expected: "number",
|
|
1361
|
+
match: this.match,
|
|
1362
|
+
inputLength: text.length
|
|
1363
|
+
}
|
|
1364
|
+
});
|
|
1365
|
+
}
|
|
1366
|
+
if (matches.length > 1) {
|
|
1367
|
+
throw new LlmExeError(`Multiple numeric values found in input.`, {
|
|
1368
|
+
code: "parser.parse_failed",
|
|
1369
|
+
context: {
|
|
1370
|
+
operation: "NumberParser.parse",
|
|
1371
|
+
parser: "number",
|
|
1372
|
+
reason: "ambiguous_number",
|
|
1373
|
+
expected: "one numeric value",
|
|
1374
|
+
match: this.match,
|
|
1375
|
+
inputLength: text.length,
|
|
1376
|
+
matchCount: matches.length
|
|
1377
|
+
}
|
|
1378
|
+
});
|
|
593
1379
|
}
|
|
1380
|
+
const value = toNumber(matches[0].replace(/,/g, ""));
|
|
1381
|
+
if (!isFinite(value)) {
|
|
1382
|
+
throw new LlmExeError(`Invalid numeric value found in input.`, {
|
|
1383
|
+
code: "parser.parse_failed",
|
|
1384
|
+
context: {
|
|
1385
|
+
operation: "NumberParser.parse",
|
|
1386
|
+
parser: "number",
|
|
1387
|
+
reason: "invalid_number",
|
|
1388
|
+
expected: "finite number",
|
|
1389
|
+
match: this.match,
|
|
1390
|
+
inputLength: text.length
|
|
1391
|
+
}
|
|
1392
|
+
});
|
|
1393
|
+
}
|
|
1394
|
+
return value;
|
|
594
1395
|
}
|
|
595
|
-
|
|
596
|
-
}
|
|
1396
|
+
};
|
|
597
1397
|
|
|
598
1398
|
// src/utils/modules/get.ts
|
|
599
1399
|
function get(obj, path, defaultValue) {
|
|
@@ -647,10 +1447,22 @@ function filterObjectOnSchema(schema, doc, detach, property) {
|
|
|
647
1447
|
return;
|
|
648
1448
|
}
|
|
649
1449
|
} else {
|
|
650
|
-
|
|
1450
|
+
var childType = getType(sp.type);
|
|
1451
|
+
if (childType === "integer" || childType === "number") {
|
|
651
1452
|
result[key] = toNumber(filteredChild);
|
|
652
|
-
} else if (
|
|
653
|
-
|
|
1453
|
+
} else if (childType === "boolean") {
|
|
1454
|
+
if (typeof filteredChild === "string") {
|
|
1455
|
+
const normalized = filteredChild.trim().toLowerCase();
|
|
1456
|
+
if (normalized === "true") {
|
|
1457
|
+
result[key] = true;
|
|
1458
|
+
} else if (normalized === "false") {
|
|
1459
|
+
result[key] = false;
|
|
1460
|
+
} else {
|
|
1461
|
+
result[key] = filteredChild;
|
|
1462
|
+
}
|
|
1463
|
+
} else {
|
|
1464
|
+
result[key] = filteredChild;
|
|
1465
|
+
}
|
|
654
1466
|
} else {
|
|
655
1467
|
result[key] = filteredChild;
|
|
656
1468
|
}
|
|
@@ -670,67 +1482,566 @@ function filterObjectOnSchema(schema, doc, detach, property) {
|
|
|
670
1482
|
return result;
|
|
671
1483
|
}
|
|
672
1484
|
|
|
673
|
-
// src/
|
|
674
|
-
import
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
1485
|
+
// src/parser/_utils.ts
|
|
1486
|
+
import { validate as validateSchema } from "jsonschema";
|
|
1487
|
+
function isPlainObject(value) {
|
|
1488
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
1489
|
+
return false;
|
|
1490
|
+
}
|
|
1491
|
+
const proto = Object.getPrototypeOf(value);
|
|
1492
|
+
return proto === Object.prototype || proto === null;
|
|
1493
|
+
}
|
|
1494
|
+
function getSchemaType(schemaType) {
|
|
1495
|
+
if (!Array.isArray(schemaType)) {
|
|
1496
|
+
return schemaType;
|
|
1497
|
+
}
|
|
1498
|
+
return schemaType.find((type) => type !== "null");
|
|
1499
|
+
}
|
|
1500
|
+
function enforceParserSchema(schema, parsed) {
|
|
1501
|
+
if (!schema || !parsed || typeof parsed !== "object") {
|
|
1502
|
+
return parsed;
|
|
1503
|
+
}
|
|
1504
|
+
return filterObjectOnSchema(schema, parsed);
|
|
1505
|
+
}
|
|
1506
|
+
function validateParserSchema(schema, parsed) {
|
|
1507
|
+
if (!schema || !parsed || typeof parsed !== "object") {
|
|
1508
|
+
return null;
|
|
1509
|
+
}
|
|
1510
|
+
const validate = validateSchema(parsed, schema);
|
|
1511
|
+
if (validate.errors.length) {
|
|
1512
|
+
return validate.errors;
|
|
1513
|
+
}
|
|
1514
|
+
return null;
|
|
1515
|
+
}
|
|
1516
|
+
function coerceParserSchemaValues(schema, parsed) {
|
|
1517
|
+
if (!schema || parsed === null || typeof parsed === "undefined") {
|
|
1518
|
+
return parsed;
|
|
1519
|
+
}
|
|
1520
|
+
const type = getSchemaType(schema.type);
|
|
1521
|
+
if (type === "object" && isPlainObject(parsed)) {
|
|
1522
|
+
const properties = schema.properties || {};
|
|
1523
|
+
return Object.keys(parsed).reduce((output, key) => {
|
|
1524
|
+
const propertySchema = properties[key];
|
|
1525
|
+
output[key] = propertySchema ? coerceParserSchemaValues(propertySchema, parsed[key]) : parsed[key];
|
|
1526
|
+
return output;
|
|
1527
|
+
}, {});
|
|
1528
|
+
}
|
|
1529
|
+
if (type === "array" && Array.isArray(parsed) && schema.items) {
|
|
1530
|
+
return parsed.map(
|
|
1531
|
+
(item) => coerceParserSchemaValues(schema.items, item)
|
|
1532
|
+
);
|
|
1533
|
+
}
|
|
1534
|
+
if ((type === "number" || type === "integer") && typeof parsed === "string") {
|
|
1535
|
+
const trimmed = parsed.trim();
|
|
1536
|
+
if (trimmed !== "") {
|
|
1537
|
+
const value = Number(trimmed);
|
|
1538
|
+
if (Number.isFinite(value)) {
|
|
1539
|
+
return value;
|
|
684
1540
|
}
|
|
685
1541
|
}
|
|
686
1542
|
}
|
|
1543
|
+
if (type === "boolean" && typeof parsed === "string") {
|
|
1544
|
+
const normalized = parsed.trim().toLowerCase();
|
|
1545
|
+
if (normalized === "true") {
|
|
1546
|
+
return true;
|
|
1547
|
+
}
|
|
1548
|
+
if (normalized === "false") {
|
|
1549
|
+
return false;
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
return parsed;
|
|
1553
|
+
}
|
|
1554
|
+
function applyParserSchemaDefaultsAndFilter(schema, parsed) {
|
|
1555
|
+
if (!schema || parsed === null || typeof parsed === "undefined") {
|
|
1556
|
+
return parsed;
|
|
1557
|
+
}
|
|
1558
|
+
const type = getSchemaType(schema.type);
|
|
1559
|
+
if (type === "object" && isPlainObject(parsed)) {
|
|
1560
|
+
const properties = schema.properties;
|
|
1561
|
+
if (!properties) {
|
|
1562
|
+
return parsed;
|
|
1563
|
+
}
|
|
1564
|
+
const keepAdditionalProperties = schema.additionalProperties !== false;
|
|
1565
|
+
const initialOutput = keepAdditionalProperties ? { ...parsed } : {};
|
|
1566
|
+
return Object.keys(properties).reduce((output, key) => {
|
|
1567
|
+
const propertySchema = properties[key];
|
|
1568
|
+
const value = parsed[key];
|
|
1569
|
+
if (typeof value === "undefined") {
|
|
1570
|
+
if (typeof propertySchema?.default !== "undefined") {
|
|
1571
|
+
output[key] = propertySchema.default;
|
|
1572
|
+
}
|
|
1573
|
+
return output;
|
|
1574
|
+
}
|
|
1575
|
+
output[key] = applyParserSchemaDefaultsAndFilter(propertySchema, value);
|
|
1576
|
+
return output;
|
|
1577
|
+
}, initialOutput);
|
|
1578
|
+
}
|
|
1579
|
+
if (type === "array" && Array.isArray(parsed) && schema.items) {
|
|
1580
|
+
return parsed.map(
|
|
1581
|
+
(item) => applyParserSchemaDefaultsAndFilter(schema.items, item)
|
|
1582
|
+
);
|
|
1583
|
+
}
|
|
1584
|
+
return parsed;
|
|
687
1585
|
}
|
|
688
1586
|
|
|
689
|
-
// src/
|
|
690
|
-
|
|
691
|
-
{
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
{
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
{
|
|
710
|
-
{{
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
1587
|
+
// src/parser/parsers/JsonParser.ts
|
|
1588
|
+
function isPlainObject2(value) {
|
|
1589
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
1590
|
+
return false;
|
|
1591
|
+
}
|
|
1592
|
+
const proto = Object.getPrototypeOf(value);
|
|
1593
|
+
return proto === Object.prototype || proto === null;
|
|
1594
|
+
}
|
|
1595
|
+
function normalizeWholeResponseJsonText(input) {
|
|
1596
|
+
const trimmed = input.trim();
|
|
1597
|
+
const fenceMatch = trimmed.match(/^```([a-zA-Z]*)[^\S\r\n]*\r?\n([\s\S]*)```$/);
|
|
1598
|
+
if (!fenceMatch) {
|
|
1599
|
+
return trimmed;
|
|
1600
|
+
}
|
|
1601
|
+
const [, language, body] = fenceMatch;
|
|
1602
|
+
if (language && language.toLowerCase() !== "json") {
|
|
1603
|
+
return trimmed;
|
|
1604
|
+
}
|
|
1605
|
+
return body.trim();
|
|
1606
|
+
}
|
|
1607
|
+
var JsonParser = class extends BaseParserWithJson {
|
|
1608
|
+
constructor(options = {}) {
|
|
1609
|
+
super("json", options);
|
|
1610
|
+
__publicField(this, "shouldValidateSchema");
|
|
1611
|
+
this.shouldValidateSchema = !!options.schema && options.validateSchema !== false;
|
|
1612
|
+
}
|
|
1613
|
+
/**
|
|
1614
|
+
* v3 parser contract:
|
|
1615
|
+
* Category: strict
|
|
1616
|
+
* Mode: whole-output
|
|
1617
|
+
*
|
|
1618
|
+
* Parses strict JSON object/array output only. Invalid JSON, empty input,
|
|
1619
|
+
* JSON primitives, and non-plain runtime objects throw typed parser errors.
|
|
1620
|
+
* Schema validation is on by default when a schema is provided unless
|
|
1621
|
+
* validateSchema: false is explicitly set.
|
|
1622
|
+
*
|
|
1623
|
+
*/
|
|
1624
|
+
parse(text, _attributes) {
|
|
1625
|
+
let parsed;
|
|
1626
|
+
let inputLength;
|
|
1627
|
+
if (typeof text === "string") {
|
|
1628
|
+
inputLength = text.length;
|
|
1629
|
+
if (text.trim() === "") {
|
|
1630
|
+
throw new LlmExeError(`No JSON value found in input.`, {
|
|
1631
|
+
code: "parser.parse_failed",
|
|
1632
|
+
context: {
|
|
1633
|
+
operation: "JsonParser.parse",
|
|
1634
|
+
parser: "json",
|
|
1635
|
+
reason: "empty_input",
|
|
1636
|
+
expected: "JSON object or array",
|
|
1637
|
+
inputLength
|
|
1638
|
+
}
|
|
1639
|
+
});
|
|
1640
|
+
}
|
|
1641
|
+
try {
|
|
1642
|
+
parsed = JSON.parse(normalizeWholeResponseJsonText(text));
|
|
1643
|
+
} catch (cause) {
|
|
1644
|
+
throw new LlmExeError(`Invalid JSON input.`, {
|
|
1645
|
+
code: "parser.parse_failed",
|
|
1646
|
+
context: {
|
|
1647
|
+
operation: "JsonParser.parse",
|
|
1648
|
+
parser: "json",
|
|
1649
|
+
reason: "invalid_json",
|
|
1650
|
+
expected: "JSON object or array",
|
|
1651
|
+
inputLength
|
|
1652
|
+
},
|
|
1653
|
+
cause
|
|
1654
|
+
});
|
|
1655
|
+
}
|
|
1656
|
+
} else if (Array.isArray(text) || isPlainObject2(text)) {
|
|
1657
|
+
parsed = text;
|
|
1658
|
+
} else {
|
|
1659
|
+
throw new LlmExeError(
|
|
1660
|
+
`Invalid input. Expected JSON string, plain object, or array. Received ${text === null ? "null" : typeof text}.`,
|
|
1661
|
+
{
|
|
1662
|
+
code: "parser.invalid_input",
|
|
1663
|
+
context: {
|
|
1664
|
+
operation: "JsonParser.parse",
|
|
1665
|
+
parser: "json",
|
|
1666
|
+
reason: "invalid_input_type",
|
|
1667
|
+
expected: "JSON string, plain object, or array",
|
|
1668
|
+
received: text === null ? "null" : typeof text
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
);
|
|
1672
|
+
}
|
|
1673
|
+
if (!Array.isArray(parsed) && !isPlainObject2(parsed)) {
|
|
1674
|
+
throw new LlmExeError(`Invalid JSON root type.`, {
|
|
1675
|
+
code: "parser.parse_failed",
|
|
1676
|
+
context: {
|
|
1677
|
+
operation: "JsonParser.parse",
|
|
1678
|
+
parser: "json",
|
|
1679
|
+
reason: "invalid_json_root_type",
|
|
1680
|
+
expected: "JSON object or array",
|
|
1681
|
+
received: parsed === null ? "null" : typeof parsed,
|
|
1682
|
+
inputLength
|
|
1683
|
+
}
|
|
1684
|
+
});
|
|
1685
|
+
}
|
|
1686
|
+
if (this.schema) {
|
|
1687
|
+
if (this.shouldValidateSchema) {
|
|
1688
|
+
const valid = validateParserSchema(this.schema, parsed);
|
|
1689
|
+
if (valid && valid.length) {
|
|
1690
|
+
throw new LlmExeError(valid[0].message, {
|
|
1691
|
+
code: "parser.schema_validation_failed",
|
|
1692
|
+
context: {
|
|
1693
|
+
operation: "JsonParser.parse",
|
|
1694
|
+
parser: "json",
|
|
1695
|
+
schemaErrors: valid.map((error) => error.message)
|
|
1696
|
+
}
|
|
1697
|
+
});
|
|
1698
|
+
}
|
|
1699
|
+
}
|
|
1700
|
+
if (this.shouldValidateSchema) {
|
|
1701
|
+
return applyParserSchemaDefaultsAndFilter(
|
|
1702
|
+
this.schema,
|
|
1703
|
+
parsed
|
|
1704
|
+
);
|
|
1705
|
+
}
|
|
1706
|
+
return enforceParserSchema(this.schema, parsed);
|
|
1707
|
+
}
|
|
1708
|
+
return parsed;
|
|
1709
|
+
}
|
|
1710
|
+
};
|
|
1711
|
+
|
|
1712
|
+
// src/utils/modules/camelCase.ts
|
|
1713
|
+
function camelCase(input) {
|
|
1714
|
+
if (!input) return input;
|
|
1715
|
+
input = input.replace(/[^a-zA-Z0-9_]+/g, " ").trim();
|
|
1716
|
+
const words = input.split(/\s+|_/);
|
|
1717
|
+
return words.map((word, index) => {
|
|
1718
|
+
if (index === 0) {
|
|
1719
|
+
return word.toLowerCase();
|
|
1720
|
+
} else {
|
|
1721
|
+
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
|
1722
|
+
}
|
|
1723
|
+
}).join("");
|
|
1724
|
+
}
|
|
1725
|
+
|
|
1726
|
+
// src/parser/_listBoundary.ts
|
|
1727
|
+
var LIST_MARKER_PATTERN = /^(?:[-*]\s+|\d+\.\s+|•\s*)/;
|
|
1728
|
+
function normalizeListLines(input, context) {
|
|
1729
|
+
const lines = input.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
|
|
1730
|
+
if (lines.length === 0) {
|
|
1731
|
+
throw new LlmExeError(`No list items found in input.`, {
|
|
1732
|
+
code: "parser.parse_failed",
|
|
1733
|
+
context: {
|
|
1734
|
+
operation: context.operation,
|
|
1735
|
+
parser: context.parser,
|
|
1736
|
+
reason: "empty_input",
|
|
1737
|
+
inputLength: input.length
|
|
1738
|
+
}
|
|
1739
|
+
});
|
|
1740
|
+
}
|
|
1741
|
+
const markedStates = lines.map((line) => LIST_MARKER_PATTERN.test(line));
|
|
1742
|
+
const hasMarked = markedStates.some(Boolean);
|
|
1743
|
+
const hasUnmarked = markedStates.some((marked) => !marked);
|
|
1744
|
+
if (hasMarked && hasUnmarked) {
|
|
1745
|
+
throw new LlmExeError(`Mixed marked and unmarked list items found.`, {
|
|
1746
|
+
code: "parser.parse_failed",
|
|
1747
|
+
context: {
|
|
1748
|
+
operation: context.operation,
|
|
1749
|
+
parser: context.parser,
|
|
1750
|
+
reason: "mixed_list_markers",
|
|
1751
|
+
inputLength: input.length
|
|
1752
|
+
}
|
|
1753
|
+
});
|
|
1754
|
+
}
|
|
1755
|
+
return {
|
|
1756
|
+
lines: hasMarked ? lines.map((line) => line.replace(LIST_MARKER_PATTERN, "").trim()) : lines,
|
|
1757
|
+
marked: hasMarked
|
|
1758
|
+
};
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
// src/parser/parsers/ListToJsonParser.ts
|
|
1762
|
+
var ListToJsonParser = class extends BaseParserWithJson {
|
|
1763
|
+
constructor(options = {}) {
|
|
1764
|
+
super("listToJson", options);
|
|
1765
|
+
__publicField(this, "keyTransform");
|
|
1766
|
+
__publicField(this, "shouldValidateSchema");
|
|
1767
|
+
this.keyTransform = options.keyTransform ?? "camelCase";
|
|
1768
|
+
this.shouldValidateSchema = !!options.schema && options.validateSchema !== false;
|
|
1769
|
+
}
|
|
1770
|
+
/**
|
|
1771
|
+
* v3 parser contract:
|
|
1772
|
+
* Category: converter
|
|
1773
|
+
* Mode: line-oriented format conversion
|
|
1774
|
+
*
|
|
1775
|
+
* Uses the shared list boundary. Parses normalized lines as key/value pairs
|
|
1776
|
+
* split at the first colon. Duplicate keys throw because object output would
|
|
1777
|
+
* overwrite data.
|
|
1778
|
+
*
|
|
1779
|
+
*/
|
|
1780
|
+
parse(text) {
|
|
1781
|
+
if (typeof text !== "string") {
|
|
1782
|
+
throw new LlmExeError(
|
|
1783
|
+
`Invalid input. Expected string. Received ${text === null ? "null" : Array.isArray(text) ? "array" : typeof text}.`,
|
|
1784
|
+
{
|
|
1785
|
+
code: "parser.invalid_input",
|
|
1786
|
+
context: {
|
|
1787
|
+
operation: "ListToJsonParser.parse",
|
|
1788
|
+
parser: "listToJson",
|
|
1789
|
+
reason: "invalid_input_type",
|
|
1790
|
+
expected: "string",
|
|
1791
|
+
received: text === null ? "null" : Array.isArray(text) ? "array" : typeof text
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
);
|
|
1795
|
+
}
|
|
1796
|
+
const { lines } = normalizeListLines(text, {
|
|
1797
|
+
operation: "ListToJsonParser.parse",
|
|
1798
|
+
parser: "listToJson"
|
|
1799
|
+
});
|
|
1800
|
+
const output = {};
|
|
1801
|
+
lines.forEach((line) => {
|
|
1802
|
+
const colonIndex = line.indexOf(":");
|
|
1803
|
+
if (colonIndex === -1) {
|
|
1804
|
+
throw new LlmExeError(`Malformed key/value line.`, {
|
|
1805
|
+
code: "parser.parse_failed",
|
|
1806
|
+
context: {
|
|
1807
|
+
operation: "ListToJsonParser.parse",
|
|
1808
|
+
parser: "listToJson",
|
|
1809
|
+
reason: "malformed_line",
|
|
1810
|
+
inputLength: text.length
|
|
1811
|
+
}
|
|
1812
|
+
});
|
|
1813
|
+
}
|
|
1814
|
+
const key = line.slice(0, colonIndex).trim();
|
|
1815
|
+
if (!key) {
|
|
1816
|
+
throw new LlmExeError(`Empty key in key/value line.`, {
|
|
1817
|
+
code: "parser.parse_failed",
|
|
1818
|
+
context: {
|
|
1819
|
+
operation: "ListToJsonParser.parse",
|
|
1820
|
+
parser: "listToJson",
|
|
1821
|
+
reason: "empty_key",
|
|
1822
|
+
inputLength: text.length
|
|
1823
|
+
}
|
|
1824
|
+
});
|
|
1825
|
+
}
|
|
1826
|
+
const transformedKey = this.keyTransform === "preserve" ? key : camelCase(key);
|
|
1827
|
+
if (Object.prototype.hasOwnProperty.call(output, transformedKey)) {
|
|
1828
|
+
throw new LlmExeError(`Duplicate key in key/value input.`, {
|
|
1829
|
+
code: "parser.parse_failed",
|
|
1830
|
+
context: {
|
|
1831
|
+
operation: "ListToJsonParser.parse",
|
|
1832
|
+
parser: "listToJson",
|
|
1833
|
+
reason: "duplicate_key",
|
|
1834
|
+
inputLength: text.length
|
|
1835
|
+
}
|
|
1836
|
+
});
|
|
1837
|
+
}
|
|
1838
|
+
output[transformedKey] = line.slice(colonIndex + 1).trim();
|
|
1839
|
+
});
|
|
1840
|
+
if (this.schema) {
|
|
1841
|
+
const coerced = coerceParserSchemaValues(this.schema, output);
|
|
1842
|
+
if (this.shouldValidateSchema) {
|
|
1843
|
+
const valid = validateParserSchema(this.schema, coerced);
|
|
1844
|
+
if (valid && valid.length) {
|
|
1845
|
+
throw new LlmExeError(valid[0].message, {
|
|
1846
|
+
code: "parser.schema_validation_failed",
|
|
1847
|
+
context: {
|
|
1848
|
+
operation: "ListToJsonParser.parse",
|
|
1849
|
+
parser: "listToJson",
|
|
1850
|
+
schemaErrors: valid.map((error) => error.message)
|
|
1851
|
+
}
|
|
1852
|
+
});
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1855
|
+
return applyParserSchemaDefaultsAndFilter(this.schema, coerced);
|
|
1856
|
+
}
|
|
1857
|
+
return output;
|
|
1858
|
+
}
|
|
1859
|
+
};
|
|
1860
|
+
|
|
1861
|
+
// src/parser/parsers/ListToKeyValueParser.ts
|
|
1862
|
+
var ListToKeyValueParser = class extends BaseParser {
|
|
1863
|
+
constructor(options) {
|
|
1864
|
+
super("listToKeyValue");
|
|
1865
|
+
__publicField(this, "keyTransform");
|
|
1866
|
+
this.keyTransform = options?.keyTransform ?? "preserve";
|
|
1867
|
+
}
|
|
1868
|
+
/**
|
|
1869
|
+
* v3 parser contract:
|
|
1870
|
+
* Category: converter
|
|
1871
|
+
* Mode: line-oriented collector
|
|
1872
|
+
*
|
|
1873
|
+
* Uses the shared list boundary. Parses normalized lines as key/value pairs
|
|
1874
|
+
* split at the first colon. Preserves duplicate keys because output is an
|
|
1875
|
+
* ordered array. Keys are returned as written by default; pass
|
|
1876
|
+
* keyTransform: "camelCase" to match listToJson's key normalization.
|
|
1877
|
+
*
|
|
1878
|
+
*/
|
|
1879
|
+
parse(text, _attributes) {
|
|
1880
|
+
if (typeof text !== "string") {
|
|
1881
|
+
throw new LlmExeError(
|
|
1882
|
+
`Invalid input. Expected string. Received ${text === null ? "null" : Array.isArray(text) ? "array" : typeof text}.`,
|
|
1883
|
+
{
|
|
1884
|
+
code: "parser.invalid_input",
|
|
1885
|
+
context: {
|
|
1886
|
+
operation: "ListToKeyValueParser.parse",
|
|
1887
|
+
parser: "listToKeyValue",
|
|
1888
|
+
reason: "invalid_input_type",
|
|
1889
|
+
expected: "string",
|
|
1890
|
+
received: text === null ? "null" : Array.isArray(text) ? "array" : typeof text
|
|
1891
|
+
}
|
|
1892
|
+
}
|
|
1893
|
+
);
|
|
1894
|
+
}
|
|
1895
|
+
const { lines } = normalizeListLines(text, {
|
|
1896
|
+
operation: "ListToKeyValueParser.parse",
|
|
1897
|
+
parser: "listToKeyValue"
|
|
1898
|
+
});
|
|
1899
|
+
let res = [];
|
|
1900
|
+
for (const line of lines) {
|
|
1901
|
+
const colonIndex = line.indexOf(":");
|
|
1902
|
+
if (colonIndex === -1) {
|
|
1903
|
+
throw new LlmExeError(`Malformed key/value line.`, {
|
|
1904
|
+
code: "parser.parse_failed",
|
|
1905
|
+
context: {
|
|
1906
|
+
operation: "ListToKeyValueParser.parse",
|
|
1907
|
+
parser: "listToKeyValue",
|
|
1908
|
+
reason: "malformed_line",
|
|
1909
|
+
inputLength: text.length
|
|
1910
|
+
}
|
|
1911
|
+
});
|
|
1912
|
+
}
|
|
1913
|
+
const rawKey = line.slice(0, colonIndex).trim();
|
|
1914
|
+
if (!rawKey) {
|
|
1915
|
+
throw new LlmExeError(`Empty key in key/value line.`, {
|
|
1916
|
+
code: "parser.parse_failed",
|
|
1917
|
+
context: {
|
|
1918
|
+
operation: "ListToKeyValueParser.parse",
|
|
1919
|
+
parser: "listToKeyValue",
|
|
1920
|
+
reason: "empty_key",
|
|
1921
|
+
inputLength: text.length
|
|
1922
|
+
}
|
|
1923
|
+
});
|
|
1924
|
+
}
|
|
1925
|
+
const key = this.keyTransform === "camelCase" ? camelCase(rawKey) : rawKey;
|
|
1926
|
+
res.push({ key, value: line.slice(colonIndex + 1).trim() });
|
|
1927
|
+
}
|
|
1928
|
+
return res;
|
|
1929
|
+
}
|
|
1930
|
+
};
|
|
1931
|
+
|
|
1932
|
+
// src/parser/parsers/CustomParser.ts
|
|
1933
|
+
var CustomParser = class extends BaseParser {
|
|
1934
|
+
constructor(name, parserFn) {
|
|
1935
|
+
super(name);
|
|
1936
|
+
__publicField(this, "parserFn");
|
|
1937
|
+
this.parserFn = parserFn;
|
|
1938
|
+
}
|
|
1939
|
+
parse(text, context) {
|
|
1940
|
+
return this.parserFn.call(this, text, context);
|
|
1941
|
+
}
|
|
1942
|
+
};
|
|
1943
|
+
|
|
1944
|
+
// src/parser/parsers/ListToArrayParser.ts
|
|
1945
|
+
var ListToArrayParser = class extends BaseParser {
|
|
1946
|
+
constructor() {
|
|
1947
|
+
super("listToArray");
|
|
1948
|
+
}
|
|
1949
|
+
parse(text, _attributes) {
|
|
1950
|
+
if (typeof text !== "string") {
|
|
1951
|
+
throw new LlmExeError(
|
|
1952
|
+
`Invalid input. Expected string. Received ${text === null ? "null" : Array.isArray(text) ? "array" : typeof text}.`,
|
|
1953
|
+
{
|
|
1954
|
+
code: "parser.invalid_input",
|
|
1955
|
+
context: {
|
|
1956
|
+
operation: "ListToArrayParser.parse",
|
|
1957
|
+
parser: "listToArray",
|
|
1958
|
+
reason: "invalid_input_type",
|
|
1959
|
+
expected: "string",
|
|
1960
|
+
received: text === null ? "null" : Array.isArray(text) ? "array" : typeof text
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
);
|
|
1964
|
+
}
|
|
1965
|
+
const normalized = normalizeListLines(text, {
|
|
1966
|
+
operation: "ListToArrayParser.parse",
|
|
1967
|
+
parser: "listToArray"
|
|
1968
|
+
});
|
|
1969
|
+
if (!normalized.marked && normalized.lines.length === 1) {
|
|
1970
|
+
throw new LlmExeError(`Input is not list-like.`, {
|
|
1971
|
+
code: "parser.parse_failed",
|
|
1972
|
+
context: {
|
|
1973
|
+
operation: "ListToArrayParser.parse",
|
|
1974
|
+
parser: "listToArray",
|
|
1975
|
+
reason: "not_list_like",
|
|
1976
|
+
inputLength: text.length
|
|
1977
|
+
}
|
|
1978
|
+
});
|
|
1979
|
+
}
|
|
1980
|
+
return normalized.lines;
|
|
1981
|
+
}
|
|
1982
|
+
};
|
|
1983
|
+
|
|
1984
|
+
// src/utils/modules/handlebars/hbs.ts
|
|
1985
|
+
import Handlebars from "handlebars";
|
|
1986
|
+
|
|
1987
|
+
// src/utils/modules/handlebars/utils/registerHelpers.ts
|
|
1988
|
+
function _registerHelpers(helpers, instance) {
|
|
1989
|
+
if (helpers && Array.isArray(helpers)) {
|
|
1990
|
+
for (const helper of helpers) {
|
|
1991
|
+
if (helper.name && typeof helper.name === "string" && typeof helper.handler === "function") {
|
|
1992
|
+
if (instance) {
|
|
1993
|
+
instance.registerHelper(helper.name, helper.handler);
|
|
1994
|
+
}
|
|
1995
|
+
}
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
}
|
|
1999
|
+
|
|
2000
|
+
// src/utils/modules/handlebars/templates/index.ts
|
|
2001
|
+
var MarkdownCode = `{{#if code}}\`\`\`{{#if language}}{{language}}{{/if}}
|
|
2002
|
+
{{{code}}}
|
|
2003
|
+
\`\`\`{{/if}}`;
|
|
2004
|
+
var ThoughtActionResult = `
|
|
2005
|
+
{{#if title}}{{#if attributes.stepsTaken.length}}{{title}}
|
|
2006
|
+
{{/if}}{{/if}}
|
|
2007
|
+
{{#each attributes.stepsTaken as | step |}}
|
|
2008
|
+
{{#if step.thought}}Thought: {{step.result}}{{/if}}
|
|
2009
|
+
{{#if step.result}}Action: {{step.action}}{{/if}}
|
|
2010
|
+
{{#if step.result}}Result: {{step.result}}{{/if}}
|
|
2011
|
+
{{/each}}`;
|
|
2012
|
+
var ChatConversationHistory = `{{~#if title}}{{~#if chat_history.length}}{{title}}
|
|
2013
|
+
{{~/if}}{{~/if}}
|
|
2014
|
+
{{#each chat_history as | item |}}
|
|
2015
|
+
{{~#eq item.role 'user'}}{{#if @last}}{{../mostRecentRolePrefix}}{{../userName}}{{../mostRecentRoleSuffix}}{{else}}{{../userName}}{{/if}}: {{#if @last}}{{../mostRecentMessagePrefix}}{{/if}}{{{item.content}}}{{#if @last}}{{../mostRecentMessageSuffix}}{{/if}}
|
|
2016
|
+
{{/eq}}
|
|
2017
|
+
{{~#eq item.role 'assistant'}}{{#if @last}}{{../mostRecentRolePrefix}}{{../assistantName}}{{../mostRecentRoleSuffix}}{{else}}{{../assistantName}}{{/if}}: {{#if @last}}{{../mostRecentMessagePrefix}}{{/if}}{{{item.content}}}{{#if @last}}{{../mostRecentMessageSuffix}}{{/if}}
|
|
2018
|
+
{{/eq}}
|
|
2019
|
+
{{~#eq item.role 'system'}}{{../systemName}}: {{{item.content}}}
|
|
2020
|
+
{{/eq}}
|
|
2021
|
+
{{~/each}}`;
|
|
2022
|
+
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}}`;
|
|
2023
|
+
var SingleChatMessage = `{{~#eq role 'user'}}{{getOr name 'User'}}: {{{content}}}{{~/eq}}
|
|
2024
|
+
{{~#eq role 'assistant'}}{{getOr assistant 'Assistant'}}: {{{content}}}{{~/eq}}
|
|
2025
|
+
{{~#eq role 'system'}}{{getOr system 'System'}}: {{{content}}}{{~/eq}}`;
|
|
2026
|
+
var ThoughtsAndObservations = `{{~#each thoughts as | step |}}
|
|
2027
|
+
{{~#if step.thought}}Thought: {{{step.thought}}}
|
|
2028
|
+
{{/if}}
|
|
2029
|
+
{{~#if step.observation}}Observation: {{{step.observation}}}
|
|
2030
|
+
{{/if}}
|
|
2031
|
+
{{~/each}}`;
|
|
2032
|
+
var JsonSchema = `{{#if (getKeyOr key false)}}
|
|
2033
|
+
\`\`\`json
|
|
2034
|
+
{{{indentJson (getKeyOr key) collapse}}}
|
|
2035
|
+
\`\`\`
|
|
2036
|
+
{{~/if}}`;
|
|
2037
|
+
var JsonSchemaExampleJson = `{{#if (getOr key false)}}
|
|
2038
|
+
\`\`\`json
|
|
2039
|
+
{{{jsonSchemaExample key (getOr property '') collapse}}}
|
|
2040
|
+
\`\`\`
|
|
2041
|
+
{{~/if}}`;
|
|
2042
|
+
var partials = {
|
|
2043
|
+
JsonSchema,
|
|
2044
|
+
JsonSchemaExampleJson,
|
|
734
2045
|
MarkdownCode,
|
|
735
2046
|
DialogueHistory,
|
|
736
2047
|
SingleChatMessage,
|
|
@@ -1047,7 +2358,15 @@ function isEmpty(value) {
|
|
|
1047
2358
|
// src/utils/modules/handlebars/helpers/async/with.ts
|
|
1048
2359
|
async function withFnAsync(context, options) {
|
|
1049
2360
|
if (arguments.length !== 2) {
|
|
1050
|
-
throw new
|
|
2361
|
+
throw new LlmExeError("#with requires exactly one argument", {
|
|
2362
|
+
code: "template.invalid_helper_arguments",
|
|
2363
|
+
context: {
|
|
2364
|
+
operation: "handlebars.asyncHelper.with",
|
|
2365
|
+
helper: "with",
|
|
2366
|
+
expected: 1,
|
|
2367
|
+
received: arguments.length
|
|
2368
|
+
}
|
|
2369
|
+
});
|
|
1051
2370
|
}
|
|
1052
2371
|
if (isPromise(context)) {
|
|
1053
2372
|
context = await context;
|
|
@@ -1075,7 +2394,15 @@ async function withFnAsync(context, options) {
|
|
|
1075
2394
|
// src/utils/modules/handlebars/helpers/async/if.ts
|
|
1076
2395
|
async function ifFnAsync(conditional, options) {
|
|
1077
2396
|
if (arguments.length !== 2) {
|
|
1078
|
-
throw new
|
|
2397
|
+
throw new LlmExeError("#if requires exactly one argument", {
|
|
2398
|
+
code: "template.invalid_helper_arguments",
|
|
2399
|
+
context: {
|
|
2400
|
+
operation: "handlebars.asyncHelper.if",
|
|
2401
|
+
helper: "if",
|
|
2402
|
+
expected: 1,
|
|
2403
|
+
received: arguments.length
|
|
2404
|
+
}
|
|
2405
|
+
});
|
|
1079
2406
|
}
|
|
1080
2407
|
if (isPromise(conditional)) {
|
|
1081
2408
|
conditional = await conditional;
|
|
@@ -1097,7 +2424,15 @@ function isReadableStream(obj) {
|
|
|
1097
2424
|
// src/utils/modules/handlebars/helpers/async/each.ts
|
|
1098
2425
|
async function eachFnAsync(arg1, options) {
|
|
1099
2426
|
if (!options) {
|
|
1100
|
-
throw new
|
|
2427
|
+
throw new LlmExeError("Must pass iterator to #each", {
|
|
2428
|
+
code: "template.invalid_helper_arguments",
|
|
2429
|
+
context: {
|
|
2430
|
+
operation: "handlebars.asyncHelper.each",
|
|
2431
|
+
helper: "each",
|
|
2432
|
+
expected: "an iterator",
|
|
2433
|
+
received: typeof options
|
|
2434
|
+
}
|
|
2435
|
+
});
|
|
1101
2436
|
}
|
|
1102
2437
|
const { fn } = options;
|
|
1103
2438
|
const { inverse } = options;
|
|
@@ -1193,7 +2528,15 @@ async function eachFnAsync(arg1, options) {
|
|
|
1193
2528
|
// src/utils/modules/handlebars/helpers/async/unless.ts
|
|
1194
2529
|
async function unlessFnAsync(conditional, options) {
|
|
1195
2530
|
if (arguments.length !== 2) {
|
|
1196
|
-
throw new
|
|
2531
|
+
throw new LlmExeError("#unless requires exactly one argument", {
|
|
2532
|
+
code: "template.invalid_helper_arguments",
|
|
2533
|
+
context: {
|
|
2534
|
+
operation: "handlebars.asyncHelper.unless",
|
|
2535
|
+
helper: "unless",
|
|
2536
|
+
expected: 1,
|
|
2537
|
+
received: arguments.length
|
|
2538
|
+
}
|
|
2539
|
+
});
|
|
1197
2540
|
}
|
|
1198
2541
|
return ifFnAsync.call(this, conditional, {
|
|
1199
2542
|
fn: options.inverse,
|
|
@@ -1387,434 +2730,609 @@ function replaceTemplateString(templateString, substitutions = {}, configuration
|
|
|
1387
2730
|
return res;
|
|
1388
2731
|
}
|
|
1389
2732
|
|
|
1390
|
-
// src/
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
}) {
|
|
1395
|
-
if (!templateString) return Promise.resolve(templateString || "");
|
|
1396
|
-
const tempHelpers = [];
|
|
1397
|
-
const tempPartials = [];
|
|
1398
|
-
if (Array.isArray(configuration.helpers)) {
|
|
1399
|
-
hbsAsync.registerHelpers(configuration.helpers);
|
|
1400
|
-
tempHelpers.push(...configuration.helpers.map((a) => a.name));
|
|
1401
|
-
}
|
|
1402
|
-
if (Array.isArray(configuration.partials)) {
|
|
1403
|
-
hbsAsync.registerPartials(configuration.partials);
|
|
1404
|
-
tempPartials.push(...configuration.partials.map((a) => a.name));
|
|
2733
|
+
// src/parser/parsers/ReplaceStringTemplateParser.ts
|
|
2734
|
+
var ReplaceStringTemplateParser = class extends BaseParser {
|
|
2735
|
+
constructor() {
|
|
2736
|
+
super("replaceStringTemplate");
|
|
1405
2737
|
}
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
}
|
|
1420
|
-
|
|
1421
|
-
// src/utils/modules/asyncCallWithTimeout.ts
|
|
1422
|
-
var asyncCallWithTimeout = async (asyncPromise, timeLimit = 1e4) => {
|
|
1423
|
-
let timeoutHandle;
|
|
1424
|
-
const timeoutPromise = new Promise((_resolve, reject) => {
|
|
1425
|
-
timeoutHandle = setTimeout(() => {
|
|
1426
|
-
return reject(
|
|
1427
|
-
new Error(`LLM call timed out after ${timeLimit}ms`)
|
|
2738
|
+
parse(text, attributes) {
|
|
2739
|
+
if (typeof text !== "string") {
|
|
2740
|
+
throw new LlmExeError(
|
|
2741
|
+
`Invalid input. Expected string. Received ${text === null ? "null" : Array.isArray(text) ? "array" : typeof text}.`,
|
|
2742
|
+
{
|
|
2743
|
+
code: "parser.invalid_input",
|
|
2744
|
+
context: {
|
|
2745
|
+
operation: "ReplaceStringTemplateParser.parse",
|
|
2746
|
+
parser: "replaceStringTemplate",
|
|
2747
|
+
reason: "invalid_input_type",
|
|
2748
|
+
expected: "string",
|
|
2749
|
+
received: text === null ? "null" : Array.isArray(text) ? "array" : typeof text
|
|
2750
|
+
}
|
|
2751
|
+
}
|
|
1428
2752
|
);
|
|
1429
|
-
}
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
if (model.startsWith("gpt-") || model.startsWith("chatgpt-")) {
|
|
1440
|
-
return true;
|
|
1441
|
-
}
|
|
1442
|
-
if (model === "o1" || model.startsWith("o1-")) {
|
|
1443
|
-
return true;
|
|
1444
|
-
}
|
|
1445
|
-
if (model === "o3-mini") {
|
|
1446
|
-
return true;
|
|
1447
|
-
}
|
|
1448
|
-
return false;
|
|
1449
|
-
}
|
|
1450
|
-
function isModelKnownAnthropic(payload) {
|
|
1451
|
-
const model = payload.model.toLowerCase();
|
|
1452
|
-
if (model.startsWith("claude-")) {
|
|
1453
|
-
return true;
|
|
1454
|
-
}
|
|
1455
|
-
return false;
|
|
1456
|
-
}
|
|
1457
|
-
function isModelKnownXai(payload) {
|
|
1458
|
-
const model = payload.model.toLowerCase();
|
|
1459
|
-
if (model.startsWith("grok-")) {
|
|
1460
|
-
return true;
|
|
1461
|
-
}
|
|
1462
|
-
return false;
|
|
1463
|
-
}
|
|
1464
|
-
function isModelKnownBedrockAnthropic(payload) {
|
|
1465
|
-
const model = payload.model.toLowerCase();
|
|
1466
|
-
if (model.startsWith("anthropic.claude-")) {
|
|
1467
|
-
return true;
|
|
1468
|
-
}
|
|
1469
|
-
return false;
|
|
1470
|
-
}
|
|
1471
|
-
function guessProviderFromModel(payload) {
|
|
1472
|
-
switch (true) {
|
|
1473
|
-
case isModelKnownOpenAi(payload):
|
|
1474
|
-
return "openai";
|
|
1475
|
-
case isModelKnownXai(payload):
|
|
1476
|
-
return "xai";
|
|
1477
|
-
case isModelKnownBedrockAnthropic(payload):
|
|
1478
|
-
return "bedrock:anthropic";
|
|
1479
|
-
case isModelKnownAnthropic(payload):
|
|
1480
|
-
return "anthropic";
|
|
1481
|
-
default:
|
|
1482
|
-
throw new Error("Unsupported model");
|
|
1483
|
-
}
|
|
1484
|
-
}
|
|
1485
|
-
|
|
1486
|
-
// src/utils/modules/index.ts
|
|
1487
|
-
function registerHelpers(helpers) {
|
|
1488
|
-
hbs.registerHelpers(helpers);
|
|
1489
|
-
hbsAsync.registerHelpers(helpers);
|
|
1490
|
-
}
|
|
1491
|
-
function registerPartials(partials2) {
|
|
1492
|
-
hbs.registerPartials(partials2);
|
|
1493
|
-
hbsAsync.registerPartials(partials2);
|
|
1494
|
-
}
|
|
1495
|
-
|
|
1496
|
-
// src/parser/_utils.ts
|
|
1497
|
-
import { validate as validateSchema } from "jsonschema";
|
|
1498
|
-
function enforceParserSchema(schema, parsed) {
|
|
1499
|
-
if (!schema || !parsed || typeof parsed !== "object") {
|
|
1500
|
-
return parsed;
|
|
1501
|
-
}
|
|
1502
|
-
return filterObjectOnSchema(schema, parsed);
|
|
1503
|
-
}
|
|
1504
|
-
function validateParserSchema(schema, parsed) {
|
|
1505
|
-
if (!schema || !parsed || typeof parsed !== "object") {
|
|
1506
|
-
return null;
|
|
1507
|
-
}
|
|
1508
|
-
const validate = validateSchema(parsed, schema);
|
|
1509
|
-
if (validate.errors.length) {
|
|
1510
|
-
return validate.errors;
|
|
1511
|
-
}
|
|
1512
|
-
return null;
|
|
1513
|
-
}
|
|
1514
|
-
|
|
1515
|
-
// src/parser/parsers/JsonParser.ts
|
|
1516
|
-
var JsonParser = class extends BaseParserWithJson {
|
|
1517
|
-
constructor(options = {}) {
|
|
1518
|
-
super("json", options);
|
|
1519
|
-
}
|
|
1520
|
-
parse(text, _attributes) {
|
|
1521
|
-
const parsed = maybeParseJSON(helpJsonMarkup(text));
|
|
1522
|
-
if (this.schema) {
|
|
1523
|
-
const enforce = enforceParserSchema(this.schema, parsed);
|
|
1524
|
-
if (this.validateSchema) {
|
|
1525
|
-
const valid = validateParserSchema(this.schema, enforce);
|
|
1526
|
-
if (valid && valid.length) {
|
|
1527
|
-
throw new LlmExeError(valid[0].message, "parser", {
|
|
1528
|
-
parser: "json",
|
|
1529
|
-
output: parsed,
|
|
1530
|
-
error: valid[0].message
|
|
1531
|
-
});
|
|
2753
|
+
}
|
|
2754
|
+
if (attributes !== void 0 && (attributes === null || typeof attributes !== "object" || Array.isArray(attributes))) {
|
|
2755
|
+
throw new LlmExeError(`Invalid attributes. Expected object.`, {
|
|
2756
|
+
code: "parser.invalid_input",
|
|
2757
|
+
context: {
|
|
2758
|
+
operation: "ReplaceStringTemplateParser.parse",
|
|
2759
|
+
parser: "replaceStringTemplate",
|
|
2760
|
+
reason: "invalid_attributes",
|
|
2761
|
+
expected: "object",
|
|
2762
|
+
received: attributes === null ? "null" : Array.isArray(attributes) ? "array" : typeof attributes
|
|
1532
2763
|
}
|
|
2764
|
+
});
|
|
2765
|
+
}
|
|
2766
|
+
try {
|
|
2767
|
+
return replaceTemplateString(text, attributes);
|
|
2768
|
+
} catch (cause) {
|
|
2769
|
+
let received = typeof cause;
|
|
2770
|
+
if (cause instanceof Error) {
|
|
2771
|
+
received = cause.name;
|
|
1533
2772
|
}
|
|
1534
|
-
|
|
2773
|
+
throw new LlmExeError(`Template replacement failed.`, {
|
|
2774
|
+
code: "parser.parse_failed",
|
|
2775
|
+
context: {
|
|
2776
|
+
operation: "ReplaceStringTemplateParser.parse",
|
|
2777
|
+
parser: "replaceStringTemplate",
|
|
2778
|
+
reason: "template_replacement_failed",
|
|
2779
|
+
inputLength: text.length,
|
|
2780
|
+
received
|
|
2781
|
+
},
|
|
2782
|
+
cause
|
|
2783
|
+
});
|
|
1535
2784
|
}
|
|
1536
|
-
return parsed;
|
|
1537
2785
|
}
|
|
1538
2786
|
};
|
|
1539
2787
|
|
|
1540
|
-
// src/
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
const words = input.split(/\s+|_/);
|
|
1545
|
-
return words.map((word, index) => {
|
|
1546
|
-
if (index === 0) {
|
|
1547
|
-
return word.toLowerCase();
|
|
1548
|
-
} else {
|
|
1549
|
-
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
|
1550
|
-
}
|
|
1551
|
-
}).join("");
|
|
1552
|
-
}
|
|
1553
|
-
|
|
1554
|
-
// src/parser/parsers/ListToJsonParser.ts
|
|
1555
|
-
var ListToJsonParser = class extends BaseParserWithJson {
|
|
1556
|
-
constructor(options = {}) {
|
|
1557
|
-
super("listToJson", options);
|
|
1558
|
-
__publicField(this, "keyTransform");
|
|
1559
|
-
this.keyTransform = options.keyTransform ?? "camelCase";
|
|
2788
|
+
// src/parser/parsers/MarkdownCodeBlocks.ts
|
|
2789
|
+
var MarkdownCodeBlocksParser = class extends BaseParser {
|
|
2790
|
+
constructor() {
|
|
2791
|
+
super("markdownCodeBlocks");
|
|
1560
2792
|
}
|
|
1561
|
-
parse(
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
2793
|
+
parse(input, _attributes) {
|
|
2794
|
+
if (typeof input !== "string") {
|
|
2795
|
+
throw new LlmExeError(
|
|
2796
|
+
`Invalid input. Expected string. Received ${input === null ? "null" : Array.isArray(input) ? "array" : typeof input}.`,
|
|
2797
|
+
{
|
|
2798
|
+
code: "parser.invalid_input",
|
|
2799
|
+
context: {
|
|
2800
|
+
operation: "MarkdownCodeBlocksParser.parse",
|
|
2801
|
+
parser: "markdownCodeBlocks",
|
|
2802
|
+
reason: "invalid_input_type",
|
|
2803
|
+
expected: "string",
|
|
2804
|
+
received: input === null ? "null" : Array.isArray(input) ? "array" : typeof input
|
|
2805
|
+
}
|
|
1572
2806
|
}
|
|
1573
|
-
|
|
1574
|
-
}
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
2807
|
+
);
|
|
2808
|
+
}
|
|
2809
|
+
const out = [];
|
|
2810
|
+
const fenceCount = input.match(/```/g)?.length ?? 0;
|
|
2811
|
+
if (fenceCount % 2 !== 0) {
|
|
2812
|
+
throw new LlmExeError(`Malformed markdown code block.`, {
|
|
2813
|
+
code: "parser.parse_failed",
|
|
2814
|
+
context: {
|
|
2815
|
+
operation: "MarkdownCodeBlocksParser.parse",
|
|
2816
|
+
parser: "markdownCodeBlocks",
|
|
2817
|
+
reason: "malformed_code_block",
|
|
2818
|
+
inputLength: input.length
|
|
1585
2819
|
}
|
|
2820
|
+
});
|
|
2821
|
+
}
|
|
2822
|
+
const regex = input.matchAll(new RegExp(/```(\w*)\n([\s\S]*?)```/, "g"));
|
|
2823
|
+
for (const iterator of regex) {
|
|
2824
|
+
if (iterator) {
|
|
2825
|
+
const [_input, language, code] = iterator;
|
|
2826
|
+
out.push({
|
|
2827
|
+
language,
|
|
2828
|
+
code
|
|
2829
|
+
});
|
|
1586
2830
|
}
|
|
1587
|
-
return parsed;
|
|
1588
2831
|
}
|
|
1589
|
-
return
|
|
2832
|
+
return out;
|
|
1590
2833
|
}
|
|
1591
2834
|
};
|
|
1592
2835
|
|
|
1593
|
-
// src/parser/parsers/
|
|
1594
|
-
var
|
|
1595
|
-
constructor(
|
|
1596
|
-
super("
|
|
2836
|
+
// src/parser/parsers/MarkdownCodeBlock.ts
|
|
2837
|
+
var MarkdownCodeBlockParser = class extends BaseParser {
|
|
2838
|
+
constructor() {
|
|
2839
|
+
super("markdownCodeBlock");
|
|
1597
2840
|
}
|
|
1598
|
-
parse(
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
2841
|
+
parse(input, _attributes) {
|
|
2842
|
+
if (typeof input !== "string") {
|
|
2843
|
+
throw new LlmExeError(
|
|
2844
|
+
`Invalid input. Expected string. Received ${input === null ? "null" : Array.isArray(input) ? "array" : typeof input}.`,
|
|
2845
|
+
{
|
|
2846
|
+
code: "parser.invalid_input",
|
|
2847
|
+
context: {
|
|
2848
|
+
operation: "MarkdownCodeBlockParser.parse",
|
|
2849
|
+
parser: "markdownCodeBlock",
|
|
2850
|
+
reason: "invalid_input_type",
|
|
2851
|
+
expected: "string",
|
|
2852
|
+
received: input === null ? "null" : Array.isArray(input) ? "array" : typeof input
|
|
2853
|
+
}
|
|
2854
|
+
}
|
|
2855
|
+
);
|
|
1606
2856
|
}
|
|
1607
|
-
|
|
2857
|
+
if (input.trim() === "") {
|
|
2858
|
+
throw new LlmExeError(`No markdown code block found.`, {
|
|
2859
|
+
code: "parser.parse_failed",
|
|
2860
|
+
context: {
|
|
2861
|
+
operation: "MarkdownCodeBlockParser.parse",
|
|
2862
|
+
parser: "markdownCodeBlock",
|
|
2863
|
+
reason: "empty_input",
|
|
2864
|
+
inputLength: input.length
|
|
2865
|
+
}
|
|
2866
|
+
});
|
|
2867
|
+
}
|
|
2868
|
+
const blocks = new MarkdownCodeBlocksParser().parse(input);
|
|
2869
|
+
if (blocks.length === 0) {
|
|
2870
|
+
throw new LlmExeError(`No markdown code block found.`, {
|
|
2871
|
+
code: "parser.parse_failed",
|
|
2872
|
+
context: {
|
|
2873
|
+
operation: "MarkdownCodeBlockParser.parse",
|
|
2874
|
+
parser: "markdownCodeBlock",
|
|
2875
|
+
reason: "no_code_block",
|
|
2876
|
+
inputLength: input.length
|
|
2877
|
+
}
|
|
2878
|
+
});
|
|
2879
|
+
}
|
|
2880
|
+
if (blocks.length > 1) {
|
|
2881
|
+
throw new LlmExeError(`Multiple markdown code blocks found.`, {
|
|
2882
|
+
code: "parser.parse_failed",
|
|
2883
|
+
context: {
|
|
2884
|
+
operation: "MarkdownCodeBlockParser.parse",
|
|
2885
|
+
parser: "markdownCodeBlock",
|
|
2886
|
+
reason: "multiple_code_blocks",
|
|
2887
|
+
inputLength: input.length,
|
|
2888
|
+
matchCount: blocks.length
|
|
2889
|
+
}
|
|
2890
|
+
});
|
|
2891
|
+
}
|
|
2892
|
+
return blocks[0];
|
|
1608
2893
|
}
|
|
1609
2894
|
};
|
|
1610
2895
|
|
|
1611
|
-
// src/parser/parsers/
|
|
1612
|
-
var
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
this
|
|
2896
|
+
// src/parser/parsers/StringExtractParser.ts
|
|
2897
|
+
var REGEX_METACHAR = /[.*+?^${}()|[\]\\]/g;
|
|
2898
|
+
var WORD_CHAR = "[\\p{L}\\p{N}]";
|
|
2899
|
+
function escapeRegex(value) {
|
|
2900
|
+
return value.replace(REGEX_METACHAR, "\\$&");
|
|
2901
|
+
}
|
|
2902
|
+
function describeType(value) {
|
|
2903
|
+
if (value === null) return "null";
|
|
2904
|
+
if (Array.isArray(value)) return "array";
|
|
2905
|
+
return typeof value;
|
|
2906
|
+
}
|
|
2907
|
+
var StringExtractParser = class extends BaseParser {
|
|
2908
|
+
constructor(options) {
|
|
2909
|
+
super("stringExtract");
|
|
2910
|
+
__publicField(this, "enum", []);
|
|
2911
|
+
__publicField(this, "ignoreCase");
|
|
2912
|
+
__publicField(this, "match");
|
|
2913
|
+
if (options?.enum) {
|
|
2914
|
+
this.enum.push(...options.enum);
|
|
2915
|
+
}
|
|
2916
|
+
this.ignoreCase = options?.ignoreCase ?? true;
|
|
2917
|
+
this.match = options?.match ?? "word";
|
|
1626
2918
|
}
|
|
1627
2919
|
/**
|
|
1628
|
-
*
|
|
1629
|
-
*
|
|
1630
|
-
*
|
|
1631
|
-
*
|
|
2920
|
+
* v3 parser contract:
|
|
2921
|
+
* Category: extractor
|
|
2922
|
+
* Mode: configured value extraction
|
|
2923
|
+
*
|
|
2924
|
+
* Returns the single configured enum value found in input. Matching is
|
|
2925
|
+
* word-bounded by default; pass match: "whole" to require exact input or
|
|
2926
|
+
* match: "substring" for legacy contains() behavior. Case-insensitive by
|
|
2927
|
+
* default.
|
|
2928
|
+
*
|
|
1632
2929
|
*/
|
|
1633
|
-
parse(text,
|
|
1634
|
-
|
|
2930
|
+
parse(text, _attributes) {
|
|
2931
|
+
if (typeof text !== "string") {
|
|
2932
|
+
const received = describeType(text);
|
|
2933
|
+
throw new LlmExeError(
|
|
2934
|
+
`Invalid input. Expected string. Received ${received}.`,
|
|
2935
|
+
{
|
|
2936
|
+
code: "parser.invalid_input",
|
|
2937
|
+
context: {
|
|
2938
|
+
operation: "StringExtractParser.parse",
|
|
2939
|
+
parser: "stringExtract",
|
|
2940
|
+
reason: "invalid_input_type",
|
|
2941
|
+
expected: "string",
|
|
2942
|
+
received
|
|
2943
|
+
}
|
|
2944
|
+
}
|
|
2945
|
+
);
|
|
2946
|
+
}
|
|
2947
|
+
if (this.enum.length === 0) {
|
|
2948
|
+
throw new LlmExeError(`No enum values configured.`, {
|
|
2949
|
+
code: "parser.parse_failed",
|
|
2950
|
+
context: {
|
|
2951
|
+
operation: "StringExtractParser.parse",
|
|
2952
|
+
parser: "stringExtract",
|
|
2953
|
+
reason: "no_enum_values",
|
|
2954
|
+
expected: "non-empty enum",
|
|
2955
|
+
inputLength: text.length
|
|
2956
|
+
}
|
|
2957
|
+
});
|
|
2958
|
+
}
|
|
2959
|
+
if (text.length === 0) {
|
|
2960
|
+
if (this.enum.includes("")) {
|
|
2961
|
+
return "";
|
|
2962
|
+
}
|
|
2963
|
+
throw new LlmExeError(`No matching enum value found in input.`, {
|
|
2964
|
+
code: "parser.parse_failed",
|
|
2965
|
+
context: {
|
|
2966
|
+
operation: "StringExtractParser.parse",
|
|
2967
|
+
parser: "stringExtract",
|
|
2968
|
+
reason: "empty_input",
|
|
2969
|
+
expected: this.enum,
|
|
2970
|
+
inputLength: text.length
|
|
2971
|
+
}
|
|
2972
|
+
});
|
|
2973
|
+
}
|
|
2974
|
+
const matches = this.findMatches(text);
|
|
2975
|
+
const uniqueMatches = Array.from(new Set(matches));
|
|
2976
|
+
if (uniqueMatches.length === 1) {
|
|
2977
|
+
return uniqueMatches[0];
|
|
2978
|
+
}
|
|
2979
|
+
if (uniqueMatches.length > 1) {
|
|
2980
|
+
throw new LlmExeError(`Multiple enum values found in input.`, {
|
|
2981
|
+
code: "parser.parse_failed",
|
|
2982
|
+
context: {
|
|
2983
|
+
operation: "StringExtractParser.parse",
|
|
2984
|
+
parser: "stringExtract",
|
|
2985
|
+
reason: "ambiguous_enum_match",
|
|
2986
|
+
expected: this.enum,
|
|
2987
|
+
match: this.match,
|
|
2988
|
+
inputLength: text.length,
|
|
2989
|
+
matchCount: uniqueMatches.length
|
|
2990
|
+
}
|
|
2991
|
+
});
|
|
2992
|
+
}
|
|
2993
|
+
throw new LlmExeError(`No matching enum value found in input.`, {
|
|
2994
|
+
code: "parser.parse_failed",
|
|
2995
|
+
context: {
|
|
2996
|
+
operation: "StringExtractParser.parse",
|
|
2997
|
+
parser: "stringExtract",
|
|
2998
|
+
reason: "no_enum_match",
|
|
2999
|
+
expected: this.enum,
|
|
3000
|
+
match: this.match,
|
|
3001
|
+
inputLength: text.length
|
|
3002
|
+
}
|
|
3003
|
+
});
|
|
1635
3004
|
}
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
3005
|
+
findMatches(text) {
|
|
3006
|
+
switch (this.match) {
|
|
3007
|
+
case "whole":
|
|
3008
|
+
return this.matchWhole(text);
|
|
3009
|
+
case "substring":
|
|
3010
|
+
return this.matchSubstring(text);
|
|
3011
|
+
case "word":
|
|
3012
|
+
default:
|
|
3013
|
+
return this.matchWord(text);
|
|
3014
|
+
}
|
|
3015
|
+
}
|
|
3016
|
+
matchWhole(text) {
|
|
3017
|
+
const candidate = this.ignoreCase ? text.trim().toLowerCase() : text.trim();
|
|
3018
|
+
return this.enum.filter((option) => {
|
|
3019
|
+
if (option === "") return false;
|
|
3020
|
+
const normalized = this.ignoreCase ? option.toLowerCase() : option;
|
|
3021
|
+
return candidate === normalized;
|
|
3022
|
+
});
|
|
1642
3023
|
}
|
|
1643
|
-
|
|
1644
|
-
const
|
|
1645
|
-
return
|
|
3024
|
+
matchSubstring(text) {
|
|
3025
|
+
const haystack = this.ignoreCase ? text.toLowerCase() : text;
|
|
3026
|
+
return this.enum.filter((option) => {
|
|
3027
|
+
if (option === "") return false;
|
|
3028
|
+
const needle = this.ignoreCase ? option.toLowerCase() : option;
|
|
3029
|
+
return haystack.includes(needle);
|
|
3030
|
+
});
|
|
3031
|
+
}
|
|
3032
|
+
matchWord(text) {
|
|
3033
|
+
const flags = this.ignoreCase ? "iu" : "u";
|
|
3034
|
+
return this.enum.filter((option) => {
|
|
3035
|
+
if (option === "") return false;
|
|
3036
|
+
const pattern = new RegExp(
|
|
3037
|
+
`(?<!${WORD_CHAR})${escapeRegex(option)}(?!${WORD_CHAR})`,
|
|
3038
|
+
flags
|
|
3039
|
+
);
|
|
3040
|
+
return pattern.test(text);
|
|
3041
|
+
});
|
|
1646
3042
|
}
|
|
1647
3043
|
};
|
|
1648
3044
|
|
|
1649
|
-
// src/parser/
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
3045
|
+
// src/parser/_functions.ts
|
|
3046
|
+
function createParser(...args) {
|
|
3047
|
+
const [type, options] = args;
|
|
3048
|
+
switch (type) {
|
|
3049
|
+
case "json":
|
|
3050
|
+
return new JsonParser(options);
|
|
3051
|
+
case "listToJson":
|
|
3052
|
+
return new ListToJsonParser(options);
|
|
3053
|
+
case "stringExtract":
|
|
3054
|
+
return new StringExtractParser(options);
|
|
3055
|
+
case "markdownCodeBlocks":
|
|
3056
|
+
return new MarkdownCodeBlocksParser();
|
|
3057
|
+
case "markdownCodeBlock":
|
|
3058
|
+
return new MarkdownCodeBlockParser();
|
|
3059
|
+
case "listToArray":
|
|
3060
|
+
return new ListToArrayParser();
|
|
3061
|
+
case "listToKeyValue":
|
|
3062
|
+
return new ListToKeyValueParser(options);
|
|
3063
|
+
case "replaceStringTemplate":
|
|
3064
|
+
return new ReplaceStringTemplateParser();
|
|
3065
|
+
case "boolean":
|
|
3066
|
+
return new BooleanParser();
|
|
3067
|
+
case "number":
|
|
3068
|
+
return new NumberParser(options);
|
|
3069
|
+
case "string":
|
|
3070
|
+
return new StringParser();
|
|
3071
|
+
default:
|
|
3072
|
+
throw new LlmExeError(
|
|
3073
|
+
`Invalid parser type: "${type}"`,
|
|
3074
|
+
{
|
|
3075
|
+
code: "parser.invalid_type",
|
|
3076
|
+
context: {
|
|
3077
|
+
operation: "createParser",
|
|
3078
|
+
parser: type,
|
|
3079
|
+
availableParsers: [
|
|
3080
|
+
"json",
|
|
3081
|
+
"string",
|
|
3082
|
+
"boolean",
|
|
3083
|
+
"number",
|
|
3084
|
+
"stringExtract",
|
|
3085
|
+
"listToArray",
|
|
3086
|
+
"listToJson",
|
|
3087
|
+
"listToKeyValue",
|
|
3088
|
+
"replaceStringTemplate",
|
|
3089
|
+
"markdownCodeBlock",
|
|
3090
|
+
"markdownCodeBlocks"
|
|
3091
|
+
],
|
|
3092
|
+
resolution: "Use a registered parser type, or define a custom parser."
|
|
3093
|
+
}
|
|
3094
|
+
}
|
|
3095
|
+
);
|
|
1653
3096
|
}
|
|
1654
|
-
|
|
1655
|
-
|
|
3097
|
+
}
|
|
3098
|
+
function createCustomParser(name, parserFn) {
|
|
3099
|
+
return new CustomParser(name, parserFn);
|
|
3100
|
+
}
|
|
3101
|
+
|
|
3102
|
+
// src/utils/index.ts
|
|
3103
|
+
var utils_exports = {};
|
|
3104
|
+
__export(utils_exports, {
|
|
3105
|
+
LLM_EXE_ERROR_SYMBOL: () => LLM_EXE_ERROR_SYMBOL,
|
|
3106
|
+
LlmExeError: () => LlmExeError,
|
|
3107
|
+
assert: () => assert,
|
|
3108
|
+
asyncCallWithTimeout: () => asyncCallWithTimeout,
|
|
3109
|
+
defineSchema: () => defineSchema,
|
|
3110
|
+
filterObjectOnSchema: () => filterObjectOnSchema,
|
|
3111
|
+
guessProviderFromModel: () => guessProviderFromModel,
|
|
3112
|
+
importHelpers: () => importHelpers,
|
|
3113
|
+
importPartials: () => importPartials,
|
|
3114
|
+
isLlmExeError: () => isLlmExeError,
|
|
3115
|
+
isObjectStringified: () => isObjectStringified,
|
|
3116
|
+
maybeParseJSON: () => maybeParseJSON,
|
|
3117
|
+
maybeStringifyJSON: () => maybeStringifyJSON,
|
|
3118
|
+
registerHelpers: () => registerHelpers,
|
|
3119
|
+
registerPartials: () => registerPartials,
|
|
3120
|
+
replaceTemplateString: () => replaceTemplateString,
|
|
3121
|
+
replaceTemplateStringAsync: () => replaceTemplateStringAsync
|
|
3122
|
+
});
|
|
3123
|
+
|
|
3124
|
+
// src/utils/modules/assert.ts
|
|
3125
|
+
function assert(condition, message) {
|
|
3126
|
+
if (condition === void 0 || condition === null || condition === false) {
|
|
3127
|
+
if (typeof message === "string") {
|
|
3128
|
+
throw new Error(message);
|
|
3129
|
+
} else if (message instanceof Error) {
|
|
3130
|
+
throw message;
|
|
3131
|
+
} else {
|
|
3132
|
+
throw new Error(`Assertion error`);
|
|
3133
|
+
}
|
|
1656
3134
|
}
|
|
1657
|
-
}
|
|
3135
|
+
}
|
|
1658
3136
|
|
|
1659
|
-
// src/
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
3137
|
+
// src/utils/modules/defineSchema.ts
|
|
3138
|
+
import { asConst } from "json-schema-to-ts";
|
|
3139
|
+
function defineSchema(obj) {
|
|
3140
|
+
obj.additionalProperties = false;
|
|
3141
|
+
return asConst(obj);
|
|
3142
|
+
}
|
|
3143
|
+
|
|
3144
|
+
// src/utils/modules/handlebars/utils/importPartials.ts
|
|
3145
|
+
function importPartials(_partials) {
|
|
3146
|
+
let partials2 = [];
|
|
3147
|
+
if (_partials) {
|
|
3148
|
+
const externalPartialKeys = Object.keys(
|
|
3149
|
+
_partials
|
|
3150
|
+
);
|
|
3151
|
+
for (const externalPartialKey of externalPartialKeys) {
|
|
3152
|
+
if (typeof externalPartialKey === "string") {
|
|
3153
|
+
partials2.push({
|
|
3154
|
+
name: externalPartialKey,
|
|
3155
|
+
template: _partials[externalPartialKey]
|
|
3156
|
+
});
|
|
1672
3157
|
}
|
|
1673
3158
|
}
|
|
1674
|
-
} catch {
|
|
1675
3159
|
}
|
|
1676
|
-
return
|
|
3160
|
+
return partials2;
|
|
1677
3161
|
}
|
|
1678
3162
|
|
|
1679
|
-
// src/
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
if (iterator) {
|
|
1692
|
-
const [_input, language, code] = iterator;
|
|
1693
|
-
out.push({
|
|
1694
|
-
language,
|
|
1695
|
-
code
|
|
3163
|
+
// src/utils/modules/handlebars/utils/importHelpers.ts
|
|
3164
|
+
function importHelpers(_helpers) {
|
|
3165
|
+
let helpers = [];
|
|
3166
|
+
if (_helpers) {
|
|
3167
|
+
const externalHelperKeys = Object.keys(
|
|
3168
|
+
_helpers
|
|
3169
|
+
);
|
|
3170
|
+
for (const externalHelperKey of externalHelperKeys) {
|
|
3171
|
+
if (typeof externalHelperKey === "string") {
|
|
3172
|
+
helpers.push({
|
|
3173
|
+
name: externalHelperKey,
|
|
3174
|
+
handler: _helpers[externalHelperKey]
|
|
1696
3175
|
});
|
|
1697
3176
|
}
|
|
1698
3177
|
}
|
|
1699
|
-
return out;
|
|
1700
3178
|
}
|
|
1701
|
-
|
|
3179
|
+
return helpers;
|
|
3180
|
+
}
|
|
1702
3181
|
|
|
1703
|
-
// src/
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
3182
|
+
// src/utils/modules/replaceTemplateStringAsync.ts
|
|
3183
|
+
async function replaceTemplateStringAsync(templateString, substitutions = {}, configuration = {
|
|
3184
|
+
helpers: [],
|
|
3185
|
+
partials: []
|
|
3186
|
+
}) {
|
|
3187
|
+
if (!templateString) return Promise.resolve(templateString || "");
|
|
3188
|
+
const tempHelpers = [];
|
|
3189
|
+
const tempPartials = [];
|
|
3190
|
+
if (Array.isArray(configuration.helpers)) {
|
|
3191
|
+
hbsAsync.registerHelpers(configuration.helpers);
|
|
3192
|
+
tempHelpers.push(...configuration.helpers.map((a) => a.name));
|
|
1707
3193
|
}
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
return {
|
|
1712
|
-
code: "",
|
|
1713
|
-
language: ""
|
|
1714
|
-
};
|
|
1715
|
-
}
|
|
1716
|
-
return block;
|
|
3194
|
+
if (Array.isArray(configuration.partials)) {
|
|
3195
|
+
hbsAsync.registerPartials(configuration.partials);
|
|
3196
|
+
tempPartials.push(...configuration.partials.map((a) => a.name));
|
|
1717
3197
|
}
|
|
3198
|
+
const template = hbsAsync.handlebars.compile(templateString);
|
|
3199
|
+
const res = await template(substitutions, {
|
|
3200
|
+
allowedProtoMethods: {
|
|
3201
|
+
substring: true
|
|
3202
|
+
}
|
|
3203
|
+
});
|
|
3204
|
+
tempHelpers.forEach(function(n) {
|
|
3205
|
+
hbsAsync.handlebars.unregisterHelper(n);
|
|
3206
|
+
});
|
|
3207
|
+
tempPartials.forEach(function(n) {
|
|
3208
|
+
hbsAsync.handlebars.unregisterPartial(n);
|
|
3209
|
+
});
|
|
3210
|
+
return res;
|
|
3211
|
+
}
|
|
3212
|
+
|
|
3213
|
+
// src/utils/modules/asyncCallWithTimeout.ts
|
|
3214
|
+
var asyncCallWithTimeout = async (asyncPromise, timeLimit = 1e4) => {
|
|
3215
|
+
let timeoutHandle;
|
|
3216
|
+
const timeoutPromise = new Promise((_resolve, reject) => {
|
|
3217
|
+
timeoutHandle = setTimeout(() => {
|
|
3218
|
+
return reject(
|
|
3219
|
+
new Error(`LLM call timed out after ${timeLimit}ms`)
|
|
3220
|
+
);
|
|
3221
|
+
}, timeLimit);
|
|
3222
|
+
});
|
|
3223
|
+
return Promise.race([asyncPromise, timeoutPromise]).finally(() => {
|
|
3224
|
+
clearTimeout(timeoutHandle);
|
|
3225
|
+
});
|
|
1718
3226
|
};
|
|
1719
3227
|
|
|
1720
|
-
// src/
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
__publicField(this, "ignoreCase");
|
|
1726
|
-
if (options?.enum) {
|
|
1727
|
-
this.enum.push(...options.enum);
|
|
1728
|
-
}
|
|
1729
|
-
if (options?.ignoreCase) {
|
|
1730
|
-
this.ignoreCase = true;
|
|
1731
|
-
}
|
|
3228
|
+
// src/utils/modules/guessProviderFromModel.ts
|
|
3229
|
+
function isModelKnownOpenAi(payload) {
|
|
3230
|
+
const model = payload.model.toLowerCase();
|
|
3231
|
+
if (model.startsWith("gpt-") || model.startsWith("chatgpt-")) {
|
|
3232
|
+
return true;
|
|
1732
3233
|
}
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
typeof text === "string",
|
|
1736
|
-
`Invalid input. Expected string. Received ${typeof text}.`
|
|
1737
|
-
);
|
|
1738
|
-
for (const option of this.enum) {
|
|
1739
|
-
const regex = this.ignoreCase ? new RegExp(option.toLowerCase(), "i") : new RegExp(option);
|
|
1740
|
-
if (regex.test(text)) {
|
|
1741
|
-
return option;
|
|
1742
|
-
}
|
|
1743
|
-
}
|
|
1744
|
-
throw new LlmExeError(
|
|
1745
|
-
`No matching enum value found in input.`,
|
|
1746
|
-
"parser",
|
|
1747
|
-
{
|
|
1748
|
-
parser: "stringExtract",
|
|
1749
|
-
output: text,
|
|
1750
|
-
error: `No matching enum value found in input. Expected one of: ${this.enum.join(", ")}`
|
|
1751
|
-
}
|
|
1752
|
-
);
|
|
3234
|
+
if (model === "o1" || model.startsWith("o1-")) {
|
|
3235
|
+
return true;
|
|
1753
3236
|
}
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
3237
|
+
if (model === "o3-mini") {
|
|
3238
|
+
return true;
|
|
3239
|
+
}
|
|
3240
|
+
return false;
|
|
3241
|
+
}
|
|
3242
|
+
function isModelKnownAnthropic(payload) {
|
|
3243
|
+
const model = payload.model.toLowerCase();
|
|
3244
|
+
if (model.startsWith("claude-")) {
|
|
3245
|
+
return true;
|
|
3246
|
+
}
|
|
3247
|
+
return false;
|
|
3248
|
+
}
|
|
3249
|
+
function isModelKnownXai(payload) {
|
|
3250
|
+
const model = payload.model.toLowerCase();
|
|
3251
|
+
if (model.startsWith("grok-")) {
|
|
3252
|
+
return true;
|
|
3253
|
+
}
|
|
3254
|
+
return false;
|
|
3255
|
+
}
|
|
3256
|
+
function isModelKnownBedrockAnthropic(payload) {
|
|
3257
|
+
const model = payload.model.toLowerCase();
|
|
3258
|
+
if (model.startsWith("anthropic.claude-")) {
|
|
3259
|
+
return true;
|
|
3260
|
+
}
|
|
3261
|
+
return false;
|
|
3262
|
+
}
|
|
3263
|
+
function guessProviderFromModel(payload) {
|
|
3264
|
+
switch (true) {
|
|
3265
|
+
case isModelKnownOpenAi(payload):
|
|
3266
|
+
return "openai";
|
|
3267
|
+
case isModelKnownXai(payload):
|
|
3268
|
+
return "xai";
|
|
3269
|
+
case isModelKnownBedrockAnthropic(payload):
|
|
3270
|
+
return "bedrock:anthropic";
|
|
3271
|
+
case isModelKnownAnthropic(payload):
|
|
3272
|
+
return "anthropic";
|
|
1781
3273
|
default:
|
|
1782
|
-
throw new
|
|
1783
|
-
|
|
1784
|
-
|
|
3274
|
+
throw new LlmExeError("Unsupported model", {
|
|
3275
|
+
code: "configuration.invalid_provider",
|
|
3276
|
+
context: {
|
|
3277
|
+
operation: "guessProviderFromModel",
|
|
3278
|
+
model: payload.model,
|
|
3279
|
+
// Mirrors the switch above. Keep these in sync when adding a new
|
|
3280
|
+
// isModelKnown* case.
|
|
3281
|
+
availableProviders: [
|
|
3282
|
+
"openai",
|
|
3283
|
+
"xai",
|
|
3284
|
+
"bedrock:anthropic",
|
|
3285
|
+
"anthropic"
|
|
3286
|
+
],
|
|
3287
|
+
resolution: "Pass a known model prefix (gpt-, chatgpt-, o1, o3-mini, claude-, grok-, anthropic.claude-) or specify the provider explicitly."
|
|
3288
|
+
}
|
|
3289
|
+
});
|
|
1785
3290
|
}
|
|
1786
3291
|
}
|
|
1787
|
-
|
|
1788
|
-
|
|
3292
|
+
|
|
3293
|
+
// src/utils/modules/index.ts
|
|
3294
|
+
function registerHelpers(helpers) {
|
|
3295
|
+
hbs.registerHelpers(helpers);
|
|
3296
|
+
hbsAsync.registerHelpers(helpers);
|
|
3297
|
+
}
|
|
3298
|
+
function registerPartials(partials2) {
|
|
3299
|
+
hbs.registerPartials(partials2);
|
|
3300
|
+
hbsAsync.registerPartials(partials2);
|
|
1789
3301
|
}
|
|
1790
3302
|
|
|
1791
3303
|
// src/parser/parsers/LlmNativeFunctionParser.ts
|
|
1792
3304
|
var LlmFunctionParser = class extends BaseParser {
|
|
1793
3305
|
constructor(options) {
|
|
1794
|
-
super("functionCall",
|
|
3306
|
+
super("functionCall", "function_call");
|
|
1795
3307
|
__publicField(this, "parser");
|
|
1796
3308
|
this.parser = options.parser;
|
|
1797
3309
|
}
|
|
1798
3310
|
parse(text, _options) {
|
|
1799
3311
|
if (typeof text === "string") {
|
|
1800
|
-
return this.parser.parse(text);
|
|
3312
|
+
return this.parser.parse(text, _options);
|
|
1801
3313
|
}
|
|
1802
3314
|
const { content } = text;
|
|
1803
3315
|
const functionUses = content?.filter((a) => a.type === "function_use") || [];
|
|
1804
3316
|
if (functionUses.length === 0) {
|
|
1805
3317
|
const [item] = content;
|
|
1806
|
-
return this.parser.parse(item.text);
|
|
3318
|
+
return this.parser.parse(item.text, _options);
|
|
1807
3319
|
}
|
|
1808
3320
|
return content;
|
|
1809
3321
|
}
|
|
1810
3322
|
};
|
|
1811
3323
|
var LlmNativeFunctionParser = class extends BaseParser {
|
|
1812
3324
|
constructor(options) {
|
|
1813
|
-
super("openAiFunction",
|
|
3325
|
+
super("openAiFunction", "function_call");
|
|
1814
3326
|
__publicField(this, "parser");
|
|
1815
3327
|
this.parser = options.parser;
|
|
1816
3328
|
}
|
|
1817
3329
|
parse(text, _options) {
|
|
3330
|
+
if (typeof text === "string") {
|
|
3331
|
+
return this.parser.parse(text, _options);
|
|
3332
|
+
}
|
|
3333
|
+
if (typeof text?.text === "string") {
|
|
3334
|
+
return this.parser.parse(text.text, _options);
|
|
3335
|
+
}
|
|
1818
3336
|
const { content } = text;
|
|
1819
3337
|
const functionUse = content?.find((a) => a.type === "function_use");
|
|
1820
3338
|
if (functionUse && "name" in functionUse && "input" in functionUse) {
|
|
@@ -1823,7 +3341,10 @@ var LlmNativeFunctionParser = class extends BaseParser {
|
|
|
1823
3341
|
arguments: maybeParseJSON(functionUse.input)
|
|
1824
3342
|
};
|
|
1825
3343
|
}
|
|
1826
|
-
|
|
3344
|
+
const textContent = content?.find(
|
|
3345
|
+
(item) => item.type === "text" && typeof item.text === "string"
|
|
3346
|
+
);
|
|
3347
|
+
return this.parser.parse(textContent?.text, _options);
|
|
1827
3348
|
}
|
|
1828
3349
|
};
|
|
1829
3350
|
var OpenAiFunctionParser = LlmNativeFunctionParser;
|
|
@@ -1850,17 +3371,29 @@ var LlmExecutor = class extends BaseExecutor {
|
|
|
1850
3371
|
this.promptFn = null;
|
|
1851
3372
|
}
|
|
1852
3373
|
}
|
|
3374
|
+
/**
|
|
3375
|
+
* Runs the executor against the configured LLM and prompt.
|
|
3376
|
+
*
|
|
3377
|
+
* `null` and `undefined` are rejected with a `TypeError`: the declared
|
|
3378
|
+
* input type requires an object, and silently coercing missing input hides a
|
|
3379
|
+
* clear contract violation. Use `{}` for prompts that declare no template
|
|
3380
|
+
* variables. See issue #410.
|
|
3381
|
+
*/
|
|
1853
3382
|
async execute(_input, _options) {
|
|
1854
|
-
|
|
3383
|
+
if (_input === null || typeof _input === "undefined") {
|
|
3384
|
+
throw new TypeError(
|
|
3385
|
+
`[llm-exe] Executor "${this.name}" received null or undefined as input. execute() expects an object matching the prompt's input type.`
|
|
3386
|
+
);
|
|
3387
|
+
}
|
|
1855
3388
|
if (this?.parser instanceof JsonParser && this.parser.schema) {
|
|
1856
3389
|
_options = Object.assign(_options || {}, {
|
|
1857
3390
|
jsonSchema: this.parser.schema
|
|
1858
3391
|
});
|
|
1859
3392
|
}
|
|
1860
|
-
return super.execute(
|
|
3393
|
+
return super.execute(_input, _options);
|
|
1861
3394
|
}
|
|
1862
|
-
async handler(_input,
|
|
1863
|
-
const call = await this.llm.call(_input,
|
|
3395
|
+
async handler(_input, _options, _context) {
|
|
3396
|
+
const call = await this.llm.call(_input, _options, _context);
|
|
1864
3397
|
return call;
|
|
1865
3398
|
}
|
|
1866
3399
|
async getHandlerInput(_input) {
|
|
@@ -1879,15 +3412,26 @@ var LlmExecutor = class extends BaseExecutor {
|
|
|
1879
3412
|
return prompt.format(_input);
|
|
1880
3413
|
}
|
|
1881
3414
|
}
|
|
1882
|
-
throw new
|
|
3415
|
+
throw new LlmExeError("Missing prompt", {
|
|
3416
|
+
code: "executor.missing_prompt",
|
|
3417
|
+
context: {
|
|
3418
|
+
operation: "LlmExecutor.getHandlerInput",
|
|
3419
|
+
executorName: this.name,
|
|
3420
|
+
executorType: this.type,
|
|
3421
|
+
traceId: this.getTraceId() ?? void 0,
|
|
3422
|
+
resolution: "Provide a prompt (or prompt factory) when constructing the LLM executor."
|
|
3423
|
+
}
|
|
3424
|
+
});
|
|
1883
3425
|
}
|
|
1884
|
-
getHandlerOutput(out, _metadata) {
|
|
3426
|
+
getHandlerOutput(out, _metadata, _options, _context) {
|
|
3427
|
+
const parse = this.parser.parse.bind(this.parser);
|
|
3428
|
+
const parserArg = _context ?? _metadata;
|
|
1885
3429
|
if (this.parser.target === "function_call") {
|
|
1886
3430
|
const outToStr = out.getResult();
|
|
1887
|
-
return
|
|
3431
|
+
return parse(outToStr, parserArg);
|
|
1888
3432
|
} else {
|
|
1889
3433
|
const outToStr = out.getResultText();
|
|
1890
|
-
return
|
|
3434
|
+
return parse(outToStr, parserArg);
|
|
1891
3435
|
}
|
|
1892
3436
|
}
|
|
1893
3437
|
metadata() {
|
|
@@ -1989,7 +3533,17 @@ var CallableExecutor = class {
|
|
|
1989
3533
|
} else if (typeof options.handler === "function") {
|
|
1990
3534
|
this._handler = createCoreExecutor(options.handler);
|
|
1991
3535
|
} else {
|
|
1992
|
-
throw new
|
|
3536
|
+
throw new LlmExeError("Invalid handler", {
|
|
3537
|
+
code: "callable.invalid_handler",
|
|
3538
|
+
context: {
|
|
3539
|
+
operation: "CallableExecutor.constructor",
|
|
3540
|
+
functionName: options.name,
|
|
3541
|
+
key: options?.key || options.name,
|
|
3542
|
+
expected: "function or BaseExecutor",
|
|
3543
|
+
received: typeof options.handler,
|
|
3544
|
+
resolution: "Pass a function or a BaseExecutor instance as the handler."
|
|
3545
|
+
}
|
|
3546
|
+
});
|
|
1993
3547
|
}
|
|
1994
3548
|
}
|
|
1995
3549
|
async execute(input) {
|
|
@@ -2007,7 +3561,16 @@ var CallableExecutor = class {
|
|
|
2007
3561
|
}
|
|
2008
3562
|
return { result: true, attributes: {} };
|
|
2009
3563
|
} catch (error) {
|
|
2010
|
-
|
|
3564
|
+
const wrapped = error instanceof LlmExeError ? error : new LlmExeError(error?.message ?? String(error), {
|
|
3565
|
+
code: "callable.validation_failed",
|
|
3566
|
+
context: {
|
|
3567
|
+
operation: "CallableExecutor.validateInput",
|
|
3568
|
+
functionName: this.name,
|
|
3569
|
+
key: this.key
|
|
3570
|
+
},
|
|
3571
|
+
cause: error
|
|
3572
|
+
});
|
|
3573
|
+
return { result: false, attributes: { error: wrapped.message } };
|
|
2011
3574
|
}
|
|
2012
3575
|
}
|
|
2013
3576
|
visibilityHandler(input, attributes) {
|
|
@@ -2044,10 +3607,19 @@ var UseExecutorsBase = class {
|
|
|
2044
3607
|
async callFunction(name, input) {
|
|
2045
3608
|
try {
|
|
2046
3609
|
const handler = this.getFunction(name);
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
3610
|
+
if (!handler) {
|
|
3611
|
+
throw new LlmExeError(
|
|
3612
|
+
`[invalid handler] The handler (${name}) does not exist.`,
|
|
3613
|
+
{
|
|
3614
|
+
code: "callable.handler_not_found",
|
|
3615
|
+
context: {
|
|
3616
|
+
operation: "UseExecutorsBase.callFunction",
|
|
3617
|
+
functionName: name,
|
|
3618
|
+
availableFunctions: this.handlers.map((h) => h.name)
|
|
3619
|
+
}
|
|
3620
|
+
}
|
|
3621
|
+
);
|
|
3622
|
+
}
|
|
2051
3623
|
const result = await handler.execute(ensureInputIsObject(input));
|
|
2052
3624
|
return result;
|
|
2053
3625
|
} catch (error) {
|
|
@@ -2057,10 +3629,19 @@ var UseExecutorsBase = class {
|
|
|
2057
3629
|
async validateFunctionInput(name, input) {
|
|
2058
3630
|
try {
|
|
2059
3631
|
const handler = this.getFunction(name);
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
3632
|
+
if (!handler) {
|
|
3633
|
+
throw new LlmExeError(
|
|
3634
|
+
`[invalid handler] The handler (${name}) does not exist.`,
|
|
3635
|
+
{
|
|
3636
|
+
code: "callable.handler_not_found",
|
|
3637
|
+
context: {
|
|
3638
|
+
operation: "UseExecutorsBase.validateFunctionInput",
|
|
3639
|
+
functionName: name,
|
|
3640
|
+
availableFunctions: this.handlers.map((h) => h.name)
|
|
3641
|
+
}
|
|
3642
|
+
}
|
|
3643
|
+
);
|
|
3644
|
+
}
|
|
2064
3645
|
const result = await handler.validateInput(
|
|
2065
3646
|
ensureInputIsObject(input)
|
|
2066
3647
|
);
|
|
@@ -2075,18 +3656,59 @@ var UseExecutorsBase = class {
|
|
|
2075
3656
|
function createCallableExecutor(options) {
|
|
2076
3657
|
return new CallableExecutor(options);
|
|
2077
3658
|
}
|
|
2078
|
-
var UseExecutors = class extends UseExecutorsBase {
|
|
2079
|
-
constructor(handlers) {
|
|
2080
|
-
super(handlers);
|
|
2081
|
-
}
|
|
2082
|
-
};
|
|
2083
|
-
function useExecutors(executors) {
|
|
2084
|
-
return new UseExecutors(
|
|
2085
|
-
executors.map((e) => {
|
|
2086
|
-
if (e instanceof CallableExecutor) return e;
|
|
2087
|
-
return createCallableExecutor(e);
|
|
2088
|
-
})
|
|
2089
|
-
);
|
|
3659
|
+
var UseExecutors = class extends UseExecutorsBase {
|
|
3660
|
+
constructor(handlers) {
|
|
3661
|
+
super(handlers);
|
|
3662
|
+
}
|
|
3663
|
+
};
|
|
3664
|
+
function useExecutors(executors) {
|
|
3665
|
+
return new UseExecutors(
|
|
3666
|
+
executors.map((e) => {
|
|
3667
|
+
if (e instanceof CallableExecutor) return e;
|
|
3668
|
+
return createCallableExecutor(e);
|
|
3669
|
+
})
|
|
3670
|
+
);
|
|
3671
|
+
}
|
|
3672
|
+
|
|
3673
|
+
// src/utils/guards.ts
|
|
3674
|
+
var guards_exports = {};
|
|
3675
|
+
__export(guards_exports, {
|
|
3676
|
+
hasFunctionCall: () => hasFunctionCall,
|
|
3677
|
+
hasToolCall: () => hasToolCall,
|
|
3678
|
+
isAssistantMessage: () => isAssistantMessage,
|
|
3679
|
+
isFunctionCall: () => isFunctionCall,
|
|
3680
|
+
isOutputResult: () => isOutputResult,
|
|
3681
|
+
isOutputResultContentText: () => isOutputResultContentText,
|
|
3682
|
+
isSystemMessage: () => isSystemMessage,
|
|
3683
|
+
isToolCall: () => isToolCall,
|
|
3684
|
+
isUserMessage: () => isUserMessage
|
|
3685
|
+
});
|
|
3686
|
+
function isOutputResult(obj) {
|
|
3687
|
+
return !!(obj && typeof obj === "object" && "id" in obj && "stopReason" in obj && "content" in obj && Array.isArray(obj.content));
|
|
3688
|
+
}
|
|
3689
|
+
function isOutputResultContentText(obj) {
|
|
3690
|
+
return !!(obj && typeof obj === "object" && "text" in obj && "type" in obj && obj.type === "text" && typeof obj.text === "string");
|
|
3691
|
+
}
|
|
3692
|
+
function isFunctionCall(result) {
|
|
3693
|
+
return !!(result && typeof result === "object" && "functionId" in result && "type" in result && result.type === "function_use");
|
|
3694
|
+
}
|
|
3695
|
+
function isToolCall(result) {
|
|
3696
|
+
return isFunctionCall(result);
|
|
3697
|
+
}
|
|
3698
|
+
function hasFunctionCall(results) {
|
|
3699
|
+
return !!(results && Array.isArray(results) && results.some(isToolCall));
|
|
3700
|
+
}
|
|
3701
|
+
function hasToolCall(results) {
|
|
3702
|
+
return hasFunctionCall(results);
|
|
3703
|
+
}
|
|
3704
|
+
function isUserMessage(message) {
|
|
3705
|
+
return message.role === "user";
|
|
3706
|
+
}
|
|
3707
|
+
function isAssistantMessage(message) {
|
|
3708
|
+
return message.role === "assistant" || message.role === "model";
|
|
3709
|
+
}
|
|
3710
|
+
function isSystemMessage(message) {
|
|
3711
|
+
return message.role === "system";
|
|
2090
3712
|
}
|
|
2091
3713
|
|
|
2092
3714
|
// src/utils/modules/deepClone.ts
|
|
@@ -2131,13 +3753,38 @@ function withDefaultModel(obj1, model) {
|
|
|
2131
3753
|
return copy;
|
|
2132
3754
|
}
|
|
2133
3755
|
|
|
2134
|
-
// src/
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
return
|
|
3756
|
+
// src/llm/_utils.deprecationWarning.ts
|
|
3757
|
+
var warned = /* @__PURE__ */ new Set();
|
|
3758
|
+
function emitDeprecationWarning(config, context) {
|
|
3759
|
+
if (!config.deprecated) return;
|
|
3760
|
+
if (typeof process !== "object" || typeof process?.emitWarning !== "function") {
|
|
3761
|
+
return;
|
|
2140
3762
|
}
|
|
3763
|
+
const { shorthand, message } = config.deprecated;
|
|
3764
|
+
if (warned.has(shorthand)) return;
|
|
3765
|
+
warned.add(shorthand);
|
|
3766
|
+
const detail = JSON.stringify({
|
|
3767
|
+
shorthand,
|
|
3768
|
+
model: config.options?.model?.default,
|
|
3769
|
+
provider: config.provider,
|
|
3770
|
+
executorName: context?.executorName,
|
|
3771
|
+
traceId: context?.traceId
|
|
3772
|
+
});
|
|
3773
|
+
process.emitWarning(message, {
|
|
3774
|
+
type: "DeprecationWarning",
|
|
3775
|
+
code: "LLM_EXE_DEPRECATED",
|
|
3776
|
+
detail
|
|
3777
|
+
});
|
|
3778
|
+
}
|
|
3779
|
+
function deprecateShorthand(shorthand, args) {
|
|
3780
|
+
const entry = {
|
|
3781
|
+
...args.config,
|
|
3782
|
+
deprecated: Object.freeze({
|
|
3783
|
+
shorthand,
|
|
3784
|
+
message: args.message
|
|
3785
|
+
})
|
|
3786
|
+
};
|
|
3787
|
+
return { [shorthand]: entry };
|
|
2141
3788
|
}
|
|
2142
3789
|
|
|
2143
3790
|
// src/llm/output/_util.ts
|
|
@@ -2419,7 +4066,10 @@ var openai = {
|
|
|
2419
4066
|
"openai.gpt-4o": withDefaultModel(openAiChatV1, "gpt-4o"),
|
|
2420
4067
|
"openai.gpt-4o-mini": withDefaultModel(openAiChatV1, "gpt-4o-mini"),
|
|
2421
4068
|
// Deprecated
|
|
2422
|
-
"openai.o4-mini"
|
|
4069
|
+
...deprecateShorthand("openai.o4-mini", {
|
|
4070
|
+
config: withDefaultModel(openAiChatV1, "o4-mini"),
|
|
4071
|
+
message: 'Shorthand "openai.o4-mini" is deprecated and may be removed in a future release.'
|
|
4072
|
+
})
|
|
2423
4073
|
};
|
|
2424
4074
|
|
|
2425
4075
|
// src/llm/config/anthropic/promptSanitizeMessageCallback.ts
|
|
@@ -2788,38 +4438,38 @@ var anthropic = {
|
|
|
2788
4438
|
"claude-sonnet-4-5"
|
|
2789
4439
|
),
|
|
2790
4440
|
// Deprecated
|
|
2791
|
-
"anthropic.claude-opus-4-6"
|
|
2792
|
-
anthropicChatV1,
|
|
2793
|
-
"claude-opus-4-6"
|
|
2794
|
-
),
|
|
2795
|
-
"anthropic.claude-opus-4-1"
|
|
2796
|
-
anthropicChatV1,
|
|
2797
|
-
"claude-opus-4-1
|
|
2798
|
-
),
|
|
2799
|
-
"anthropic.claude-sonnet-4"
|
|
2800
|
-
anthropicChatV1,
|
|
2801
|
-
"claude-sonnet-4
|
|
2802
|
-
),
|
|
2803
|
-
"anthropic.claude-opus-4"
|
|
2804
|
-
anthropicChatV1,
|
|
2805
|
-
"claude-opus-4
|
|
2806
|
-
),
|
|
2807
|
-
"anthropic.claude-3-7-sonnet"
|
|
2808
|
-
anthropicChatV1,
|
|
2809
|
-
"claude-3-7-sonnet
|
|
2810
|
-
),
|
|
2811
|
-
"anthropic.claude-3-5-sonnet"
|
|
2812
|
-
anthropicChatV1,
|
|
2813
|
-
"claude-3-5-sonnet
|
|
2814
|
-
),
|
|
2815
|
-
"anthropic.claude-3-5-haiku"
|
|
2816
|
-
anthropicChatV1,
|
|
2817
|
-
"claude-3-5-haiku
|
|
2818
|
-
),
|
|
2819
|
-
"anthropic.claude-3-opus"
|
|
2820
|
-
anthropicChatV1,
|
|
2821
|
-
"claude-3-opus
|
|
2822
|
-
)
|
|
4441
|
+
...deprecateShorthand("anthropic.claude-opus-4-6", {
|
|
4442
|
+
config: withDefaultModel(anthropicChatV1, "claude-opus-4-6"),
|
|
4443
|
+
message: 'Shorthand "anthropic.claude-opus-4-6" is deprecated and may be removed in a future release.'
|
|
4444
|
+
}),
|
|
4445
|
+
...deprecateShorthand("anthropic.claude-opus-4-1", {
|
|
4446
|
+
config: withDefaultModel(anthropicChatV1, "claude-opus-4-1-20250805"),
|
|
4447
|
+
message: 'Shorthand "anthropic.claude-opus-4-1" is deprecated and may be removed in a future release.'
|
|
4448
|
+
}),
|
|
4449
|
+
...deprecateShorthand("anthropic.claude-sonnet-4", {
|
|
4450
|
+
config: withDefaultModel(anthropicChatV1, "claude-sonnet-4-0"),
|
|
4451
|
+
message: 'Shorthand "anthropic.claude-sonnet-4" is deprecated and may be removed in a future release.'
|
|
4452
|
+
}),
|
|
4453
|
+
...deprecateShorthand("anthropic.claude-opus-4", {
|
|
4454
|
+
config: withDefaultModel(anthropicChatV1, "claude-opus-4-0"),
|
|
4455
|
+
message: 'Shorthand "anthropic.claude-opus-4" is deprecated and may be removed in a future release.'
|
|
4456
|
+
}),
|
|
4457
|
+
...deprecateShorthand("anthropic.claude-3-7-sonnet", {
|
|
4458
|
+
config: withDefaultModel(anthropicChatV1, "claude-3-7-sonnet-20250219"),
|
|
4459
|
+
message: 'Shorthand "anthropic.claude-3-7-sonnet" is deprecated and may be removed in a future release.'
|
|
4460
|
+
}),
|
|
4461
|
+
...deprecateShorthand("anthropic.claude-3-5-sonnet", {
|
|
4462
|
+
config: withDefaultModel(anthropicChatV1, "claude-3-5-sonnet-latest"),
|
|
4463
|
+
message: 'Shorthand "anthropic.claude-3-5-sonnet" is deprecated and may be removed in a future release.'
|
|
4464
|
+
}),
|
|
4465
|
+
...deprecateShorthand("anthropic.claude-3-5-haiku", {
|
|
4466
|
+
config: withDefaultModel(anthropicChatV1, "claude-3-5-haiku-latest"),
|
|
4467
|
+
message: 'Shorthand "anthropic.claude-3-5-haiku" is deprecated and may be removed in a future release.'
|
|
4468
|
+
}),
|
|
4469
|
+
...deprecateShorthand("anthropic.claude-3-opus", {
|
|
4470
|
+
config: withDefaultModel(anthropicChatV1, "claude-3-opus-20240229"),
|
|
4471
|
+
message: 'Shorthand "anthropic.claude-3-opus" is deprecated and may be removed in a future release.'
|
|
4472
|
+
})
|
|
2823
4473
|
};
|
|
2824
4474
|
|
|
2825
4475
|
// src/llm/config/x/index.ts
|
|
@@ -2838,20 +4488,41 @@ var xai = {
|
|
|
2838
4488
|
"xai.grok-4": withDefaultModel(xaiChatV1, "grok-4"),
|
|
2839
4489
|
"xai.grok-4-fast": withDefaultModel(xaiChatV1, "grok-4-fast-non-reasoning"),
|
|
2840
4490
|
"xai.grok-4-1-fast": withDefaultModel(xaiChatV1, "grok-4-1-fast-non-reasoning"),
|
|
2841
|
-
"xai.grok-4.3": withDefaultModel(xaiChatV1, "grok-4.3")
|
|
4491
|
+
"xai.grok-4.3": withDefaultModel(xaiChatV1, "grok-4.3"),
|
|
4492
|
+
"xai.grok-4.20": withDefaultModel(xaiChatV1, "grok-4.20-0309-non-reasoning"),
|
|
4493
|
+
"xai.grok-4.20-reasoning": withDefaultModel(
|
|
4494
|
+
xaiChatV1,
|
|
4495
|
+
"grok-4.20-0309-reasoning"
|
|
4496
|
+
)
|
|
2842
4497
|
};
|
|
2843
4498
|
|
|
2844
4499
|
// src/llm/output/_utils/combineJsonl.ts
|
|
2845
4500
|
function combineJsonl(jsonl) {
|
|
2846
|
-
const
|
|
4501
|
+
const rawLines = jsonl.trim().split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
|
|
4502
|
+
const lines = rawLines.map((line, idx) => {
|
|
2847
4503
|
try {
|
|
2848
4504
|
return JSON.parse(line);
|
|
2849
4505
|
} catch (e) {
|
|
2850
|
-
throw new
|
|
4506
|
+
throw new LlmExeError(`Invalid JSON: ${line}`, {
|
|
4507
|
+
code: "llm.invalid_jsonl_response",
|
|
4508
|
+
context: {
|
|
4509
|
+
operation: "combineJsonl",
|
|
4510
|
+
lineNumber: idx + 1,
|
|
4511
|
+
lineExcerpt: line
|
|
4512
|
+
},
|
|
4513
|
+
cause: e
|
|
4514
|
+
});
|
|
2851
4515
|
}
|
|
2852
4516
|
});
|
|
2853
4517
|
if (lines.length === 0) {
|
|
2854
|
-
throw new
|
|
4518
|
+
throw new LlmExeError("No JSON lines provided.", {
|
|
4519
|
+
code: "llm.invalid_jsonl_response",
|
|
4520
|
+
context: {
|
|
4521
|
+
operation: "combineJsonl",
|
|
4522
|
+
received: 0,
|
|
4523
|
+
expected: "at least one JSONL line"
|
|
4524
|
+
}
|
|
4525
|
+
});
|
|
2855
4526
|
}
|
|
2856
4527
|
lines.sort(
|
|
2857
4528
|
(a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime()
|
|
@@ -2860,7 +4531,14 @@ function combineJsonl(jsonl) {
|
|
|
2860
4531
|
combinedContent = combinedContent.replace(/\\u003c/g, "<").replace(/\\u003e/g, ">");
|
|
2861
4532
|
const finalLine = lines.find((line) => line.done === true);
|
|
2862
4533
|
if (!finalLine) {
|
|
2863
|
-
throw new
|
|
4534
|
+
throw new LlmExeError("No line found where done = true.", {
|
|
4535
|
+
code: "llm.invalid_jsonl_response",
|
|
4536
|
+
context: {
|
|
4537
|
+
operation: "combineJsonl",
|
|
4538
|
+
lineCount: lines.length,
|
|
4539
|
+
expected: "a final line with done = true"
|
|
4540
|
+
}
|
|
4541
|
+
});
|
|
2864
4542
|
}
|
|
2865
4543
|
const result = {
|
|
2866
4544
|
model: finalLine.model,
|
|
@@ -2949,7 +4627,10 @@ var ollama = {
|
|
|
2949
4627
|
"ollama.gemma3": withDefaultModel(ollamaChatV1, "gemma3"),
|
|
2950
4628
|
"ollama.mistral": withDefaultModel(ollamaChatV1, "mistral"),
|
|
2951
4629
|
"ollama.qwen2.5": withDefaultModel(ollamaChatV1, "qwen2.5"),
|
|
2952
|
-
"ollama.qwen3": withDefaultModel(ollamaChatV1, "qwen3")
|
|
4630
|
+
"ollama.qwen3": withDefaultModel(ollamaChatV1, "qwen3"),
|
|
4631
|
+
"ollama.qwen3.5": withDefaultModel(ollamaChatV1, "qwen3.5"),
|
|
4632
|
+
"ollama.gemma4": withDefaultModel(ollamaChatV1, "gemma4"),
|
|
4633
|
+
"ollama.gpt-oss": withDefaultModel(ollamaChatV1, "gpt-oss")
|
|
2953
4634
|
};
|
|
2954
4635
|
|
|
2955
4636
|
// src/llm/config/google/promptSanitizeMessageCallback.ts
|
|
@@ -3022,7 +4703,16 @@ function googleGeminiPromptSanitize(_messages, _inputBodyObj, _outputObj) {
|
|
|
3022
4703
|
}
|
|
3023
4704
|
if (Array.isArray(_messages)) {
|
|
3024
4705
|
if (_messages.length === 0) {
|
|
3025
|
-
throw new
|
|
4706
|
+
throw new LlmExeError("Empty messages array", {
|
|
4707
|
+
code: "prompt.invalid_messages",
|
|
4708
|
+
context: {
|
|
4709
|
+
operation: "googleGeminiPromptSanitize",
|
|
4710
|
+
provider: "google",
|
|
4711
|
+
received: "empty array",
|
|
4712
|
+
expected: "a non-empty messages array",
|
|
4713
|
+
resolution: "Pass at least one message to the prompt."
|
|
4714
|
+
}
|
|
4715
|
+
});
|
|
3026
4716
|
}
|
|
3027
4717
|
if (_messages.length === 1 && _messages[0].role === "system") {
|
|
3028
4718
|
return [{ role: "user", parts: [{ text: _messages[0].content }] }];
|
|
@@ -3050,7 +4740,16 @@ function googleGeminiPromptSanitize(_messages, _inputBodyObj, _outputObj) {
|
|
|
3050
4740
|
const result = _messages.map(googleGeminiPromptMessageCallback);
|
|
3051
4741
|
return mergeConsecutiveSameRole2(result);
|
|
3052
4742
|
}
|
|
3053
|
-
throw new
|
|
4743
|
+
throw new LlmExeError("Invalid messages format", {
|
|
4744
|
+
code: "prompt.invalid_messages",
|
|
4745
|
+
context: {
|
|
4746
|
+
operation: "googleGeminiPromptSanitize",
|
|
4747
|
+
provider: "google",
|
|
4748
|
+
received: typeof _messages,
|
|
4749
|
+
expected: "string or messages array",
|
|
4750
|
+
resolution: "Pass a string or an array of chat messages."
|
|
4751
|
+
}
|
|
4752
|
+
});
|
|
3054
4753
|
}
|
|
3055
4754
|
|
|
3056
4755
|
// src/llm/output/google.gemini/formatResult.ts
|
|
@@ -3166,23 +4865,27 @@ var googleGeminiChatV1 = {
|
|
|
3166
4865
|
};
|
|
3167
4866
|
var google = {
|
|
3168
4867
|
"google.chat.v1": googleGeminiChatV1,
|
|
3169
|
-
"google.gemini-2.5-flash": withDefaultModel(
|
|
3170
|
-
googleGeminiChatV1,
|
|
3171
|
-
"gemini-2.5-flash"
|
|
3172
|
-
),
|
|
3173
|
-
"google.gemini-2.5-flash-lite": withDefaultModel(
|
|
3174
|
-
googleGeminiChatV1,
|
|
3175
|
-
"gemini-2.5-flash-lite"
|
|
3176
|
-
),
|
|
3177
|
-
"google.gemini-2.5-pro": withDefaultModel(
|
|
3178
|
-
googleGeminiChatV1,
|
|
3179
|
-
"gemini-2.5-pro"
|
|
3180
|
-
),
|
|
3181
4868
|
"google.gemini-3.1-flash-lite": withDefaultModel(
|
|
3182
4869
|
googleGeminiChatV1,
|
|
3183
4870
|
"gemini-3.1-flash-lite"
|
|
3184
4871
|
),
|
|
4872
|
+
"google.gemini-3.5-flash": withDefaultModel(
|
|
4873
|
+
googleGeminiChatV1,
|
|
4874
|
+
"gemini-3.5-flash"
|
|
4875
|
+
),
|
|
3185
4876
|
// Deprecated
|
|
4877
|
+
...deprecateShorthand("google.gemini-2.5-flash", {
|
|
4878
|
+
config: withDefaultModel(googleGeminiChatV1, "gemini-2.5-flash"),
|
|
4879
|
+
message: 'Model "google.gemini-2.5-flash" is deprecated and will shut down on 2026-06-17.'
|
|
4880
|
+
}),
|
|
4881
|
+
...deprecateShorthand("google.gemini-2.5-flash-lite", {
|
|
4882
|
+
config: withDefaultModel(googleGeminiChatV1, "gemini-2.5-flash-lite"),
|
|
4883
|
+
message: 'Model "google.gemini-2.5-flash-lite" is deprecated and will shut down on 2026-07-22.'
|
|
4884
|
+
}),
|
|
4885
|
+
...deprecateShorthand("google.gemini-2.5-pro", {
|
|
4886
|
+
config: withDefaultModel(googleGeminiChatV1, "gemini-2.5-pro"),
|
|
4887
|
+
message: 'Model "google.gemini-2.5-pro" is deprecated and will shut down on 2026-06-17.'
|
|
4888
|
+
}),
|
|
3186
4889
|
"google.gemini-2.0-flash": withDefaultModel(
|
|
3187
4890
|
googleGeminiChatV1,
|
|
3188
4891
|
"gemini-2.0-flash"
|
|
@@ -3223,81 +4926,28 @@ var configs = {
|
|
|
3223
4926
|
};
|
|
3224
4927
|
function getLlmConfig(provider) {
|
|
3225
4928
|
if (!provider) {
|
|
3226
|
-
throw new LlmExeError(`Missing provider`,
|
|
3227
|
-
|
|
3228
|
-
|
|
4929
|
+
throw new LlmExeError(`Missing provider`, {
|
|
4930
|
+
code: "configuration.missing_provider",
|
|
4931
|
+
context: {
|
|
4932
|
+
operation: "getLlmConfig",
|
|
4933
|
+
availableProviders: Object.keys(configs),
|
|
4934
|
+
resolution: "Provide a valid provider"
|
|
4935
|
+
}
|
|
3229
4936
|
});
|
|
3230
4937
|
}
|
|
3231
4938
|
const pick2 = configs[provider];
|
|
3232
4939
|
if (pick2) {
|
|
3233
4940
|
return pick2;
|
|
3234
4941
|
}
|
|
3235
|
-
throw new LlmExeError(`Invalid provider: ${provider}`,
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
// src/utils/modules/maskApiKeysInDebug.ts
|
|
3243
|
-
function maskApiKeys(log) {
|
|
3244
|
-
return log.replace(
|
|
3245
|
-
/\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,
|
|
3246
|
-
(match) => {
|
|
3247
|
-
if (match.length <= 8) return match;
|
|
3248
|
-
const prefix = match.substring(0, 4);
|
|
3249
|
-
const suffix = match.substring(match.length - 4);
|
|
3250
|
-
const maskLength = match.length - 8;
|
|
3251
|
-
return `${prefix}${"*".repeat(maskLength)}${suffix}`;
|
|
3252
|
-
}
|
|
3253
|
-
);
|
|
3254
|
-
}
|
|
3255
|
-
|
|
3256
|
-
// src/utils/modules/debug.ts
|
|
3257
|
-
function debug(...args) {
|
|
3258
|
-
const debugValue = getEnvironmentVariable("LLM_EXE_DEBUG");
|
|
3259
|
-
const logs = [];
|
|
3260
|
-
for (const arg of args) {
|
|
3261
|
-
if (arg && typeof arg === "object") {
|
|
3262
|
-
if (arg instanceof Error) {
|
|
3263
|
-
} else if (arg instanceof Array) {
|
|
3264
|
-
logs.push(arg.map((item) => JSON.stringify(item, null, 2)));
|
|
3265
|
-
} else if (arg instanceof Map) {
|
|
3266
|
-
logs.push(
|
|
3267
|
-
Array.from(arg.entries()).map(
|
|
3268
|
-
([key, value]) => `${key}: ${JSON.stringify(value, null, 2)}`
|
|
3269
|
-
)
|
|
3270
|
-
);
|
|
3271
|
-
} else if (arg instanceof Set) {
|
|
3272
|
-
logs.push(Array.from(arg).map((item) => JSON.stringify(item, null, 2)));
|
|
3273
|
-
} else if (arg instanceof Date) {
|
|
3274
|
-
logs.push(arg.toISOString());
|
|
3275
|
-
} else if (arg instanceof RegExp) {
|
|
3276
|
-
logs.push(arg.toString());
|
|
3277
|
-
} else {
|
|
3278
|
-
try {
|
|
3279
|
-
let shouldMask = false;
|
|
3280
|
-
if (arg.headers && arg.headers.Authorization) {
|
|
3281
|
-
shouldMask = true;
|
|
3282
|
-
}
|
|
3283
|
-
let str = JSON.stringify(arg, null, 2);
|
|
3284
|
-
if (shouldMask) {
|
|
3285
|
-
str = maskApiKeys(str);
|
|
3286
|
-
}
|
|
3287
|
-
logs.push(str);
|
|
3288
|
-
} catch (error) {
|
|
3289
|
-
console.error("Error parsing object:", error);
|
|
3290
|
-
}
|
|
3291
|
-
}
|
|
3292
|
-
} else if (typeof arg === "string") {
|
|
3293
|
-
logs.push(arg);
|
|
3294
|
-
} else {
|
|
3295
|
-
logs.push(arg);
|
|
4942
|
+
throw new LlmExeError(`Invalid provider: ${provider}`, {
|
|
4943
|
+
code: "configuration.invalid_provider",
|
|
4944
|
+
context: {
|
|
4945
|
+
operation: "getLlmConfig",
|
|
4946
|
+
provider,
|
|
4947
|
+
availableProviders: Object.keys(configs),
|
|
4948
|
+
resolution: "Provide a valid provider"
|
|
3296
4949
|
}
|
|
3297
|
-
}
|
|
3298
|
-
if (typeof debugValue === "string" && debugValue !== "" && debugValue.toLowerCase() !== "undefined" && debugValue.toLowerCase() !== "null") {
|
|
3299
|
-
console.debug(...logs);
|
|
3300
|
-
}
|
|
4950
|
+
});
|
|
3301
4951
|
}
|
|
3302
4952
|
|
|
3303
4953
|
// src/utils/modules/isValidUrl.ts
|
|
@@ -3315,41 +4965,93 @@ async function apiRequest(url, options) {
|
|
|
3315
4965
|
const finalOptions = {
|
|
3316
4966
|
...options
|
|
3317
4967
|
};
|
|
4968
|
+
debug(url, finalOptions);
|
|
4969
|
+
if (!url || !isValidUrl(url)) {
|
|
4970
|
+
const safeUrl = safeRequestUrl(url);
|
|
4971
|
+
throw new LlmExeError("Invalid URL", {
|
|
4972
|
+
code: "request.invalid_url",
|
|
4973
|
+
context: {
|
|
4974
|
+
operation: "apiRequest",
|
|
4975
|
+
url: safeUrl,
|
|
4976
|
+
expected: "valid URL"
|
|
4977
|
+
}
|
|
4978
|
+
});
|
|
4979
|
+
}
|
|
4980
|
+
let response;
|
|
3318
4981
|
try {
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
4982
|
+
response = await fetch(url, finalOptions);
|
|
4983
|
+
} catch (fetchError) {
|
|
4984
|
+
const innerMsg = fetchError instanceof Error ? fetchError.message : "Error";
|
|
4985
|
+
const safeUrl = safeRequestUrl(url);
|
|
4986
|
+
throw new LlmExeError(`Request to ${safeUrl} failed: ${innerMsg}`, {
|
|
4987
|
+
code: "request.http_error",
|
|
4988
|
+
context: {
|
|
4989
|
+
operation: "apiRequest",
|
|
4990
|
+
url: safeUrl
|
|
4991
|
+
},
|
|
4992
|
+
cause: fetchError
|
|
4993
|
+
});
|
|
4994
|
+
}
|
|
4995
|
+
if (!response.ok) {
|
|
4996
|
+
let bodyText = "";
|
|
4997
|
+
let bodyJson = void 0;
|
|
4998
|
+
let bodyReadError = void 0;
|
|
4999
|
+
try {
|
|
5000
|
+
bodyText = await response.text();
|
|
5001
|
+
if (bodyText) {
|
|
5002
|
+
try {
|
|
5003
|
+
bodyJson = JSON.parse(bodyText);
|
|
5004
|
+
} catch {
|
|
3337
5005
|
}
|
|
3338
|
-
} catch {
|
|
3339
5006
|
}
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
5007
|
+
} catch (e) {
|
|
5008
|
+
bodyReadError = e;
|
|
5009
|
+
}
|
|
5010
|
+
let message;
|
|
5011
|
+
if (bodyText) {
|
|
5012
|
+
let detail = bodyText;
|
|
5013
|
+
if (bodyJson) {
|
|
5014
|
+
const b = bodyJson;
|
|
5015
|
+
detail = b.error?.message || b.error || b.message || bodyText;
|
|
5016
|
+
if (typeof detail !== "string") detail = JSON.stringify(detail);
|
|
5017
|
+
}
|
|
5018
|
+
const safeDetail = safeProviderString(detail) ?? "";
|
|
5019
|
+
message = `HTTP error. Status Code: ${response.status}. Error Message: ${safeDetail}`;
|
|
3346
5020
|
} else {
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
const
|
|
3352
|
-
|
|
5021
|
+
message = `HTTP error. Status: ${response.status}. Error Message: ${response.statusText || "Unknown error."}`;
|
|
5022
|
+
}
|
|
5023
|
+
const safeUrl = safeRequestUrl(url);
|
|
5024
|
+
const wrappedMessage = `Request to ${safeUrl} failed: ${message}`;
|
|
5025
|
+
const safeHeaders = safeResponseHeaders(response.headers);
|
|
5026
|
+
const providerError = parseProviderErrorGeneric({
|
|
5027
|
+
status: response.status,
|
|
5028
|
+
statusText: response.statusText,
|
|
5029
|
+
headers: safeHeaders,
|
|
5030
|
+
bodyJson,
|
|
5031
|
+
bodyText
|
|
5032
|
+
});
|
|
5033
|
+
throw new LlmExeError(wrappedMessage, {
|
|
5034
|
+
code: "request.http_error",
|
|
5035
|
+
context: {
|
|
5036
|
+
operation: "apiRequest",
|
|
5037
|
+
url: safeUrl,
|
|
5038
|
+
status: response.status,
|
|
5039
|
+
statusText: response.statusText,
|
|
5040
|
+
responseHeaders: safeHeaders,
|
|
5041
|
+
providerError,
|
|
5042
|
+
providerErrorBody: bodyJson !== void 0 ? safeProviderErrorBody(bodyJson) : void 0,
|
|
5043
|
+
providerErrorRaw: bodyText ? safeProviderErrorBody(bodyText) : void 0
|
|
5044
|
+
},
|
|
5045
|
+
cause: bodyReadError
|
|
5046
|
+
});
|
|
5047
|
+
}
|
|
5048
|
+
const contentType = response.headers.get("content-type");
|
|
5049
|
+
if (contentType?.includes("application/json")) {
|
|
5050
|
+
const responseData = await response.json();
|
|
5051
|
+
return responseData;
|
|
5052
|
+
} else {
|
|
5053
|
+
const responseData = await response.text();
|
|
5054
|
+
return responseData;
|
|
3353
5055
|
}
|
|
3354
5056
|
}
|
|
3355
5057
|
|
|
@@ -3470,7 +5172,19 @@ async function runWithTemporaryEnv(env, handler) {
|
|
|
3470
5172
|
// src/utils/modules/getAwsAuthorizationHeaders.ts
|
|
3471
5173
|
async function getAwsAuthorizationHeaders(req, props) {
|
|
3472
5174
|
if (!props.url || !props.regionName) {
|
|
3473
|
-
throw new
|
|
5175
|
+
throw new LlmExeError(
|
|
5176
|
+
"URL and region name are required for AWS authorization",
|
|
5177
|
+
{
|
|
5178
|
+
code: "auth.aws_signing_input_missing",
|
|
5179
|
+
context: {
|
|
5180
|
+
operation: "getAwsAuthorizationHeaders",
|
|
5181
|
+
url: props.url,
|
|
5182
|
+
regionName: props.regionName,
|
|
5183
|
+
expected: "both url and regionName to be set",
|
|
5184
|
+
resolution: "Set AWS_REGION as an environment variable (or pass regionName) and provide a valid request URL."
|
|
5185
|
+
}
|
|
5186
|
+
}
|
|
5187
|
+
);
|
|
3474
5188
|
}
|
|
3475
5189
|
const providerChain = fromNodeProviderChain();
|
|
3476
5190
|
const credentials = await runWithTemporaryEnv(
|
|
@@ -3509,6 +5223,12 @@ async function getAwsAuthorizationHeaders(req, props) {
|
|
|
3509
5223
|
}
|
|
3510
5224
|
|
|
3511
5225
|
// src/llm/_utils.parseHeaders.ts
|
|
5226
|
+
var REPLACED_HEADERS_EXCERPT_MAX = 500;
|
|
5227
|
+
function safeReplacedHeaders(value) {
|
|
5228
|
+
if (!value) return "";
|
|
5229
|
+
const truncated = value.length > REPLACED_HEADERS_EXCERPT_MAX ? value.slice(0, REPLACED_HEADERS_EXCERPT_MAX) + "\u2026(truncated)" : value;
|
|
5230
|
+
return redactSecrets(truncated);
|
|
5231
|
+
}
|
|
3512
5232
|
async function parseHeaders(config, replacements, payload) {
|
|
3513
5233
|
const replace = replaceTemplateStringSimple(config.headers, replacements);
|
|
3514
5234
|
let parsedHeaders = {};
|
|
@@ -3520,8 +5240,21 @@ async function parseHeaders(config, replacements, payload) {
|
|
|
3520
5240
|
}
|
|
3521
5241
|
} catch (error) {
|
|
3522
5242
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
3523
|
-
|
|
3524
|
-
|
|
5243
|
+
const safeReplaced = safeReplacedHeaders(replace);
|
|
5244
|
+
throw new LlmExeError(
|
|
5245
|
+
`Failed to parse headers configuration: ${errorMessage}. Headers template: "${config.headers}". After replacement: "${safeReplaced}"`,
|
|
5246
|
+
{
|
|
5247
|
+
code: "configuration.invalid_headers",
|
|
5248
|
+
context: {
|
|
5249
|
+
operation: "parseHeaders",
|
|
5250
|
+
provider: config.provider,
|
|
5251
|
+
key: config.key,
|
|
5252
|
+
headerTemplate: config.headers,
|
|
5253
|
+
replacedHeadersExcerpt: safeReplaced,
|
|
5254
|
+
resolution: "Fix the headers template so replacement produces a JSON object."
|
|
5255
|
+
},
|
|
5256
|
+
cause: error
|
|
5257
|
+
}
|
|
3525
5258
|
);
|
|
3526
5259
|
}
|
|
3527
5260
|
}
|
|
@@ -3675,29 +5408,47 @@ async function useLlm_call(state, messages, _options) {
|
|
|
3675
5408
|
headers: {},
|
|
3676
5409
|
body
|
|
3677
5410
|
});
|
|
3678
|
-
const response = config.provider === "openai.chat-mock" ? {
|
|
3679
|
-
id: "0123-45-6789",
|
|
3680
|
-
model: "model",
|
|
3681
|
-
created: (/* @__PURE__ */ new Date()).getTime(),
|
|
3682
|
-
usage: { completion_tokens: 0, prompt_tokens: 0, total_tokens: 0 },
|
|
3683
|
-
choices: [
|
|
3684
|
-
{
|
|
3685
|
-
message: {
|
|
3686
|
-
role: "assistant",
|
|
3687
|
-
content: `Hello world from LLM! The input was ${JSON.stringify(
|
|
3688
|
-
messages
|
|
3689
|
-
)}`
|
|
3690
|
-
}
|
|
3691
|
-
}
|
|
3692
|
-
]
|
|
3693
|
-
} : await apiRequest(url, {
|
|
3694
|
-
method: config.method,
|
|
3695
|
-
body,
|
|
3696
|
-
headers
|
|
3697
|
-
});
|
|
3698
5411
|
const { transformResponse = OutputDefault } = config;
|
|
3699
|
-
|
|
3700
|
-
|
|
5412
|
+
if (config.provider === "openai.chat-mock") {
|
|
5413
|
+
const mockResponse = {
|
|
5414
|
+
id: "0123-45-6789",
|
|
5415
|
+
model: "model",
|
|
5416
|
+
created: (/* @__PURE__ */ new Date()).getTime(),
|
|
5417
|
+
usage: { completion_tokens: 0, prompt_tokens: 0, total_tokens: 0 },
|
|
5418
|
+
choices: [
|
|
5419
|
+
{
|
|
5420
|
+
message: {
|
|
5421
|
+
role: "assistant",
|
|
5422
|
+
content: `Hello world from LLM! The input was ${JSON.stringify(messages)}`
|
|
5423
|
+
}
|
|
5424
|
+
}
|
|
5425
|
+
]
|
|
5426
|
+
};
|
|
5427
|
+
return BaseLlmOutput(transformResponse(mockResponse, config));
|
|
5428
|
+
}
|
|
5429
|
+
try {
|
|
5430
|
+
const response = await apiRequest(url, {
|
|
5431
|
+
method: config.method,
|
|
5432
|
+
body,
|
|
5433
|
+
headers
|
|
5434
|
+
});
|
|
5435
|
+
return BaseLlmOutput(transformResponse(response, config));
|
|
5436
|
+
} catch (e) {
|
|
5437
|
+
if (!isLlmExeError(e, "request.http_error")) throw e;
|
|
5438
|
+
const ctx = e.context ?? {};
|
|
5439
|
+
const status = typeof ctx.status === "number" ? ctx.status : void 0;
|
|
5440
|
+
const code = status ? statusToLlmProviderCode(status) : "llm.provider_http_error";
|
|
5441
|
+
throw new LlmExeError(e.message, {
|
|
5442
|
+
code,
|
|
5443
|
+
context: {
|
|
5444
|
+
...ctx,
|
|
5445
|
+
operation: "useLlm_call",
|
|
5446
|
+
provider: state.provider,
|
|
5447
|
+
model: state.model
|
|
5448
|
+
},
|
|
5449
|
+
cause: e
|
|
5450
|
+
});
|
|
5451
|
+
}
|
|
3701
5452
|
}
|
|
3702
5453
|
|
|
3703
5454
|
// src/llm/_utils.stateFromOptions.ts
|
|
@@ -3721,7 +5472,16 @@ function stateFromOptions(options, config) {
|
|
|
3721
5472
|
if (Array.isArray(thisConfig?.required)) {
|
|
3722
5473
|
const [required, message = `Error: [${key}] is required`] = thisConfig.required;
|
|
3723
5474
|
if (required && typeof value === "undefined") {
|
|
3724
|
-
throw new
|
|
5475
|
+
throw new LlmExeError(message, {
|
|
5476
|
+
code: "configuration.missing_option",
|
|
5477
|
+
context: {
|
|
5478
|
+
operation: "stateFromOptions",
|
|
5479
|
+
provider: config.provider,
|
|
5480
|
+
key: config.key,
|
|
5481
|
+
option: String(key),
|
|
5482
|
+
resolution: `Provide a value for "${String(key)}" via options or environment.`
|
|
5483
|
+
}
|
|
5484
|
+
});
|
|
3725
5485
|
}
|
|
3726
5486
|
}
|
|
3727
5487
|
}
|
|
@@ -3768,8 +5528,12 @@ function apiRequestWrapper(config, options, handler, doNotRetryErrorMessages = [
|
|
|
3768
5528
|
const numOfAttempts = options.numOfAttempts || 2;
|
|
3769
5529
|
const jitter = options.jitter || "none";
|
|
3770
5530
|
let traceId = options?.traceId || null;
|
|
3771
|
-
async function call(messages, options2) {
|
|
5531
|
+
async function call(messages, options2, context) {
|
|
3772
5532
|
try {
|
|
5533
|
+
emitDeprecationWarning(config, {
|
|
5534
|
+
executorName: context?.executor?.name,
|
|
5535
|
+
traceId: context?.traceId ?? getTraceId() ?? void 0
|
|
5536
|
+
});
|
|
3773
5537
|
metrics.total_calls++;
|
|
3774
5538
|
const result = await backOff(
|
|
3775
5539
|
() => asyncCallWithTimeout(
|
|
@@ -3947,8 +5711,19 @@ var embeddingConfigs = {
|
|
|
3947
5711
|
const isV3 = /embed-(english|multilingual)-v3/.test(model);
|
|
3948
5712
|
if (isV3) {
|
|
3949
5713
|
if (value === 1024) return void 0;
|
|
3950
|
-
throw new
|
|
3951
|
-
`Cohere Embed v3 only supports 1024-dimensional output (model: "${model}", requested: ${value}). Use cohere.embed-v4:0 for configurable dimensions
|
|
5714
|
+
throw new LlmExeError(
|
|
5715
|
+
`Cohere Embed v3 only supports 1024-dimensional output (model: "${model}", requested: ${value}). Use cohere.embed-v4:0 for configurable dimensions.`,
|
|
5716
|
+
{
|
|
5717
|
+
code: "embedding.unsupported_dimensions",
|
|
5718
|
+
context: {
|
|
5719
|
+
operation: "embedding.dimensionTransform",
|
|
5720
|
+
provider: "amazon:cohere.embedding",
|
|
5721
|
+
model,
|
|
5722
|
+
dimensions: value,
|
|
5723
|
+
expected: 1024,
|
|
5724
|
+
resolution: "Use cohere.embed-v4:0 for configurable dimensions."
|
|
5725
|
+
}
|
|
5726
|
+
}
|
|
3952
5727
|
);
|
|
3953
5728
|
}
|
|
3954
5729
|
return value;
|
|
@@ -3959,13 +5734,28 @@ var embeddingConfigs = {
|
|
|
3959
5734
|
};
|
|
3960
5735
|
function getEmbeddingConfig(provider) {
|
|
3961
5736
|
if (!provider) {
|
|
3962
|
-
throw new
|
|
5737
|
+
throw new LlmExeError(`Missing provider`, {
|
|
5738
|
+
code: "embedding.missing_provider",
|
|
5739
|
+
context: {
|
|
5740
|
+
operation: "getEmbeddingConfig",
|
|
5741
|
+
availableProviders: Object.keys(embeddingConfigs),
|
|
5742
|
+
resolution: "Provide a valid embedding provider key."
|
|
5743
|
+
}
|
|
5744
|
+
});
|
|
3963
5745
|
}
|
|
3964
5746
|
const pick2 = embeddingConfigs[provider];
|
|
3965
5747
|
if (pick2) {
|
|
3966
5748
|
return pick2;
|
|
3967
5749
|
}
|
|
3968
|
-
throw new
|
|
5750
|
+
throw new LlmExeError(`Invalid provider: ${provider}`, {
|
|
5751
|
+
code: "embedding.invalid_provider",
|
|
5752
|
+
context: {
|
|
5753
|
+
operation: "getEmbeddingConfig",
|
|
5754
|
+
provider,
|
|
5755
|
+
availableProviders: Object.keys(embeddingConfigs),
|
|
5756
|
+
resolution: "Provide a valid embedding provider key."
|
|
5757
|
+
}
|
|
5758
|
+
});
|
|
3969
5759
|
}
|
|
3970
5760
|
|
|
3971
5761
|
// src/embedding/output/BaseEmbeddingOutput.ts
|
|
@@ -4069,7 +5859,16 @@ function getEmbeddingOutputParser(config, response) {
|
|
|
4069
5859
|
case "amazon:cohere.embedding.v1":
|
|
4070
5860
|
return CohereBedrockEmbedding(response, config);
|
|
4071
5861
|
default:
|
|
4072
|
-
throw new
|
|
5862
|
+
throw new LlmExeError("Unsupported provider", {
|
|
5863
|
+
code: "embedding.invalid_response_shape",
|
|
5864
|
+
context: {
|
|
5865
|
+
operation: "getEmbeddingOutputParser",
|
|
5866
|
+
provider: config.key,
|
|
5867
|
+
model: config.model,
|
|
5868
|
+
availableProviders: Object.keys(embeddingConfigs),
|
|
5869
|
+
resolution: "Use a supported embedding provider key."
|
|
5870
|
+
}
|
|
5871
|
+
});
|
|
4073
5872
|
}
|
|
4074
5873
|
}
|
|
4075
5874
|
|
|
@@ -4089,12 +5888,29 @@ async function createEmbedding_call(state, _input, _options) {
|
|
|
4089
5888
|
headers: {},
|
|
4090
5889
|
body
|
|
4091
5890
|
});
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
5891
|
+
try {
|
|
5892
|
+
const request = await apiRequest(url, {
|
|
5893
|
+
method: config.method,
|
|
5894
|
+
body,
|
|
5895
|
+
headers
|
|
5896
|
+
});
|
|
5897
|
+
return getEmbeddingOutputParser(state, request);
|
|
5898
|
+
} catch (e) {
|
|
5899
|
+
if (!isLlmExeError(e, "request.http_error")) throw e;
|
|
5900
|
+
const ctx = e.context ?? {};
|
|
5901
|
+
const status = typeof ctx.status === "number" ? ctx.status : void 0;
|
|
5902
|
+
const code = status ? statusToEmbeddingProviderCode(status) : "embedding.provider_http_error";
|
|
5903
|
+
throw new LlmExeError(e.message, {
|
|
5904
|
+
code,
|
|
5905
|
+
context: {
|
|
5906
|
+
...ctx,
|
|
5907
|
+
operation: "createEmbedding_call",
|
|
5908
|
+
provider: state.provider,
|
|
5909
|
+
model: state.model
|
|
5910
|
+
},
|
|
5911
|
+
cause: e
|
|
5912
|
+
});
|
|
5913
|
+
}
|
|
4098
5914
|
}
|
|
4099
5915
|
|
|
4100
5916
|
// src/embedding/embedding.ts
|
|
@@ -4103,6 +5919,245 @@ function createEmbedding(provider, options) {
|
|
|
4103
5919
|
return apiRequestWrapper(config, options, createEmbedding_call);
|
|
4104
5920
|
}
|
|
4105
5921
|
|
|
5922
|
+
// src/prompt/_templateValidation.ts
|
|
5923
|
+
var BUILT_IN_HELPERS = /* @__PURE__ */ new Set([
|
|
5924
|
+
"if",
|
|
5925
|
+
"unless",
|
|
5926
|
+
"each",
|
|
5927
|
+
"with",
|
|
5928
|
+
"lookup",
|
|
5929
|
+
"log",
|
|
5930
|
+
"blockHelperMissing",
|
|
5931
|
+
"helperMissing"
|
|
5932
|
+
]);
|
|
5933
|
+
function isKnownHelper(name, customHelpers) {
|
|
5934
|
+
if (BUILT_IN_HELPERS.has(name)) return true;
|
|
5935
|
+
if (customHelpers && Object.prototype.hasOwnProperty.call(customHelpers, name)) {
|
|
5936
|
+
return true;
|
|
5937
|
+
}
|
|
5938
|
+
return false;
|
|
5939
|
+
}
|
|
5940
|
+
function pathRootSegment(path) {
|
|
5941
|
+
if (path.depth > 0) return null;
|
|
5942
|
+
if (path.data) return null;
|
|
5943
|
+
if (path.parts.length === 0) return null;
|
|
5944
|
+
return path.parts[0];
|
|
5945
|
+
}
|
|
5946
|
+
function pathToCollectedString(path) {
|
|
5947
|
+
const parts = path.parts.slice();
|
|
5948
|
+
return parts.join(".");
|
|
5949
|
+
}
|
|
5950
|
+
function collectFromPath(path, source, locals, options, references, seen) {
|
|
5951
|
+
const root = pathRootSegment(path);
|
|
5952
|
+
if (!root) return;
|
|
5953
|
+
if (locals.has(root)) return;
|
|
5954
|
+
const collected = pathToCollectedString(path);
|
|
5955
|
+
const dedupKey = `${source}::${collected}`;
|
|
5956
|
+
if (seen.has(dedupKey)) return;
|
|
5957
|
+
seen.add(dedupKey);
|
|
5958
|
+
references.push({
|
|
5959
|
+
path: collected,
|
|
5960
|
+
source,
|
|
5961
|
+
location: options.location
|
|
5962
|
+
});
|
|
5963
|
+
}
|
|
5964
|
+
function collectFromExpression(expr, source, locals, options, references, missingHelpers, seen) {
|
|
5965
|
+
if (expr.type === "PathExpression") {
|
|
5966
|
+
collectFromPath(expr, source, locals, options, references, seen);
|
|
5967
|
+
return;
|
|
5968
|
+
}
|
|
5969
|
+
if (expr.type === "SubExpression") {
|
|
5970
|
+
walkCall(
|
|
5971
|
+
expr.path,
|
|
5972
|
+
expr.params,
|
|
5973
|
+
expr.hash,
|
|
5974
|
+
locals,
|
|
5975
|
+
options,
|
|
5976
|
+
references,
|
|
5977
|
+
missingHelpers,
|
|
5978
|
+
seen
|
|
5979
|
+
);
|
|
5980
|
+
return;
|
|
5981
|
+
}
|
|
5982
|
+
}
|
|
5983
|
+
function walkHash(hash, locals, options, references, missingHelpers, seen) {
|
|
5984
|
+
if (!hash || !hash.pairs) return;
|
|
5985
|
+
for (const pair of hash.pairs) {
|
|
5986
|
+
collectFromExpression(
|
|
5987
|
+
pair.value,
|
|
5988
|
+
"hash",
|
|
5989
|
+
locals,
|
|
5990
|
+
options,
|
|
5991
|
+
references,
|
|
5992
|
+
missingHelpers,
|
|
5993
|
+
seen
|
|
5994
|
+
);
|
|
5995
|
+
}
|
|
5996
|
+
}
|
|
5997
|
+
function walkCall(path, params, hash, locals, options, references, missingHelpers, seen) {
|
|
5998
|
+
const root = pathRootSegment(path);
|
|
5999
|
+
const hasArgs = params.length > 0 || hash !== void 0 && hash.pairs.length > 0;
|
|
6000
|
+
if (hasArgs) {
|
|
6001
|
+
if (root) {
|
|
6002
|
+
if (!isKnownHelper(path.original, options.helpers) && !locals.has(root)) {
|
|
6003
|
+
missingHelpers.add(path.original);
|
|
6004
|
+
}
|
|
6005
|
+
}
|
|
6006
|
+
for (const param of params) {
|
|
6007
|
+
collectFromExpression(
|
|
6008
|
+
param,
|
|
6009
|
+
"helper-param",
|
|
6010
|
+
locals,
|
|
6011
|
+
options,
|
|
6012
|
+
references,
|
|
6013
|
+
missingHelpers,
|
|
6014
|
+
seen
|
|
6015
|
+
);
|
|
6016
|
+
}
|
|
6017
|
+
walkHash(hash, locals, options, references, missingHelpers, seen);
|
|
6018
|
+
return;
|
|
6019
|
+
}
|
|
6020
|
+
if (root && isKnownHelper(path.original, options.helpers)) {
|
|
6021
|
+
return;
|
|
6022
|
+
}
|
|
6023
|
+
collectFromPath(path, "mustache", locals, options, references, seen);
|
|
6024
|
+
}
|
|
6025
|
+
function walkProgram(program, parentLocals, options, references, missingHelpers, seen) {
|
|
6026
|
+
if (!program) return;
|
|
6027
|
+
const locals = new Set(parentLocals);
|
|
6028
|
+
if (program.blockParams) {
|
|
6029
|
+
for (const bp of program.blockParams) {
|
|
6030
|
+
locals.add(bp);
|
|
6031
|
+
}
|
|
6032
|
+
}
|
|
6033
|
+
for (const node of program.body) {
|
|
6034
|
+
walkStatement(node, locals, options, references, missingHelpers, seen);
|
|
6035
|
+
}
|
|
6036
|
+
}
|
|
6037
|
+
function walkStatement(node, locals, options, references, missingHelpers, seen) {
|
|
6038
|
+
switch (node.type) {
|
|
6039
|
+
case "MustacheStatement": {
|
|
6040
|
+
const m = node;
|
|
6041
|
+
if (m.path.type === "PathExpression") {
|
|
6042
|
+
walkCall(
|
|
6043
|
+
m.path,
|
|
6044
|
+
m.params,
|
|
6045
|
+
m.hash,
|
|
6046
|
+
locals,
|
|
6047
|
+
options,
|
|
6048
|
+
references,
|
|
6049
|
+
missingHelpers,
|
|
6050
|
+
seen
|
|
6051
|
+
);
|
|
6052
|
+
}
|
|
6053
|
+
return;
|
|
6054
|
+
}
|
|
6055
|
+
case "BlockStatement": {
|
|
6056
|
+
const b = node;
|
|
6057
|
+
const root = pathRootSegment(b.path);
|
|
6058
|
+
if (root && !isKnownHelper(b.path.original, options.helpers) && !locals.has(root)) {
|
|
6059
|
+
missingHelpers.add(b.path.original);
|
|
6060
|
+
}
|
|
6061
|
+
for (const param of b.params) {
|
|
6062
|
+
collectFromExpression(
|
|
6063
|
+
param,
|
|
6064
|
+
"block-param",
|
|
6065
|
+
locals,
|
|
6066
|
+
options,
|
|
6067
|
+
references,
|
|
6068
|
+
missingHelpers,
|
|
6069
|
+
seen
|
|
6070
|
+
);
|
|
6071
|
+
}
|
|
6072
|
+
walkHash(b.hash, locals, options, references, missingHelpers, seen);
|
|
6073
|
+
const isEach = b.path.original === "each";
|
|
6074
|
+
const hasBlockParams = b.program?.blockParams && b.program.blockParams.length > 0 || b.inverse?.blockParams && b.inverse.blockParams.length > 0;
|
|
6075
|
+
if (isEach && !hasBlockParams) {
|
|
6076
|
+
return;
|
|
6077
|
+
}
|
|
6078
|
+
walkProgram(b.program, locals, options, references, missingHelpers, seen);
|
|
6079
|
+
walkProgram(b.inverse, locals, options, references, missingHelpers, seen);
|
|
6080
|
+
return;
|
|
6081
|
+
}
|
|
6082
|
+
case "PartialStatement": {
|
|
6083
|
+
const p = node;
|
|
6084
|
+
for (const param of p.params) {
|
|
6085
|
+
collectFromExpression(
|
|
6086
|
+
param,
|
|
6087
|
+
"helper-param",
|
|
6088
|
+
locals,
|
|
6089
|
+
options,
|
|
6090
|
+
references,
|
|
6091
|
+
missingHelpers,
|
|
6092
|
+
seen
|
|
6093
|
+
);
|
|
6094
|
+
}
|
|
6095
|
+
walkHash(p.hash, locals, options, references, missingHelpers, seen);
|
|
6096
|
+
return;
|
|
6097
|
+
}
|
|
6098
|
+
}
|
|
6099
|
+
}
|
|
6100
|
+
function collectAll(template, options) {
|
|
6101
|
+
const references = [];
|
|
6102
|
+
const missingHelpers = /* @__PURE__ */ new Set();
|
|
6103
|
+
let ast;
|
|
6104
|
+
try {
|
|
6105
|
+
ast = hbs.handlebars.parse(template);
|
|
6106
|
+
} catch {
|
|
6107
|
+
return { references, missingHelpers: [] };
|
|
6108
|
+
}
|
|
6109
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6110
|
+
walkProgram(ast, /* @__PURE__ */ new Set(), options, references, missingHelpers, seen);
|
|
6111
|
+
return { references, missingHelpers: Array.from(missingHelpers) };
|
|
6112
|
+
}
|
|
6113
|
+
function hasInputPath(input, path) {
|
|
6114
|
+
if (!input || typeof input !== "object") return false;
|
|
6115
|
+
let current = input;
|
|
6116
|
+
for (const part of path.split(".")) {
|
|
6117
|
+
if (!current || typeof current !== "object") return false;
|
|
6118
|
+
if (!Object.prototype.hasOwnProperty.call(current, part)) return false;
|
|
6119
|
+
current = current[part];
|
|
6120
|
+
}
|
|
6121
|
+
return current !== void 0;
|
|
6122
|
+
}
|
|
6123
|
+
function validateTemplateInputReferences(template, input, options = {}) {
|
|
6124
|
+
const { references, missingHelpers } = collectAll(template, options);
|
|
6125
|
+
const missingVariables = [];
|
|
6126
|
+
const seenMissing = /* @__PURE__ */ new Set();
|
|
6127
|
+
for (const ref of references) {
|
|
6128
|
+
if (hasInputPath(input, ref.path)) continue;
|
|
6129
|
+
const key = ref.path;
|
|
6130
|
+
if (seenMissing.has(key)) continue;
|
|
6131
|
+
seenMissing.add(key);
|
|
6132
|
+
missingVariables.push(ref);
|
|
6133
|
+
}
|
|
6134
|
+
return { references, missingVariables, missingHelpers };
|
|
6135
|
+
}
|
|
6136
|
+
|
|
6137
|
+
// src/prompt/errors.ts
|
|
6138
|
+
function buildMessage(context) {
|
|
6139
|
+
const { missingVariables, missingHelpers } = context;
|
|
6140
|
+
const vars = missingVariables.length ? `Missing variables: ${formatErrorList(missingVariables)}.` : "";
|
|
6141
|
+
const helpers = missingHelpers.length ? `Missing helpers: ${formatErrorList(missingHelpers)}.` : "";
|
|
6142
|
+
if (vars && helpers) {
|
|
6143
|
+
return `Prompt template has unresolved references. ${vars} ${helpers}`;
|
|
6144
|
+
}
|
|
6145
|
+
if (vars) {
|
|
6146
|
+
return `Prompt template references variables not provided. ${vars}`;
|
|
6147
|
+
}
|
|
6148
|
+
return `Prompt template references helpers not registered. ${helpers}`;
|
|
6149
|
+
}
|
|
6150
|
+
function missingTemplateReferencesError(context) {
|
|
6151
|
+
return createLlmExeError(
|
|
6152
|
+
{
|
|
6153
|
+
code: "prompt.missing_template_variable",
|
|
6154
|
+
message: buildMessage,
|
|
6155
|
+
resolution: "Pass every variable referenced by the prompt template, or register any custom helpers used."
|
|
6156
|
+
},
|
|
6157
|
+
context
|
|
6158
|
+
);
|
|
6159
|
+
}
|
|
6160
|
+
|
|
4106
6161
|
// src/prompt/_base.ts
|
|
4107
6162
|
var BasePrompt = class {
|
|
4108
6163
|
/**
|
|
@@ -4114,6 +6169,7 @@ var BasePrompt = class {
|
|
|
4114
6169
|
__publicField(this, "messages", []);
|
|
4115
6170
|
__publicField(this, "partials", []);
|
|
4116
6171
|
__publicField(this, "helpers", []);
|
|
6172
|
+
__publicField(this, "validateInput", false);
|
|
4117
6173
|
__publicField(this, "replaceTemplateString", replaceTemplateString);
|
|
4118
6174
|
__publicField(this, "replaceTemplateStringAsync", replaceTemplateStringAsync);
|
|
4119
6175
|
__publicField(this, "filters", {
|
|
@@ -4139,6 +6195,9 @@ var BasePrompt = class {
|
|
|
4139
6195
|
if (options.replaceTemplateString) {
|
|
4140
6196
|
this.replaceTemplateString = options.replaceTemplateString;
|
|
4141
6197
|
}
|
|
6198
|
+
if (options.validateInput !== void 0) {
|
|
6199
|
+
this.validateInput = options.validateInput;
|
|
6200
|
+
}
|
|
4142
6201
|
}
|
|
4143
6202
|
}
|
|
4144
6203
|
/**
|
|
@@ -4190,6 +6249,40 @@ var BasePrompt = class {
|
|
|
4190
6249
|
this.helpers.push(...helpers);
|
|
4191
6250
|
return this;
|
|
4192
6251
|
}
|
|
6252
|
+
/**
|
|
6253
|
+
* Returns the Handlebars-bearing strings that should be validated, along
|
|
6254
|
+
* with a location label used for error context. Subclasses with structured
|
|
6255
|
+
* message content (e.g. ChatPrompt) should override.
|
|
6256
|
+
*/
|
|
6257
|
+
getTemplateContents() {
|
|
6258
|
+
return this.messages.map((message, index) => {
|
|
6259
|
+
if (!message.content || Array.isArray(message.content)) {
|
|
6260
|
+
return null;
|
|
6261
|
+
}
|
|
6262
|
+
return {
|
|
6263
|
+
content: message.content,
|
|
6264
|
+
location: `messages[${index}].content`
|
|
6265
|
+
};
|
|
6266
|
+
}).filter(
|
|
6267
|
+
(entry) => entry !== null
|
|
6268
|
+
);
|
|
6269
|
+
}
|
|
6270
|
+
preflightValidate(values) {
|
|
6271
|
+
if (this.validateInput === false || !this.validateInput) {
|
|
6272
|
+
return;
|
|
6273
|
+
}
|
|
6274
|
+
try {
|
|
6275
|
+
this.validate(values);
|
|
6276
|
+
} catch (error) {
|
|
6277
|
+
if (this.validateInput === "warn" && isLlmExeError(error, "prompt.missing_template_variable")) {
|
|
6278
|
+
if (typeof process === "object" && typeof process?.emitWarning === "function") {
|
|
6279
|
+
process.emitWarning(error);
|
|
6280
|
+
}
|
|
6281
|
+
return;
|
|
6282
|
+
}
|
|
6283
|
+
throw error;
|
|
6284
|
+
}
|
|
6285
|
+
}
|
|
4193
6286
|
/**
|
|
4194
6287
|
* format description
|
|
4195
6288
|
* @param values The message content
|
|
@@ -4197,6 +6290,7 @@ var BasePrompt = class {
|
|
|
4197
6290
|
* @return returns messages formatted with template replacement
|
|
4198
6291
|
*/
|
|
4199
6292
|
format(values, separator = "\n\n") {
|
|
6293
|
+
this.preflightValidate(values);
|
|
4200
6294
|
const replacements = this.getReplacements(values);
|
|
4201
6295
|
const messages = this.messages.map((message) => {
|
|
4202
6296
|
return message.content && !Array.isArray(message.content) ? this.replaceTemplateString(
|
|
@@ -4217,6 +6311,7 @@ var BasePrompt = class {
|
|
|
4217
6311
|
* @return returns messages formatted with template replacement
|
|
4218
6312
|
*/
|
|
4219
6313
|
async formatAsync(values, separator = "\n\n") {
|
|
6314
|
+
this.preflightValidate(values);
|
|
4220
6315
|
const replacements = this.getReplacements(values);
|
|
4221
6316
|
const _messages = await Promise.all(this.messages.map((message) => {
|
|
4222
6317
|
return message.content && !Array.isArray(message.content) ? this.replaceTemplateStringAsync(
|
|
@@ -4240,8 +6335,18 @@ var BasePrompt = class {
|
|
|
4240
6335
|
}
|
|
4241
6336
|
getReplacements(values) {
|
|
4242
6337
|
if (values === void 0 || values === null) {
|
|
4243
|
-
throw new
|
|
4244
|
-
"format() requires an input object. Did you forget to pass arguments?"
|
|
6338
|
+
throw new LlmExeError(
|
|
6339
|
+
"format() requires an input object. Did you forget to pass arguments?",
|
|
6340
|
+
{
|
|
6341
|
+
code: "prompt.missing_input",
|
|
6342
|
+
context: {
|
|
6343
|
+
operation: "BasePrompt.getReplacements",
|
|
6344
|
+
promptType: this.type,
|
|
6345
|
+
expected: "object",
|
|
6346
|
+
received: values === null ? "null" : "undefined",
|
|
6347
|
+
resolution: "Pass an object of template values to format()."
|
|
6348
|
+
}
|
|
6349
|
+
}
|
|
4245
6350
|
);
|
|
4246
6351
|
}
|
|
4247
6352
|
const { input = "", ...restOfValues } = values;
|
|
@@ -4256,11 +6361,52 @@ var BasePrompt = class {
|
|
|
4256
6361
|
return replacements;
|
|
4257
6362
|
}
|
|
4258
6363
|
/**
|
|
4259
|
-
* Validates
|
|
4260
|
-
*
|
|
6364
|
+
* Validates that `input` provides every variable referenced by this prompt's
|
|
6365
|
+
* templates, and that every identifiable helper call is registered.
|
|
6366
|
+
*
|
|
6367
|
+
* @breaking v3: previously returned `this.messages.length > 0` with no
|
|
6368
|
+
* `input` parameter. For the old behavior, read `prompt.messages.length > 0`
|
|
6369
|
+
* directly.
|
|
6370
|
+
*
|
|
6371
|
+
* @throws LlmExeError with code `"prompt.missing_template_variable"` listing
|
|
6372
|
+
* all missing variables and helpers.
|
|
4261
6373
|
*/
|
|
4262
|
-
validate() {
|
|
4263
|
-
|
|
6374
|
+
validate(input) {
|
|
6375
|
+
const allMissingVariables = [];
|
|
6376
|
+
const allMissingHelpers = /* @__PURE__ */ new Set();
|
|
6377
|
+
const registeredHelpers = this.helpers.reduce(
|
|
6378
|
+
(acc, h) => {
|
|
6379
|
+
acc[h.name] = h.handler;
|
|
6380
|
+
return acc;
|
|
6381
|
+
},
|
|
6382
|
+
{}
|
|
6383
|
+
);
|
|
6384
|
+
const knownHelpers = {
|
|
6385
|
+
...hbs.handlebars.helpers,
|
|
6386
|
+
...registeredHelpers
|
|
6387
|
+
};
|
|
6388
|
+
for (const template of this.getTemplateContents()) {
|
|
6389
|
+
const result = validateTemplateInputReferences(template.content, input, {
|
|
6390
|
+
helpers: knownHelpers,
|
|
6391
|
+
location: template.location
|
|
6392
|
+
});
|
|
6393
|
+
allMissingVariables.push(...result.missingVariables);
|
|
6394
|
+
for (const helper of result.missingHelpers) {
|
|
6395
|
+
allMissingHelpers.add(helper);
|
|
6396
|
+
}
|
|
6397
|
+
}
|
|
6398
|
+
if (allMissingVariables.length === 0 && allMissingHelpers.size === 0) {
|
|
6399
|
+
return;
|
|
6400
|
+
}
|
|
6401
|
+
const dedupedVariables = Array.from(
|
|
6402
|
+
new Set(allMissingVariables.map((r) => r.path))
|
|
6403
|
+
);
|
|
6404
|
+
throw missingTemplateReferencesError({
|
|
6405
|
+
operation: "Prompt.validate",
|
|
6406
|
+
promptType: this.type,
|
|
6407
|
+
missingVariables: dedupedVariables,
|
|
6408
|
+
missingHelpers: Array.from(allMissingHelpers)
|
|
6409
|
+
});
|
|
4264
6410
|
}
|
|
4265
6411
|
};
|
|
4266
6412
|
|
|
@@ -4562,6 +6708,7 @@ var ChatPrompt = class extends BasePrompt {
|
|
|
4562
6708
|
* @return formatted prompt.
|
|
4563
6709
|
*/
|
|
4564
6710
|
format(values) {
|
|
6711
|
+
this.preflightValidate(values);
|
|
4565
6712
|
const messagesOut = [];
|
|
4566
6713
|
const replacements = this.getReplacements(values);
|
|
4567
6714
|
const safeToParseTemplate = ["assistant", "system"];
|
|
@@ -4687,6 +6834,7 @@ var ChatPrompt = class extends BasePrompt {
|
|
|
4687
6834
|
* @return formatted prompt.
|
|
4688
6835
|
*/
|
|
4689
6836
|
async formatAsync(values) {
|
|
6837
|
+
this.preflightValidate(values);
|
|
4690
6838
|
const messagesOut = [];
|
|
4691
6839
|
const replacements = this.getReplacements(values);
|
|
4692
6840
|
const safeToParseTemplate = ["assistant", "system"];
|
|
@@ -4989,16 +7137,26 @@ var Dialogue = class extends BaseStateItem {
|
|
|
4989
7137
|
}
|
|
4990
7138
|
setFunctionCallMessage(input) {
|
|
4991
7139
|
if (!input || typeof input !== "object") {
|
|
4992
|
-
throw new LlmExeError(`Invalid arguments`,
|
|
4993
|
-
|
|
4994
|
-
|
|
7140
|
+
throw new LlmExeError(`Invalid arguments`, {
|
|
7141
|
+
code: "state.invalid_arguments",
|
|
7142
|
+
context: {
|
|
7143
|
+
operation: "Dialogue.setFunctionCallMessage",
|
|
7144
|
+
module: "dialogue",
|
|
7145
|
+
expected: "object",
|
|
7146
|
+
received: typeof input
|
|
7147
|
+
}
|
|
4995
7148
|
});
|
|
4996
7149
|
}
|
|
4997
7150
|
if ("function_call" in input) {
|
|
4998
7151
|
if (!input.function_call || typeof input.function_call !== "object") {
|
|
4999
|
-
throw new LlmExeError(`Invalid arguments`,
|
|
5000
|
-
|
|
5001
|
-
|
|
7152
|
+
throw new LlmExeError(`Invalid arguments`, {
|
|
7153
|
+
code: "state.invalid_arguments",
|
|
7154
|
+
context: {
|
|
7155
|
+
operation: "Dialogue.setFunctionCallMessage",
|
|
7156
|
+
module: "dialogue",
|
|
7157
|
+
expected: "object",
|
|
7158
|
+
received: typeof input.function_call
|
|
7159
|
+
}
|
|
5002
7160
|
});
|
|
5003
7161
|
}
|
|
5004
7162
|
this.value.push({
|
|
@@ -5233,6 +7391,8 @@ export {
|
|
|
5233
7391
|
CustomParser,
|
|
5234
7392
|
DefaultState,
|
|
5235
7393
|
DefaultStateItem,
|
|
7394
|
+
LLM_EXE_ERROR_SYMBOL,
|
|
7395
|
+
LlmExeError,
|
|
5236
7396
|
LlmExecutorOpenAiFunctions,
|
|
5237
7397
|
LlmExecutorWithFunctions,
|
|
5238
7398
|
LlmNativeFunctionParser,
|
|
@@ -5253,6 +7413,7 @@ export {
|
|
|
5253
7413
|
createStateItem,
|
|
5254
7414
|
defineSchema,
|
|
5255
7415
|
guards_exports as guards,
|
|
7416
|
+
isLlmExeError,
|
|
5256
7417
|
registerHelpers,
|
|
5257
7418
|
registerPartials,
|
|
5258
7419
|
useExecutors,
|