llm-exe 2.3.1 → 2.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -59,6 +59,7 @@ __export(index_exports, {
59
59
  createEmbedding: () => createEmbedding,
60
60
  createLlmExecutor: () => createLlmExecutor,
61
61
  createLlmFunctionExecutor: () => createLlmFunctionExecutor,
62
+ createOpenAiCompatibleConfiguration: () => createOpenAiCompatibleConfiguration,
62
63
  createParser: () => createParser,
63
64
  createPrompt: () => createPrompt,
64
65
  createState: () => createState,
@@ -69,6 +70,7 @@ __export(index_exports, {
69
70
  registerPartials: () => registerPartials,
70
71
  useExecutors: () => useExecutors,
71
72
  useLlm: () => useLlm,
73
+ useLlmConfiguration: () => useLlmConfiguration,
72
74
  utils: () => utils_exports
73
75
  });
74
76
  module.exports = __toCommonJS(index_exports);
@@ -186,6 +188,10 @@ var BaseExecutor = class {
186
188
  */
187
189
  __publicField(this, "hooks");
188
190
  __publicField(this, "allowedHooks", [hookOnComplete, hookOnError, hookOnSuccess]);
191
+ /**
192
+ * @property maxHooksPerEvent - Maximum number of hooks allowed per event
193
+ */
194
+ __publicField(this, "maxHooksPerEvent", 100);
189
195
  this.id = (0, import_uuid.v4)();
190
196
  this.type = type;
191
197
  this.name = name;
@@ -291,6 +297,11 @@ var BaseExecutor = class {
291
297
  const _hooks = Array.isArray(hookInput) ? hookInput : [hookInput];
292
298
  for (const hook of _hooks) {
293
299
  if (hook && typeof hook === "function" && !this.hooks[hookKey].find((h) => h === hook)) {
300
+ if (this.hooks[hookKey].length >= this.maxHooksPerEvent) {
301
+ throw new Error(
302
+ `Maximum number of hooks (${this.maxHooksPerEvent}) reached for event "${String(hookKey)}". Consider removing unused hooks or increasing the limit.`
303
+ );
304
+ }
294
305
  this.hooks[hookKey].push(hook);
295
306
  }
296
307
  }
@@ -318,10 +329,18 @@ var BaseExecutor = class {
318
329
  }
319
330
  once(eventName, fn) {
320
331
  if (typeof fn !== "function") return this;
332
+ if (this.hooks[eventName] && this.hooks[eventName].length >= this.maxHooksPerEvent) {
333
+ throw new Error(
334
+ `Maximum number of hooks (${this.maxHooksPerEvent}) reached for event "${String(eventName)}". Consider removing unused hooks or increasing the limit.`
335
+ );
336
+ }
321
337
  const onceWrapper = (...args) => {
322
338
  fn(...args);
323
339
  this.off(eventName, onceWrapper);
324
340
  };
341
+ if (!this.hooks[eventName]) {
342
+ this.hooks[eventName] = [];
343
+ }
325
344
  this.hooks[eventName].push(onceWrapper);
326
345
  return this;
327
346
  }
@@ -332,6 +351,40 @@ var BaseExecutor = class {
332
351
  getTraceId() {
333
352
  return this.traceId;
334
353
  }
354
+ /**
355
+ * Clear all hooks for a specific event or all events
356
+ * Useful for preventing memory leaks in long-running processes
357
+ * @param eventName - The event name to clear hooks for
358
+ */
359
+ clearHooks(eventName) {
360
+ if (eventName) {
361
+ if (this.hooks[eventName]) {
362
+ this.hooks[eventName] = [];
363
+ }
364
+ } else {
365
+ for (const key of this.allowedHooks) {
366
+ if (this.hooks[key]) {
367
+ this.hooks[key] = [];
368
+ }
369
+ }
370
+ }
371
+ return this;
372
+ }
373
+ /**
374
+ * Get the count of hooks for monitoring memory usage
375
+ * @param eventName - Optional event name to get count for
376
+ * @returns Hook count for specific event or all events
377
+ */
378
+ getHookCount(eventName) {
379
+ if (eventName) {
380
+ return this.hooks[eventName]?.length || 0;
381
+ }
382
+ const counts = {};
383
+ for (const key of this.allowedHooks) {
384
+ counts[key] = this.hooks[key]?.length || 0;
385
+ }
386
+ return counts;
387
+ }
335
388
  };
336
389
 
337
390
  // src/utils/modules/inferFunctionName.ts
@@ -477,7 +530,7 @@ var BooleanParser = class extends BaseParser {
477
530
  `Invalid input. Expected string. Received ${typeof text}.`
478
531
  );
479
532
  const clean = text.toLowerCase().trim();
480
- if (clean === "true") {
533
+ if (clean === "true" || clean === "yes" || clean === "y" || clean === "1") {
481
534
  return true;
482
535
  }
483
536
  return false;
@@ -506,7 +559,7 @@ var NumberParser = class extends BaseParser {
506
559
  super("number", options);
507
560
  }
508
561
  parse(text) {
509
- const match = text.match(/\d/g);
562
+ const match = text.match(/-?\d+(\.\d+)?/);
510
563
  return match && isFinite(toNumber(match[0])) ? toNumber(match[0]) : -1;
511
564
  }
512
565
  };
@@ -1408,9 +1461,8 @@ var asyncCallWithTimeout = async (asyncPromise, timeLimit = 1e4) => {
1408
1461
  );
1409
1462
  }, timeLimit);
1410
1463
  });
1411
- return Promise.race([asyncPromise, timeoutPromise]).then((result) => {
1464
+ return Promise.race([asyncPromise, timeoutPromise]).finally(() => {
1412
1465
  clearTimeout(timeoutHandle);
1413
- return result;
1414
1466
  });
1415
1467
  };
1416
1468
 
@@ -1556,9 +1608,13 @@ var ListToJsonParser = class extends BaseParserWithJson {
1556
1608
  const lines = text.split("\n");
1557
1609
  const output = {};
1558
1610
  lines.forEach((line) => {
1559
- const [key, value] = line.split(":");
1560
- if (value) {
1561
- output[camelCase(key)] = value.trim();
1611
+ const colonIndex = line.indexOf(":");
1612
+ if (colonIndex !== -1) {
1613
+ const key = line.slice(0, colonIndex);
1614
+ const value = line.slice(colonIndex + 1).trim();
1615
+ if (value) {
1616
+ output[camelCase(key)] = value;
1617
+ }
1562
1618
  }
1563
1619
  });
1564
1620
  if (this.schema) {
@@ -1630,7 +1686,7 @@ var ListToArrayParser = class extends BaseParser {
1630
1686
  super("listToArray");
1631
1687
  }
1632
1688
  parse(text) {
1633
- const lines = text.split("\n").map((s) => s.replace(/^- /, "").replace(/'/g, "'").trim());
1689
+ const lines = text.split("\n").map((s) => s.replace(/^(?:[-*] |\d+\. )/, "").replace(/'/g, "\u2019").trim());
1634
1690
  return lines;
1635
1691
  }
1636
1692
  };
@@ -1758,8 +1814,11 @@ function createParser(type, options = {}) {
1758
1814
  case "stringExtract":
1759
1815
  return new StringExtractParser(options);
1760
1816
  case "string":
1761
- default:
1762
1817
  return new StringParser();
1818
+ default:
1819
+ throw new Error(
1820
+ `Invalid parser type: "${type}". Valid types are: json, string, boolean, number, stringExtract, listToArray, listToJson, listToKeyValue, replaceStringTemplate, markdownCodeBlock, markdownCodeBlocks`
1821
+ );
1763
1822
  }
1764
1823
  }
1765
1824
  function createCustomParser(name, parserFn) {
@@ -2118,6 +2177,63 @@ function getEnvironmentVariable(name) {
2118
2177
  }
2119
2178
  }
2120
2179
 
2180
+ // src/llm/output/_util.ts
2181
+ function formatOptions(response, handler) {
2182
+ const out = [];
2183
+ for (const item of response) {
2184
+ const result = handler(item);
2185
+ if (result) {
2186
+ out.push([result]);
2187
+ }
2188
+ }
2189
+ return out;
2190
+ }
2191
+
2192
+ // src/llm/output/openai.ts
2193
+ function formatResult(result) {
2194
+ const out = [];
2195
+ if (typeof result?.message?.content === "string") {
2196
+ out.push({
2197
+ type: "text",
2198
+ text: result.message.content
2199
+ });
2200
+ }
2201
+ if (result?.message?.tool_calls) {
2202
+ for (const call of result.message.tool_calls) {
2203
+ out.push({
2204
+ functionId: call.id,
2205
+ type: "function_use",
2206
+ name: call.function.name,
2207
+ input: maybeParseJSON(call.function.arguments)
2208
+ });
2209
+ }
2210
+ }
2211
+ return out;
2212
+ }
2213
+ function OutputOpenAIChat(result, _config) {
2214
+ const id = result.id;
2215
+ const name = result.model || _config?.options.model?.default || "openai.unknown";
2216
+ const created = result.created;
2217
+ const [_content, ..._options] = result?.choices || [];
2218
+ const stopReason = _content?.finish_reason;
2219
+ const content = formatResult(_content);
2220
+ const options = formatOptions(_options, formatResult);
2221
+ const usage = {
2222
+ output_tokens: result?.usage?.completion_tokens,
2223
+ input_tokens: result?.usage?.prompt_tokens,
2224
+ total_tokens: result?.usage?.total_tokens
2225
+ };
2226
+ return {
2227
+ id,
2228
+ name,
2229
+ created,
2230
+ usage,
2231
+ stopReason,
2232
+ content,
2233
+ options
2234
+ };
2235
+ }
2236
+
2121
2237
  // src/llm/config/openai/promptSanitizeMessageCallback.ts
2122
2238
  function openaiPromptMessageCallback(_message) {
2123
2239
  let message = { ..._message };
@@ -2151,38 +2267,127 @@ function openaiPromptSanitize(_messages, _inputBodyObj, _outputObj) {
2151
2267
  return _messages.map(openaiPromptMessageCallback);
2152
2268
  }
2153
2269
 
2154
- // src/llm/config/openai/index.ts
2155
- var openAiChatV1 = {
2156
- key: "openai.chat.v1",
2157
- provider: "openai.chat",
2158
- endpoint: `https://api.openai.com/v1/chat/completions`,
2159
- options: {
2160
- prompt: {},
2161
- topP: {},
2162
- useJson: {},
2163
- openAiApiKey: {
2164
- default: getEnvironmentVariable("OPENAI_API_KEY")
2270
+ // src/llm/output/_utils/cleanJsonSchemaFor.ts
2271
+ var providerFieldExclusions = {
2272
+ "openai.chat": ["default"],
2273
+ // fields to exclude for openai.chat, xai, deepseek
2274
+ "anthropic.chat": [],
2275
+ "google.chat": ["additionalProperties"]
2276
+ };
2277
+ function cleanJsonSchemaFor(schema = {}, provider) {
2278
+ const clone = deepClone(schema);
2279
+ if (Object.keys(clone).length === 0) {
2280
+ return {
2281
+ type: "object",
2282
+ properties: {},
2283
+ required: []
2284
+ };
2285
+ }
2286
+ const exclusions = providerFieldExclusions[provider] || [];
2287
+ function removeDisallowedFields(obj) {
2288
+ if (Array.isArray(obj)) {
2289
+ return obj.map(removeDisallowedFields);
2290
+ } else if (typeof obj === "object" && obj !== null) {
2291
+ return Object.keys(obj).reduce((acc, key) => {
2292
+ if (!exclusions.includes(key)) {
2293
+ acc[key] = removeDisallowedFields(obj[key]);
2294
+ }
2295
+ return acc;
2296
+ }, {});
2165
2297
  }
2166
- },
2167
- method: "POST",
2168
- headers: `{"Authorization":"Bearer {{openAiApiKey}}", "Content-Type": "application/json" }`,
2169
- mapBody: {
2170
- prompt: {
2171
- key: "messages",
2172
- sanitize: openaiPromptSanitize
2298
+ return obj;
2299
+ }
2300
+ return removeDisallowedFields(clone);
2301
+ }
2302
+
2303
+ // src/llm/config/openai/compatible.ts
2304
+ function createOpenAiCompatibleConfiguration(overrides) {
2305
+ const [apiKeyPropertyKey, apiKeyPropertyValue] = overrides.apiKeyMapping;
2306
+ const config = {
2307
+ key: overrides.key,
2308
+ provider: overrides.provider,
2309
+ endpoint: overrides.endpoint,
2310
+ options: {
2311
+ prompt: {},
2312
+ effort: {},
2313
+ topP: {},
2314
+ useJson: {},
2315
+ [apiKeyPropertyKey]: {
2316
+ default: getEnvironmentVariable(apiKeyPropertyValue)
2317
+ }
2173
2318
  },
2174
- model: {
2175
- key: "model"
2319
+ method: "POST",
2320
+ headers: `{"Authorization":"Bearer {{${apiKeyPropertyKey}}}", "Content-Type": "application/json" }`,
2321
+ mapBody: {
2322
+ prompt: {
2323
+ key: "messages",
2324
+ transform: openaiPromptSanitize
2325
+ },
2326
+ model: {
2327
+ key: "model"
2328
+ },
2329
+ topP: {
2330
+ key: "top_p"
2331
+ },
2332
+ useJson: {
2333
+ key: "response_format.type",
2334
+ transform: (v) => v ? "json_object" : "text"
2335
+ },
2336
+ effort: {
2337
+ key: "reasoning_effort",
2338
+ transform: (v, _s) => {
2339
+ if (
2340
+ // only supported reasoning models
2341
+ ["gpt-5"].includes(_s.model) && typeof v === "string" && ["minimal", "low", "medium", "high"].includes(v)
2342
+ ) {
2343
+ return v;
2344
+ }
2345
+ return void 0;
2346
+ }
2347
+ }
2176
2348
  },
2177
- topP: {
2178
- key: "top_p"
2349
+ mapOptions: {
2350
+ jsonSchema: (schema, options, currentInput) => ({
2351
+ response_format: {
2352
+ ...currentInput?.response_format || {},
2353
+ type: "json_schema",
2354
+ json_schema: {
2355
+ name: "output",
2356
+ strict: !!options?.functionCallStrictInput,
2357
+ schema: cleanJsonSchemaFor(schema, "openai.chat")
2358
+ }
2359
+ }
2360
+ }),
2361
+ functionCall: (call) => {
2362
+ if (call === "any") return { tool_choice: "required" };
2363
+ if (call === "none") return { tool_choice: "none" };
2364
+ if (call === "auto") return { tool_choice: "auto" };
2365
+ return { tool_choice: call };
2366
+ },
2367
+ functions: (functions, options) => ({
2368
+ tools: functions.map((f) => ({
2369
+ type: "function",
2370
+ function: {
2371
+ name: f.name,
2372
+ description: f.description,
2373
+ parameters: cleanJsonSchemaFor(f.parameters, "openai.chat"),
2374
+ strict: !!options?.functionCallStrictInput
2375
+ }
2376
+ }))
2377
+ })
2179
2378
  },
2180
- useJson: {
2181
- key: "response_format.type",
2182
- sanitize: (v) => v ? "json_object" : "text"
2183
- }
2184
- }
2185
- };
2379
+ transformResponse: overrides.transformResponse ?? OutputOpenAIChat
2380
+ };
2381
+ return config;
2382
+ }
2383
+
2384
+ // src/llm/config/openai/index.ts
2385
+ var openAiChatV1 = createOpenAiCompatibleConfiguration({
2386
+ key: "openai.chat.v1",
2387
+ provider: "openai.chat",
2388
+ endpoint: `https://api.openai.com/v1/chat/completions`,
2389
+ apiKeyMapping: ["openAiApiKey", "OPENAI_API_KEY"]
2390
+ });
2186
2391
  var openAiChatMockV1 = {
2187
2392
  key: "openai.chat-mock.v1",
2188
2393
  provider: "openai.chat-mock",
@@ -2209,13 +2414,26 @@ var openAiChatMockV1 = {
2209
2414
  },
2210
2415
  useJson: {
2211
2416
  key: "response_format.type",
2212
- sanitize: (v) => v ? "json_object" : "text"
2417
+ transform: (v) => v ? "json_object" : "text"
2213
2418
  }
2214
- }
2419
+ },
2420
+ transformResponse: OutputOpenAIChat
2215
2421
  };
2216
2422
  var openai = {
2217
2423
  "openai.chat.v1": openAiChatV1,
2218
2424
  "openai.chat-mock.v1": openAiChatMockV1,
2425
+ // GPT-5 family
2426
+ "openai.gpt-5.2": withDefaultModel(openAiChatV1, "gpt-5.2"),
2427
+ "openai.gpt-5-mini": withDefaultModel(openAiChatV1, "gpt-5-mini"),
2428
+ "openai.gpt-5-nano": withDefaultModel(openAiChatV1, "gpt-5-nano"),
2429
+ // GPT-4.1 family
2430
+ "openai.gpt-4.1": withDefaultModel(openAiChatV1, "gpt-4.1"),
2431
+ "openai.gpt-4.1-mini": withDefaultModel(openAiChatV1, "gpt-4.1-mini"),
2432
+ "openai.gpt-4.1-nano": withDefaultModel(openAiChatV1, "gpt-4.1-nano"),
2433
+ // Reasoning models
2434
+ "openai.o3": withDefaultModel(openAiChatV1, "o3"),
2435
+ "openai.o4-mini": withDefaultModel(openAiChatV1, "o4-mini"),
2436
+ // GPT-4o family
2219
2437
  "openai.gpt-4o": withDefaultModel(openAiChatV1, "gpt-4o"),
2220
2438
  "openai.gpt-4o-mini": withDefaultModel(openAiChatV1, "gpt-4o-mini")
2221
2439
  };
@@ -2254,6 +2472,20 @@ function anthropicPromptMessageCallback(_message) {
2254
2472
  }
2255
2473
 
2256
2474
  // src/llm/config/anthropic/promptSanitize.ts
2475
+ function mergeConsecutiveSameRole(messages) {
2476
+ if (messages.length <= 1) return messages;
2477
+ const merged = [messages[0]];
2478
+ for (let i = 1; i < messages.length; i++) {
2479
+ const prev = merged[merged.length - 1];
2480
+ const curr = messages[i];
2481
+ if (curr.role === prev.role && Array.isArray(prev.content) && Array.isArray(curr.content)) {
2482
+ prev.content = [...prev.content, ...curr.content];
2483
+ } else {
2484
+ merged.push(curr);
2485
+ }
2486
+ }
2487
+ return merged;
2488
+ }
2257
2489
  function anthropicPromptSanitize(_messages, _inputBodyObj, _outputObj) {
2258
2490
  if (typeof _messages === "string") {
2259
2491
  return [{ role: "user", content: _messages }].map(
@@ -2271,14 +2503,15 @@ function anthropicPromptSanitize(_messages, _inputBodyObj, _outputObj) {
2271
2503
  }
2272
2504
  if (first.role === "system" && messages.length > 0) {
2273
2505
  _outputObj.system = first.content;
2274
- return messages.map((m) => {
2506
+ const result2 = messages.map((m) => {
2275
2507
  if (m.role === "system") {
2276
2508
  return { ...m, role: "user" };
2277
2509
  }
2278
2510
  return m;
2279
2511
  }).map(anthropicPromptMessageCallback);
2512
+ return mergeConsecutiveSameRole(result2);
2280
2513
  }
2281
- return [
2514
+ const result = [
2282
2515
  first,
2283
2516
  ...messages.map((m) => {
2284
2517
  if (m.role === "system") {
@@ -2287,10 +2520,78 @@ function anthropicPromptSanitize(_messages, _inputBodyObj, _outputObj) {
2287
2520
  return m;
2288
2521
  })
2289
2522
  ].map(anthropicPromptMessageCallback);
2523
+ return mergeConsecutiveSameRole(result);
2524
+ }
2525
+
2526
+ // src/llm/output/claude.ts
2527
+ function formatResult2(response) {
2528
+ const content = response?.content || [];
2529
+ const out = [];
2530
+ for (let i = 0; i < content.length; i++) {
2531
+ const result = content[i];
2532
+ if (result.type === "text") {
2533
+ out.push({
2534
+ type: "text",
2535
+ text: result.text
2536
+ });
2537
+ } else if (result.type === "tool_use") {
2538
+ out.push({
2539
+ functionId: result.id,
2540
+ type: "function_use",
2541
+ name: result.name,
2542
+ input: result.input
2543
+ });
2544
+ }
2545
+ }
2546
+ return out;
2547
+ }
2548
+ function OutputAnthropicClaude3Chat(result, _config) {
2549
+ const id = result.id;
2550
+ const name = result.model || _config?.options.model?.default || "anthropic.unknown";
2551
+ const stopReason = result.stop_reason;
2552
+ const content = formatResult2(result);
2553
+ const usage = {
2554
+ input_tokens: result?.usage?.input_tokens,
2555
+ output_tokens: result?.usage?.output_tokens,
2556
+ total_tokens: result?.usage?.input_tokens + result?.usage?.output_tokens
2557
+ };
2558
+ return {
2559
+ id,
2560
+ name,
2561
+ created: Date.now(),
2562
+ usage,
2563
+ stopReason,
2564
+ content
2565
+ };
2566
+ }
2567
+
2568
+ // src/llm/output/llama.ts
2569
+ function OutputMetaLlama3Chat(result, _config) {
2570
+ const id = (0, import_uuid.v4)();
2571
+ const name = _config?.options?.model?.default || "meta";
2572
+ const created = (/* @__PURE__ */ new Date()).getTime();
2573
+ const stopReason = result.stop_reason;
2574
+ const content = [
2575
+ { type: "text", text: result.generation }
2576
+ ];
2577
+ const usage = {
2578
+ output_tokens: result?.generation_token_count,
2579
+ input_tokens: result?.prompt_token_count,
2580
+ total_tokens: result?.generation_token_count + result?.prompt_token_count
2581
+ };
2582
+ return {
2583
+ id,
2584
+ name,
2585
+ created,
2586
+ usage,
2587
+ stopReason,
2588
+ content,
2589
+ options: []
2590
+ };
2290
2591
  }
2291
2592
 
2292
2593
  // src/llm/config/bedrock/index.ts
2293
- var ANTORPIC_BEDROCK_VERSION = "bedrock-2023-05-31";
2594
+ var ANTHROPIC_BEDROCK_VERSION = "bedrock-2023-05-31";
2294
2595
  var amazonAnthropicChatV1 = {
2295
2596
  key: "amazon:anthropic.chat.v1",
2296
2597
  provider: "amazon:anthropic.chat",
@@ -2311,7 +2612,7 @@ var amazonAnthropicChatV1 = {
2311
2612
  mapBody: {
2312
2613
  prompt: {
2313
2614
  key: "messages",
2314
- sanitize: anthropicPromptSanitize
2615
+ transform: anthropicPromptSanitize
2315
2616
  },
2316
2617
  topP: {
2317
2618
  key: "top_p"
@@ -2322,9 +2623,26 @@ var amazonAnthropicChatV1 = {
2322
2623
  },
2323
2624
  anthropic_version: {
2324
2625
  key: "anthropic_version",
2325
- default: ANTORPIC_BEDROCK_VERSION
2626
+ default: ANTHROPIC_BEDROCK_VERSION
2326
2627
  }
2327
- }
2628
+ },
2629
+ mapOptions: {
2630
+ functionCall: (call, _options) => {
2631
+ if (call === "none") return { _clearFunctions: true };
2632
+ if (call === "auto" || call === "any") {
2633
+ return { tool_choice: { type: call } };
2634
+ }
2635
+ return { tool_choice: call };
2636
+ },
2637
+ functions: (functions) => ({
2638
+ tools: functions.map((f) => ({
2639
+ name: f.name,
2640
+ description: f.description,
2641
+ input_schema: cleanJsonSchemaFor(f.parameters, "anthropic.chat")
2642
+ }))
2643
+ })
2644
+ },
2645
+ transformResponse: OutputAnthropicClaude3Chat
2328
2646
  };
2329
2647
  var amazonMetaChatV1 = {
2330
2648
  key: "amazon:meta.chat.v1",
@@ -2346,7 +2664,7 @@ var amazonMetaChatV1 = {
2346
2664
  mapBody: {
2347
2665
  prompt: {
2348
2666
  key: "prompt",
2349
- sanitize: (messages) => {
2667
+ transform: (messages) => {
2350
2668
  if (typeof messages === "string") {
2351
2669
  return messages;
2352
2670
  } else {
@@ -2366,7 +2684,8 @@ var amazonMetaChatV1 = {
2366
2684
  key: "max_gen_len",
2367
2685
  default: 2048
2368
2686
  }
2369
- }
2687
+ },
2688
+ transformResponse: OutputMetaLlama3Chat
2370
2689
  };
2371
2690
  var bedrock = {
2372
2691
  "amazon:anthropic.chat.v1": amazonAnthropicChatV1,
@@ -2405,24 +2724,74 @@ var anthropicChatV1 = {
2405
2724
  },
2406
2725
  prompt: {
2407
2726
  key: "messages",
2408
- sanitize: anthropicPromptSanitize
2409
- }
2410
- }
2411
- };
2412
- var anthropic = {
2413
- "anthropic.chat.v1": anthropicChatV1,
2414
- "anthropic.claude-sonnet-4-0": withDefaultModel(
2415
- anthropicChatV1,
2416
- "claude-sonnet-4-0"
2417
- ),
2418
- "anthropic.claude-opus-4-0": withDefaultModel(
2727
+ transform: anthropicPromptSanitize
2728
+ },
2729
+ temperature: {
2730
+ key: "temperature"
2731
+ },
2732
+ topP: {
2733
+ key: "top_p"
2734
+ },
2735
+ topK: {
2736
+ key: "top_k"
2737
+ },
2738
+ stopSequences: {
2739
+ key: "stop_sequences"
2740
+ },
2741
+ stream: {
2742
+ key: "stream"
2743
+ },
2744
+ metadata: {
2745
+ key: "metadata"
2746
+ },
2747
+ serviceTier: {
2748
+ key: "service_tier"
2749
+ // Map camelCase to snake_case
2750
+ }
2751
+ },
2752
+ mapOptions: {
2753
+ functionCall: (call, _options) => {
2754
+ if (call === "none") return { _clearFunctions: true };
2755
+ if (call === "auto" || call === "any") {
2756
+ return { tool_choice: { type: call } };
2757
+ }
2758
+ return { tool_choice: call };
2759
+ },
2760
+ functions: (functions) => ({
2761
+ tools: functions.map((f) => ({
2762
+ name: f.name,
2763
+ description: f.description,
2764
+ input_schema: cleanJsonSchemaFor(f.parameters, "anthropic.chat")
2765
+ }))
2766
+ })
2767
+ },
2768
+ transformResponse: OutputAnthropicClaude3Chat
2769
+ };
2770
+ var anthropic = {
2771
+ "anthropic.chat.v1": anthropicChatV1,
2772
+ // Claude 4.6 models
2773
+ "anthropic.claude-opus-4-6": withDefaultModel(
2774
+ anthropicChatV1,
2775
+ "claude-opus-4-6"
2776
+ ),
2777
+ "anthropic.claude-sonnet-4-6": withDefaultModel(
2778
+ anthropicChatV1,
2779
+ "claude-sonnet-4-6"
2780
+ ),
2781
+ // Claude 4 models
2782
+ "anthropic.claude-sonnet-4": withDefaultModel(
2419
2783
  anthropicChatV1,
2420
2784
  "claude-sonnet-4-0"
2421
2785
  ),
2786
+ "anthropic.claude-opus-4": withDefaultModel(
2787
+ anthropicChatV1,
2788
+ "claude-opus-4-0"
2789
+ ),
2422
2790
  "anthropic.claude-3-7-sonnet": withDefaultModel(
2423
2791
  anthropicChatV1,
2424
- "claude-3-7-sonnet-latest"
2792
+ "claude-3-7-sonnet-20250219"
2425
2793
  ),
2794
+ // Claude 3.5 models
2426
2795
  "anthropic.claude-3-5-sonnet": withDefaultModel(
2427
2796
  anthropicChatV1,
2428
2797
  "claude-3-5-sonnet-latest"
@@ -2434,49 +2803,102 @@ var anthropic = {
2434
2803
  // Deprecated
2435
2804
  "anthropic.claude-3-opus": withDefaultModel(
2436
2805
  anthropicChatV1,
2437
- "claude-3-opus-latest"
2806
+ "claude-3-opus-20240229"
2807
+ ),
2808
+ "anthropic.claude-3-haiku": withDefaultModel(
2809
+ anthropicChatV1,
2810
+ "claude-3-haiku-20240307"
2438
2811
  )
2439
2812
  };
2440
2813
 
2441
2814
  // src/llm/config/x/index.ts
2442
- var xaiChatV1 = {
2815
+ var xaiChatV1 = createOpenAiCompatibleConfiguration({
2443
2816
  key: "xai.chat.v1",
2444
2817
  provider: "xai.chat",
2445
2818
  endpoint: `https://api.x.ai/v1/chat/completions`,
2446
- options: {
2447
- prompt: {},
2448
- topP: {},
2449
- useJson: {},
2450
- xAiApiKey: {
2451
- default: getEnvironmentVariable("XAI_API_KEY")
2452
- }
2453
- },
2454
- method: "POST",
2455
- headers: `{"Authorization":"Bearer {{xAiApiKey}}", "Content-Type": "application/json" }`,
2456
- mapBody: {
2457
- prompt: {
2458
- key: "messages",
2459
- sanitize: openaiPromptSanitize
2460
- },
2461
- model: {
2462
- key: "model"
2463
- },
2464
- topP: {
2465
- key: "top_p"
2466
- },
2467
- useJson: {
2468
- key: "response_format.type",
2469
- sanitize: (v) => v ? "json_object" : "text"
2470
- }
2471
- }
2472
- };
2819
+ apiKeyMapping: ["xAiApiKey", "XAI_API_KEY"]
2820
+ });
2473
2821
  var xai = {
2474
2822
  "xai.chat.v1": xaiChatV1,
2475
2823
  "xai.grok-2": withDefaultModel(xaiChatV1, "grok-2-latest"),
2476
2824
  "xai.grok-3": withDefaultModel(xaiChatV1, "grok-3"),
2477
- "xai.grok-4": withDefaultModel(xaiChatV1, "grok-4")
2825
+ "xai.grok-3-mini": withDefaultModel(xaiChatV1, "grok-3-mini"),
2826
+ "xai.grok-4": withDefaultModel(xaiChatV1, "grok-4"),
2827
+ "xai.grok-4-fast": withDefaultModel(xaiChatV1, "grok-4-fast-non-reasoning")
2478
2828
  };
2479
2829
 
2830
+ // src/llm/output/_utils/combineJsonl.ts
2831
+ function combineJsonl(jsonl) {
2832
+ const lines = jsonl.trim().split("\n").map((line) => line.trim()).filter((line) => line.length > 0).map((line) => {
2833
+ try {
2834
+ return JSON.parse(line);
2835
+ } catch (e) {
2836
+ throw new Error(`Invalid JSON: ${line}`);
2837
+ }
2838
+ });
2839
+ if (lines.length === 0) {
2840
+ throw new Error("No JSON lines provided.");
2841
+ }
2842
+ lines.sort(
2843
+ (a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime()
2844
+ );
2845
+ let combinedContent = lines.map((line) => line?.message?.content ?? "").join("");
2846
+ combinedContent = combinedContent.replace(/\\u003c/g, "<").replace(/\\u003e/g, ">");
2847
+ const finalLine = lines.find((line) => line.done === true);
2848
+ if (!finalLine) {
2849
+ throw new Error("No line found where done = true.");
2850
+ }
2851
+ const result = {
2852
+ model: finalLine.model,
2853
+ created_at: finalLine.created_at,
2854
+ message: {
2855
+ role: finalLine?.message?.role || "assistant",
2856
+ content: combinedContent
2857
+ },
2858
+ done_reason: finalLine.done_reason,
2859
+ done: finalLine.done,
2860
+ total_duration: finalLine.total_duration,
2861
+ load_duration: finalLine.load_duration,
2862
+ prompt_eval_count: finalLine.prompt_eval_count,
2863
+ prompt_eval_duration: finalLine.prompt_eval_duration,
2864
+ eval_count: finalLine.eval_count,
2865
+ eval_duration: finalLine.eval_duration
2866
+ };
2867
+ const content = {
2868
+ type: "text",
2869
+ text: combinedContent
2870
+ };
2871
+ return {
2872
+ lines,
2873
+ result,
2874
+ content
2875
+ };
2876
+ }
2877
+
2878
+ // src/llm/output/ollama.ts
2879
+ function OutputOllamaChat(result, _config) {
2880
+ const combined = combineJsonl(result);
2881
+ const id = `${combined.result.model}.${combined.result.created_at}`;
2882
+ const name = combined.result.model || _config?.options.model?.default || "ollama.unknown";
2883
+ const created = (/* @__PURE__ */ new Date(`${combined.result.created_at}`)).getTime();
2884
+ const stopReason = `${combined?.result?.done_reason || "stop"}`;
2885
+ const content = [combined.content];
2886
+ const usage = {
2887
+ output_tokens: 0,
2888
+ input_tokens: 0,
2889
+ total_tokens: 0
2890
+ };
2891
+ return {
2892
+ id,
2893
+ name,
2894
+ created,
2895
+ usage,
2896
+ stopReason,
2897
+ content,
2898
+ options: []
2899
+ };
2900
+ }
2901
+
2480
2902
  // src/llm/config/ollama/index.ts
2481
2903
  var ollamaChatV1 = {
2482
2904
  key: "ollama.chat.v1",
@@ -2490,7 +2912,7 @@ var ollamaChatV1 = {
2490
2912
  mapBody: {
2491
2913
  prompt: {
2492
2914
  key: "messages",
2493
- sanitize: (v) => {
2915
+ transform: (v) => {
2494
2916
  if (typeof v === "string") {
2495
2917
  return [{ role: "user", content: v }];
2496
2918
  }
@@ -2500,7 +2922,8 @@ var ollamaChatV1 = {
2500
2922
  model: {
2501
2923
  key: "model"
2502
2924
  }
2503
- }
2925
+ },
2926
+ transformResponse: OutputOllamaChat
2504
2927
  };
2505
2928
  var ollama = {
2506
2929
  "ollama.chat.v1": ollamaChatV1,
@@ -2522,7 +2945,7 @@ function googleGeminiPromptMessageCallback(_message) {
2522
2945
  message.role = "model";
2523
2946
  }
2524
2947
  let { role, ...payload } = message;
2525
- if (typeof payload.content === "string") {
2948
+ if (typeof payload.content === "string" && message.role !== "function") {
2526
2949
  parts.push({ text: message.content });
2527
2950
  }
2528
2951
  if (message.role === "function") {
@@ -2545,487 +2968,75 @@ function googleGeminiPromptMessageCallback(_message) {
2545
2968
  ...toolsArr.map((call) => {
2546
2969
  const { name, arguments: input } = call;
2547
2970
  return {
2548
- functionCall: {
2549
- name,
2550
- args: maybeParseJSON(input)
2551
- }
2552
- };
2553
- })
2554
- );
2555
- delete message.function_call;
2556
- }
2557
- return {
2558
- role,
2559
- parts
2560
- };
2561
- }
2562
-
2563
- // src/llm/config/google/promptSanitize.ts
2564
- function googleGeminiPromptSanitize(_messages, _inputBodyObj, _outputObj) {
2565
- if (typeof _messages === "string") {
2566
- return [{ role: "user", parts: [{ text: _messages }] }];
2567
- }
2568
- if (Array.isArray(_messages)) {
2569
- if (_messages.length === 0) {
2570
- throw new Error("Empty messages array");
2571
- }
2572
- if (_messages.length === 1 && _messages[0].role === "system") {
2573
- return [{ role: "user", parts: [{ text: _messages[0].content }] }];
2574
- }
2575
- const hasSystemInstruction = _messages.some(
2576
- (message) => message.role === "system"
2577
- );
2578
- if (hasSystemInstruction) {
2579
- const theSystemInstructions = _messages.filter(
2580
- (message) => message.role === "system"
2581
- );
2582
- const withoutSystemInstructions = _messages.filter(
2583
- (message) => message.role !== "system"
2584
- );
2585
- _outputObj.system_instruction = {
2586
- parts: theSystemInstructions.map((message) => ({
2587
- text: message.content
2588
- }))
2589
- };
2590
- return withoutSystemInstructions.map(googleGeminiPromptMessageCallback);
2591
- }
2592
- return _messages.map(googleGeminiPromptMessageCallback);
2593
- }
2594
- throw new Error("Invalid messages format");
2595
- }
2596
-
2597
- // src/llm/config/google/index.ts
2598
- var googleGeminiChatV1 = {
2599
- key: "google.chat.v1",
2600
- provider: "google.chat",
2601
- endpoint: `https://generativelanguage.googleapis.com/v1beta/models/{{model}}:generateContent?key={{geminiApiKey}}`,
2602
- options: {
2603
- prompt: {},
2604
- // topP: {},
2605
- geminiApiKey: {
2606
- default: getEnvironmentVariable("GEMINI_API_KEY")
2607
- }
2608
- },
2609
- method: "POST",
2610
- headers: `{"Content-Type": "application/json" }`,
2611
- mapBody: {
2612
- prompt: {
2613
- key: "contents",
2614
- sanitize: googleGeminiPromptSanitize
2615
- }
2616
- // topP: {
2617
- // key: "top_p",
2618
- // }
2619
- }
2620
- };
2621
- var google = {
2622
- "google.chat.v1": googleGeminiChatV1,
2623
- "google.gemini-2.0-flash": withDefaultModel(
2624
- googleGeminiChatV1,
2625
- "gemini-2.0-flash"
2626
- ),
2627
- "google.gemini-2.0-flash-lite": withDefaultModel(
2628
- googleGeminiChatV1,
2629
- "gemini-2.0-flash-lite"
2630
- ),
2631
- "google.gemini-2.5-flash": withDefaultModel(
2632
- googleGeminiChatV1,
2633
- "gemini-2.5-flash"
2634
- ),
2635
- "google.gemini-2.5-flash-lite": withDefaultModel(
2636
- googleGeminiChatV1,
2637
- "gemini-2.5-flash-lite"
2638
- ),
2639
- "google.gemini-1.5-pro": withDefaultModel(
2640
- googleGeminiChatV1,
2641
- "gemini-1.5-pro"
2642
- ),
2643
- "google.gemini-2.5-pro": withDefaultModel(
2644
- googleGeminiChatV1,
2645
- "gemini-2.5-pro"
2646
- )
2647
- };
2648
-
2649
- // src/llm/config/deepseek/index.ts
2650
- var deepseekChatV1 = {
2651
- key: "deepseek.chat.v1",
2652
- provider: "deepseek.chat",
2653
- endpoint: `https://api.deepseek.com/v1/chat/completions`,
2654
- options: {
2655
- prompt: {},
2656
- topP: {},
2657
- useJson: {},
2658
- deepseekApiKey: {
2659
- default: getEnvironmentVariable("DEEPSEEK_API_KEY")
2660
- }
2661
- },
2662
- method: "POST",
2663
- headers: `{"Authorization":"Bearer {{deepseekApiKey}}", "Content-Type": "application/json" }`,
2664
- mapBody: {
2665
- prompt: {
2666
- key: "messages",
2667
- sanitize: openaiPromptSanitize
2668
- },
2669
- model: {
2670
- key: "model"
2671
- },
2672
- topP: {
2673
- key: "top_p"
2674
- },
2675
- useJson: {
2676
- key: "response_format.type",
2677
- sanitize: (v) => v ? "json_object" : "text"
2678
- }
2679
- }
2680
- };
2681
- var deepseek = {
2682
- "deepseek.chat.v1": deepseekChatV1,
2683
- "deepseek.chat": withDefaultModel(deepseekChatV1, "deepseek-chat")
2684
- };
2685
-
2686
- // src/llm/config.ts
2687
- var configs = {
2688
- ...openai,
2689
- ...anthropic,
2690
- ...bedrock,
2691
- ...xai,
2692
- ...ollama,
2693
- ...google,
2694
- ...deepseek
2695
- };
2696
- function getLlmConfig(provider) {
2697
- if (!provider) {
2698
- throw new LlmExeError(`Missing provider`, "unknown", {
2699
- error: "Missing provider",
2700
- resolution: "Provide a valid provider"
2701
- });
2702
- }
2703
- const pick2 = configs[provider];
2704
- if (pick2) {
2705
- return pick2;
2706
- }
2707
- throw new LlmExeError(`Invalid provider: ${provider}`, "unknown", {
2708
- provider,
2709
- error: `Invalid provider: ${provider}`,
2710
- resolution: "Provide a valid provider"
2711
- });
2712
- }
2713
-
2714
- // src/llm/output/_utils/getResultContent.ts
2715
- function getResultContent(result, index) {
2716
- if (typeof index === "number" && index > 0) {
2717
- const arr = result?.options || [];
2718
- const val = arr[index];
2719
- return val ? val : [];
2720
- }
2721
- return [...result.content];
2722
- }
2723
-
2724
- // src/llm/output/_utils/getResultText.ts
2725
- function getResultText(result, index) {
2726
- if (typeof index === "number" && index > 0) {
2727
- const arr = result?.options || [];
2728
- const val = arr[index];
2729
- return isOutputResultContentText(val?.[0]) ? val[0]?.text : "";
2730
- }
2731
- return isOutputResultContentText(result?.content?.[0]) ? result.content[0]?.text : "";
2732
- }
2733
-
2734
- // src/llm/output/base.ts
2735
- function BaseLlmOutput2(result) {
2736
- const __result = Object.freeze({
2737
- id: result.id || (0, import_uuid.v4)(),
2738
- name: result.name,
2739
- usage: result.usage,
2740
- stopReason: result.stopReason,
2741
- options: [...result?.options || []],
2742
- content: [...result.content],
2743
- created: result?.created || (/* @__PURE__ */ new Date()).getTime()
2744
- });
2745
- function getResult() {
2746
- return {
2747
- id: __result.id,
2748
- name: __result.name,
2749
- created: __result.created,
2750
- usage: __result.usage,
2751
- options: __result.options,
2752
- content: __result.content,
2753
- stopReason: __result.stopReason
2754
- };
2755
- }
2756
- return {
2757
- getResultContent: (index) => getResultContent(__result, index),
2758
- getResultText: (index) => getResultText(__result, index),
2759
- getResult
2760
- };
2761
- }
2762
-
2763
- // src/llm/output/_util.ts
2764
- function normalizeFunctionCall(input, provider) {
2765
- if (input === "any") {
2766
- if (provider === "openai") {
2767
- return "required";
2768
- }
2769
- }
2770
- return input;
2771
- }
2772
- function formatOptions(response, handler) {
2773
- const out = [];
2774
- for (const item of response) {
2775
- const result = handler(item);
2776
- if (result) {
2777
- out.push([result]);
2778
- }
2779
- }
2780
- return out;
2781
- }
2782
-
2783
- // src/llm/output/openai.ts
2784
- function formatResult(result) {
2785
- const out = [];
2786
- if (typeof result?.message?.content === "string") {
2787
- out.push({
2788
- type: "text",
2789
- text: result.message.content
2790
- });
2791
- }
2792
- if (result?.message?.tool_calls) {
2793
- for (const call of result.message.tool_calls) {
2794
- out.push({
2795
- functionId: call.id,
2796
- type: "function_use",
2797
- name: call.function.name,
2798
- input: maybeParseJSON(call.function.arguments)
2799
- });
2800
- }
2801
- }
2802
- return out;
2803
- }
2804
- function OutputOpenAIChat(result, _config) {
2805
- const id = result.id;
2806
- const name = result.model || _config?.model || "openai.unknown";
2807
- const created = result.created;
2808
- const [_content, ..._options] = result?.choices || [];
2809
- const stopReason = _content?.finish_reason;
2810
- const content = formatResult(_content);
2811
- const options = formatOptions(_options, formatResult);
2812
- const usage = {
2813
- output_tokens: result?.usage?.completion_tokens,
2814
- input_tokens: result?.usage?.prompt_tokens,
2815
- total_tokens: result?.usage?.total_tokens
2816
- };
2817
- return BaseLlmOutput2({
2818
- id,
2819
- name,
2820
- created,
2821
- usage,
2822
- stopReason,
2823
- content,
2824
- options
2825
- });
2826
- }
2827
-
2828
- // src/llm/output/claude.ts
2829
- function formatResult2(response) {
2830
- const content = response?.content || [];
2831
- const out = [];
2832
- for (let i = 0; i < content.length; i++) {
2833
- const result = content[i];
2834
- if (result.type === "text") {
2835
- out.push({
2836
- type: "text",
2837
- text: result.text
2838
- });
2839
- } else if (result.type === "tool_use") {
2840
- out.push({
2841
- functionId: result.id,
2842
- type: "function_use",
2843
- name: result.name,
2844
- input: result.input
2845
- });
2846
- }
2847
- }
2848
- return out;
2849
- }
2850
- function OutputAnthropicClaude3Chat(result, _config) {
2851
- const id = result.id;
2852
- const name = result.model || _config?.model || "anthropic.unknown";
2853
- const stopReason = result.stop_reason;
2854
- const content = formatResult2(result);
2855
- const usage = {
2856
- input_tokens: result?.usage?.input_tokens,
2857
- output_tokens: result?.usage?.output_tokens,
2858
- total_tokens: result?.usage?.input_tokens + result?.usage?.input_tokens
2859
- };
2860
- return BaseLlmOutput2({
2861
- id,
2862
- name,
2863
- usage,
2864
- stopReason,
2865
- content
2866
- });
2867
- }
2868
-
2869
- // src/llm/output/llama.ts
2870
- function OutputMetaLlama3Chat(result, _config) {
2871
- const name = _config?.model || "meta";
2872
- const stopReason = result.stop_reason;
2873
- const content = [
2874
- { type: "text", text: result.generation }
2875
- ];
2876
- const usage = {
2877
- output_tokens: result?.generation_token_count,
2878
- input_tokens: result?.prompt_token_count,
2879
- total_tokens: result?.generation_token_count + result?.prompt_token_count
2880
- };
2881
- return BaseLlmOutput2({
2882
- name,
2883
- usage,
2884
- stopReason,
2885
- content
2886
- });
2887
- }
2888
-
2889
- // src/llm/output/default.ts
2890
- function OutputDefault(result, _config) {
2891
- const name = _config.model || "unknown";
2892
- const stopReason = result?.stopReason || "stop";
2893
- const content = [];
2894
- if (result?.text) {
2895
- content.push({ type: "text", text: result.text });
2896
- }
2897
- const usage = {
2898
- output_tokens: result?.output_tokens || 0,
2899
- input_tokens: result?.input_tokens || 0,
2900
- total_tokens: (result?.input_tokens || 0) + (result?.output_tokens || 0)
2901
- };
2902
- return BaseLlmOutput2({
2903
- name,
2904
- usage,
2905
- stopReason,
2906
- content
2907
- });
2908
- }
2909
-
2910
- // src/llm/output/xai.ts
2911
- function formatResult3(result) {
2912
- const out = [];
2913
- if (typeof result?.message?.content === "string") {
2914
- out.push({
2915
- type: "text",
2916
- text: result.message.content
2917
- });
2918
- }
2919
- if (result?.message?.tool_calls) {
2920
- for (const call of result.message.tool_calls) {
2921
- out.push({
2922
- functionId: call.id,
2923
- type: "function_use",
2924
- name: call.function.name,
2925
- input: maybeParseJSON(call.function.arguments)
2926
- });
2927
- }
2928
- }
2929
- return out;
2930
- }
2931
- function OutputXAIChat(result, _config) {
2932
- const id = result.id;
2933
- const name = result.model || _config?.model || "openai.unknown";
2934
- const created = result.created;
2935
- const [_content, ..._options] = result?.choices || [];
2936
- const stopReason = _content?.finish_reason;
2937
- const content = formatResult3(_content);
2938
- const options = formatOptions(_options, formatResult3);
2939
- const usage = {
2940
- output_tokens: result?.usage?.completion_tokens,
2941
- input_tokens: result?.usage?.prompt_tokens,
2942
- total_tokens: result?.usage?.total_tokens
2943
- };
2944
- return BaseLlmOutput2({
2945
- id,
2946
- name,
2947
- created,
2948
- usage,
2949
- stopReason,
2950
- content,
2951
- options
2952
- });
2953
- }
2954
-
2955
- // src/llm/output/_utils/combineJsonl.ts
2956
- function combineJsonl(jsonl) {
2957
- const lines = jsonl.trim().split("\n").map((line) => line.trim()).filter((line) => line.length > 0).map((line) => {
2958
- try {
2959
- return JSON.parse(line);
2960
- } catch (e) {
2961
- throw new Error(`Invalid JSON: ${line}`);
2962
- }
2963
- });
2964
- if (lines.length === 0) {
2965
- throw new Error("No JSON lines provided.");
2966
- }
2967
- lines.sort(
2968
- (a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime()
2969
- );
2970
- let combinedContent = lines.map((line) => line?.message?.content ?? "").join("");
2971
- combinedContent = combinedContent.replace(/\\u003c/g, "<").replace(/\\u003e/g, ">");
2972
- const finalLine = lines.find((line) => line.done === true);
2973
- if (!finalLine) {
2974
- throw new Error("No line found where done = true.");
2975
- }
2976
- const result = {
2977
- model: finalLine.model,
2978
- created_at: finalLine.created_at,
2979
- message: {
2980
- role: finalLine?.message?.role || "assistant",
2981
- content: combinedContent
2982
- },
2983
- done_reason: finalLine.done_reason,
2984
- done: finalLine.done,
2985
- total_duration: finalLine.total_duration,
2986
- load_duration: finalLine.load_duration,
2987
- prompt_eval_count: finalLine.prompt_eval_count,
2988
- prompt_eval_duration: finalLine.prompt_eval_duration,
2989
- eval_count: finalLine.eval_count,
2990
- eval_duration: finalLine.eval_duration
2991
- };
2992
- const content = {
2993
- type: "text",
2994
- text: combinedContent
2995
- };
2971
+ functionCall: {
2972
+ name,
2973
+ args: maybeParseJSON(input)
2974
+ }
2975
+ };
2976
+ })
2977
+ );
2978
+ delete message.function_call;
2979
+ }
2996
2980
  return {
2997
- lines,
2998
- result,
2999
- content
2981
+ role,
2982
+ parts
3000
2983
  };
3001
2984
  }
3002
2985
 
3003
- // src/llm/output/ollama.ts
3004
- function OutputOllamaChat(result, _config) {
3005
- const combined = combineJsonl(result);
3006
- const id = `${combined.result.model}.${combined.result.created_at}`;
3007
- const name = combined.result.model || _config?.model || "ollama.unknown";
3008
- const created = (/* @__PURE__ */ new Date(`${combined.result.created_at}`)).getTime();
3009
- const stopReason = `${combined?.result?.done_reason || "stop"}`;
3010
- const content = [combined.content];
3011
- const usage = {
3012
- output_tokens: 0,
3013
- input_tokens: 0,
3014
- total_tokens: 0
3015
- };
3016
- return BaseLlmOutput2({
3017
- id,
3018
- name,
3019
- created,
3020
- usage,
3021
- stopReason,
3022
- content,
3023
- options: []
3024
- });
2986
+ // src/llm/config/google/promptSanitize.ts
2987
+ function mergeConsecutiveSameRole2(messages) {
2988
+ if (messages.length <= 1) return messages;
2989
+ const merged = [messages[0]];
2990
+ for (let i = 1; i < messages.length; i++) {
2991
+ const prev = merged[merged.length - 1];
2992
+ const curr = messages[i];
2993
+ if (curr.role === prev.role && Array.isArray(prev.parts) && Array.isArray(curr.parts)) {
2994
+ prev.parts = [...prev.parts, ...curr.parts];
2995
+ } else {
2996
+ merged.push(curr);
2997
+ }
2998
+ }
2999
+ return merged;
3000
+ }
3001
+ function googleGeminiPromptSanitize(_messages, _inputBodyObj, _outputObj) {
3002
+ if (typeof _messages === "string") {
3003
+ return [{ role: "user", parts: [{ text: _messages }] }];
3004
+ }
3005
+ if (Array.isArray(_messages)) {
3006
+ if (_messages.length === 0) {
3007
+ throw new Error("Empty messages array");
3008
+ }
3009
+ if (_messages.length === 1 && _messages[0].role === "system") {
3010
+ return [{ role: "user", parts: [{ text: _messages[0].content }] }];
3011
+ }
3012
+ const hasSystemInstruction = _messages.some(
3013
+ (message) => message.role === "system"
3014
+ );
3015
+ if (hasSystemInstruction) {
3016
+ const theSystemInstructions = _messages.filter(
3017
+ (message) => message.role === "system"
3018
+ );
3019
+ const withoutSystemInstructions = _messages.filter(
3020
+ (message) => message.role !== "system"
3021
+ );
3022
+ _outputObj.system_instruction = {
3023
+ parts: theSystemInstructions.map((message) => ({
3024
+ text: message.content
3025
+ }))
3026
+ };
3027
+ const result2 = withoutSystemInstructions.map(
3028
+ googleGeminiPromptMessageCallback
3029
+ );
3030
+ return mergeConsecutiveSameRole2(result2);
3031
+ }
3032
+ const result = _messages.map(googleGeminiPromptMessageCallback);
3033
+ return mergeConsecutiveSameRole2(result);
3034
+ }
3035
+ throw new Error("Invalid messages format");
3025
3036
  }
3026
3037
 
3027
3038
  // src/llm/output/google.gemini/formatResult.ts
3028
- function formatResult4(result, id) {
3039
+ function formatResult3(result, id) {
3029
3040
  const { parts = [] } = result?.content || {};
3030
3041
  const out = [];
3031
3042
  for (let i = 0; i < parts.length; i++) {
@@ -3050,18 +3061,18 @@ function formatResult4(result, id) {
3050
3061
  // src/llm/output/google.gemini/index.ts
3051
3062
  function OutputGoogleGeminiChat(result, _config) {
3052
3063
  const id = result.responseId;
3053
- const name = result.modelVersion || _config?.model || "gemini";
3064
+ const name = result.modelVersion || _config?.options.model?.default || "gemini";
3054
3065
  const created = (/* @__PURE__ */ new Date()).getTime();
3055
3066
  const [_content, ..._options] = result?.candidates || [];
3056
3067
  const stopReason = _content?.finishReason?.toLowerCase();
3057
- const content = formatResult4(_content, id);
3058
- const options = formatOptions(_options, formatResult4);
3068
+ const content = formatResult3(_content, id);
3069
+ const options = formatOptions(_options, formatResult3);
3059
3070
  const usage = {
3060
3071
  output_tokens: result?.usageMetadata?.candidatesTokenCount,
3061
3072
  input_tokens: result?.usageMetadata?.promptTokenCount,
3062
3073
  total_tokens: result?.usageMetadata?.totalTokenCount
3063
3074
  };
3064
- return BaseLlmOutput2({
3075
+ return {
3065
3076
  id,
3066
3077
  name,
3067
3078
  created,
@@ -3069,83 +3080,152 @@ function OutputGoogleGeminiChat(result, _config) {
3069
3080
  stopReason,
3070
3081
  content,
3071
3082
  options
3072
- });
3083
+ };
3073
3084
  }
3074
3085
 
3075
- // src/llm/output/deepseek.ts
3076
- function formatResult5(result) {
3077
- const out = [];
3078
- if (typeof result?.message?.content === "string" && result?.message?.content) {
3079
- out.push({
3080
- type: "text",
3081
- text: result.message.content
3086
+ // src/llm/config/google/index.ts
3087
+ var googleGeminiChatV1 = {
3088
+ key: "google.chat.v1",
3089
+ provider: "google.chat",
3090
+ endpoint: `https://generativelanguage.googleapis.com/v1beta/models/{{model}}:generateContent?key={{geminiApiKey}}`,
3091
+ options: {
3092
+ effort: {},
3093
+ prompt: {},
3094
+ // topP: {},
3095
+ geminiApiKey: {
3096
+ default: getEnvironmentVariable("GEMINI_API_KEY")
3097
+ }
3098
+ },
3099
+ method: "POST",
3100
+ headers: `{"Content-Type": "application/json" }`,
3101
+ mapBody: {
3102
+ prompt: {
3103
+ key: "contents",
3104
+ transform: googleGeminiPromptSanitize
3105
+ },
3106
+ effort: {
3107
+ key: "config.thinkingConfig.thinkingBudget",
3108
+ transform: (v, _s) => {
3109
+ if (
3110
+ // only supported reasoning models
3111
+ ["gemini-2.5-pro", "gemini-2.5-flash", "gemini-2.5-light"].includes(
3112
+ _s.model
3113
+ ) && typeof v === "string" && ["minimal", "low", "medium", "high"].includes(v)
3114
+ ) {
3115
+ if (v === "low" || v === "minimal") {
3116
+ return 1024;
3117
+ } else if (v === "medium") {
3118
+ return 8192;
3119
+ } else if (v === "high") {
3120
+ return 24576;
3121
+ }
3122
+ }
3123
+ return void 0;
3124
+ }
3125
+ }
3126
+ },
3127
+ mapOptions: {
3128
+ functionCall: (call) => ({
3129
+ toolConfig: {
3130
+ functionCallingConfig: {
3131
+ mode: call === "any" ? "any" : call === "none" ? "none" : "auto"
3132
+ }
3133
+ }
3134
+ }),
3135
+ functions: (functions) => ({
3136
+ tools: [
3137
+ {
3138
+ functionDeclarations: functions.map((f) => ({
3139
+ name: f.name,
3140
+ description: f.description,
3141
+ parameters: cleanJsonSchemaFor(f.parameters, "google.chat")
3142
+ }))
3143
+ }
3144
+ ]
3145
+ })
3146
+ },
3147
+ transformResponse: OutputGoogleGeminiChat
3148
+ };
3149
+ var google = {
3150
+ "google.chat.v1": googleGeminiChatV1,
3151
+ "google.gemini-2.0-flash": withDefaultModel(
3152
+ googleGeminiChatV1,
3153
+ "gemini-2.0-flash"
3154
+ ),
3155
+ "google.gemini-2.0-flash-lite": withDefaultModel(
3156
+ googleGeminiChatV1,
3157
+ "gemini-2.0-flash-lite"
3158
+ ),
3159
+ "google.gemini-2.5-flash": withDefaultModel(
3160
+ googleGeminiChatV1,
3161
+ "gemini-2.5-flash"
3162
+ ),
3163
+ "google.gemini-2.5-flash-lite": withDefaultModel(
3164
+ googleGeminiChatV1,
3165
+ "gemini-2.5-flash-lite"
3166
+ ),
3167
+ "google.gemini-1.5-pro": withDefaultModel(
3168
+ googleGeminiChatV1,
3169
+ "gemini-1.5-pro"
3170
+ ),
3171
+ "google.gemini-2.5-pro": withDefaultModel(
3172
+ googleGeminiChatV1,
3173
+ "gemini-2.5-pro"
3174
+ )
3175
+ };
3176
+
3177
+ // src/llm/config/deepseek/index.ts
3178
+ var deepseekChatV1 = createOpenAiCompatibleConfiguration({
3179
+ key: "deepseek.chat.v1",
3180
+ provider: "deepseek.chat",
3181
+ endpoint: `https://api.deepseek.com/v1/chat/completions`,
3182
+ apiKeyMapping: ["deepseekApiKey", "DEEPSEEK_API_KEY"]
3183
+ });
3184
+ var deepseek = {
3185
+ "deepseek.chat.v1": deepseekChatV1,
3186
+ "deepseek.chat": withDefaultModel(deepseekChatV1, "deepseek-chat")
3187
+ };
3188
+
3189
+ // src/llm/config.ts
3190
+ var configs = {
3191
+ ...openai,
3192
+ ...anthropic,
3193
+ ...bedrock,
3194
+ ...xai,
3195
+ ...ollama,
3196
+ ...google,
3197
+ ...deepseek
3198
+ };
3199
+ function getLlmConfig(provider) {
3200
+ if (!provider) {
3201
+ throw new LlmExeError(`Missing provider`, "unknown", {
3202
+ error: "Missing provider",
3203
+ resolution: "Provide a valid provider"
3082
3204
  });
3083
3205
  }
3084
- if (result?.message?.tool_calls) {
3085
- for (const call of result.message.tool_calls) {
3086
- out.push({
3087
- functionId: call.id,
3088
- type: "function_use",
3089
- name: call.function.name,
3090
- input: maybeParseJSON(call.function.arguments)
3091
- });
3092
- }
3206
+ const pick2 = configs[provider];
3207
+ if (pick2) {
3208
+ return pick2;
3093
3209
  }
3094
- return out;
3095
- }
3096
- function OutputDeepSeekChat(result, _config) {
3097
- const id = result.id;
3098
- const name = result.model || _config?.model || "deepseek.unknown";
3099
- const created = result.created;
3100
- const [_content, ..._options] = result?.choices || [];
3101
- const stopReason = _content?.finish_reason;
3102
- const content = formatResult5(_content);
3103
- const options = formatOptions(_options, formatResult5);
3104
- const usage = {
3105
- output_tokens: result?.usage?.completion_tokens,
3106
- input_tokens: result?.usage?.prompt_tokens,
3107
- total_tokens: result?.usage?.total_tokens
3108
- };
3109
- return BaseLlmOutput2({
3110
- id,
3111
- name,
3112
- created,
3113
- usage,
3114
- stopReason,
3115
- content,
3116
- options
3210
+ throw new LlmExeError(`Invalid provider: ${provider}`, "unknown", {
3211
+ provider,
3212
+ error: `Invalid provider: ${provider}`,
3213
+ resolution: "Provide a valid provider"
3117
3214
  });
3118
3215
  }
3119
3216
 
3120
- // src/llm/output/index.ts
3121
- function normalizeLlmOutputToInternalFormat(config, response) {
3122
- switch (config?.key) {
3123
- case "openai.chat.v1":
3124
- case "openai.chat-mock.v1":
3125
- return OutputOpenAIChat(response, config);
3126
- case "anthropic.chat.v1":
3127
- case "amazon:anthropic.chat.v1":
3128
- return OutputAnthropicClaude3Chat(response, config);
3129
- case "amazon:meta.chat.v1":
3130
- return OutputMetaLlama3Chat(response, config);
3131
- // case "amazon:nova.chat.v1":
3132
- // return OutputDefault(response, config);
3133
- case "xai.chat.v1":
3134
- return OutputXAIChat(response, config);
3135
- case "ollama.chat.v1":
3136
- return OutputOllamaChat(response, config);
3137
- case "google.chat.v1":
3138
- return OutputGoogleGeminiChat(response, config);
3139
- case "deepseek.chat.v1":
3140
- return OutputDeepSeekChat(response, config);
3141
- // use oai for now
3142
- default: {
3143
- if (config?.key?.startsWith("custom:")) {
3144
- return OutputDefault(response, config);
3145
- }
3146
- throw new Error("Unsupported provider");
3217
+ // src/utils/modules/maskApiKeysInDebug.ts
3218
+ function maskApiKeys(log) {
3219
+ return log.replace(
3220
+ /\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,
3221
+ (match) => {
3222
+ if (match.length <= 8) return match;
3223
+ const prefix = match.substring(0, 4);
3224
+ const suffix = match.substring(match.length - 4);
3225
+ const maskLength = match.length - 8;
3226
+ return `${prefix}${"*".repeat(maskLength)}${suffix}`;
3147
3227
  }
3148
- }
3228
+ );
3149
3229
  }
3150
3230
 
3151
3231
  // src/utils/modules/debug.ts
@@ -3171,7 +3251,15 @@ function debug(...args) {
3171
3251
  logs.push(arg.toString());
3172
3252
  } else {
3173
3253
  try {
3174
- logs.push(JSON.stringify(arg, null, 2));
3254
+ let shouldMask = false;
3255
+ if (arg.headers && arg.headers.Authorization) {
3256
+ shouldMask = true;
3257
+ }
3258
+ let str = JSON.stringify(arg, null, 2);
3259
+ if (shouldMask) {
3260
+ str = maskApiKeys(str);
3261
+ }
3262
+ logs.push(str);
3175
3263
  } catch (error) {
3176
3264
  console.error("Error parsing object:", error);
3177
3265
  }
@@ -3219,7 +3307,8 @@ async function apiRequest(url, options) {
3219
3307
  }
3220
3308
  throw new Error(message);
3221
3309
  }
3222
- if (response.headers.get("content-type")?.includes("application/json")) {
3310
+ const contentType = response.headers.get("content-type");
3311
+ if (contentType?.includes("application/json")) {
3223
3312
  const responseData = await response.json();
3224
3313
  return responseData;
3225
3314
  } else {
@@ -3236,20 +3325,26 @@ async function apiRequest(url, options) {
3236
3325
  function convertDotNotation(obj) {
3237
3326
  const result = {};
3238
3327
  for (const key in obj) {
3239
- if (obj.hasOwnProperty(key)) {
3240
- if (key.includes(".")) {
3241
- const keys = key.split(".");
3242
- let currentLevel = result;
3243
- for (let i = 0; i < keys.length; i++) {
3244
- if (i === keys.length - 1) {
3245
- currentLevel[keys[i]] = obj[key];
3246
- } else {
3247
- currentLevel[keys[i]] = currentLevel[keys[i]] || {};
3248
- currentLevel = currentLevel[keys[i]];
3328
+ if (Object.prototype.hasOwnProperty.call(obj, key) && !key.includes(".")) {
3329
+ result[key] = obj[key];
3330
+ }
3331
+ }
3332
+ for (const key in obj) {
3333
+ if (Object.prototype.hasOwnProperty.call(obj, key) && key.includes(".")) {
3334
+ const keys = key.split(".");
3335
+ let currentLevel = result;
3336
+ for (let i = 0; i < keys.length; i++) {
3337
+ const currentKey = keys[i];
3338
+ if (i === keys.length - 1) {
3339
+ currentLevel[currentKey] = obj[key];
3340
+ } else {
3341
+ if (!(currentKey in currentLevel)) {
3342
+ currentLevel[currentKey] = {};
3343
+ } else if (typeof currentLevel[currentKey] !== "object" || currentLevel[currentKey] === null || Array.isArray(currentLevel[currentKey])) {
3344
+ currentLevel[currentKey] = {};
3249
3345
  }
3346
+ currentLevel = currentLevel[currentKey];
3250
3347
  }
3251
- } else {
3252
- result[key] = obj[key];
3253
3348
  }
3254
3349
  }
3255
3350
  }
@@ -3266,8 +3361,8 @@ function mapBody(template, body) {
3266
3361
  const { key: providerSpecificKey, default: defaultValue } = providerSpecificSettings;
3267
3362
  if (providerSpecificKey) {
3268
3363
  let valueForThisKey = body[genericInputKey];
3269
- if (providerSpecificSettings.sanitize && typeof providerSpecificSettings.sanitize === "function") {
3270
- valueForThisKey = providerSpecificSettings.sanitize(
3364
+ if (providerSpecificSettings.transform && typeof providerSpecificSettings.transform === "function") {
3365
+ valueForThisKey = providerSpecificSettings.transform(
3271
3366
  valueForThisKey,
3272
3367
  Object.freeze({ ...body }),
3273
3368
  output
@@ -3291,28 +3386,70 @@ var import_sha256_js = require("@aws-crypto/sha256-js");
3291
3386
 
3292
3387
  // src/utils/modules/runWithTemporaryEnv.ts
3293
3388
  async function runWithTemporaryEnv(env, handler) {
3294
- const previousEnv = { ...process.env };
3389
+ const modifiedKeys = [];
3390
+ const originalValues = {};
3391
+ const envBefore = { ...process.env };
3295
3392
  try {
3296
- env();
3393
+ try {
3394
+ env();
3395
+ } catch (envError) {
3396
+ const envAfter2 = process.env;
3397
+ for (const key in envAfter2) {
3398
+ if (envBefore[key] !== envAfter2[key]) {
3399
+ modifiedKeys.push(key);
3400
+ originalValues[key] = envBefore[key];
3401
+ }
3402
+ }
3403
+ for (const key in envBefore) {
3404
+ if (!(key in envAfter2) && !modifiedKeys.includes(key)) {
3405
+ modifiedKeys.push(key);
3406
+ originalValues[key] = envBefore[key];
3407
+ }
3408
+ }
3409
+ throw envError;
3410
+ }
3411
+ const envAfter = process.env;
3412
+ for (const key in envAfter) {
3413
+ if (envBefore[key] !== envAfter[key]) {
3414
+ modifiedKeys.push(key);
3415
+ originalValues[key] = envBefore[key];
3416
+ }
3417
+ }
3418
+ for (const key in envBefore) {
3419
+ if (!(key in envAfter) && !modifiedKeys.includes(key)) {
3420
+ modifiedKeys.push(key);
3421
+ originalValues[key] = envBefore[key];
3422
+ }
3423
+ }
3297
3424
  const value = await handler();
3298
3425
  return value;
3299
3426
  } finally {
3300
- process.env = previousEnv;
3427
+ for (const key of modifiedKeys) {
3428
+ const originalValue = originalValues[key];
3429
+ if (originalValue === void 0) {
3430
+ delete process.env[key];
3431
+ } else {
3432
+ process.env[key] = originalValue;
3433
+ }
3434
+ }
3301
3435
  }
3302
3436
  }
3303
3437
 
3304
3438
  // src/utils/modules/getAwsAuthorizationHeaders.ts
3305
3439
  async function getAwsAuthorizationHeaders(req, props) {
3440
+ if (!props.url || !props.regionName) {
3441
+ throw new Error("URL and region name are required for AWS authorization");
3442
+ }
3306
3443
  const providerChain = (0, import_credential_providers.fromNodeProviderChain)();
3307
3444
  const credentials = await runWithTemporaryEnv(
3308
3445
  () => {
3309
- if (props.awsAccessKey) {
3446
+ if (props.awsAccessKey && typeof props.awsAccessKey === "string") {
3310
3447
  process.env["AWS_ACCESS_KEY_ID"] = props.awsAccessKey;
3311
3448
  }
3312
- if (props.awsSecretKey) {
3449
+ if (props.awsSecretKey && typeof props.awsSecretKey === "string") {
3313
3450
  process.env["AWS_SECRET_ACCESS_KEY"] = props.awsSecretKey;
3314
3451
  }
3315
- if (props.awsSessionToken) {
3452
+ if (props.awsSessionToken && typeof props.awsSessionToken === "string") {
3316
3453
  process.env["AWS_SESSION_TOKEN"] = props.awsSessionToken;
3317
3454
  }
3318
3455
  },
@@ -3342,8 +3479,21 @@ async function getAwsAuthorizationHeaders(req, props) {
3342
3479
  // src/llm/_utils.parseHeaders.ts
3343
3480
  async function parseHeaders(config, replacements, payload) {
3344
3481
  const replace = replaceTemplateStringSimple(config.headers, replacements);
3345
- const parse = replace ? JSON.parse(replace) : {};
3346
- const headers = Object.assign({}, payload.headers, parse);
3482
+ let parsedHeaders = {};
3483
+ if (replace) {
3484
+ try {
3485
+ parsedHeaders = JSON.parse(replace);
3486
+ if (typeof parsedHeaders !== "object" || parsedHeaders === null || Array.isArray(parsedHeaders)) {
3487
+ throw new Error("Headers must be a JSON object");
3488
+ }
3489
+ } catch (error) {
3490
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
3491
+ throw new Error(
3492
+ `Failed to parse headers configuration: ${errorMessage}. Headers template: "${config.headers}". After replacement: "${replace}"`
3493
+ );
3494
+ }
3495
+ }
3496
+ const headers = Object.assign({}, payload.headers, parsedHeaders);
3347
3497
  if (config.provider.startsWith("amazon:") || config.provider.startsWith("amazon.")) {
3348
3498
  const url = payload.url;
3349
3499
  return getAwsAuthorizationHeaders(
@@ -3364,122 +3514,129 @@ async function parseHeaders(config, replacements, payload) {
3364
3514
  }
3365
3515
  }
3366
3516
 
3367
- // src/llm/output/_utils/cleanJsonSchemaFor.ts
3368
- var providerFieldExclusions = {
3369
- "openai.chat": ["default"],
3370
- // fields to exclude for openai.chat, xai, deepseek
3371
- "anthropic.chat": [],
3372
- "google.chat": ["additionalProperties"]
3373
- };
3374
- function cleanJsonSchemaFor(schema = {}, provider) {
3375
- const clone = deepClone(schema);
3376
- if (Object.keys(clone).length === 0) {
3517
+ // src/llm/output/default.ts
3518
+ function OutputDefault(result, _config) {
3519
+ const name = _config?.options.model?.default || "unknown";
3520
+ const stopReason = result?.stopReason || "stop";
3521
+ const content = [];
3522
+ if (result?.text) {
3523
+ content.push({ type: "text", text: result.text });
3524
+ }
3525
+ const usage = {
3526
+ output_tokens: result?.output_tokens || 0,
3527
+ input_tokens: result?.input_tokens || 0,
3528
+ total_tokens: (result?.input_tokens || 0) + (result?.output_tokens || 0)
3529
+ };
3530
+ return {
3531
+ name,
3532
+ usage,
3533
+ stopReason,
3534
+ content
3535
+ };
3536
+ }
3537
+
3538
+ // src/llm/output/_utils/getResultContent.ts
3539
+ function getResultContent(result, index) {
3540
+ if (typeof index === "number" && index > 0) {
3541
+ const arr = result?.options || [];
3542
+ const val = arr[index];
3543
+ return val ? val : [];
3544
+ }
3545
+ return [...result.content];
3546
+ }
3547
+
3548
+ // src/llm/output/_utils/getResultText.ts
3549
+ function getResultText(result, index) {
3550
+ if (typeof index === "number" && index > 0) {
3551
+ const arr = result?.options || [];
3552
+ const val = arr[index];
3553
+ return isOutputResultContentText(val?.[0]) ? val[0]?.text : "";
3554
+ }
3555
+ return isOutputResultContentText(result?.content?.[0]) ? result.content[0]?.text : "";
3556
+ }
3557
+
3558
+ // src/llm/output/base.ts
3559
+ function BaseLlmOutput(result) {
3560
+ const __result = Object.freeze({
3561
+ id: result.id || (0, import_uuid.v4)(),
3562
+ name: result.name,
3563
+ usage: result.usage,
3564
+ stopReason: result.stopReason,
3565
+ options: [...result?.options || []],
3566
+ content: [...result.content],
3567
+ created: result?.created || (/* @__PURE__ */ new Date()).getTime()
3568
+ });
3569
+ function getResult() {
3377
3570
  return {
3378
- type: "object",
3379
- properties: {},
3380
- required: []
3571
+ id: __result.id,
3572
+ name: __result.name,
3573
+ created: __result.created,
3574
+ usage: __result.usage,
3575
+ options: __result.options,
3576
+ content: __result.content,
3577
+ stopReason: __result.stopReason
3381
3578
  };
3382
3579
  }
3383
- const exclusions = providerFieldExclusions[provider] || [];
3384
- function removeDisallowedFields(obj) {
3385
- if (Array.isArray(obj)) {
3386
- return obj.map(removeDisallowedFields);
3387
- } else if (typeof obj === "object" && obj !== null) {
3388
- return Object.keys(obj).reduce((acc, key) => {
3389
- if (!exclusions.includes(key)) {
3390
- acc[key] = removeDisallowedFields(obj[key]);
3391
- }
3392
- return acc;
3393
- }, {});
3580
+ return {
3581
+ getResultContent: (index) => getResultContent(__result, index),
3582
+ getResultText: (index) => getResultText(__result, index),
3583
+ getResult
3584
+ };
3585
+ }
3586
+
3587
+ // src/llm/_utils.mapOptions.ts
3588
+ function mapOptions(input, options, config) {
3589
+ if (!config?.mapOptions || !options) {
3590
+ return input;
3591
+ }
3592
+ let result = { ...input };
3593
+ let processedOptions = options;
3594
+ if (options.functionCall && config.mapOptions.functionCall) {
3595
+ const mapping = config.mapOptions.functionCall(
3596
+ options.functionCall,
3597
+ options,
3598
+ result,
3599
+ config
3600
+ );
3601
+ if (mapping._clearFunctions) {
3602
+ processedOptions = { ...options, functions: [] };
3603
+ const { _clearFunctions, ...rest } = mapping;
3604
+ result = { ...result, ...rest };
3605
+ } else {
3606
+ result = { ...result, ...mapping };
3394
3607
  }
3395
- return obj;
3396
3608
  }
3397
- return removeDisallowedFields(clone);
3609
+ if (processedOptions.functions?.length && config.mapOptions.functions) {
3610
+ result = {
3611
+ ...result,
3612
+ ...config.mapOptions.functions(
3613
+ processedOptions.functions,
3614
+ processedOptions,
3615
+ result,
3616
+ config
3617
+ )
3618
+ };
3619
+ }
3620
+ if (options.jsonSchema && config.mapOptions.jsonSchema) {
3621
+ result = {
3622
+ ...result,
3623
+ ...config.mapOptions.jsonSchema(options.jsonSchema, options, result, config)
3624
+ };
3625
+ }
3626
+ return result;
3398
3627
  }
3399
3628
 
3400
3629
  // src/llm/llm.call.ts
3401
3630
  async function useLlm_call(state, messages, _options) {
3402
3631
  const config = getLlmConfig(state.key);
3403
- const { functionCallStrictInput = false } = _options || {};
3404
- const input = mapBody(
3632
+ const transformBody = mapBody(
3405
3633
  config.mapBody,
3406
3634
  Object.assign({}, state, {
3407
3635
  prompt: messages
3408
3636
  })
3409
3637
  );
3410
- if (_options && _options?.jsonSchema) {
3411
- if (state.provider.startsWith("openai") || state.provider.startsWith("deepseek") || state.provider.startsWith("xai")) {
3412
- const curr = input["response_format"] || {};
3413
- input["response_format"] = Object.assign(curr, {
3414
- type: "json_schema",
3415
- json_schema: {
3416
- name: "output",
3417
- strict: !!functionCallStrictInput,
3418
- schema: cleanJsonSchemaFor(_options?.jsonSchema, "openai.chat")
3419
- }
3420
- });
3421
- }
3422
- }
3423
- if (_options && _options?.functionCall) {
3424
- if (state.provider.startsWith("anthropic")) {
3425
- if (_options?.functionCall === "none") {
3426
- _options.functions = [];
3427
- } else if (_options?.functionCall === "auto" || _options?.functionCall === "any") {
3428
- input["tool_choice"] = { type: _options?.functionCall };
3429
- } else {
3430
- input["tool_choice"] = _options?.functionCall;
3431
- }
3432
- } else if (state.provider.startsWith("openai") || state.provider.startsWith("deepseek") || state.provider.startsWith("xai")) {
3433
- input["tool_choice"] = normalizeFunctionCall(
3434
- _options?.functionCall,
3435
- "openai"
3436
- );
3437
- } else if (state.provider.startsWith("google")) {
3438
- input["toolConfig"] = {
3439
- functionCallingConfig: {
3440
- mode: normalizeFunctionCall(_options?.functionCall, "google")
3441
- }
3442
- };
3443
- }
3444
- }
3445
- if (_options && _options?.functions?.length) {
3446
- if (state.provider.startsWith("anthropic")) {
3447
- input["tools"] = _options.functions.map((f) => ({
3448
- name: f.name,
3449
- description: f.description,
3450
- input_schema: cleanJsonSchemaFor(f.parameters, "anthropic.chat")
3451
- }));
3452
- } else if (state.provider.startsWith("openai") || state.provider.startsWith("deepseek") || state.provider.startsWith("xai")) {
3453
- input["tools"] = _options.functions.map((f) => {
3454
- const props = {
3455
- name: f?.name,
3456
- description: f?.description,
3457
- parameters: f?.parameters
3458
- };
3459
- return {
3460
- type: "function",
3461
- function: Object.assign(
3462
- props,
3463
- {
3464
- parameters: cleanJsonSchemaFor(props.parameters, "openai.chat")
3465
- },
3466
- { strict: functionCallStrictInput }
3467
- )
3468
- };
3469
- });
3470
- } else if (state.provider.startsWith("google")) {
3471
- input["tools"] = [
3472
- {
3473
- functionDeclarations: _options.functions.map((f) => ({
3474
- name: f.name,
3475
- description: f.description,
3476
- parameters: cleanJsonSchemaFor(f.parameters, "google.chat")
3477
- }))
3478
- }
3479
- ];
3480
- }
3481
- }
3482
- const body = JSON.stringify(input);
3638
+ const applyOptions = mapOptions(transformBody, _options, config);
3639
+ const body = JSON.stringify(applyOptions);
3483
3640
  const url = replaceTemplateStringSimple(config.endpoint, state);
3484
3641
  const headers = await parseHeaders(config, state, {
3485
3642
  url,
@@ -3506,7 +3663,9 @@ async function useLlm_call(state, messages, _options) {
3506
3663
  body,
3507
3664
  headers
3508
3665
  });
3509
- return normalizeLlmOutputToInternalFormat(state, response);
3666
+ const { transformResponse = OutputDefault } = config;
3667
+ const normalized = transformResponse(response, config);
3668
+ return BaseLlmOutput(normalized);
3510
3669
  }
3511
3670
 
3512
3671
  // src/llm/_utils.stateFromOptions.ts
@@ -3649,6 +3808,80 @@ function useLlm(provider, options = {}) {
3649
3808
  const config = getLlmConfig(provider);
3650
3809
  return apiRequestWrapper(config, options, useLlm_call);
3651
3810
  }
3811
+ function useLlmConfiguration(config) {
3812
+ return (options = {}) => apiRequestWrapper(config, options, useLlm_call);
3813
+ }
3814
+
3815
+ // src/embedding/output/BaseEmbeddingOutput.ts
3816
+ function BaseEmbeddingOutput(result) {
3817
+ const __result = Object.freeze({
3818
+ id: result.id || (0, import_uuid.v4)(),
3819
+ model: result.model,
3820
+ usage: result.usage,
3821
+ embedding: [...result?.embedding || []],
3822
+ created: result?.created || (/* @__PURE__ */ new Date()).getTime()
3823
+ });
3824
+ function getResult() {
3825
+ return {
3826
+ id: __result.id,
3827
+ model: __result.model,
3828
+ created: __result.created,
3829
+ usage: __result.usage,
3830
+ embedding: __result.embedding
3831
+ };
3832
+ }
3833
+ function getEmbedding(index) {
3834
+ if (index && index > 0) {
3835
+ const arr = __result?.embedding;
3836
+ const val = arr[index];
3837
+ return val ? val : [];
3838
+ }
3839
+ return __result.embedding[0];
3840
+ }
3841
+ return {
3842
+ getEmbedding,
3843
+ getResult
3844
+ };
3845
+ }
3846
+
3847
+ // src/embedding/output/OpenAiEmbedding.ts
3848
+ function OpenAiEmbedding(result, config) {
3849
+ const __result = deepClone(result);
3850
+ const model = __result.model || config.model || "openai.unknown";
3851
+ const created = (/* @__PURE__ */ new Date()).getTime();
3852
+ const results = result?.data || [];
3853
+ const embedding = results.map((a) => a.embedding);
3854
+ const usage = {
3855
+ output_tokens: 0,
3856
+ input_tokens: result?.usage?.prompt_tokens,
3857
+ total_tokens: result?.usage?.total_tokens
3858
+ };
3859
+ return BaseEmbeddingOutput({
3860
+ model,
3861
+ created,
3862
+ usage,
3863
+ embedding
3864
+ });
3865
+ }
3866
+
3867
+ // src/embedding/output/AmazonTitan.ts
3868
+ function AmazonTitanEmbedding(result, config) {
3869
+ const __result = deepClone(result);
3870
+ const model = config.model || "amazon.unknown";
3871
+ const created = (/* @__PURE__ */ new Date()).getTime();
3872
+ const embedding = [__result.embedding];
3873
+ const usage = {
3874
+ output_tokens: 0,
3875
+ input_tokens: __result.inputTextTokenCount,
3876
+ total_tokens: __result.inputTextTokenCount
3877
+ };
3878
+ return BaseEmbeddingOutput({
3879
+ model,
3880
+ created,
3881
+ usage,
3882
+ embedding
3883
+ });
3884
+ }
3652
3885
 
3653
3886
  // src/embedding/config.ts
3654
3887
  var embeddingConfigs = {
@@ -3681,7 +3914,8 @@ var embeddingConfigs = {
3681
3914
  encodingFormat: {
3682
3915
  key: "encoding_format"
3683
3916
  }
3684
- }
3917
+ },
3918
+ transformResponse: OpenAiEmbedding
3685
3919
  },
3686
3920
  "amazon.embedding.v1": {
3687
3921
  key: "amazon.embedding.v1",
@@ -3708,7 +3942,8 @@ var embeddingConfigs = {
3708
3942
  dimensions: {
3709
3943
  key: "dimensions"
3710
3944
  }
3711
- }
3945
+ },
3946
+ transformResponse: AmazonTitanEmbedding
3712
3947
  }
3713
3948
  };
3714
3949
  function getEmbeddingConfig(provider) {
@@ -3722,77 +3957,6 @@ function getEmbeddingConfig(provider) {
3722
3957
  throw new Error(`Invalid provider: ${provider}`);
3723
3958
  }
3724
3959
 
3725
- // src/embedding/output/BaseEmbeddingOutput.ts
3726
- function BaseEmbeddingOutput(result) {
3727
- const __result = Object.freeze({
3728
- id: result.id || (0, import_uuid.v4)(),
3729
- model: result.model,
3730
- usage: result.usage,
3731
- embedding: [...result?.embedding || []],
3732
- created: result?.created || (/* @__PURE__ */ new Date()).getTime()
3733
- });
3734
- function getResult() {
3735
- return {
3736
- id: __result.id,
3737
- model: __result.model,
3738
- created: __result.created,
3739
- usage: __result.usage,
3740
- embedding: __result.embedding
3741
- };
3742
- }
3743
- function getEmbedding(index) {
3744
- if (index && index > 0) {
3745
- const arr = __result?.embedding;
3746
- const val = arr[index];
3747
- return val ? val : [];
3748
- }
3749
- return __result.embedding[0];
3750
- }
3751
- return {
3752
- getEmbedding,
3753
- getResult
3754
- };
3755
- }
3756
-
3757
- // src/embedding/output/AmazonTitan.ts
3758
- function AmazonTitanEmbedding(result, config) {
3759
- const __result = deepClone(result);
3760
- const model = config.model || "amazon.unknown";
3761
- const created = (/* @__PURE__ */ new Date()).getTime();
3762
- const embedding = [__result.embedding];
3763
- const usage = {
3764
- output_tokens: 0,
3765
- input_tokens: __result.inputTextTokenCount,
3766
- total_tokens: __result.inputTextTokenCount
3767
- };
3768
- return BaseEmbeddingOutput({
3769
- model,
3770
- created,
3771
- usage,
3772
- embedding
3773
- });
3774
- }
3775
-
3776
- // src/embedding/output/OpenAiEmbedding.ts
3777
- function OpenAiEmbedding(result, config) {
3778
- const __result = deepClone(result);
3779
- const model = __result.model || config.model || "openai.unknown";
3780
- const created = (/* @__PURE__ */ new Date()).getTime();
3781
- const results = result?.data || [];
3782
- const embedding = results.map((a) => a.embedding);
3783
- const usage = {
3784
- output_tokens: 0,
3785
- input_tokens: result?.usage?.prompt_tokens,
3786
- total_tokens: result?.usage?.total_tokens
3787
- };
3788
- return BaseEmbeddingOutput({
3789
- model,
3790
- created,
3791
- usage,
3792
- embedding
3793
- });
3794
- }
3795
-
3796
3960
  // src/embedding/output/getEmbeddingOutputParser.ts
3797
3961
  function getEmbeddingOutputParser(config, response) {
3798
3962
  switch (config.key) {
@@ -4070,8 +4234,8 @@ var ChatPrompt = class extends BasePrompt {
4070
4234
  __publicField(this, "type", "chat");
4071
4235
  /**
4072
4236
  * @property parseUserTemplates - Whether or not to allow parsing
4073
- * user messages with the template engine. This could be a risk,
4074
- * so we only parse user messages if explicitly set.
4237
+ * user messages with the template engine. Defaults to true.
4238
+ * Set `allowUnsafeUserTemplate: false` in options to disable.
4075
4239
  */
4076
4240
  __publicField(this, "parseUserTemplates", true);
4077
4241
  if (typeof options?.allowUnsafeUserTemplate === "boolean") {
@@ -4132,7 +4296,7 @@ var ChatPrompt = class extends BasePrompt {
4132
4296
  return this;
4133
4297
  }
4134
4298
  /**
4135
- * addFunctionMessage Helper to add an assistant message to the prompt.
4299
+ * addFunctionMessage Helper to add a function message to the prompt.
4136
4300
  * @param content The message content.
4137
4301
  * @return ChatPrompt so it can be chained.
4138
4302
  */
@@ -4146,7 +4310,7 @@ var ChatPrompt = class extends BasePrompt {
4146
4310
  return this;
4147
4311
  }
4148
4312
  /**
4149
- * addFunctionCallMessage Helper to add an assistant message to the prompt.
4313
+ * addFunctionCallMessage Helper to add a function_call message to the prompt.
4150
4314
  * @param content The message content.
4151
4315
  * @return ChatPrompt so it can be chained.
4152
4316
  */
@@ -4701,7 +4865,7 @@ var Dialogue = class extends BaseStateItem {
4701
4865
  return this;
4702
4866
  }
4703
4867
  setToolMessage(content, name, id) {
4704
- this.setFunctionMessage(content, name, id);
4868
+ return this.setFunctionMessage(content, name, id);
4705
4869
  }
4706
4870
  setFunctionMessage(content, name, id) {
4707
4871
  if (content) {
@@ -4718,7 +4882,7 @@ var Dialogue = class extends BaseStateItem {
4718
4882
  * Set
4719
4883
  */
4720
4884
  setToolCallMessage(input) {
4721
- this.setFunctionCallMessage(input);
4885
+ return this.setFunctionCallMessage(input);
4722
4886
  }
4723
4887
  setFunctionCallMessage(input) {
4724
4888
  if (!input || typeof input !== "object") {
@@ -4810,6 +4974,9 @@ var Dialogue = class extends BaseStateItem {
4810
4974
  * @returns this for chaining
4811
4975
  */
4812
4976
  addFromOutput(output) {
4977
+ if (!output || typeof output !== "object") {
4978
+ return this;
4979
+ }
4813
4980
  const result = "getResult" in output ? output.getResult() : output;
4814
4981
  if (!result || typeof result !== "object") {
4815
4982
  return this;
@@ -4946,6 +5113,7 @@ function createStateItem(name, defaultValue) {
4946
5113
  createEmbedding,
4947
5114
  createLlmExecutor,
4948
5115
  createLlmFunctionExecutor,
5116
+ createOpenAiCompatibleConfiguration,
4949
5117
  createParser,
4950
5118
  createPrompt,
4951
5119
  createState,
@@ -4956,5 +5124,6 @@ function createStateItem(name, defaultValue) {
4956
5124
  registerPartials,
4957
5125
  useExecutors,
4958
5126
  useLlm,
5127
+ useLlmConfiguration,
4959
5128
  utils
4960
5129
  });