llm-exe 2.3.2 → 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.d.mts CHANGED
@@ -226,14 +226,14 @@ declare class StringExtractParser extends BaseParser<string> {
226
226
  * Creates a parser based on the given type.
227
227
  * @template S - JSON schema type.
228
228
  * @param type - The type of parser to create.
229
- * @returns An instance of ListToKeyValueParser.
229
+ * @returns An instance of MarkdownCodeBlocksParser.
230
230
  */
231
231
  declare function createParser<T extends Extract<CreateParserType, "markdownCodeBlocks">>(type: T, options?: BaseParserOptions): MarkdownCodeBlocksParser;
232
232
  /**
233
233
  * Creates a parser based on the given type.
234
234
  * @template S - JSON schema type.
235
235
  * @param type - The type of parser to create.
236
- * @returns An instance of ListToKeyValueParser.
236
+ * @returns An instance of MarkdownCodeBlockParser.
237
237
  */
238
238
  declare function createParser<T extends Extract<CreateParserType, "markdownCodeBlock">>(type: T, options?: BaseParserOptions): MarkdownCodeBlockParser;
239
239
  /**
@@ -432,8 +432,8 @@ declare class ChatPrompt<I extends Record<string, any>> extends BasePrompt<I> {
432
432
  readonly type: ChatPromptType;
433
433
  /**
434
434
  * @property parseUserTemplates - Whether or not to allow parsing
435
- * user messages with the template engine. This could be a risk,
436
- * so we only parse user messages if explicitly set.
435
+ * user messages with the template engine. Defaults to true.
436
+ * Set `allowUnsafeUserTemplate: false` in options to disable.
437
437
  */
438
438
  private parseUserTemplates;
439
439
  /**
@@ -468,13 +468,13 @@ declare class ChatPrompt<I extends Record<string, any>> extends BasePrompt<I> {
468
468
  */
469
469
  addAssistantMessage(content: string): ChatPrompt<I>;
470
470
  /**
471
- * addFunctionMessage Helper to add an assistant message to the prompt.
471
+ * addFunctionMessage Helper to add a function message to the prompt.
472
472
  * @param content The message content.
473
473
  * @return ChatPrompt so it can be chained.
474
474
  */
475
475
  addFunctionMessage(content: string, name: string, id?: string): ChatPrompt<I>;
476
476
  /**
477
- * addFunctionCallMessage Helper to add an assistant message to the prompt.
477
+ * addFunctionCallMessage Helper to add a function_call message to the prompt.
478
478
  * @param content The message content.
479
479
  * @return ChatPrompt so it can be chained.
480
480
  */
@@ -690,7 +690,7 @@ declare class Dialogue extends BaseStateItem<IChatMessages> {
690
690
  setUserMessage(content: string | IChatMessageContentDetailed[], name?: string): this;
691
691
  setAssistantMessage(content: string | OutputResultsText): this;
692
692
  setSystemMessage(content: string): this;
693
- setToolMessage(content: string, name: string, id?: string): void;
693
+ setToolMessage(content: string, name: string, id?: string): this;
694
694
  setFunctionMessage(content: string, name: string, id?: string): this;
695
695
  /**
696
696
  * Set
@@ -699,7 +699,7 @@ declare class Dialogue extends BaseStateItem<IChatMessages> {
699
699
  name: string;
700
700
  arguments: string;
701
701
  id?: string;
702
- }): void;
702
+ }): this;
703
703
  setFunctionCallMessage(input: {
704
704
  name: string;
705
705
  arguments: string;
@@ -1057,6 +1057,30 @@ type AllLlm = {
1057
1057
  };
1058
1058
  };
1059
1059
  type AllUseLlmOptions = AllLlm & {
1060
+ "openai.gpt-5.2": {
1061
+ input: Omit<OpenAiRequest, "model">;
1062
+ };
1063
+ "openai.gpt-5-mini": {
1064
+ input: Omit<OpenAiRequest, "model">;
1065
+ };
1066
+ "openai.gpt-5-nano": {
1067
+ input: Omit<OpenAiRequest, "model">;
1068
+ };
1069
+ "openai.gpt-4.1": {
1070
+ input: Omit<OpenAiRequest, "model">;
1071
+ };
1072
+ "openai.gpt-4.1-mini": {
1073
+ input: Omit<OpenAiRequest, "model">;
1074
+ };
1075
+ "openai.gpt-4.1-nano": {
1076
+ input: Omit<OpenAiRequest, "model">;
1077
+ };
1078
+ "openai.o3": {
1079
+ input: Omit<OpenAiRequest, "model">;
1080
+ };
1081
+ "openai.o4-mini": {
1082
+ input: Omit<OpenAiRequest, "model">;
1083
+ };
1060
1084
  "openai.gpt-4": {
1061
1085
  input: OpenAiRequest;
1062
1086
  };
@@ -1066,6 +1090,12 @@ type AllUseLlmOptions = AllLlm & {
1066
1090
  "openai.gpt-4o-mini": {
1067
1091
  input: Omit<OpenAiRequest, "model">;
1068
1092
  };
1093
+ "anthropic.claude-opus-4-6": {
1094
+ input: Omit<AnthropicRequest, "model">;
1095
+ };
1096
+ "anthropic.claude-sonnet-4-6": {
1097
+ input: Omit<AnthropicRequest, "model">;
1098
+ };
1069
1099
  "anthropic.claude-sonnet-4-0": {
1070
1100
  input: Omit<AnthropicRequest, "model">;
1071
1101
  };
@@ -1120,9 +1150,15 @@ type AllUseLlmOptions = AllLlm & {
1120
1150
  "xai.grok-3": {
1121
1151
  input: OpenAiRequest;
1122
1152
  };
1153
+ "xai.grok-3-mini": {
1154
+ input: Omit<OpenAiRequest, "model">;
1155
+ };
1123
1156
  "xai.grok-4": {
1124
1157
  input: OpenAiRequest;
1125
1158
  };
1159
+ "xai.grok-4-fast": {
1160
+ input: Omit<OpenAiRequest, "model">;
1161
+ };
1126
1162
  "ollama.deepseek-r1": {
1127
1163
  input: GenericLLm;
1128
1164
  };
@@ -1466,10 +1502,14 @@ declare const configs: {
1466
1502
  "xai.chat.v1": Config<keyof AllLlm>;
1467
1503
  "xai.grok-2": Config<keyof AllLlm>;
1468
1504
  "xai.grok-3": Config<keyof AllLlm>;
1505
+ "xai.grok-3-mini": Config<keyof AllLlm>;
1469
1506
  "xai.grok-4": Config<keyof AllLlm>;
1507
+ "xai.grok-4-fast": Config<keyof AllLlm>;
1470
1508
  "amazon:anthropic.chat.v1": Config<keyof AllLlm>;
1471
1509
  "amazon:meta.chat.v1": Config<keyof AllLlm>;
1472
1510
  "anthropic.chat.v1": Config<keyof AllLlm>;
1511
+ "anthropic.claude-opus-4-6": Config<keyof AllLlm>;
1512
+ "anthropic.claude-sonnet-4-6": Config<keyof AllLlm>;
1473
1513
  "anthropic.claude-sonnet-4": Config<keyof AllLlm>;
1474
1514
  "anthropic.claude-opus-4": Config<keyof AllLlm>;
1475
1515
  "anthropic.claude-3-7-sonnet": Config<keyof AllLlm>;
@@ -1479,6 +1519,14 @@ declare const configs: {
1479
1519
  "anthropic.claude-3-haiku": Config<keyof AllLlm>;
1480
1520
  "openai.chat.v1": Config<keyof AllLlm>;
1481
1521
  "openai.chat-mock.v1": Config<keyof AllLlm>;
1522
+ "openai.gpt-5.2": Config<keyof AllLlm>;
1523
+ "openai.gpt-5-mini": Config<keyof AllLlm>;
1524
+ "openai.gpt-5-nano": Config<keyof AllLlm>;
1525
+ "openai.gpt-4.1": Config<keyof AllLlm>;
1526
+ "openai.gpt-4.1-mini": Config<keyof AllLlm>;
1527
+ "openai.gpt-4.1-nano": Config<keyof AllLlm>;
1528
+ "openai.o3": Config<keyof AllLlm>;
1529
+ "openai.o4-mini": Config<keyof AllLlm>;
1482
1530
  "openai.gpt-4o": Config<keyof AllLlm>;
1483
1531
  "openai.gpt-4o-mini": Config<keyof AllLlm>;
1484
1532
  };
package/dist/index.d.ts CHANGED
@@ -226,14 +226,14 @@ declare class StringExtractParser extends BaseParser<string> {
226
226
  * Creates a parser based on the given type.
227
227
  * @template S - JSON schema type.
228
228
  * @param type - The type of parser to create.
229
- * @returns An instance of ListToKeyValueParser.
229
+ * @returns An instance of MarkdownCodeBlocksParser.
230
230
  */
231
231
  declare function createParser<T extends Extract<CreateParserType, "markdownCodeBlocks">>(type: T, options?: BaseParserOptions): MarkdownCodeBlocksParser;
232
232
  /**
233
233
  * Creates a parser based on the given type.
234
234
  * @template S - JSON schema type.
235
235
  * @param type - The type of parser to create.
236
- * @returns An instance of ListToKeyValueParser.
236
+ * @returns An instance of MarkdownCodeBlockParser.
237
237
  */
238
238
  declare function createParser<T extends Extract<CreateParserType, "markdownCodeBlock">>(type: T, options?: BaseParserOptions): MarkdownCodeBlockParser;
239
239
  /**
@@ -432,8 +432,8 @@ declare class ChatPrompt<I extends Record<string, any>> extends BasePrompt<I> {
432
432
  readonly type: ChatPromptType;
433
433
  /**
434
434
  * @property parseUserTemplates - Whether or not to allow parsing
435
- * user messages with the template engine. This could be a risk,
436
- * so we only parse user messages if explicitly set.
435
+ * user messages with the template engine. Defaults to true.
436
+ * Set `allowUnsafeUserTemplate: false` in options to disable.
437
437
  */
438
438
  private parseUserTemplates;
439
439
  /**
@@ -468,13 +468,13 @@ declare class ChatPrompt<I extends Record<string, any>> extends BasePrompt<I> {
468
468
  */
469
469
  addAssistantMessage(content: string): ChatPrompt<I>;
470
470
  /**
471
- * addFunctionMessage Helper to add an assistant message to the prompt.
471
+ * addFunctionMessage Helper to add a function message to the prompt.
472
472
  * @param content The message content.
473
473
  * @return ChatPrompt so it can be chained.
474
474
  */
475
475
  addFunctionMessage(content: string, name: string, id?: string): ChatPrompt<I>;
476
476
  /**
477
- * addFunctionCallMessage Helper to add an assistant message to the prompt.
477
+ * addFunctionCallMessage Helper to add a function_call message to the prompt.
478
478
  * @param content The message content.
479
479
  * @return ChatPrompt so it can be chained.
480
480
  */
@@ -690,7 +690,7 @@ declare class Dialogue extends BaseStateItem<IChatMessages> {
690
690
  setUserMessage(content: string | IChatMessageContentDetailed[], name?: string): this;
691
691
  setAssistantMessage(content: string | OutputResultsText): this;
692
692
  setSystemMessage(content: string): this;
693
- setToolMessage(content: string, name: string, id?: string): void;
693
+ setToolMessage(content: string, name: string, id?: string): this;
694
694
  setFunctionMessage(content: string, name: string, id?: string): this;
695
695
  /**
696
696
  * Set
@@ -699,7 +699,7 @@ declare class Dialogue extends BaseStateItem<IChatMessages> {
699
699
  name: string;
700
700
  arguments: string;
701
701
  id?: string;
702
- }): void;
702
+ }): this;
703
703
  setFunctionCallMessage(input: {
704
704
  name: string;
705
705
  arguments: string;
@@ -1057,6 +1057,30 @@ type AllLlm = {
1057
1057
  };
1058
1058
  };
1059
1059
  type AllUseLlmOptions = AllLlm & {
1060
+ "openai.gpt-5.2": {
1061
+ input: Omit<OpenAiRequest, "model">;
1062
+ };
1063
+ "openai.gpt-5-mini": {
1064
+ input: Omit<OpenAiRequest, "model">;
1065
+ };
1066
+ "openai.gpt-5-nano": {
1067
+ input: Omit<OpenAiRequest, "model">;
1068
+ };
1069
+ "openai.gpt-4.1": {
1070
+ input: Omit<OpenAiRequest, "model">;
1071
+ };
1072
+ "openai.gpt-4.1-mini": {
1073
+ input: Omit<OpenAiRequest, "model">;
1074
+ };
1075
+ "openai.gpt-4.1-nano": {
1076
+ input: Omit<OpenAiRequest, "model">;
1077
+ };
1078
+ "openai.o3": {
1079
+ input: Omit<OpenAiRequest, "model">;
1080
+ };
1081
+ "openai.o4-mini": {
1082
+ input: Omit<OpenAiRequest, "model">;
1083
+ };
1060
1084
  "openai.gpt-4": {
1061
1085
  input: OpenAiRequest;
1062
1086
  };
@@ -1066,6 +1090,12 @@ type AllUseLlmOptions = AllLlm & {
1066
1090
  "openai.gpt-4o-mini": {
1067
1091
  input: Omit<OpenAiRequest, "model">;
1068
1092
  };
1093
+ "anthropic.claude-opus-4-6": {
1094
+ input: Omit<AnthropicRequest, "model">;
1095
+ };
1096
+ "anthropic.claude-sonnet-4-6": {
1097
+ input: Omit<AnthropicRequest, "model">;
1098
+ };
1069
1099
  "anthropic.claude-sonnet-4-0": {
1070
1100
  input: Omit<AnthropicRequest, "model">;
1071
1101
  };
@@ -1120,9 +1150,15 @@ type AllUseLlmOptions = AllLlm & {
1120
1150
  "xai.grok-3": {
1121
1151
  input: OpenAiRequest;
1122
1152
  };
1153
+ "xai.grok-3-mini": {
1154
+ input: Omit<OpenAiRequest, "model">;
1155
+ };
1123
1156
  "xai.grok-4": {
1124
1157
  input: OpenAiRequest;
1125
1158
  };
1159
+ "xai.grok-4-fast": {
1160
+ input: Omit<OpenAiRequest, "model">;
1161
+ };
1126
1162
  "ollama.deepseek-r1": {
1127
1163
  input: GenericLLm;
1128
1164
  };
@@ -1466,10 +1502,14 @@ declare const configs: {
1466
1502
  "xai.chat.v1": Config<keyof AllLlm>;
1467
1503
  "xai.grok-2": Config<keyof AllLlm>;
1468
1504
  "xai.grok-3": Config<keyof AllLlm>;
1505
+ "xai.grok-3-mini": Config<keyof AllLlm>;
1469
1506
  "xai.grok-4": Config<keyof AllLlm>;
1507
+ "xai.grok-4-fast": Config<keyof AllLlm>;
1470
1508
  "amazon:anthropic.chat.v1": Config<keyof AllLlm>;
1471
1509
  "amazon:meta.chat.v1": Config<keyof AllLlm>;
1472
1510
  "anthropic.chat.v1": Config<keyof AllLlm>;
1511
+ "anthropic.claude-opus-4-6": Config<keyof AllLlm>;
1512
+ "anthropic.claude-sonnet-4-6": Config<keyof AllLlm>;
1473
1513
  "anthropic.claude-sonnet-4": Config<keyof AllLlm>;
1474
1514
  "anthropic.claude-opus-4": Config<keyof AllLlm>;
1475
1515
  "anthropic.claude-3-7-sonnet": Config<keyof AllLlm>;
@@ -1479,6 +1519,14 @@ declare const configs: {
1479
1519
  "anthropic.claude-3-haiku": Config<keyof AllLlm>;
1480
1520
  "openai.chat.v1": Config<keyof AllLlm>;
1481
1521
  "openai.chat-mock.v1": Config<keyof AllLlm>;
1522
+ "openai.gpt-5.2": Config<keyof AllLlm>;
1523
+ "openai.gpt-5-mini": Config<keyof AllLlm>;
1524
+ "openai.gpt-5-nano": Config<keyof AllLlm>;
1525
+ "openai.gpt-4.1": Config<keyof AllLlm>;
1526
+ "openai.gpt-4.1-mini": Config<keyof AllLlm>;
1527
+ "openai.gpt-4.1-nano": Config<keyof AllLlm>;
1528
+ "openai.o3": Config<keyof AllLlm>;
1529
+ "openai.o4-mini": Config<keyof AllLlm>;
1482
1530
  "openai.gpt-4o": Config<keyof AllLlm>;
1483
1531
  "openai.gpt-4o-mini": Config<keyof AllLlm>;
1484
1532
  };
package/dist/index.js CHANGED
@@ -530,7 +530,7 @@ var BooleanParser = class extends BaseParser {
530
530
  `Invalid input. Expected string. Received ${typeof text}.`
531
531
  );
532
532
  const clean = text.toLowerCase().trim();
533
- if (clean === "true") {
533
+ if (clean === "true" || clean === "yes" || clean === "y" || clean === "1") {
534
534
  return true;
535
535
  }
536
536
  return false;
@@ -559,7 +559,7 @@ var NumberParser = class extends BaseParser {
559
559
  super("number", options);
560
560
  }
561
561
  parse(text) {
562
- const match = text.match(/\d/g);
562
+ const match = text.match(/-?\d+(\.\d+)?/);
563
563
  return match && isFinite(toNumber(match[0])) ? toNumber(match[0]) : -1;
564
564
  }
565
565
  };
@@ -1461,9 +1461,8 @@ var asyncCallWithTimeout = async (asyncPromise, timeLimit = 1e4) => {
1461
1461
  );
1462
1462
  }, timeLimit);
1463
1463
  });
1464
- return Promise.race([asyncPromise, timeoutPromise]).then((result) => {
1464
+ return Promise.race([asyncPromise, timeoutPromise]).finally(() => {
1465
1465
  clearTimeout(timeoutHandle);
1466
- return result;
1467
1466
  });
1468
1467
  };
1469
1468
 
@@ -1609,9 +1608,13 @@ var ListToJsonParser = class extends BaseParserWithJson {
1609
1608
  const lines = text.split("\n");
1610
1609
  const output = {};
1611
1610
  lines.forEach((line) => {
1612
- const [key, value] = line.split(":");
1613
- if (value) {
1614
- 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
+ }
1615
1618
  }
1616
1619
  });
1617
1620
  if (this.schema) {
@@ -1683,7 +1686,7 @@ var ListToArrayParser = class extends BaseParser {
1683
1686
  super("listToArray");
1684
1687
  }
1685
1688
  parse(text) {
1686
- 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());
1687
1690
  return lines;
1688
1691
  }
1689
1692
  };
@@ -1811,8 +1814,11 @@ function createParser(type, options = {}) {
1811
1814
  case "stringExtract":
1812
1815
  return new StringExtractParser(options);
1813
1816
  case "string":
1814
- default:
1815
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
+ );
1816
1822
  }
1817
1823
  }
1818
1824
  function createCustomParser(name, parserFn) {
@@ -2416,6 +2422,18 @@ var openAiChatMockV1 = {
2416
2422
  var openai = {
2417
2423
  "openai.chat.v1": openAiChatV1,
2418
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
2419
2437
  "openai.gpt-4o": withDefaultModel(openAiChatV1, "gpt-4o"),
2420
2438
  "openai.gpt-4o-mini": withDefaultModel(openAiChatV1, "gpt-4o-mini")
2421
2439
  };
@@ -2454,6 +2472,20 @@ function anthropicPromptMessageCallback(_message) {
2454
2472
  }
2455
2473
 
2456
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
+ }
2457
2489
  function anthropicPromptSanitize(_messages, _inputBodyObj, _outputObj) {
2458
2490
  if (typeof _messages === "string") {
2459
2491
  return [{ role: "user", content: _messages }].map(
@@ -2471,14 +2503,15 @@ function anthropicPromptSanitize(_messages, _inputBodyObj, _outputObj) {
2471
2503
  }
2472
2504
  if (first.role === "system" && messages.length > 0) {
2473
2505
  _outputObj.system = first.content;
2474
- return messages.map((m) => {
2506
+ const result2 = messages.map((m) => {
2475
2507
  if (m.role === "system") {
2476
2508
  return { ...m, role: "user" };
2477
2509
  }
2478
2510
  return m;
2479
2511
  }).map(anthropicPromptMessageCallback);
2512
+ return mergeConsecutiveSameRole(result2);
2480
2513
  }
2481
- return [
2514
+ const result = [
2482
2515
  first,
2483
2516
  ...messages.map((m) => {
2484
2517
  if (m.role === "system") {
@@ -2487,6 +2520,7 @@ function anthropicPromptSanitize(_messages, _inputBodyObj, _outputObj) {
2487
2520
  return m;
2488
2521
  })
2489
2522
  ].map(anthropicPromptMessageCallback);
2523
+ return mergeConsecutiveSameRole(result);
2490
2524
  }
2491
2525
 
2492
2526
  // src/llm/output/claude.ts
@@ -2735,7 +2769,16 @@ var anthropicChatV1 = {
2735
2769
  };
2736
2770
  var anthropic = {
2737
2771
  "anthropic.chat.v1": anthropicChatV1,
2738
- // Claude 4 models (latest generation)
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
2739
2782
  "anthropic.claude-sonnet-4": withDefaultModel(
2740
2783
  anthropicChatV1,
2741
2784
  "claude-sonnet-4-0"
@@ -2779,7 +2822,9 @@ var xai = {
2779
2822
  "xai.chat.v1": xaiChatV1,
2780
2823
  "xai.grok-2": withDefaultModel(xaiChatV1, "grok-2-latest"),
2781
2824
  "xai.grok-3": withDefaultModel(xaiChatV1, "grok-3"),
2782
- "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")
2783
2828
  };
2784
2829
 
2785
2830
  // src/llm/output/_utils/combineJsonl.ts
@@ -2900,7 +2945,7 @@ function googleGeminiPromptMessageCallback(_message) {
2900
2945
  message.role = "model";
2901
2946
  }
2902
2947
  let { role, ...payload } = message;
2903
- if (typeof payload.content === "string") {
2948
+ if (typeof payload.content === "string" && message.role !== "function") {
2904
2949
  parts.push({ text: message.content });
2905
2950
  }
2906
2951
  if (message.role === "function") {
@@ -2939,6 +2984,20 @@ function googleGeminiPromptMessageCallback(_message) {
2939
2984
  }
2940
2985
 
2941
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
+ }
2942
3001
  function googleGeminiPromptSanitize(_messages, _inputBodyObj, _outputObj) {
2943
3002
  if (typeof _messages === "string") {
2944
3003
  return [{ role: "user", parts: [{ text: _messages }] }];
@@ -2965,9 +3024,13 @@ function googleGeminiPromptSanitize(_messages, _inputBodyObj, _outputObj) {
2965
3024
  text: message.content
2966
3025
  }))
2967
3026
  };
2968
- return withoutSystemInstructions.map(googleGeminiPromptMessageCallback);
3027
+ const result2 = withoutSystemInstructions.map(
3028
+ googleGeminiPromptMessageCallback
3029
+ );
3030
+ return mergeConsecutiveSameRole2(result2);
2969
3031
  }
2970
- return _messages.map(googleGeminiPromptMessageCallback);
3032
+ const result = _messages.map(googleGeminiPromptMessageCallback);
3033
+ return mergeConsecutiveSameRole2(result);
2971
3034
  }
2972
3035
  throw new Error("Invalid messages format");
2973
3036
  }
@@ -4171,8 +4234,8 @@ var ChatPrompt = class extends BasePrompt {
4171
4234
  __publicField(this, "type", "chat");
4172
4235
  /**
4173
4236
  * @property parseUserTemplates - Whether or not to allow parsing
4174
- * user messages with the template engine. This could be a risk,
4175
- * 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.
4176
4239
  */
4177
4240
  __publicField(this, "parseUserTemplates", true);
4178
4241
  if (typeof options?.allowUnsafeUserTemplate === "boolean") {
@@ -4233,7 +4296,7 @@ var ChatPrompt = class extends BasePrompt {
4233
4296
  return this;
4234
4297
  }
4235
4298
  /**
4236
- * addFunctionMessage Helper to add an assistant message to the prompt.
4299
+ * addFunctionMessage Helper to add a function message to the prompt.
4237
4300
  * @param content The message content.
4238
4301
  * @return ChatPrompt so it can be chained.
4239
4302
  */
@@ -4247,7 +4310,7 @@ var ChatPrompt = class extends BasePrompt {
4247
4310
  return this;
4248
4311
  }
4249
4312
  /**
4250
- * addFunctionCallMessage Helper to add an assistant message to the prompt.
4313
+ * addFunctionCallMessage Helper to add a function_call message to the prompt.
4251
4314
  * @param content The message content.
4252
4315
  * @return ChatPrompt so it can be chained.
4253
4316
  */
@@ -4802,7 +4865,7 @@ var Dialogue = class extends BaseStateItem {
4802
4865
  return this;
4803
4866
  }
4804
4867
  setToolMessage(content, name, id) {
4805
- this.setFunctionMessage(content, name, id);
4868
+ return this.setFunctionMessage(content, name, id);
4806
4869
  }
4807
4870
  setFunctionMessage(content, name, id) {
4808
4871
  if (content) {
@@ -4819,7 +4882,7 @@ var Dialogue = class extends BaseStateItem {
4819
4882
  * Set
4820
4883
  */
4821
4884
  setToolCallMessage(input) {
4822
- this.setFunctionCallMessage(input);
4885
+ return this.setFunctionCallMessage(input);
4823
4886
  }
4824
4887
  setFunctionCallMessage(input) {
4825
4888
  if (!input || typeof input !== "object") {
package/dist/index.mjs CHANGED
@@ -467,7 +467,7 @@ var BooleanParser = class extends BaseParser {
467
467
  `Invalid input. Expected string. Received ${typeof text}.`
468
468
  );
469
469
  const clean = text.toLowerCase().trim();
470
- if (clean === "true") {
470
+ if (clean === "true" || clean === "yes" || clean === "y" || clean === "1") {
471
471
  return true;
472
472
  }
473
473
  return false;
@@ -496,7 +496,7 @@ var NumberParser = class extends BaseParser {
496
496
  super("number", options);
497
497
  }
498
498
  parse(text) {
499
- const match = text.match(/\d/g);
499
+ const match = text.match(/-?\d+(\.\d+)?/);
500
500
  return match && isFinite(toNumber(match[0])) ? toNumber(match[0]) : -1;
501
501
  }
502
502
  };
@@ -1398,9 +1398,8 @@ var asyncCallWithTimeout = async (asyncPromise, timeLimit = 1e4) => {
1398
1398
  );
1399
1399
  }, timeLimit);
1400
1400
  });
1401
- return Promise.race([asyncPromise, timeoutPromise]).then((result) => {
1401
+ return Promise.race([asyncPromise, timeoutPromise]).finally(() => {
1402
1402
  clearTimeout(timeoutHandle);
1403
- return result;
1404
1403
  });
1405
1404
  };
1406
1405
 
@@ -1546,9 +1545,13 @@ var ListToJsonParser = class extends BaseParserWithJson {
1546
1545
  const lines = text.split("\n");
1547
1546
  const output = {};
1548
1547
  lines.forEach((line) => {
1549
- const [key, value] = line.split(":");
1550
- if (value) {
1551
- 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
+ }
1552
1555
  }
1553
1556
  });
1554
1557
  if (this.schema) {
@@ -1620,7 +1623,7 @@ var ListToArrayParser = class extends BaseParser {
1620
1623
  super("listToArray");
1621
1624
  }
1622
1625
  parse(text) {
1623
- 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());
1624
1627
  return lines;
1625
1628
  }
1626
1629
  };
@@ -1748,8 +1751,11 @@ function createParser(type, options = {}) {
1748
1751
  case "stringExtract":
1749
1752
  return new StringExtractParser(options);
1750
1753
  case "string":
1751
- default:
1752
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
+ );
1753
1759
  }
1754
1760
  }
1755
1761
  function createCustomParser(name, parserFn) {
@@ -2353,6 +2359,18 @@ var openAiChatMockV1 = {
2353
2359
  var openai = {
2354
2360
  "openai.chat.v1": openAiChatV1,
2355
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
2356
2374
  "openai.gpt-4o": withDefaultModel(openAiChatV1, "gpt-4o"),
2357
2375
  "openai.gpt-4o-mini": withDefaultModel(openAiChatV1, "gpt-4o-mini")
2358
2376
  };
@@ -2391,6 +2409,20 @@ function anthropicPromptMessageCallback(_message) {
2391
2409
  }
2392
2410
 
2393
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
+ }
2394
2426
  function anthropicPromptSanitize(_messages, _inputBodyObj, _outputObj) {
2395
2427
  if (typeof _messages === "string") {
2396
2428
  return [{ role: "user", content: _messages }].map(
@@ -2408,14 +2440,15 @@ function anthropicPromptSanitize(_messages, _inputBodyObj, _outputObj) {
2408
2440
  }
2409
2441
  if (first.role === "system" && messages.length > 0) {
2410
2442
  _outputObj.system = first.content;
2411
- return messages.map((m) => {
2443
+ const result2 = messages.map((m) => {
2412
2444
  if (m.role === "system") {
2413
2445
  return { ...m, role: "user" };
2414
2446
  }
2415
2447
  return m;
2416
2448
  }).map(anthropicPromptMessageCallback);
2449
+ return mergeConsecutiveSameRole(result2);
2417
2450
  }
2418
- return [
2451
+ const result = [
2419
2452
  first,
2420
2453
  ...messages.map((m) => {
2421
2454
  if (m.role === "system") {
@@ -2424,6 +2457,7 @@ function anthropicPromptSanitize(_messages, _inputBodyObj, _outputObj) {
2424
2457
  return m;
2425
2458
  })
2426
2459
  ].map(anthropicPromptMessageCallback);
2460
+ return mergeConsecutiveSameRole(result);
2427
2461
  }
2428
2462
 
2429
2463
  // src/llm/output/claude.ts
@@ -2672,7 +2706,16 @@ var anthropicChatV1 = {
2672
2706
  };
2673
2707
  var anthropic = {
2674
2708
  "anthropic.chat.v1": anthropicChatV1,
2675
- // Claude 4 models (latest generation)
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
2676
2719
  "anthropic.claude-sonnet-4": withDefaultModel(
2677
2720
  anthropicChatV1,
2678
2721
  "claude-sonnet-4-0"
@@ -2716,7 +2759,9 @@ var xai = {
2716
2759
  "xai.chat.v1": xaiChatV1,
2717
2760
  "xai.grok-2": withDefaultModel(xaiChatV1, "grok-2-latest"),
2718
2761
  "xai.grok-3": withDefaultModel(xaiChatV1, "grok-3"),
2719
- "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")
2720
2765
  };
2721
2766
 
2722
2767
  // src/llm/output/_utils/combineJsonl.ts
@@ -2837,7 +2882,7 @@ function googleGeminiPromptMessageCallback(_message) {
2837
2882
  message.role = "model";
2838
2883
  }
2839
2884
  let { role, ...payload } = message;
2840
- if (typeof payload.content === "string") {
2885
+ if (typeof payload.content === "string" && message.role !== "function") {
2841
2886
  parts.push({ text: message.content });
2842
2887
  }
2843
2888
  if (message.role === "function") {
@@ -2876,6 +2921,20 @@ function googleGeminiPromptMessageCallback(_message) {
2876
2921
  }
2877
2922
 
2878
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
+ }
2879
2938
  function googleGeminiPromptSanitize(_messages, _inputBodyObj, _outputObj) {
2880
2939
  if (typeof _messages === "string") {
2881
2940
  return [{ role: "user", parts: [{ text: _messages }] }];
@@ -2902,9 +2961,13 @@ function googleGeminiPromptSanitize(_messages, _inputBodyObj, _outputObj) {
2902
2961
  text: message.content
2903
2962
  }))
2904
2963
  };
2905
- return withoutSystemInstructions.map(googleGeminiPromptMessageCallback);
2964
+ const result2 = withoutSystemInstructions.map(
2965
+ googleGeminiPromptMessageCallback
2966
+ );
2967
+ return mergeConsecutiveSameRole2(result2);
2906
2968
  }
2907
- return _messages.map(googleGeminiPromptMessageCallback);
2969
+ const result = _messages.map(googleGeminiPromptMessageCallback);
2970
+ return mergeConsecutiveSameRole2(result);
2908
2971
  }
2909
2972
  throw new Error("Invalid messages format");
2910
2973
  }
@@ -4108,8 +4171,8 @@ var ChatPrompt = class extends BasePrompt {
4108
4171
  __publicField(this, "type", "chat");
4109
4172
  /**
4110
4173
  * @property parseUserTemplates - Whether or not to allow parsing
4111
- * user messages with the template engine. This could be a risk,
4112
- * 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.
4113
4176
  */
4114
4177
  __publicField(this, "parseUserTemplates", true);
4115
4178
  if (typeof options?.allowUnsafeUserTemplate === "boolean") {
@@ -4170,7 +4233,7 @@ var ChatPrompt = class extends BasePrompt {
4170
4233
  return this;
4171
4234
  }
4172
4235
  /**
4173
- * addFunctionMessage Helper to add an assistant message to the prompt.
4236
+ * addFunctionMessage Helper to add a function message to the prompt.
4174
4237
  * @param content The message content.
4175
4238
  * @return ChatPrompt so it can be chained.
4176
4239
  */
@@ -4184,7 +4247,7 @@ var ChatPrompt = class extends BasePrompt {
4184
4247
  return this;
4185
4248
  }
4186
4249
  /**
4187
- * addFunctionCallMessage Helper to add an assistant message to the prompt.
4250
+ * addFunctionCallMessage Helper to add a function_call message to the prompt.
4188
4251
  * @param content The message content.
4189
4252
  * @return ChatPrompt so it can be chained.
4190
4253
  */
@@ -4739,7 +4802,7 @@ var Dialogue = class extends BaseStateItem {
4739
4802
  return this;
4740
4803
  }
4741
4804
  setToolMessage(content, name, id) {
4742
- this.setFunctionMessage(content, name, id);
4805
+ return this.setFunctionMessage(content, name, id);
4743
4806
  }
4744
4807
  setFunctionMessage(content, name, id) {
4745
4808
  if (content) {
@@ -4756,7 +4819,7 @@ var Dialogue = class extends BaseStateItem {
4756
4819
  * Set
4757
4820
  */
4758
4821
  setToolCallMessage(input) {
4759
- this.setFunctionCallMessage(input);
4822
+ return this.setFunctionCallMessage(input);
4760
4823
  }
4761
4824
  setFunctionCallMessage(input) {
4762
4825
  if (!input || typeof input !== "object") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "llm-exe",
3
- "version": "2.3.2",
3
+ "version": "2.3.3",
4
4
  "description": "Simplify building LLM-powered apps with easy-to-use base components, supporting text and chat-based prompts with handlebars template engine, output parsers, and flexible function calling capabilities.",
5
5
  "keywords": [
6
6
  "ai",
@@ -38,7 +38,7 @@
38
38
  "typecheck": "tsc --noEmit",
39
39
  "test": "NODE_OPTIONS=--experimental-vm-modules jest --config jest.config.ts --detectOpenHandles --coverage --forceExit",
40
40
  "test-examples": "eval $(cat .env) NODE_OPTIONS=--experimental-vm-modules jest --config jest.config.examples.ts --detectOpenHandles --coverage --forceExit",
41
- "test-one": "eval $(cat .env) NODE_OPTIONS=--experimental-vm-modules jest --detectOpenHandles --coverage --forceExit --config jest.config.examples.ts examples/intentBot.test.ts",
41
+ "test-one": "eval $(cat .env) NODE_OPTIONS=--experimental-vm-modules jest --detectOpenHandles --coverage --forceExit --config jest.config.examples.ts examples/helloWorld.test.ts",
42
42
  "run-one": "eval $(cat .env) ts-node ./examples/chains/self-refinement/usage.ts",
43
43
  "build": "(concurrently \"tsc --p ./tsconfig.json -w\" \"tsc-alias -p tsconfig.json -w\")",
44
44
  "build:ci": "tsup src/index.ts --format cjs,esm --dts --clean",
@@ -46,7 +46,7 @@
46
46
  "build:package": "tsup src/index.ts --format cjs,esm --dts --clean --external jsonschema,json-schema-to-ts,exponential-backoff,@aws-sdk/credential-providers,@aws-crypto/sha256-js,@smithy/protocol-http,@smithy/signature-v4",
47
47
  "build:docs-examples": "./node_modules/.bin/esbuild examples/prompt/index.ts examples/state/index.ts --bundle --outdir=docs/.vitepress/components/examples --platform=node --target=es6 --format=esm",
48
48
  "build:watch:docs-examples": "./node_modules/.bin/esbuild examples/prompt/index.ts examples/state/index.ts --watch --bundle --outdir=docs/.vitepress/components/examples --platform=node --target=es6 --format=esm",
49
- "predocs:build": "npm run build:docs-examples",
49
+ "predocs:build": "npm run build:docs-examples && bash scripts/generate-llms-txt.sh",
50
50
  "docs:dev": "eval $(cat docs/.env) && concurrently \"vitepress dev docs\" \"npm run build:watch:docs-examples\"",
51
51
  "docs:build": "eval $(cat docs/.env) && vitepress build docs",
52
52
  "docs:update-providers": "node docs/.vitepress/scripts/updateProviders.js",
package/readme.md CHANGED
@@ -41,6 +41,8 @@ const llmExe = require("llm-exe");
41
41
  ## Overview
42
42
 
43
43
  ```ts
44
+ import { useLlm, createChatPrompt, createParser, createLlmExecutor, defineSchema } from "llm-exe";
45
+
44
46
  // Prompt
45
47
  const prompt = createChatPrompt("You are a support agent. Help the user.");
46
48
  prompt.addUserMessage("I need help with my order.");
@@ -48,8 +50,16 @@ prompt.addUserMessage("I need help with my order.");
48
50
  // LLM
49
51
  const llm = useLlm("openai.gpt-4o");
50
52
 
51
- // Parser
52
- const parser = createParser("json", { schema: mySchema });
53
+ // Parser — schema uses JSON Schema (via defineSchema)
54
+ const schema = defineSchema({
55
+ type: "object",
56
+ properties: {
57
+ answer: { type: "string" },
58
+ action: { type: "string" },
59
+ },
60
+ required: ["answer", "action"],
61
+ } as const);
62
+ const parser = createParser("json", { schema });
53
63
 
54
64
  // Executor
55
65
  const executor = createLlmExecutor({ llm, prompt, parser });
@@ -71,11 +81,17 @@ Welcome back!
71
81
  #### Built-In Parsers
72
82
 
73
83
  ```ts
74
- createParser("stringExtract", { enum: ["yes", "no"] });
75
- createParser("listToJson");
76
- createParser("listToArray");
77
- createParser("markdownCodeBlock");
78
- // ...etc
84
+ createParser("string"); // pass-through, returns string
85
+ createParser("json", { schema }); // JSON with optional schema validation
86
+ createParser("boolean"); // extracts boolean from response
87
+ createParser("number"); // extracts number from response
88
+ createParser("stringExtract", { enum: ["yes", "no"] }); // match one of the enum values
89
+ createParser("listToArray"); // newline-separated list → string[]
90
+ createParser("listToJson"); // key: value list → object (with optional schema)
91
+ createParser("listToKeyValue"); // key: value list → Array<{ key, value }>
92
+ createParser("markdownCodeBlock"); // single code block → { code, language }
93
+ createParser("markdownCodeBlocks"); // multiple code blocks → Array<{ code, language }>
94
+ createParser("replaceStringTemplate"); // handlebars-based output templating
79
95
  ```
80
96
 
81
97
  #### Custom Parsers