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.mjs CHANGED
@@ -125,6 +125,10 @@ var BaseExecutor = class {
125
125
  */
126
126
  __publicField(this, "hooks");
127
127
  __publicField(this, "allowedHooks", [hookOnComplete, hookOnError, hookOnSuccess]);
128
+ /**
129
+ * @property maxHooksPerEvent - Maximum number of hooks allowed per event
130
+ */
131
+ __publicField(this, "maxHooksPerEvent", 100);
128
132
  this.id = uuidv4();
129
133
  this.type = type;
130
134
  this.name = name;
@@ -230,6 +234,11 @@ var BaseExecutor = class {
230
234
  const _hooks = Array.isArray(hookInput) ? hookInput : [hookInput];
231
235
  for (const hook of _hooks) {
232
236
  if (hook && typeof hook === "function" && !this.hooks[hookKey].find((h) => h === hook)) {
237
+ if (this.hooks[hookKey].length >= this.maxHooksPerEvent) {
238
+ throw new Error(
239
+ `Maximum number of hooks (${this.maxHooksPerEvent}) reached for event "${String(hookKey)}". Consider removing unused hooks or increasing the limit.`
240
+ );
241
+ }
233
242
  this.hooks[hookKey].push(hook);
234
243
  }
235
244
  }
@@ -257,10 +266,18 @@ var BaseExecutor = class {
257
266
  }
258
267
  once(eventName, fn) {
259
268
  if (typeof fn !== "function") return this;
269
+ if (this.hooks[eventName] && this.hooks[eventName].length >= this.maxHooksPerEvent) {
270
+ throw new Error(
271
+ `Maximum number of hooks (${this.maxHooksPerEvent}) reached for event "${String(eventName)}". Consider removing unused hooks or increasing the limit.`
272
+ );
273
+ }
260
274
  const onceWrapper = (...args) => {
261
275
  fn(...args);
262
276
  this.off(eventName, onceWrapper);
263
277
  };
278
+ if (!this.hooks[eventName]) {
279
+ this.hooks[eventName] = [];
280
+ }
264
281
  this.hooks[eventName].push(onceWrapper);
265
282
  return this;
266
283
  }
@@ -271,6 +288,40 @@ var BaseExecutor = class {
271
288
  getTraceId() {
272
289
  return this.traceId;
273
290
  }
291
+ /**
292
+ * Clear all hooks for a specific event or all events
293
+ * Useful for preventing memory leaks in long-running processes
294
+ * @param eventName - The event name to clear hooks for
295
+ */
296
+ clearHooks(eventName) {
297
+ if (eventName) {
298
+ if (this.hooks[eventName]) {
299
+ this.hooks[eventName] = [];
300
+ }
301
+ } else {
302
+ for (const key of this.allowedHooks) {
303
+ if (this.hooks[key]) {
304
+ this.hooks[key] = [];
305
+ }
306
+ }
307
+ }
308
+ return this;
309
+ }
310
+ /**
311
+ * Get the count of hooks for monitoring memory usage
312
+ * @param eventName - Optional event name to get count for
313
+ * @returns Hook count for specific event or all events
314
+ */
315
+ getHookCount(eventName) {
316
+ if (eventName) {
317
+ return this.hooks[eventName]?.length || 0;
318
+ }
319
+ const counts = {};
320
+ for (const key of this.allowedHooks) {
321
+ counts[key] = this.hooks[key]?.length || 0;
322
+ }
323
+ return counts;
324
+ }
274
325
  };
275
326
 
276
327
  // src/utils/modules/inferFunctionName.ts
@@ -416,7 +467,7 @@ var BooleanParser = class extends BaseParser {
416
467
  `Invalid input. Expected string. Received ${typeof text}.`
417
468
  );
418
469
  const clean = text.toLowerCase().trim();
419
- if (clean === "true") {
470
+ if (clean === "true" || clean === "yes" || clean === "y" || clean === "1") {
420
471
  return true;
421
472
  }
422
473
  return false;
@@ -445,7 +496,7 @@ var NumberParser = class extends BaseParser {
445
496
  super("number", options);
446
497
  }
447
498
  parse(text) {
448
- const match = text.match(/\d/g);
499
+ const match = text.match(/-?\d+(\.\d+)?/);
449
500
  return match && isFinite(toNumber(match[0])) ? toNumber(match[0]) : -1;
450
501
  }
451
502
  };
@@ -1347,9 +1398,8 @@ var asyncCallWithTimeout = async (asyncPromise, timeLimit = 1e4) => {
1347
1398
  );
1348
1399
  }, timeLimit);
1349
1400
  });
1350
- return Promise.race([asyncPromise, timeoutPromise]).then((result) => {
1401
+ return Promise.race([asyncPromise, timeoutPromise]).finally(() => {
1351
1402
  clearTimeout(timeoutHandle);
1352
- return result;
1353
1403
  });
1354
1404
  };
1355
1405
 
@@ -1495,9 +1545,13 @@ var ListToJsonParser = class extends BaseParserWithJson {
1495
1545
  const lines = text.split("\n");
1496
1546
  const output = {};
1497
1547
  lines.forEach((line) => {
1498
- const [key, value] = line.split(":");
1499
- if (value) {
1500
- output[camelCase(key)] = value.trim();
1548
+ const colonIndex = line.indexOf(":");
1549
+ if (colonIndex !== -1) {
1550
+ const key = line.slice(0, colonIndex);
1551
+ const value = line.slice(colonIndex + 1).trim();
1552
+ if (value) {
1553
+ output[camelCase(key)] = value;
1554
+ }
1501
1555
  }
1502
1556
  });
1503
1557
  if (this.schema) {
@@ -1569,7 +1623,7 @@ var ListToArrayParser = class extends BaseParser {
1569
1623
  super("listToArray");
1570
1624
  }
1571
1625
  parse(text) {
1572
- const lines = text.split("\n").map((s) => s.replace(/^- /, "").replace(/'/g, "'").trim());
1626
+ const lines = text.split("\n").map((s) => s.replace(/^(?:[-*] |\d+\. )/, "").replace(/'/g, "\u2019").trim());
1573
1627
  return lines;
1574
1628
  }
1575
1629
  };
@@ -1697,8 +1751,11 @@ function createParser(type, options = {}) {
1697
1751
  case "stringExtract":
1698
1752
  return new StringExtractParser(options);
1699
1753
  case "string":
1700
- default:
1701
1754
  return new StringParser();
1755
+ default:
1756
+ throw new Error(
1757
+ `Invalid parser type: "${type}". Valid types are: json, string, boolean, number, stringExtract, listToArray, listToJson, listToKeyValue, replaceStringTemplate, markdownCodeBlock, markdownCodeBlocks`
1758
+ );
1702
1759
  }
1703
1760
  }
1704
1761
  function createCustomParser(name, parserFn) {
@@ -2057,6 +2114,63 @@ function getEnvironmentVariable(name) {
2057
2114
  }
2058
2115
  }
2059
2116
 
2117
+ // src/llm/output/_util.ts
2118
+ function formatOptions(response, handler) {
2119
+ const out = [];
2120
+ for (const item of response) {
2121
+ const result = handler(item);
2122
+ if (result) {
2123
+ out.push([result]);
2124
+ }
2125
+ }
2126
+ return out;
2127
+ }
2128
+
2129
+ // src/llm/output/openai.ts
2130
+ function formatResult(result) {
2131
+ const out = [];
2132
+ if (typeof result?.message?.content === "string") {
2133
+ out.push({
2134
+ type: "text",
2135
+ text: result.message.content
2136
+ });
2137
+ }
2138
+ if (result?.message?.tool_calls) {
2139
+ for (const call of result.message.tool_calls) {
2140
+ out.push({
2141
+ functionId: call.id,
2142
+ type: "function_use",
2143
+ name: call.function.name,
2144
+ input: maybeParseJSON(call.function.arguments)
2145
+ });
2146
+ }
2147
+ }
2148
+ return out;
2149
+ }
2150
+ function OutputOpenAIChat(result, _config) {
2151
+ const id = result.id;
2152
+ const name = result.model || _config?.options.model?.default || "openai.unknown";
2153
+ const created = result.created;
2154
+ const [_content, ..._options] = result?.choices || [];
2155
+ const stopReason = _content?.finish_reason;
2156
+ const content = formatResult(_content);
2157
+ const options = formatOptions(_options, formatResult);
2158
+ const usage = {
2159
+ output_tokens: result?.usage?.completion_tokens,
2160
+ input_tokens: result?.usage?.prompt_tokens,
2161
+ total_tokens: result?.usage?.total_tokens
2162
+ };
2163
+ return {
2164
+ id,
2165
+ name,
2166
+ created,
2167
+ usage,
2168
+ stopReason,
2169
+ content,
2170
+ options
2171
+ };
2172
+ }
2173
+
2060
2174
  // src/llm/config/openai/promptSanitizeMessageCallback.ts
2061
2175
  function openaiPromptMessageCallback(_message) {
2062
2176
  let message = { ..._message };
@@ -2090,38 +2204,127 @@ function openaiPromptSanitize(_messages, _inputBodyObj, _outputObj) {
2090
2204
  return _messages.map(openaiPromptMessageCallback);
2091
2205
  }
2092
2206
 
2093
- // src/llm/config/openai/index.ts
2094
- var openAiChatV1 = {
2095
- key: "openai.chat.v1",
2096
- provider: "openai.chat",
2097
- endpoint: `https://api.openai.com/v1/chat/completions`,
2098
- options: {
2099
- prompt: {},
2100
- topP: {},
2101
- useJson: {},
2102
- openAiApiKey: {
2103
- default: getEnvironmentVariable("OPENAI_API_KEY")
2207
+ // src/llm/output/_utils/cleanJsonSchemaFor.ts
2208
+ var providerFieldExclusions = {
2209
+ "openai.chat": ["default"],
2210
+ // fields to exclude for openai.chat, xai, deepseek
2211
+ "anthropic.chat": [],
2212
+ "google.chat": ["additionalProperties"]
2213
+ };
2214
+ function cleanJsonSchemaFor(schema = {}, provider) {
2215
+ const clone = deepClone(schema);
2216
+ if (Object.keys(clone).length === 0) {
2217
+ return {
2218
+ type: "object",
2219
+ properties: {},
2220
+ required: []
2221
+ };
2222
+ }
2223
+ const exclusions = providerFieldExclusions[provider] || [];
2224
+ function removeDisallowedFields(obj) {
2225
+ if (Array.isArray(obj)) {
2226
+ return obj.map(removeDisallowedFields);
2227
+ } else if (typeof obj === "object" && obj !== null) {
2228
+ return Object.keys(obj).reduce((acc, key) => {
2229
+ if (!exclusions.includes(key)) {
2230
+ acc[key] = removeDisallowedFields(obj[key]);
2231
+ }
2232
+ return acc;
2233
+ }, {});
2104
2234
  }
2105
- },
2106
- method: "POST",
2107
- headers: `{"Authorization":"Bearer {{openAiApiKey}}", "Content-Type": "application/json" }`,
2108
- mapBody: {
2109
- prompt: {
2110
- key: "messages",
2111
- sanitize: openaiPromptSanitize
2235
+ return obj;
2236
+ }
2237
+ return removeDisallowedFields(clone);
2238
+ }
2239
+
2240
+ // src/llm/config/openai/compatible.ts
2241
+ function createOpenAiCompatibleConfiguration(overrides) {
2242
+ const [apiKeyPropertyKey, apiKeyPropertyValue] = overrides.apiKeyMapping;
2243
+ const config = {
2244
+ key: overrides.key,
2245
+ provider: overrides.provider,
2246
+ endpoint: overrides.endpoint,
2247
+ options: {
2248
+ prompt: {},
2249
+ effort: {},
2250
+ topP: {},
2251
+ useJson: {},
2252
+ [apiKeyPropertyKey]: {
2253
+ default: getEnvironmentVariable(apiKeyPropertyValue)
2254
+ }
2112
2255
  },
2113
- model: {
2114
- key: "model"
2256
+ method: "POST",
2257
+ headers: `{"Authorization":"Bearer {{${apiKeyPropertyKey}}}", "Content-Type": "application/json" }`,
2258
+ mapBody: {
2259
+ prompt: {
2260
+ key: "messages",
2261
+ transform: openaiPromptSanitize
2262
+ },
2263
+ model: {
2264
+ key: "model"
2265
+ },
2266
+ topP: {
2267
+ key: "top_p"
2268
+ },
2269
+ useJson: {
2270
+ key: "response_format.type",
2271
+ transform: (v) => v ? "json_object" : "text"
2272
+ },
2273
+ effort: {
2274
+ key: "reasoning_effort",
2275
+ transform: (v, _s) => {
2276
+ if (
2277
+ // only supported reasoning models
2278
+ ["gpt-5"].includes(_s.model) && typeof v === "string" && ["minimal", "low", "medium", "high"].includes(v)
2279
+ ) {
2280
+ return v;
2281
+ }
2282
+ return void 0;
2283
+ }
2284
+ }
2115
2285
  },
2116
- topP: {
2117
- key: "top_p"
2286
+ mapOptions: {
2287
+ jsonSchema: (schema, options, currentInput) => ({
2288
+ response_format: {
2289
+ ...currentInput?.response_format || {},
2290
+ type: "json_schema",
2291
+ json_schema: {
2292
+ name: "output",
2293
+ strict: !!options?.functionCallStrictInput,
2294
+ schema: cleanJsonSchemaFor(schema, "openai.chat")
2295
+ }
2296
+ }
2297
+ }),
2298
+ functionCall: (call) => {
2299
+ if (call === "any") return { tool_choice: "required" };
2300
+ if (call === "none") return { tool_choice: "none" };
2301
+ if (call === "auto") return { tool_choice: "auto" };
2302
+ return { tool_choice: call };
2303
+ },
2304
+ functions: (functions, options) => ({
2305
+ tools: functions.map((f) => ({
2306
+ type: "function",
2307
+ function: {
2308
+ name: f.name,
2309
+ description: f.description,
2310
+ parameters: cleanJsonSchemaFor(f.parameters, "openai.chat"),
2311
+ strict: !!options?.functionCallStrictInput
2312
+ }
2313
+ }))
2314
+ })
2118
2315
  },
2119
- useJson: {
2120
- key: "response_format.type",
2121
- sanitize: (v) => v ? "json_object" : "text"
2122
- }
2123
- }
2124
- };
2316
+ transformResponse: overrides.transformResponse ?? OutputOpenAIChat
2317
+ };
2318
+ return config;
2319
+ }
2320
+
2321
+ // src/llm/config/openai/index.ts
2322
+ var openAiChatV1 = createOpenAiCompatibleConfiguration({
2323
+ key: "openai.chat.v1",
2324
+ provider: "openai.chat",
2325
+ endpoint: `https://api.openai.com/v1/chat/completions`,
2326
+ apiKeyMapping: ["openAiApiKey", "OPENAI_API_KEY"]
2327
+ });
2125
2328
  var openAiChatMockV1 = {
2126
2329
  key: "openai.chat-mock.v1",
2127
2330
  provider: "openai.chat-mock",
@@ -2148,13 +2351,26 @@ var openAiChatMockV1 = {
2148
2351
  },
2149
2352
  useJson: {
2150
2353
  key: "response_format.type",
2151
- sanitize: (v) => v ? "json_object" : "text"
2354
+ transform: (v) => v ? "json_object" : "text"
2152
2355
  }
2153
- }
2356
+ },
2357
+ transformResponse: OutputOpenAIChat
2154
2358
  };
2155
2359
  var openai = {
2156
2360
  "openai.chat.v1": openAiChatV1,
2157
2361
  "openai.chat-mock.v1": openAiChatMockV1,
2362
+ // GPT-5 family
2363
+ "openai.gpt-5.2": withDefaultModel(openAiChatV1, "gpt-5.2"),
2364
+ "openai.gpt-5-mini": withDefaultModel(openAiChatV1, "gpt-5-mini"),
2365
+ "openai.gpt-5-nano": withDefaultModel(openAiChatV1, "gpt-5-nano"),
2366
+ // GPT-4.1 family
2367
+ "openai.gpt-4.1": withDefaultModel(openAiChatV1, "gpt-4.1"),
2368
+ "openai.gpt-4.1-mini": withDefaultModel(openAiChatV1, "gpt-4.1-mini"),
2369
+ "openai.gpt-4.1-nano": withDefaultModel(openAiChatV1, "gpt-4.1-nano"),
2370
+ // Reasoning models
2371
+ "openai.o3": withDefaultModel(openAiChatV1, "o3"),
2372
+ "openai.o4-mini": withDefaultModel(openAiChatV1, "o4-mini"),
2373
+ // GPT-4o family
2158
2374
  "openai.gpt-4o": withDefaultModel(openAiChatV1, "gpt-4o"),
2159
2375
  "openai.gpt-4o-mini": withDefaultModel(openAiChatV1, "gpt-4o-mini")
2160
2376
  };
@@ -2193,6 +2409,20 @@ function anthropicPromptMessageCallback(_message) {
2193
2409
  }
2194
2410
 
2195
2411
  // src/llm/config/anthropic/promptSanitize.ts
2412
+ function mergeConsecutiveSameRole(messages) {
2413
+ if (messages.length <= 1) return messages;
2414
+ const merged = [messages[0]];
2415
+ for (let i = 1; i < messages.length; i++) {
2416
+ const prev = merged[merged.length - 1];
2417
+ const curr = messages[i];
2418
+ if (curr.role === prev.role && Array.isArray(prev.content) && Array.isArray(curr.content)) {
2419
+ prev.content = [...prev.content, ...curr.content];
2420
+ } else {
2421
+ merged.push(curr);
2422
+ }
2423
+ }
2424
+ return merged;
2425
+ }
2196
2426
  function anthropicPromptSanitize(_messages, _inputBodyObj, _outputObj) {
2197
2427
  if (typeof _messages === "string") {
2198
2428
  return [{ role: "user", content: _messages }].map(
@@ -2210,14 +2440,15 @@ function anthropicPromptSanitize(_messages, _inputBodyObj, _outputObj) {
2210
2440
  }
2211
2441
  if (first.role === "system" && messages.length > 0) {
2212
2442
  _outputObj.system = first.content;
2213
- return messages.map((m) => {
2443
+ const result2 = messages.map((m) => {
2214
2444
  if (m.role === "system") {
2215
2445
  return { ...m, role: "user" };
2216
2446
  }
2217
2447
  return m;
2218
2448
  }).map(anthropicPromptMessageCallback);
2449
+ return mergeConsecutiveSameRole(result2);
2219
2450
  }
2220
- return [
2451
+ const result = [
2221
2452
  first,
2222
2453
  ...messages.map((m) => {
2223
2454
  if (m.role === "system") {
@@ -2226,10 +2457,78 @@ function anthropicPromptSanitize(_messages, _inputBodyObj, _outputObj) {
2226
2457
  return m;
2227
2458
  })
2228
2459
  ].map(anthropicPromptMessageCallback);
2460
+ return mergeConsecutiveSameRole(result);
2461
+ }
2462
+
2463
+ // src/llm/output/claude.ts
2464
+ function formatResult2(response) {
2465
+ const content = response?.content || [];
2466
+ const out = [];
2467
+ for (let i = 0; i < content.length; i++) {
2468
+ const result = content[i];
2469
+ if (result.type === "text") {
2470
+ out.push({
2471
+ type: "text",
2472
+ text: result.text
2473
+ });
2474
+ } else if (result.type === "tool_use") {
2475
+ out.push({
2476
+ functionId: result.id,
2477
+ type: "function_use",
2478
+ name: result.name,
2479
+ input: result.input
2480
+ });
2481
+ }
2482
+ }
2483
+ return out;
2484
+ }
2485
+ function OutputAnthropicClaude3Chat(result, _config) {
2486
+ const id = result.id;
2487
+ const name = result.model || _config?.options.model?.default || "anthropic.unknown";
2488
+ const stopReason = result.stop_reason;
2489
+ const content = formatResult2(result);
2490
+ const usage = {
2491
+ input_tokens: result?.usage?.input_tokens,
2492
+ output_tokens: result?.usage?.output_tokens,
2493
+ total_tokens: result?.usage?.input_tokens + result?.usage?.output_tokens
2494
+ };
2495
+ return {
2496
+ id,
2497
+ name,
2498
+ created: Date.now(),
2499
+ usage,
2500
+ stopReason,
2501
+ content
2502
+ };
2503
+ }
2504
+
2505
+ // src/llm/output/llama.ts
2506
+ function OutputMetaLlama3Chat(result, _config) {
2507
+ const id = uuidv4();
2508
+ const name = _config?.options?.model?.default || "meta";
2509
+ const created = (/* @__PURE__ */ new Date()).getTime();
2510
+ const stopReason = result.stop_reason;
2511
+ const content = [
2512
+ { type: "text", text: result.generation }
2513
+ ];
2514
+ const usage = {
2515
+ output_tokens: result?.generation_token_count,
2516
+ input_tokens: result?.prompt_token_count,
2517
+ total_tokens: result?.generation_token_count + result?.prompt_token_count
2518
+ };
2519
+ return {
2520
+ id,
2521
+ name,
2522
+ created,
2523
+ usage,
2524
+ stopReason,
2525
+ content,
2526
+ options: []
2527
+ };
2229
2528
  }
2230
2529
 
2231
2530
  // src/llm/config/bedrock/index.ts
2232
- var ANTORPIC_BEDROCK_VERSION = "bedrock-2023-05-31";
2531
+ var ANTHROPIC_BEDROCK_VERSION = "bedrock-2023-05-31";
2233
2532
  var amazonAnthropicChatV1 = {
2234
2533
  key: "amazon:anthropic.chat.v1",
2235
2534
  provider: "amazon:anthropic.chat",
@@ -2250,7 +2549,7 @@ var amazonAnthropicChatV1 = {
2250
2549
  mapBody: {
2251
2550
  prompt: {
2252
2551
  key: "messages",
2253
- sanitize: anthropicPromptSanitize
2552
+ transform: anthropicPromptSanitize
2254
2553
  },
2255
2554
  topP: {
2256
2555
  key: "top_p"
@@ -2261,9 +2560,26 @@ var amazonAnthropicChatV1 = {
2261
2560
  },
2262
2561
  anthropic_version: {
2263
2562
  key: "anthropic_version",
2264
- default: ANTORPIC_BEDROCK_VERSION
2563
+ default: ANTHROPIC_BEDROCK_VERSION
2265
2564
  }
2266
- }
2565
+ },
2566
+ mapOptions: {
2567
+ functionCall: (call, _options) => {
2568
+ if (call === "none") return { _clearFunctions: true };
2569
+ if (call === "auto" || call === "any") {
2570
+ return { tool_choice: { type: call } };
2571
+ }
2572
+ return { tool_choice: call };
2573
+ },
2574
+ functions: (functions) => ({
2575
+ tools: functions.map((f) => ({
2576
+ name: f.name,
2577
+ description: f.description,
2578
+ input_schema: cleanJsonSchemaFor(f.parameters, "anthropic.chat")
2579
+ }))
2580
+ })
2581
+ },
2582
+ transformResponse: OutputAnthropicClaude3Chat
2267
2583
  };
2268
2584
  var amazonMetaChatV1 = {
2269
2585
  key: "amazon:meta.chat.v1",
@@ -2285,7 +2601,7 @@ var amazonMetaChatV1 = {
2285
2601
  mapBody: {
2286
2602
  prompt: {
2287
2603
  key: "prompt",
2288
- sanitize: (messages) => {
2604
+ transform: (messages) => {
2289
2605
  if (typeof messages === "string") {
2290
2606
  return messages;
2291
2607
  } else {
@@ -2305,7 +2621,8 @@ var amazonMetaChatV1 = {
2305
2621
  key: "max_gen_len",
2306
2622
  default: 2048
2307
2623
  }
2308
- }
2624
+ },
2625
+ transformResponse: OutputMetaLlama3Chat
2309
2626
  };
2310
2627
  var bedrock = {
2311
2628
  "amazon:anthropic.chat.v1": amazonAnthropicChatV1,
@@ -2344,24 +2661,74 @@ var anthropicChatV1 = {
2344
2661
  },
2345
2662
  prompt: {
2346
2663
  key: "messages",
2347
- sanitize: anthropicPromptSanitize
2348
- }
2349
- }
2350
- };
2351
- var anthropic = {
2352
- "anthropic.chat.v1": anthropicChatV1,
2353
- "anthropic.claude-sonnet-4-0": withDefaultModel(
2354
- anthropicChatV1,
2355
- "claude-sonnet-4-0"
2356
- ),
2357
- "anthropic.claude-opus-4-0": withDefaultModel(
2664
+ transform: anthropicPromptSanitize
2665
+ },
2666
+ temperature: {
2667
+ key: "temperature"
2668
+ },
2669
+ topP: {
2670
+ key: "top_p"
2671
+ },
2672
+ topK: {
2673
+ key: "top_k"
2674
+ },
2675
+ stopSequences: {
2676
+ key: "stop_sequences"
2677
+ },
2678
+ stream: {
2679
+ key: "stream"
2680
+ },
2681
+ metadata: {
2682
+ key: "metadata"
2683
+ },
2684
+ serviceTier: {
2685
+ key: "service_tier"
2686
+ // Map camelCase to snake_case
2687
+ }
2688
+ },
2689
+ mapOptions: {
2690
+ functionCall: (call, _options) => {
2691
+ if (call === "none") return { _clearFunctions: true };
2692
+ if (call === "auto" || call === "any") {
2693
+ return { tool_choice: { type: call } };
2694
+ }
2695
+ return { tool_choice: call };
2696
+ },
2697
+ functions: (functions) => ({
2698
+ tools: functions.map((f) => ({
2699
+ name: f.name,
2700
+ description: f.description,
2701
+ input_schema: cleanJsonSchemaFor(f.parameters, "anthropic.chat")
2702
+ }))
2703
+ })
2704
+ },
2705
+ transformResponse: OutputAnthropicClaude3Chat
2706
+ };
2707
+ var anthropic = {
2708
+ "anthropic.chat.v1": anthropicChatV1,
2709
+ // Claude 4.6 models
2710
+ "anthropic.claude-opus-4-6": withDefaultModel(
2711
+ anthropicChatV1,
2712
+ "claude-opus-4-6"
2713
+ ),
2714
+ "anthropic.claude-sonnet-4-6": withDefaultModel(
2715
+ anthropicChatV1,
2716
+ "claude-sonnet-4-6"
2717
+ ),
2718
+ // Claude 4 models
2719
+ "anthropic.claude-sonnet-4": withDefaultModel(
2358
2720
  anthropicChatV1,
2359
2721
  "claude-sonnet-4-0"
2360
2722
  ),
2723
+ "anthropic.claude-opus-4": withDefaultModel(
2724
+ anthropicChatV1,
2725
+ "claude-opus-4-0"
2726
+ ),
2361
2727
  "anthropic.claude-3-7-sonnet": withDefaultModel(
2362
2728
  anthropicChatV1,
2363
- "claude-3-7-sonnet-latest"
2729
+ "claude-3-7-sonnet-20250219"
2364
2730
  ),
2731
+ // Claude 3.5 models
2365
2732
  "anthropic.claude-3-5-sonnet": withDefaultModel(
2366
2733
  anthropicChatV1,
2367
2734
  "claude-3-5-sonnet-latest"
@@ -2373,49 +2740,102 @@ var anthropic = {
2373
2740
  // Deprecated
2374
2741
  "anthropic.claude-3-opus": withDefaultModel(
2375
2742
  anthropicChatV1,
2376
- "claude-3-opus-latest"
2743
+ "claude-3-opus-20240229"
2744
+ ),
2745
+ "anthropic.claude-3-haiku": withDefaultModel(
2746
+ anthropicChatV1,
2747
+ "claude-3-haiku-20240307"
2377
2748
  )
2378
2749
  };
2379
2750
 
2380
2751
  // src/llm/config/x/index.ts
2381
- var xaiChatV1 = {
2752
+ var xaiChatV1 = createOpenAiCompatibleConfiguration({
2382
2753
  key: "xai.chat.v1",
2383
2754
  provider: "xai.chat",
2384
2755
  endpoint: `https://api.x.ai/v1/chat/completions`,
2385
- options: {
2386
- prompt: {},
2387
- topP: {},
2388
- useJson: {},
2389
- xAiApiKey: {
2390
- default: getEnvironmentVariable("XAI_API_KEY")
2391
- }
2392
- },
2393
- method: "POST",
2394
- headers: `{"Authorization":"Bearer {{xAiApiKey}}", "Content-Type": "application/json" }`,
2395
- mapBody: {
2396
- prompt: {
2397
- key: "messages",
2398
- sanitize: openaiPromptSanitize
2399
- },
2400
- model: {
2401
- key: "model"
2402
- },
2403
- topP: {
2404
- key: "top_p"
2405
- },
2406
- useJson: {
2407
- key: "response_format.type",
2408
- sanitize: (v) => v ? "json_object" : "text"
2409
- }
2410
- }
2411
- };
2756
+ apiKeyMapping: ["xAiApiKey", "XAI_API_KEY"]
2757
+ });
2412
2758
  var xai = {
2413
2759
  "xai.chat.v1": xaiChatV1,
2414
2760
  "xai.grok-2": withDefaultModel(xaiChatV1, "grok-2-latest"),
2415
2761
  "xai.grok-3": withDefaultModel(xaiChatV1, "grok-3"),
2416
- "xai.grok-4": withDefaultModel(xaiChatV1, "grok-4")
2762
+ "xai.grok-3-mini": withDefaultModel(xaiChatV1, "grok-3-mini"),
2763
+ "xai.grok-4": withDefaultModel(xaiChatV1, "grok-4"),
2764
+ "xai.grok-4-fast": withDefaultModel(xaiChatV1, "grok-4-fast-non-reasoning")
2417
2765
  };
2418
2766
 
2767
+ // src/llm/output/_utils/combineJsonl.ts
2768
+ function combineJsonl(jsonl) {
2769
+ const lines = jsonl.trim().split("\n").map((line) => line.trim()).filter((line) => line.length > 0).map((line) => {
2770
+ try {
2771
+ return JSON.parse(line);
2772
+ } catch (e) {
2773
+ throw new Error(`Invalid JSON: ${line}`);
2774
+ }
2775
+ });
2776
+ if (lines.length === 0) {
2777
+ throw new Error("No JSON lines provided.");
2778
+ }
2779
+ lines.sort(
2780
+ (a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime()
2781
+ );
2782
+ let combinedContent = lines.map((line) => line?.message?.content ?? "").join("");
2783
+ combinedContent = combinedContent.replace(/\\u003c/g, "<").replace(/\\u003e/g, ">");
2784
+ const finalLine = lines.find((line) => line.done === true);
2785
+ if (!finalLine) {
2786
+ throw new Error("No line found where done = true.");
2787
+ }
2788
+ const result = {
2789
+ model: finalLine.model,
2790
+ created_at: finalLine.created_at,
2791
+ message: {
2792
+ role: finalLine?.message?.role || "assistant",
2793
+ content: combinedContent
2794
+ },
2795
+ done_reason: finalLine.done_reason,
2796
+ done: finalLine.done,
2797
+ total_duration: finalLine.total_duration,
2798
+ load_duration: finalLine.load_duration,
2799
+ prompt_eval_count: finalLine.prompt_eval_count,
2800
+ prompt_eval_duration: finalLine.prompt_eval_duration,
2801
+ eval_count: finalLine.eval_count,
2802
+ eval_duration: finalLine.eval_duration
2803
+ };
2804
+ const content = {
2805
+ type: "text",
2806
+ text: combinedContent
2807
+ };
2808
+ return {
2809
+ lines,
2810
+ result,
2811
+ content
2812
+ };
2813
+ }
2814
+
2815
+ // src/llm/output/ollama.ts
2816
+ function OutputOllamaChat(result, _config) {
2817
+ const combined = combineJsonl(result);
2818
+ const id = `${combined.result.model}.${combined.result.created_at}`;
2819
+ const name = combined.result.model || _config?.options.model?.default || "ollama.unknown";
2820
+ const created = (/* @__PURE__ */ new Date(`${combined.result.created_at}`)).getTime();
2821
+ const stopReason = `${combined?.result?.done_reason || "stop"}`;
2822
+ const content = [combined.content];
2823
+ const usage = {
2824
+ output_tokens: 0,
2825
+ input_tokens: 0,
2826
+ total_tokens: 0
2827
+ };
2828
+ return {
2829
+ id,
2830
+ name,
2831
+ created,
2832
+ usage,
2833
+ stopReason,
2834
+ content,
2835
+ options: []
2836
+ };
2837
+ }
2838
+
2419
2839
  // src/llm/config/ollama/index.ts
2420
2840
  var ollamaChatV1 = {
2421
2841
  key: "ollama.chat.v1",
@@ -2429,7 +2849,7 @@ var ollamaChatV1 = {
2429
2849
  mapBody: {
2430
2850
  prompt: {
2431
2851
  key: "messages",
2432
- sanitize: (v) => {
2852
+ transform: (v) => {
2433
2853
  if (typeof v === "string") {
2434
2854
  return [{ role: "user", content: v }];
2435
2855
  }
@@ -2439,7 +2859,8 @@ var ollamaChatV1 = {
2439
2859
  model: {
2440
2860
  key: "model"
2441
2861
  }
2442
- }
2862
+ },
2863
+ transformResponse: OutputOllamaChat
2443
2864
  };
2444
2865
  var ollama = {
2445
2866
  "ollama.chat.v1": ollamaChatV1,
@@ -2461,7 +2882,7 @@ function googleGeminiPromptMessageCallback(_message) {
2461
2882
  message.role = "model";
2462
2883
  }
2463
2884
  let { role, ...payload } = message;
2464
- if (typeof payload.content === "string") {
2885
+ if (typeof payload.content === "string" && message.role !== "function") {
2465
2886
  parts.push({ text: message.content });
2466
2887
  }
2467
2888
  if (message.role === "function") {
@@ -2484,487 +2905,75 @@ function googleGeminiPromptMessageCallback(_message) {
2484
2905
  ...toolsArr.map((call) => {
2485
2906
  const { name, arguments: input } = call;
2486
2907
  return {
2487
- functionCall: {
2488
- name,
2489
- args: maybeParseJSON(input)
2490
- }
2491
- };
2492
- })
2493
- );
2494
- delete message.function_call;
2495
- }
2496
- return {
2497
- role,
2498
- parts
2499
- };
2500
- }
2501
-
2502
- // src/llm/config/google/promptSanitize.ts
2503
- function googleGeminiPromptSanitize(_messages, _inputBodyObj, _outputObj) {
2504
- if (typeof _messages === "string") {
2505
- return [{ role: "user", parts: [{ text: _messages }] }];
2506
- }
2507
- if (Array.isArray(_messages)) {
2508
- if (_messages.length === 0) {
2509
- throw new Error("Empty messages array");
2510
- }
2511
- if (_messages.length === 1 && _messages[0].role === "system") {
2512
- return [{ role: "user", parts: [{ text: _messages[0].content }] }];
2513
- }
2514
- const hasSystemInstruction = _messages.some(
2515
- (message) => message.role === "system"
2516
- );
2517
- if (hasSystemInstruction) {
2518
- const theSystemInstructions = _messages.filter(
2519
- (message) => message.role === "system"
2520
- );
2521
- const withoutSystemInstructions = _messages.filter(
2522
- (message) => message.role !== "system"
2523
- );
2524
- _outputObj.system_instruction = {
2525
- parts: theSystemInstructions.map((message) => ({
2526
- text: message.content
2527
- }))
2528
- };
2529
- return withoutSystemInstructions.map(googleGeminiPromptMessageCallback);
2530
- }
2531
- return _messages.map(googleGeminiPromptMessageCallback);
2532
- }
2533
- throw new Error("Invalid messages format");
2534
- }
2535
-
2536
- // src/llm/config/google/index.ts
2537
- var googleGeminiChatV1 = {
2538
- key: "google.chat.v1",
2539
- provider: "google.chat",
2540
- endpoint: `https://generativelanguage.googleapis.com/v1beta/models/{{model}}:generateContent?key={{geminiApiKey}}`,
2541
- options: {
2542
- prompt: {},
2543
- // topP: {},
2544
- geminiApiKey: {
2545
- default: getEnvironmentVariable("GEMINI_API_KEY")
2546
- }
2547
- },
2548
- method: "POST",
2549
- headers: `{"Content-Type": "application/json" }`,
2550
- mapBody: {
2551
- prompt: {
2552
- key: "contents",
2553
- sanitize: googleGeminiPromptSanitize
2554
- }
2555
- // topP: {
2556
- // key: "top_p",
2557
- // }
2558
- }
2559
- };
2560
- var google = {
2561
- "google.chat.v1": googleGeminiChatV1,
2562
- "google.gemini-2.0-flash": withDefaultModel(
2563
- googleGeminiChatV1,
2564
- "gemini-2.0-flash"
2565
- ),
2566
- "google.gemini-2.0-flash-lite": withDefaultModel(
2567
- googleGeminiChatV1,
2568
- "gemini-2.0-flash-lite"
2569
- ),
2570
- "google.gemini-2.5-flash": withDefaultModel(
2571
- googleGeminiChatV1,
2572
- "gemini-2.5-flash"
2573
- ),
2574
- "google.gemini-2.5-flash-lite": withDefaultModel(
2575
- googleGeminiChatV1,
2576
- "gemini-2.5-flash-lite"
2577
- ),
2578
- "google.gemini-1.5-pro": withDefaultModel(
2579
- googleGeminiChatV1,
2580
- "gemini-1.5-pro"
2581
- ),
2582
- "google.gemini-2.5-pro": withDefaultModel(
2583
- googleGeminiChatV1,
2584
- "gemini-2.5-pro"
2585
- )
2586
- };
2587
-
2588
- // src/llm/config/deepseek/index.ts
2589
- var deepseekChatV1 = {
2590
- key: "deepseek.chat.v1",
2591
- provider: "deepseek.chat",
2592
- endpoint: `https://api.deepseek.com/v1/chat/completions`,
2593
- options: {
2594
- prompt: {},
2595
- topP: {},
2596
- useJson: {},
2597
- deepseekApiKey: {
2598
- default: getEnvironmentVariable("DEEPSEEK_API_KEY")
2599
- }
2600
- },
2601
- method: "POST",
2602
- headers: `{"Authorization":"Bearer {{deepseekApiKey}}", "Content-Type": "application/json" }`,
2603
- mapBody: {
2604
- prompt: {
2605
- key: "messages",
2606
- sanitize: openaiPromptSanitize
2607
- },
2608
- model: {
2609
- key: "model"
2610
- },
2611
- topP: {
2612
- key: "top_p"
2613
- },
2614
- useJson: {
2615
- key: "response_format.type",
2616
- sanitize: (v) => v ? "json_object" : "text"
2617
- }
2618
- }
2619
- };
2620
- var deepseek = {
2621
- "deepseek.chat.v1": deepseekChatV1,
2622
- "deepseek.chat": withDefaultModel(deepseekChatV1, "deepseek-chat")
2623
- };
2624
-
2625
- // src/llm/config.ts
2626
- var configs = {
2627
- ...openai,
2628
- ...anthropic,
2629
- ...bedrock,
2630
- ...xai,
2631
- ...ollama,
2632
- ...google,
2633
- ...deepseek
2634
- };
2635
- function getLlmConfig(provider) {
2636
- if (!provider) {
2637
- throw new LlmExeError(`Missing provider`, "unknown", {
2638
- error: "Missing provider",
2639
- resolution: "Provide a valid provider"
2640
- });
2641
- }
2642
- const pick2 = configs[provider];
2643
- if (pick2) {
2644
- return pick2;
2645
- }
2646
- throw new LlmExeError(`Invalid provider: ${provider}`, "unknown", {
2647
- provider,
2648
- error: `Invalid provider: ${provider}`,
2649
- resolution: "Provide a valid provider"
2650
- });
2651
- }
2652
-
2653
- // src/llm/output/_utils/getResultContent.ts
2654
- function getResultContent(result, index) {
2655
- if (typeof index === "number" && index > 0) {
2656
- const arr = result?.options || [];
2657
- const val = arr[index];
2658
- return val ? val : [];
2659
- }
2660
- return [...result.content];
2661
- }
2662
-
2663
- // src/llm/output/_utils/getResultText.ts
2664
- function getResultText(result, index) {
2665
- if (typeof index === "number" && index > 0) {
2666
- const arr = result?.options || [];
2667
- const val = arr[index];
2668
- return isOutputResultContentText(val?.[0]) ? val[0]?.text : "";
2669
- }
2670
- return isOutputResultContentText(result?.content?.[0]) ? result.content[0]?.text : "";
2671
- }
2672
-
2673
- // src/llm/output/base.ts
2674
- function BaseLlmOutput2(result) {
2675
- const __result = Object.freeze({
2676
- id: result.id || uuidv4(),
2677
- name: result.name,
2678
- usage: result.usage,
2679
- stopReason: result.stopReason,
2680
- options: [...result?.options || []],
2681
- content: [...result.content],
2682
- created: result?.created || (/* @__PURE__ */ new Date()).getTime()
2683
- });
2684
- function getResult() {
2685
- return {
2686
- id: __result.id,
2687
- name: __result.name,
2688
- created: __result.created,
2689
- usage: __result.usage,
2690
- options: __result.options,
2691
- content: __result.content,
2692
- stopReason: __result.stopReason
2693
- };
2694
- }
2695
- return {
2696
- getResultContent: (index) => getResultContent(__result, index),
2697
- getResultText: (index) => getResultText(__result, index),
2698
- getResult
2699
- };
2700
- }
2701
-
2702
- // src/llm/output/_util.ts
2703
- function normalizeFunctionCall(input, provider) {
2704
- if (input === "any") {
2705
- if (provider === "openai") {
2706
- return "required";
2707
- }
2708
- }
2709
- return input;
2710
- }
2711
- function formatOptions(response, handler) {
2712
- const out = [];
2713
- for (const item of response) {
2714
- const result = handler(item);
2715
- if (result) {
2716
- out.push([result]);
2717
- }
2718
- }
2719
- return out;
2720
- }
2721
-
2722
- // src/llm/output/openai.ts
2723
- function formatResult(result) {
2724
- const out = [];
2725
- if (typeof result?.message?.content === "string") {
2726
- out.push({
2727
- type: "text",
2728
- text: result.message.content
2729
- });
2730
- }
2731
- if (result?.message?.tool_calls) {
2732
- for (const call of result.message.tool_calls) {
2733
- out.push({
2734
- functionId: call.id,
2735
- type: "function_use",
2736
- name: call.function.name,
2737
- input: maybeParseJSON(call.function.arguments)
2738
- });
2739
- }
2740
- }
2741
- return out;
2742
- }
2743
- function OutputOpenAIChat(result, _config) {
2744
- const id = result.id;
2745
- const name = result.model || _config?.model || "openai.unknown";
2746
- const created = result.created;
2747
- const [_content, ..._options] = result?.choices || [];
2748
- const stopReason = _content?.finish_reason;
2749
- const content = formatResult(_content);
2750
- const options = formatOptions(_options, formatResult);
2751
- const usage = {
2752
- output_tokens: result?.usage?.completion_tokens,
2753
- input_tokens: result?.usage?.prompt_tokens,
2754
- total_tokens: result?.usage?.total_tokens
2755
- };
2756
- return BaseLlmOutput2({
2757
- id,
2758
- name,
2759
- created,
2760
- usage,
2761
- stopReason,
2762
- content,
2763
- options
2764
- });
2765
- }
2766
-
2767
- // src/llm/output/claude.ts
2768
- function formatResult2(response) {
2769
- const content = response?.content || [];
2770
- const out = [];
2771
- for (let i = 0; i < content.length; i++) {
2772
- const result = content[i];
2773
- if (result.type === "text") {
2774
- out.push({
2775
- type: "text",
2776
- text: result.text
2777
- });
2778
- } else if (result.type === "tool_use") {
2779
- out.push({
2780
- functionId: result.id,
2781
- type: "function_use",
2782
- name: result.name,
2783
- input: result.input
2784
- });
2785
- }
2786
- }
2787
- return out;
2788
- }
2789
- function OutputAnthropicClaude3Chat(result, _config) {
2790
- const id = result.id;
2791
- const name = result.model || _config?.model || "anthropic.unknown";
2792
- const stopReason = result.stop_reason;
2793
- const content = formatResult2(result);
2794
- const usage = {
2795
- input_tokens: result?.usage?.input_tokens,
2796
- output_tokens: result?.usage?.output_tokens,
2797
- total_tokens: result?.usage?.input_tokens + result?.usage?.input_tokens
2798
- };
2799
- return BaseLlmOutput2({
2800
- id,
2801
- name,
2802
- usage,
2803
- stopReason,
2804
- content
2805
- });
2806
- }
2807
-
2808
- // src/llm/output/llama.ts
2809
- function OutputMetaLlama3Chat(result, _config) {
2810
- const name = _config?.model || "meta";
2811
- const stopReason = result.stop_reason;
2812
- const content = [
2813
- { type: "text", text: result.generation }
2814
- ];
2815
- const usage = {
2816
- output_tokens: result?.generation_token_count,
2817
- input_tokens: result?.prompt_token_count,
2818
- total_tokens: result?.generation_token_count + result?.prompt_token_count
2819
- };
2820
- return BaseLlmOutput2({
2821
- name,
2822
- usage,
2823
- stopReason,
2824
- content
2825
- });
2826
- }
2827
-
2828
- // src/llm/output/default.ts
2829
- function OutputDefault(result, _config) {
2830
- const name = _config.model || "unknown";
2831
- const stopReason = result?.stopReason || "stop";
2832
- const content = [];
2833
- if (result?.text) {
2834
- content.push({ type: "text", text: result.text });
2835
- }
2836
- const usage = {
2837
- output_tokens: result?.output_tokens || 0,
2838
- input_tokens: result?.input_tokens || 0,
2839
- total_tokens: (result?.input_tokens || 0) + (result?.output_tokens || 0)
2840
- };
2841
- return BaseLlmOutput2({
2842
- name,
2843
- usage,
2844
- stopReason,
2845
- content
2846
- });
2847
- }
2848
-
2849
- // src/llm/output/xai.ts
2850
- function formatResult3(result) {
2851
- const out = [];
2852
- if (typeof result?.message?.content === "string") {
2853
- out.push({
2854
- type: "text",
2855
- text: result.message.content
2856
- });
2857
- }
2858
- if (result?.message?.tool_calls) {
2859
- for (const call of result.message.tool_calls) {
2860
- out.push({
2861
- functionId: call.id,
2862
- type: "function_use",
2863
- name: call.function.name,
2864
- input: maybeParseJSON(call.function.arguments)
2865
- });
2866
- }
2867
- }
2868
- return out;
2869
- }
2870
- function OutputXAIChat(result, _config) {
2871
- const id = result.id;
2872
- const name = result.model || _config?.model || "openai.unknown";
2873
- const created = result.created;
2874
- const [_content, ..._options] = result?.choices || [];
2875
- const stopReason = _content?.finish_reason;
2876
- const content = formatResult3(_content);
2877
- const options = formatOptions(_options, formatResult3);
2878
- const usage = {
2879
- output_tokens: result?.usage?.completion_tokens,
2880
- input_tokens: result?.usage?.prompt_tokens,
2881
- total_tokens: result?.usage?.total_tokens
2882
- };
2883
- return BaseLlmOutput2({
2884
- id,
2885
- name,
2886
- created,
2887
- usage,
2888
- stopReason,
2889
- content,
2890
- options
2891
- });
2892
- }
2893
-
2894
- // src/llm/output/_utils/combineJsonl.ts
2895
- function combineJsonl(jsonl) {
2896
- const lines = jsonl.trim().split("\n").map((line) => line.trim()).filter((line) => line.length > 0).map((line) => {
2897
- try {
2898
- return JSON.parse(line);
2899
- } catch (e) {
2900
- throw new Error(`Invalid JSON: ${line}`);
2901
- }
2902
- });
2903
- if (lines.length === 0) {
2904
- throw new Error("No JSON lines provided.");
2905
- }
2906
- lines.sort(
2907
- (a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime()
2908
- );
2909
- let combinedContent = lines.map((line) => line?.message?.content ?? "").join("");
2910
- combinedContent = combinedContent.replace(/\\u003c/g, "<").replace(/\\u003e/g, ">");
2911
- const finalLine = lines.find((line) => line.done === true);
2912
- if (!finalLine) {
2913
- throw new Error("No line found where done = true.");
2914
- }
2915
- const result = {
2916
- model: finalLine.model,
2917
- created_at: finalLine.created_at,
2918
- message: {
2919
- role: finalLine?.message?.role || "assistant",
2920
- content: combinedContent
2921
- },
2922
- done_reason: finalLine.done_reason,
2923
- done: finalLine.done,
2924
- total_duration: finalLine.total_duration,
2925
- load_duration: finalLine.load_duration,
2926
- prompt_eval_count: finalLine.prompt_eval_count,
2927
- prompt_eval_duration: finalLine.prompt_eval_duration,
2928
- eval_count: finalLine.eval_count,
2929
- eval_duration: finalLine.eval_duration
2930
- };
2931
- const content = {
2932
- type: "text",
2933
- text: combinedContent
2934
- };
2908
+ functionCall: {
2909
+ name,
2910
+ args: maybeParseJSON(input)
2911
+ }
2912
+ };
2913
+ })
2914
+ );
2915
+ delete message.function_call;
2916
+ }
2935
2917
  return {
2936
- lines,
2937
- result,
2938
- content
2918
+ role,
2919
+ parts
2939
2920
  };
2940
2921
  }
2941
2922
 
2942
- // src/llm/output/ollama.ts
2943
- function OutputOllamaChat(result, _config) {
2944
- const combined = combineJsonl(result);
2945
- const id = `${combined.result.model}.${combined.result.created_at}`;
2946
- const name = combined.result.model || _config?.model || "ollama.unknown";
2947
- const created = (/* @__PURE__ */ new Date(`${combined.result.created_at}`)).getTime();
2948
- const stopReason = `${combined?.result?.done_reason || "stop"}`;
2949
- const content = [combined.content];
2950
- const usage = {
2951
- output_tokens: 0,
2952
- input_tokens: 0,
2953
- total_tokens: 0
2954
- };
2955
- return BaseLlmOutput2({
2956
- id,
2957
- name,
2958
- created,
2959
- usage,
2960
- stopReason,
2961
- content,
2962
- options: []
2963
- });
2923
+ // src/llm/config/google/promptSanitize.ts
2924
+ function mergeConsecutiveSameRole2(messages) {
2925
+ if (messages.length <= 1) return messages;
2926
+ const merged = [messages[0]];
2927
+ for (let i = 1; i < messages.length; i++) {
2928
+ const prev = merged[merged.length - 1];
2929
+ const curr = messages[i];
2930
+ if (curr.role === prev.role && Array.isArray(prev.parts) && Array.isArray(curr.parts)) {
2931
+ prev.parts = [...prev.parts, ...curr.parts];
2932
+ } else {
2933
+ merged.push(curr);
2934
+ }
2935
+ }
2936
+ return merged;
2937
+ }
2938
+ function googleGeminiPromptSanitize(_messages, _inputBodyObj, _outputObj) {
2939
+ if (typeof _messages === "string") {
2940
+ return [{ role: "user", parts: [{ text: _messages }] }];
2941
+ }
2942
+ if (Array.isArray(_messages)) {
2943
+ if (_messages.length === 0) {
2944
+ throw new Error("Empty messages array");
2945
+ }
2946
+ if (_messages.length === 1 && _messages[0].role === "system") {
2947
+ return [{ role: "user", parts: [{ text: _messages[0].content }] }];
2948
+ }
2949
+ const hasSystemInstruction = _messages.some(
2950
+ (message) => message.role === "system"
2951
+ );
2952
+ if (hasSystemInstruction) {
2953
+ const theSystemInstructions = _messages.filter(
2954
+ (message) => message.role === "system"
2955
+ );
2956
+ const withoutSystemInstructions = _messages.filter(
2957
+ (message) => message.role !== "system"
2958
+ );
2959
+ _outputObj.system_instruction = {
2960
+ parts: theSystemInstructions.map((message) => ({
2961
+ text: message.content
2962
+ }))
2963
+ };
2964
+ const result2 = withoutSystemInstructions.map(
2965
+ googleGeminiPromptMessageCallback
2966
+ );
2967
+ return mergeConsecutiveSameRole2(result2);
2968
+ }
2969
+ const result = _messages.map(googleGeminiPromptMessageCallback);
2970
+ return mergeConsecutiveSameRole2(result);
2971
+ }
2972
+ throw new Error("Invalid messages format");
2964
2973
  }
2965
2974
 
2966
2975
  // src/llm/output/google.gemini/formatResult.ts
2967
- function formatResult4(result, id) {
2976
+ function formatResult3(result, id) {
2968
2977
  const { parts = [] } = result?.content || {};
2969
2978
  const out = [];
2970
2979
  for (let i = 0; i < parts.length; i++) {
@@ -2989,18 +2998,18 @@ function formatResult4(result, id) {
2989
2998
  // src/llm/output/google.gemini/index.ts
2990
2999
  function OutputGoogleGeminiChat(result, _config) {
2991
3000
  const id = result.responseId;
2992
- const name = result.modelVersion || _config?.model || "gemini";
3001
+ const name = result.modelVersion || _config?.options.model?.default || "gemini";
2993
3002
  const created = (/* @__PURE__ */ new Date()).getTime();
2994
3003
  const [_content, ..._options] = result?.candidates || [];
2995
3004
  const stopReason = _content?.finishReason?.toLowerCase();
2996
- const content = formatResult4(_content, id);
2997
- const options = formatOptions(_options, formatResult4);
3005
+ const content = formatResult3(_content, id);
3006
+ const options = formatOptions(_options, formatResult3);
2998
3007
  const usage = {
2999
3008
  output_tokens: result?.usageMetadata?.candidatesTokenCount,
3000
3009
  input_tokens: result?.usageMetadata?.promptTokenCount,
3001
3010
  total_tokens: result?.usageMetadata?.totalTokenCount
3002
3011
  };
3003
- return BaseLlmOutput2({
3012
+ return {
3004
3013
  id,
3005
3014
  name,
3006
3015
  created,
@@ -3008,83 +3017,152 @@ function OutputGoogleGeminiChat(result, _config) {
3008
3017
  stopReason,
3009
3018
  content,
3010
3019
  options
3011
- });
3020
+ };
3012
3021
  }
3013
3022
 
3014
- // src/llm/output/deepseek.ts
3015
- function formatResult5(result) {
3016
- const out = [];
3017
- if (typeof result?.message?.content === "string" && result?.message?.content) {
3018
- out.push({
3019
- type: "text",
3020
- text: result.message.content
3023
+ // src/llm/config/google/index.ts
3024
+ var googleGeminiChatV1 = {
3025
+ key: "google.chat.v1",
3026
+ provider: "google.chat",
3027
+ endpoint: `https://generativelanguage.googleapis.com/v1beta/models/{{model}}:generateContent?key={{geminiApiKey}}`,
3028
+ options: {
3029
+ effort: {},
3030
+ prompt: {},
3031
+ // topP: {},
3032
+ geminiApiKey: {
3033
+ default: getEnvironmentVariable("GEMINI_API_KEY")
3034
+ }
3035
+ },
3036
+ method: "POST",
3037
+ headers: `{"Content-Type": "application/json" }`,
3038
+ mapBody: {
3039
+ prompt: {
3040
+ key: "contents",
3041
+ transform: googleGeminiPromptSanitize
3042
+ },
3043
+ effort: {
3044
+ key: "config.thinkingConfig.thinkingBudget",
3045
+ transform: (v, _s) => {
3046
+ if (
3047
+ // only supported reasoning models
3048
+ ["gemini-2.5-pro", "gemini-2.5-flash", "gemini-2.5-light"].includes(
3049
+ _s.model
3050
+ ) && typeof v === "string" && ["minimal", "low", "medium", "high"].includes(v)
3051
+ ) {
3052
+ if (v === "low" || v === "minimal") {
3053
+ return 1024;
3054
+ } else if (v === "medium") {
3055
+ return 8192;
3056
+ } else if (v === "high") {
3057
+ return 24576;
3058
+ }
3059
+ }
3060
+ return void 0;
3061
+ }
3062
+ }
3063
+ },
3064
+ mapOptions: {
3065
+ functionCall: (call) => ({
3066
+ toolConfig: {
3067
+ functionCallingConfig: {
3068
+ mode: call === "any" ? "any" : call === "none" ? "none" : "auto"
3069
+ }
3070
+ }
3071
+ }),
3072
+ functions: (functions) => ({
3073
+ tools: [
3074
+ {
3075
+ functionDeclarations: functions.map((f) => ({
3076
+ name: f.name,
3077
+ description: f.description,
3078
+ parameters: cleanJsonSchemaFor(f.parameters, "google.chat")
3079
+ }))
3080
+ }
3081
+ ]
3082
+ })
3083
+ },
3084
+ transformResponse: OutputGoogleGeminiChat
3085
+ };
3086
+ var google = {
3087
+ "google.chat.v1": googleGeminiChatV1,
3088
+ "google.gemini-2.0-flash": withDefaultModel(
3089
+ googleGeminiChatV1,
3090
+ "gemini-2.0-flash"
3091
+ ),
3092
+ "google.gemini-2.0-flash-lite": withDefaultModel(
3093
+ googleGeminiChatV1,
3094
+ "gemini-2.0-flash-lite"
3095
+ ),
3096
+ "google.gemini-2.5-flash": withDefaultModel(
3097
+ googleGeminiChatV1,
3098
+ "gemini-2.5-flash"
3099
+ ),
3100
+ "google.gemini-2.5-flash-lite": withDefaultModel(
3101
+ googleGeminiChatV1,
3102
+ "gemini-2.5-flash-lite"
3103
+ ),
3104
+ "google.gemini-1.5-pro": withDefaultModel(
3105
+ googleGeminiChatV1,
3106
+ "gemini-1.5-pro"
3107
+ ),
3108
+ "google.gemini-2.5-pro": withDefaultModel(
3109
+ googleGeminiChatV1,
3110
+ "gemini-2.5-pro"
3111
+ )
3112
+ };
3113
+
3114
+ // src/llm/config/deepseek/index.ts
3115
+ var deepseekChatV1 = createOpenAiCompatibleConfiguration({
3116
+ key: "deepseek.chat.v1",
3117
+ provider: "deepseek.chat",
3118
+ endpoint: `https://api.deepseek.com/v1/chat/completions`,
3119
+ apiKeyMapping: ["deepseekApiKey", "DEEPSEEK_API_KEY"]
3120
+ });
3121
+ var deepseek = {
3122
+ "deepseek.chat.v1": deepseekChatV1,
3123
+ "deepseek.chat": withDefaultModel(deepseekChatV1, "deepseek-chat")
3124
+ };
3125
+
3126
+ // src/llm/config.ts
3127
+ var configs = {
3128
+ ...openai,
3129
+ ...anthropic,
3130
+ ...bedrock,
3131
+ ...xai,
3132
+ ...ollama,
3133
+ ...google,
3134
+ ...deepseek
3135
+ };
3136
+ function getLlmConfig(provider) {
3137
+ if (!provider) {
3138
+ throw new LlmExeError(`Missing provider`, "unknown", {
3139
+ error: "Missing provider",
3140
+ resolution: "Provide a valid provider"
3021
3141
  });
3022
3142
  }
3023
- if (result?.message?.tool_calls) {
3024
- for (const call of result.message.tool_calls) {
3025
- out.push({
3026
- functionId: call.id,
3027
- type: "function_use",
3028
- name: call.function.name,
3029
- input: maybeParseJSON(call.function.arguments)
3030
- });
3031
- }
3143
+ const pick2 = configs[provider];
3144
+ if (pick2) {
3145
+ return pick2;
3032
3146
  }
3033
- return out;
3034
- }
3035
- function OutputDeepSeekChat(result, _config) {
3036
- const id = result.id;
3037
- const name = result.model || _config?.model || "deepseek.unknown";
3038
- const created = result.created;
3039
- const [_content, ..._options] = result?.choices || [];
3040
- const stopReason = _content?.finish_reason;
3041
- const content = formatResult5(_content);
3042
- const options = formatOptions(_options, formatResult5);
3043
- const usage = {
3044
- output_tokens: result?.usage?.completion_tokens,
3045
- input_tokens: result?.usage?.prompt_tokens,
3046
- total_tokens: result?.usage?.total_tokens
3047
- };
3048
- return BaseLlmOutput2({
3049
- id,
3050
- name,
3051
- created,
3052
- usage,
3053
- stopReason,
3054
- content,
3055
- options
3147
+ throw new LlmExeError(`Invalid provider: ${provider}`, "unknown", {
3148
+ provider,
3149
+ error: `Invalid provider: ${provider}`,
3150
+ resolution: "Provide a valid provider"
3056
3151
  });
3057
3152
  }
3058
3153
 
3059
- // src/llm/output/index.ts
3060
- function normalizeLlmOutputToInternalFormat(config, response) {
3061
- switch (config?.key) {
3062
- case "openai.chat.v1":
3063
- case "openai.chat-mock.v1":
3064
- return OutputOpenAIChat(response, config);
3065
- case "anthropic.chat.v1":
3066
- case "amazon:anthropic.chat.v1":
3067
- return OutputAnthropicClaude3Chat(response, config);
3068
- case "amazon:meta.chat.v1":
3069
- return OutputMetaLlama3Chat(response, config);
3070
- // case "amazon:nova.chat.v1":
3071
- // return OutputDefault(response, config);
3072
- case "xai.chat.v1":
3073
- return OutputXAIChat(response, config);
3074
- case "ollama.chat.v1":
3075
- return OutputOllamaChat(response, config);
3076
- case "google.chat.v1":
3077
- return OutputGoogleGeminiChat(response, config);
3078
- case "deepseek.chat.v1":
3079
- return OutputDeepSeekChat(response, config);
3080
- // use oai for now
3081
- default: {
3082
- if (config?.key?.startsWith("custom:")) {
3083
- return OutputDefault(response, config);
3084
- }
3085
- throw new Error("Unsupported provider");
3154
+ // src/utils/modules/maskApiKeysInDebug.ts
3155
+ function maskApiKeys(log) {
3156
+ return log.replace(
3157
+ /\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,
3158
+ (match) => {
3159
+ if (match.length <= 8) return match;
3160
+ const prefix = match.substring(0, 4);
3161
+ const suffix = match.substring(match.length - 4);
3162
+ const maskLength = match.length - 8;
3163
+ return `${prefix}${"*".repeat(maskLength)}${suffix}`;
3086
3164
  }
3087
- }
3165
+ );
3088
3166
  }
3089
3167
 
3090
3168
  // src/utils/modules/debug.ts
@@ -3110,7 +3188,15 @@ function debug(...args) {
3110
3188
  logs.push(arg.toString());
3111
3189
  } else {
3112
3190
  try {
3113
- logs.push(JSON.stringify(arg, null, 2));
3191
+ let shouldMask = false;
3192
+ if (arg.headers && arg.headers.Authorization) {
3193
+ shouldMask = true;
3194
+ }
3195
+ let str = JSON.stringify(arg, null, 2);
3196
+ if (shouldMask) {
3197
+ str = maskApiKeys(str);
3198
+ }
3199
+ logs.push(str);
3114
3200
  } catch (error) {
3115
3201
  console.error("Error parsing object:", error);
3116
3202
  }
@@ -3158,7 +3244,8 @@ async function apiRequest(url, options) {
3158
3244
  }
3159
3245
  throw new Error(message);
3160
3246
  }
3161
- if (response.headers.get("content-type")?.includes("application/json")) {
3247
+ const contentType = response.headers.get("content-type");
3248
+ if (contentType?.includes("application/json")) {
3162
3249
  const responseData = await response.json();
3163
3250
  return responseData;
3164
3251
  } else {
@@ -3175,20 +3262,26 @@ async function apiRequest(url, options) {
3175
3262
  function convertDotNotation(obj) {
3176
3263
  const result = {};
3177
3264
  for (const key in obj) {
3178
- if (obj.hasOwnProperty(key)) {
3179
- if (key.includes(".")) {
3180
- const keys = key.split(".");
3181
- let currentLevel = result;
3182
- for (let i = 0; i < keys.length; i++) {
3183
- if (i === keys.length - 1) {
3184
- currentLevel[keys[i]] = obj[key];
3185
- } else {
3186
- currentLevel[keys[i]] = currentLevel[keys[i]] || {};
3187
- currentLevel = currentLevel[keys[i]];
3265
+ if (Object.prototype.hasOwnProperty.call(obj, key) && !key.includes(".")) {
3266
+ result[key] = obj[key];
3267
+ }
3268
+ }
3269
+ for (const key in obj) {
3270
+ if (Object.prototype.hasOwnProperty.call(obj, key) && key.includes(".")) {
3271
+ const keys = key.split(".");
3272
+ let currentLevel = result;
3273
+ for (let i = 0; i < keys.length; i++) {
3274
+ const currentKey = keys[i];
3275
+ if (i === keys.length - 1) {
3276
+ currentLevel[currentKey] = obj[key];
3277
+ } else {
3278
+ if (!(currentKey in currentLevel)) {
3279
+ currentLevel[currentKey] = {};
3280
+ } else if (typeof currentLevel[currentKey] !== "object" || currentLevel[currentKey] === null || Array.isArray(currentLevel[currentKey])) {
3281
+ currentLevel[currentKey] = {};
3188
3282
  }
3283
+ currentLevel = currentLevel[currentKey];
3189
3284
  }
3190
- } else {
3191
- result[key] = obj[key];
3192
3285
  }
3193
3286
  }
3194
3287
  }
@@ -3205,8 +3298,8 @@ function mapBody(template, body) {
3205
3298
  const { key: providerSpecificKey, default: defaultValue } = providerSpecificSettings;
3206
3299
  if (providerSpecificKey) {
3207
3300
  let valueForThisKey = body[genericInputKey];
3208
- if (providerSpecificSettings.sanitize && typeof providerSpecificSettings.sanitize === "function") {
3209
- valueForThisKey = providerSpecificSettings.sanitize(
3301
+ if (providerSpecificSettings.transform && typeof providerSpecificSettings.transform === "function") {
3302
+ valueForThisKey = providerSpecificSettings.transform(
3210
3303
  valueForThisKey,
3211
3304
  Object.freeze({ ...body }),
3212
3305
  output
@@ -3230,28 +3323,70 @@ import { Sha256 } from "@aws-crypto/sha256-js";
3230
3323
 
3231
3324
  // src/utils/modules/runWithTemporaryEnv.ts
3232
3325
  async function runWithTemporaryEnv(env, handler) {
3233
- const previousEnv = { ...process.env };
3326
+ const modifiedKeys = [];
3327
+ const originalValues = {};
3328
+ const envBefore = { ...process.env };
3234
3329
  try {
3235
- env();
3330
+ try {
3331
+ env();
3332
+ } catch (envError) {
3333
+ const envAfter2 = process.env;
3334
+ for (const key in envAfter2) {
3335
+ if (envBefore[key] !== envAfter2[key]) {
3336
+ modifiedKeys.push(key);
3337
+ originalValues[key] = envBefore[key];
3338
+ }
3339
+ }
3340
+ for (const key in envBefore) {
3341
+ if (!(key in envAfter2) && !modifiedKeys.includes(key)) {
3342
+ modifiedKeys.push(key);
3343
+ originalValues[key] = envBefore[key];
3344
+ }
3345
+ }
3346
+ throw envError;
3347
+ }
3348
+ const envAfter = process.env;
3349
+ for (const key in envAfter) {
3350
+ if (envBefore[key] !== envAfter[key]) {
3351
+ modifiedKeys.push(key);
3352
+ originalValues[key] = envBefore[key];
3353
+ }
3354
+ }
3355
+ for (const key in envBefore) {
3356
+ if (!(key in envAfter) && !modifiedKeys.includes(key)) {
3357
+ modifiedKeys.push(key);
3358
+ originalValues[key] = envBefore[key];
3359
+ }
3360
+ }
3236
3361
  const value = await handler();
3237
3362
  return value;
3238
3363
  } finally {
3239
- process.env = previousEnv;
3364
+ for (const key of modifiedKeys) {
3365
+ const originalValue = originalValues[key];
3366
+ if (originalValue === void 0) {
3367
+ delete process.env[key];
3368
+ } else {
3369
+ process.env[key] = originalValue;
3370
+ }
3371
+ }
3240
3372
  }
3241
3373
  }
3242
3374
 
3243
3375
  // src/utils/modules/getAwsAuthorizationHeaders.ts
3244
3376
  async function getAwsAuthorizationHeaders(req, props) {
3377
+ if (!props.url || !props.regionName) {
3378
+ throw new Error("URL and region name are required for AWS authorization");
3379
+ }
3245
3380
  const providerChain = fromNodeProviderChain();
3246
3381
  const credentials = await runWithTemporaryEnv(
3247
3382
  () => {
3248
- if (props.awsAccessKey) {
3383
+ if (props.awsAccessKey && typeof props.awsAccessKey === "string") {
3249
3384
  process.env["AWS_ACCESS_KEY_ID"] = props.awsAccessKey;
3250
3385
  }
3251
- if (props.awsSecretKey) {
3386
+ if (props.awsSecretKey && typeof props.awsSecretKey === "string") {
3252
3387
  process.env["AWS_SECRET_ACCESS_KEY"] = props.awsSecretKey;
3253
3388
  }
3254
- if (props.awsSessionToken) {
3389
+ if (props.awsSessionToken && typeof props.awsSessionToken === "string") {
3255
3390
  process.env["AWS_SESSION_TOKEN"] = props.awsSessionToken;
3256
3391
  }
3257
3392
  },
@@ -3281,8 +3416,21 @@ async function getAwsAuthorizationHeaders(req, props) {
3281
3416
  // src/llm/_utils.parseHeaders.ts
3282
3417
  async function parseHeaders(config, replacements, payload) {
3283
3418
  const replace = replaceTemplateStringSimple(config.headers, replacements);
3284
- const parse = replace ? JSON.parse(replace) : {};
3285
- const headers = Object.assign({}, payload.headers, parse);
3419
+ let parsedHeaders = {};
3420
+ if (replace) {
3421
+ try {
3422
+ parsedHeaders = JSON.parse(replace);
3423
+ if (typeof parsedHeaders !== "object" || parsedHeaders === null || Array.isArray(parsedHeaders)) {
3424
+ throw new Error("Headers must be a JSON object");
3425
+ }
3426
+ } catch (error) {
3427
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
3428
+ throw new Error(
3429
+ `Failed to parse headers configuration: ${errorMessage}. Headers template: "${config.headers}". After replacement: "${replace}"`
3430
+ );
3431
+ }
3432
+ }
3433
+ const headers = Object.assign({}, payload.headers, parsedHeaders);
3286
3434
  if (config.provider.startsWith("amazon:") || config.provider.startsWith("amazon.")) {
3287
3435
  const url = payload.url;
3288
3436
  return getAwsAuthorizationHeaders(
@@ -3303,122 +3451,129 @@ async function parseHeaders(config, replacements, payload) {
3303
3451
  }
3304
3452
  }
3305
3453
 
3306
- // src/llm/output/_utils/cleanJsonSchemaFor.ts
3307
- var providerFieldExclusions = {
3308
- "openai.chat": ["default"],
3309
- // fields to exclude for openai.chat, xai, deepseek
3310
- "anthropic.chat": [],
3311
- "google.chat": ["additionalProperties"]
3312
- };
3313
- function cleanJsonSchemaFor(schema = {}, provider) {
3314
- const clone = deepClone(schema);
3315
- if (Object.keys(clone).length === 0) {
3454
+ // src/llm/output/default.ts
3455
+ function OutputDefault(result, _config) {
3456
+ const name = _config?.options.model?.default || "unknown";
3457
+ const stopReason = result?.stopReason || "stop";
3458
+ const content = [];
3459
+ if (result?.text) {
3460
+ content.push({ type: "text", text: result.text });
3461
+ }
3462
+ const usage = {
3463
+ output_tokens: result?.output_tokens || 0,
3464
+ input_tokens: result?.input_tokens || 0,
3465
+ total_tokens: (result?.input_tokens || 0) + (result?.output_tokens || 0)
3466
+ };
3467
+ return {
3468
+ name,
3469
+ usage,
3470
+ stopReason,
3471
+ content
3472
+ };
3473
+ }
3474
+
3475
+ // src/llm/output/_utils/getResultContent.ts
3476
+ function getResultContent(result, index) {
3477
+ if (typeof index === "number" && index > 0) {
3478
+ const arr = result?.options || [];
3479
+ const val = arr[index];
3480
+ return val ? val : [];
3481
+ }
3482
+ return [...result.content];
3483
+ }
3484
+
3485
+ // src/llm/output/_utils/getResultText.ts
3486
+ function getResultText(result, index) {
3487
+ if (typeof index === "number" && index > 0) {
3488
+ const arr = result?.options || [];
3489
+ const val = arr[index];
3490
+ return isOutputResultContentText(val?.[0]) ? val[0]?.text : "";
3491
+ }
3492
+ return isOutputResultContentText(result?.content?.[0]) ? result.content[0]?.text : "";
3493
+ }
3494
+
3495
+ // src/llm/output/base.ts
3496
+ function BaseLlmOutput(result) {
3497
+ const __result = Object.freeze({
3498
+ id: result.id || uuidv4(),
3499
+ name: result.name,
3500
+ usage: result.usage,
3501
+ stopReason: result.stopReason,
3502
+ options: [...result?.options || []],
3503
+ content: [...result.content],
3504
+ created: result?.created || (/* @__PURE__ */ new Date()).getTime()
3505
+ });
3506
+ function getResult() {
3316
3507
  return {
3317
- type: "object",
3318
- properties: {},
3319
- required: []
3508
+ id: __result.id,
3509
+ name: __result.name,
3510
+ created: __result.created,
3511
+ usage: __result.usage,
3512
+ options: __result.options,
3513
+ content: __result.content,
3514
+ stopReason: __result.stopReason
3320
3515
  };
3321
3516
  }
3322
- const exclusions = providerFieldExclusions[provider] || [];
3323
- function removeDisallowedFields(obj) {
3324
- if (Array.isArray(obj)) {
3325
- return obj.map(removeDisallowedFields);
3326
- } else if (typeof obj === "object" && obj !== null) {
3327
- return Object.keys(obj).reduce((acc, key) => {
3328
- if (!exclusions.includes(key)) {
3329
- acc[key] = removeDisallowedFields(obj[key]);
3330
- }
3331
- return acc;
3332
- }, {});
3517
+ return {
3518
+ getResultContent: (index) => getResultContent(__result, index),
3519
+ getResultText: (index) => getResultText(__result, index),
3520
+ getResult
3521
+ };
3522
+ }
3523
+
3524
+ // src/llm/_utils.mapOptions.ts
3525
+ function mapOptions(input, options, config) {
3526
+ if (!config?.mapOptions || !options) {
3527
+ return input;
3528
+ }
3529
+ let result = { ...input };
3530
+ let processedOptions = options;
3531
+ if (options.functionCall && config.mapOptions.functionCall) {
3532
+ const mapping = config.mapOptions.functionCall(
3533
+ options.functionCall,
3534
+ options,
3535
+ result,
3536
+ config
3537
+ );
3538
+ if (mapping._clearFunctions) {
3539
+ processedOptions = { ...options, functions: [] };
3540
+ const { _clearFunctions, ...rest } = mapping;
3541
+ result = { ...result, ...rest };
3542
+ } else {
3543
+ result = { ...result, ...mapping };
3333
3544
  }
3334
- return obj;
3335
3545
  }
3336
- return removeDisallowedFields(clone);
3546
+ if (processedOptions.functions?.length && config.mapOptions.functions) {
3547
+ result = {
3548
+ ...result,
3549
+ ...config.mapOptions.functions(
3550
+ processedOptions.functions,
3551
+ processedOptions,
3552
+ result,
3553
+ config
3554
+ )
3555
+ };
3556
+ }
3557
+ if (options.jsonSchema && config.mapOptions.jsonSchema) {
3558
+ result = {
3559
+ ...result,
3560
+ ...config.mapOptions.jsonSchema(options.jsonSchema, options, result, config)
3561
+ };
3562
+ }
3563
+ return result;
3337
3564
  }
3338
3565
 
3339
3566
  // src/llm/llm.call.ts
3340
3567
  async function useLlm_call(state, messages, _options) {
3341
3568
  const config = getLlmConfig(state.key);
3342
- const { functionCallStrictInput = false } = _options || {};
3343
- const input = mapBody(
3569
+ const transformBody = mapBody(
3344
3570
  config.mapBody,
3345
3571
  Object.assign({}, state, {
3346
3572
  prompt: messages
3347
3573
  })
3348
3574
  );
3349
- if (_options && _options?.jsonSchema) {
3350
- if (state.provider.startsWith("openai") || state.provider.startsWith("deepseek") || state.provider.startsWith("xai")) {
3351
- const curr = input["response_format"] || {};
3352
- input["response_format"] = Object.assign(curr, {
3353
- type: "json_schema",
3354
- json_schema: {
3355
- name: "output",
3356
- strict: !!functionCallStrictInput,
3357
- schema: cleanJsonSchemaFor(_options?.jsonSchema, "openai.chat")
3358
- }
3359
- });
3360
- }
3361
- }
3362
- if (_options && _options?.functionCall) {
3363
- if (state.provider.startsWith("anthropic")) {
3364
- if (_options?.functionCall === "none") {
3365
- _options.functions = [];
3366
- } else if (_options?.functionCall === "auto" || _options?.functionCall === "any") {
3367
- input["tool_choice"] = { type: _options?.functionCall };
3368
- } else {
3369
- input["tool_choice"] = _options?.functionCall;
3370
- }
3371
- } else if (state.provider.startsWith("openai") || state.provider.startsWith("deepseek") || state.provider.startsWith("xai")) {
3372
- input["tool_choice"] = normalizeFunctionCall(
3373
- _options?.functionCall,
3374
- "openai"
3375
- );
3376
- } else if (state.provider.startsWith("google")) {
3377
- input["toolConfig"] = {
3378
- functionCallingConfig: {
3379
- mode: normalizeFunctionCall(_options?.functionCall, "google")
3380
- }
3381
- };
3382
- }
3383
- }
3384
- if (_options && _options?.functions?.length) {
3385
- if (state.provider.startsWith("anthropic")) {
3386
- input["tools"] = _options.functions.map((f) => ({
3387
- name: f.name,
3388
- description: f.description,
3389
- input_schema: cleanJsonSchemaFor(f.parameters, "anthropic.chat")
3390
- }));
3391
- } else if (state.provider.startsWith("openai") || state.provider.startsWith("deepseek") || state.provider.startsWith("xai")) {
3392
- input["tools"] = _options.functions.map((f) => {
3393
- const props = {
3394
- name: f?.name,
3395
- description: f?.description,
3396
- parameters: f?.parameters
3397
- };
3398
- return {
3399
- type: "function",
3400
- function: Object.assign(
3401
- props,
3402
- {
3403
- parameters: cleanJsonSchemaFor(props.parameters, "openai.chat")
3404
- },
3405
- { strict: functionCallStrictInput }
3406
- )
3407
- };
3408
- });
3409
- } else if (state.provider.startsWith("google")) {
3410
- input["tools"] = [
3411
- {
3412
- functionDeclarations: _options.functions.map((f) => ({
3413
- name: f.name,
3414
- description: f.description,
3415
- parameters: cleanJsonSchemaFor(f.parameters, "google.chat")
3416
- }))
3417
- }
3418
- ];
3419
- }
3420
- }
3421
- const body = JSON.stringify(input);
3575
+ const applyOptions = mapOptions(transformBody, _options, config);
3576
+ const body = JSON.stringify(applyOptions);
3422
3577
  const url = replaceTemplateStringSimple(config.endpoint, state);
3423
3578
  const headers = await parseHeaders(config, state, {
3424
3579
  url,
@@ -3445,7 +3600,9 @@ async function useLlm_call(state, messages, _options) {
3445
3600
  body,
3446
3601
  headers
3447
3602
  });
3448
- return normalizeLlmOutputToInternalFormat(state, response);
3603
+ const { transformResponse = OutputDefault } = config;
3604
+ const normalized = transformResponse(response, config);
3605
+ return BaseLlmOutput(normalized);
3449
3606
  }
3450
3607
 
3451
3608
  // src/llm/_utils.stateFromOptions.ts
@@ -3588,6 +3745,80 @@ function useLlm(provider, options = {}) {
3588
3745
  const config = getLlmConfig(provider);
3589
3746
  return apiRequestWrapper(config, options, useLlm_call);
3590
3747
  }
3748
+ function useLlmConfiguration(config) {
3749
+ return (options = {}) => apiRequestWrapper(config, options, useLlm_call);
3750
+ }
3751
+
3752
+ // src/embedding/output/BaseEmbeddingOutput.ts
3753
+ function BaseEmbeddingOutput(result) {
3754
+ const __result = Object.freeze({
3755
+ id: result.id || uuidv4(),
3756
+ model: result.model,
3757
+ usage: result.usage,
3758
+ embedding: [...result?.embedding || []],
3759
+ created: result?.created || (/* @__PURE__ */ new Date()).getTime()
3760
+ });
3761
+ function getResult() {
3762
+ return {
3763
+ id: __result.id,
3764
+ model: __result.model,
3765
+ created: __result.created,
3766
+ usage: __result.usage,
3767
+ embedding: __result.embedding
3768
+ };
3769
+ }
3770
+ function getEmbedding(index) {
3771
+ if (index && index > 0) {
3772
+ const arr = __result?.embedding;
3773
+ const val = arr[index];
3774
+ return val ? val : [];
3775
+ }
3776
+ return __result.embedding[0];
3777
+ }
3778
+ return {
3779
+ getEmbedding,
3780
+ getResult
3781
+ };
3782
+ }
3783
+
3784
+ // src/embedding/output/OpenAiEmbedding.ts
3785
+ function OpenAiEmbedding(result, config) {
3786
+ const __result = deepClone(result);
3787
+ const model = __result.model || config.model || "openai.unknown";
3788
+ const created = (/* @__PURE__ */ new Date()).getTime();
3789
+ const results = result?.data || [];
3790
+ const embedding = results.map((a) => a.embedding);
3791
+ const usage = {
3792
+ output_tokens: 0,
3793
+ input_tokens: result?.usage?.prompt_tokens,
3794
+ total_tokens: result?.usage?.total_tokens
3795
+ };
3796
+ return BaseEmbeddingOutput({
3797
+ model,
3798
+ created,
3799
+ usage,
3800
+ embedding
3801
+ });
3802
+ }
3803
+
3804
+ // src/embedding/output/AmazonTitan.ts
3805
+ function AmazonTitanEmbedding(result, config) {
3806
+ const __result = deepClone(result);
3807
+ const model = config.model || "amazon.unknown";
3808
+ const created = (/* @__PURE__ */ new Date()).getTime();
3809
+ const embedding = [__result.embedding];
3810
+ const usage = {
3811
+ output_tokens: 0,
3812
+ input_tokens: __result.inputTextTokenCount,
3813
+ total_tokens: __result.inputTextTokenCount
3814
+ };
3815
+ return BaseEmbeddingOutput({
3816
+ model,
3817
+ created,
3818
+ usage,
3819
+ embedding
3820
+ });
3821
+ }
3591
3822
 
3592
3823
  // src/embedding/config.ts
3593
3824
  var embeddingConfigs = {
@@ -3620,7 +3851,8 @@ var embeddingConfigs = {
3620
3851
  encodingFormat: {
3621
3852
  key: "encoding_format"
3622
3853
  }
3623
- }
3854
+ },
3855
+ transformResponse: OpenAiEmbedding
3624
3856
  },
3625
3857
  "amazon.embedding.v1": {
3626
3858
  key: "amazon.embedding.v1",
@@ -3647,7 +3879,8 @@ var embeddingConfigs = {
3647
3879
  dimensions: {
3648
3880
  key: "dimensions"
3649
3881
  }
3650
- }
3882
+ },
3883
+ transformResponse: AmazonTitanEmbedding
3651
3884
  }
3652
3885
  };
3653
3886
  function getEmbeddingConfig(provider) {
@@ -3661,77 +3894,6 @@ function getEmbeddingConfig(provider) {
3661
3894
  throw new Error(`Invalid provider: ${provider}`);
3662
3895
  }
3663
3896
 
3664
- // src/embedding/output/BaseEmbeddingOutput.ts
3665
- function BaseEmbeddingOutput(result) {
3666
- const __result = Object.freeze({
3667
- id: result.id || uuidv4(),
3668
- model: result.model,
3669
- usage: result.usage,
3670
- embedding: [...result?.embedding || []],
3671
- created: result?.created || (/* @__PURE__ */ new Date()).getTime()
3672
- });
3673
- function getResult() {
3674
- return {
3675
- id: __result.id,
3676
- model: __result.model,
3677
- created: __result.created,
3678
- usage: __result.usage,
3679
- embedding: __result.embedding
3680
- };
3681
- }
3682
- function getEmbedding(index) {
3683
- if (index && index > 0) {
3684
- const arr = __result?.embedding;
3685
- const val = arr[index];
3686
- return val ? val : [];
3687
- }
3688
- return __result.embedding[0];
3689
- }
3690
- return {
3691
- getEmbedding,
3692
- getResult
3693
- };
3694
- }
3695
-
3696
- // src/embedding/output/AmazonTitan.ts
3697
- function AmazonTitanEmbedding(result, config) {
3698
- const __result = deepClone(result);
3699
- const model = config.model || "amazon.unknown";
3700
- const created = (/* @__PURE__ */ new Date()).getTime();
3701
- const embedding = [__result.embedding];
3702
- const usage = {
3703
- output_tokens: 0,
3704
- input_tokens: __result.inputTextTokenCount,
3705
- total_tokens: __result.inputTextTokenCount
3706
- };
3707
- return BaseEmbeddingOutput({
3708
- model,
3709
- created,
3710
- usage,
3711
- embedding
3712
- });
3713
- }
3714
-
3715
- // src/embedding/output/OpenAiEmbedding.ts
3716
- function OpenAiEmbedding(result, config) {
3717
- const __result = deepClone(result);
3718
- const model = __result.model || config.model || "openai.unknown";
3719
- const created = (/* @__PURE__ */ new Date()).getTime();
3720
- const results = result?.data || [];
3721
- const embedding = results.map((a) => a.embedding);
3722
- const usage = {
3723
- output_tokens: 0,
3724
- input_tokens: result?.usage?.prompt_tokens,
3725
- total_tokens: result?.usage?.total_tokens
3726
- };
3727
- return BaseEmbeddingOutput({
3728
- model,
3729
- created,
3730
- usage,
3731
- embedding
3732
- });
3733
- }
3734
-
3735
3897
  // src/embedding/output/getEmbeddingOutputParser.ts
3736
3898
  function getEmbeddingOutputParser(config, response) {
3737
3899
  switch (config.key) {
@@ -4009,8 +4171,8 @@ var ChatPrompt = class extends BasePrompt {
4009
4171
  __publicField(this, "type", "chat");
4010
4172
  /**
4011
4173
  * @property parseUserTemplates - Whether or not to allow parsing
4012
- * user messages with the template engine. This could be a risk,
4013
- * so we only parse user messages if explicitly set.
4174
+ * user messages with the template engine. Defaults to true.
4175
+ * Set `allowUnsafeUserTemplate: false` in options to disable.
4014
4176
  */
4015
4177
  __publicField(this, "parseUserTemplates", true);
4016
4178
  if (typeof options?.allowUnsafeUserTemplate === "boolean") {
@@ -4071,7 +4233,7 @@ var ChatPrompt = class extends BasePrompt {
4071
4233
  return this;
4072
4234
  }
4073
4235
  /**
4074
- * addFunctionMessage Helper to add an assistant message to the prompt.
4236
+ * addFunctionMessage Helper to add a function message to the prompt.
4075
4237
  * @param content The message content.
4076
4238
  * @return ChatPrompt so it can be chained.
4077
4239
  */
@@ -4085,7 +4247,7 @@ var ChatPrompt = class extends BasePrompt {
4085
4247
  return this;
4086
4248
  }
4087
4249
  /**
4088
- * addFunctionCallMessage Helper to add an assistant message to the prompt.
4250
+ * addFunctionCallMessage Helper to add a function_call message to the prompt.
4089
4251
  * @param content The message content.
4090
4252
  * @return ChatPrompt so it can be chained.
4091
4253
  */
@@ -4640,7 +4802,7 @@ var Dialogue = class extends BaseStateItem {
4640
4802
  return this;
4641
4803
  }
4642
4804
  setToolMessage(content, name, id) {
4643
- this.setFunctionMessage(content, name, id);
4805
+ return this.setFunctionMessage(content, name, id);
4644
4806
  }
4645
4807
  setFunctionMessage(content, name, id) {
4646
4808
  if (content) {
@@ -4657,7 +4819,7 @@ var Dialogue = class extends BaseStateItem {
4657
4819
  * Set
4658
4820
  */
4659
4821
  setToolCallMessage(input) {
4660
- this.setFunctionCallMessage(input);
4822
+ return this.setFunctionCallMessage(input);
4661
4823
  }
4662
4824
  setFunctionCallMessage(input) {
4663
4825
  if (!input || typeof input !== "object") {
@@ -4749,6 +4911,9 @@ var Dialogue = class extends BaseStateItem {
4749
4911
  * @returns this for chaining
4750
4912
  */
4751
4913
  addFromOutput(output) {
4914
+ if (!output || typeof output !== "object") {
4915
+ return this;
4916
+ }
4752
4917
  const result = "getResult" in output ? output.getResult() : output;
4753
4918
  if (!result || typeof result !== "object") {
4754
4919
  return this;
@@ -4884,6 +5049,7 @@ export {
4884
5049
  createEmbedding,
4885
5050
  createLlmExecutor,
4886
5051
  createLlmFunctionExecutor,
5052
+ createOpenAiCompatibleConfiguration,
4887
5053
  createParser,
4888
5054
  createPrompt,
4889
5055
  createState,
@@ -4894,5 +5060,6 @@ export {
4894
5060
  registerPartials,
4895
5061
  useExecutors,
4896
5062
  useLlm,
5063
+ useLlmConfiguration,
4897
5064
  utils_exports as utils
4898
5065
  };