llm-exe 3.0.0-beta.1 → 3.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -92,7 +92,7 @@ declare abstract class BaseParser<T = any, TInput = string> {
92
92
  declare abstract class BaseParserWithJson<S extends JSONSchema | undefined = undefined, T = S extends JSONSchema ? FromSchema<S> : Record<string, any>, TInput = string> extends BaseParser<T, TInput> {
93
93
  schema: S;
94
94
  validateSchema: boolean;
95
- constructor(name: string, options: JsonParserOptions<S>);
95
+ constructor(name: string, options: ParserSchemaOptions<S>);
96
96
  }
97
97
 
98
98
  /**
@@ -111,25 +111,31 @@ declare class StringParser extends BaseParser<string> {
111
111
  parse(text: string, _attributes?: Record<string, any>): string;
112
112
  }
113
113
 
114
+ type BooleanParserMatch = "exact" | "extract";
115
+ interface BooleanParserOptions {
116
+ match?: BooleanParserMatch;
117
+ }
114
118
  /**
115
119
  * v3 parser contract:
116
120
  * Category: strict
117
- * Mode: whole-output
121
+ * Mode: exact
118
122
  *
119
123
  * Accepts only documented boolean literals after trim/lowercase.
120
- * Returns true/false only when input is recognized.
121
- * Throws LlmExeError(parser.parse_failed) for empty, invalid-type, or
122
- * unrecognized input. Does not extract booleans from prose.
124
+ * Returns true/false only when input is recognized. Pass match: "extract" to
125
+ * extract one documented boolean literal from surrounding text.
126
+ * Throws LlmExeError(parser.parse_failed) for empty or unrecognized input.
127
+ * Invalid input types throw LlmExeError(parser.invalid_input).
123
128
  * Error context does not include input content unless LLM_EXE_DEBUG is enabled.
124
129
  *
125
130
  */
126
131
  declare class BooleanParser extends BaseParser<boolean> {
127
- constructor();
132
+ private match;
133
+ constructor(options?: BooleanParserOptions);
128
134
  private getInputErrorContext;
129
135
  parse(text: string, _attributes?: Record<string, any>): boolean;
130
136
  }
131
137
 
132
- type NumberParserMatch = "extract" | "whole";
138
+ type NumberParserMatch = "exact" | "extract";
133
139
  interface NumberParserOptions {
134
140
  match?: NumberParserMatch;
135
141
  }
@@ -138,7 +144,7 @@ interface NumberParserOptions {
138
144
  * Category: extractor
139
145
  * Mode: numeric token extraction
140
146
  *
141
- * Extracts one documented numeric token from text. Pass match: "whole" to
147
+ * Extracts one documented numeric token from text. Pass match: "exact" to
142
148
  * require the input to consist of exactly one numeric token (after trim) with
143
149
  * no surrounding prose.
144
150
  *
@@ -156,14 +162,16 @@ type JsonParserInput = string | Record<string, unknown> | unknown[];
156
162
  type JsonParserOutput<S extends JSONSchema | undefined> = S extends JSONSchema ? FromSchema<S> : Record<string, any>;
157
163
  declare class JsonParser<S extends JSONSchema | undefined = undefined> extends BaseParserWithJson<S, JsonParserOutput<S>, JsonParserInput> {
158
164
  private shouldValidateSchema;
165
+ private match;
159
166
  constructor(options?: JsonParserOptions<S>);
160
167
  /**
161
168
  * v3 parser contract:
162
169
  * Category: strict
163
- * Mode: whole-output
170
+ * Mode: exact
164
171
  *
165
- * Parses strict JSON object/array output only. Invalid JSON, empty input,
166
- * JSON primitives, and non-plain runtime objects throw typed parser errors.
172
+ * Parses strict JSON object/array output by default. Pass match: "extract"
173
+ * to extract one JSON object or array from surrounding text. Invalid JSON,
174
+ * empty input, JSON primitives, and non-plain runtime objects throw typed parser errors.
167
175
  * Schema validation is on by default when a schema is provided unless
168
176
  * validateSchema: false is explicitly set.
169
177
  *
@@ -314,7 +322,7 @@ declare class MarkdownCodeBlocksParser extends BaseParser<{
314
322
  }[];
315
323
  }
316
324
 
317
- type StringExtractMatch = "word" | "whole" | "substring";
325
+ type StringExtractMatch = "exact" | "word" | "substring";
318
326
  interface StringExtractParserOptions<E extends readonly string[] = readonly string[]> {
319
327
  enum: E;
320
328
  ignoreCase?: boolean;
@@ -331,14 +339,14 @@ declare class StringExtractParser<E extends readonly string[] = readonly string[
331
339
  * Mode: configured value extraction
332
340
  *
333
341
  * Returns the single configured enum value found in input. Matching is
334
- * word-bounded by default; pass match: "whole" to require exact input or
342
+ * word-bounded by default; pass match: "exact" to require exact input or
335
343
  * match: "substring" for legacy contains() behavior. Case-insensitive by
336
344
  * default.
337
345
  *
338
346
  */
339
347
  parse(text: string, _attributes?: Record<string, any>): E[number];
340
348
  private findMatches;
341
- private matchWhole;
349
+ private matchExact;
342
350
  private matchSubstring;
343
351
  private matchWord;
344
352
  }
@@ -350,16 +358,22 @@ declare class StringExtractParser<E extends readonly string[] = readonly string[
350
358
  * (e.g. "Source has 1 element(s) but target requires 2" when stringExtract
351
359
  * is called without options) instead of overload-resolution mystery.
352
360
  */
353
- type CreateParserArgs = [type: "string", options?: never] | [type: "boolean", options?: never] | [type: "listToArray", options?: never] | [type: "markdownCodeBlock", options?: never] | [type: "markdownCodeBlocks", options?: never] | [type: "replaceStringTemplate", options?: never] | [type: "number", options?: NumberParserOptions] | [type: "listToKeyValue", options?: ListToKeyValueParserOptions] | [type: "json", options?: JsonParserOptions<JSONSchema | undefined>] | [
361
+ type CreateParserArgs = [type: "string", options?: never] | [type: "boolean", options?: BooleanParserOptions] | [type: "listToArray", options?: never] | [type: "markdownCodeBlock", options?: never] | [type: "markdownCodeBlocks", options?: never] | [type: "replaceStringTemplate", options?: never] | [type: "number", options?: NumberParserOptions] | [type: "listToKeyValue", options?: ListToKeyValueParserOptions] | [type: "json", options?: JsonParserOptions<JSONSchema | undefined>] | [
354
362
  type: "listToJson",
355
363
  options?: ListToJsonParserOptions<JSONSchema | undefined>
356
- ] | [type: "stringExtract", options: StringExtractParserOptions<readonly string[]>];
364
+ ] | [
365
+ type: "stringExtract",
366
+ options: StringExtractParserOptions<readonly string[]>
367
+ ];
357
368
  /**
358
369
  * Maps a concrete argument tuple back to the parser instance type, preserving
359
370
  * schema inference for json/listToJson and enum literal narrowing for
360
371
  * stringExtract.
361
372
  */
362
- type CreateParserReturn<A extends readonly unknown[]> = A extends readonly ["string", ...unknown[]] ? StringParser : A extends readonly ["boolean", ...unknown[]] ? BooleanParser : A extends readonly ["number", ...unknown[]] ? NumberParser : A extends readonly ["listToArray", ...unknown[]] ? ListToArrayParser : A extends readonly ["listToKeyValue", ...unknown[]] ? ListToKeyValueParser : A extends readonly ["markdownCodeBlock", ...unknown[]] ? MarkdownCodeBlockParser : A extends readonly ["markdownCodeBlocks", ...unknown[]] ? MarkdownCodeBlocksParser : A extends readonly ["replaceStringTemplate", ...unknown[]] ? ReplaceStringTemplateParser : A extends readonly ["json"] | readonly ["json", undefined] ? JsonParser<undefined> : A extends readonly ["json", JsonParserOptions<infer S>] ? JsonParser<S> : A extends readonly ["listToJson"] | readonly ["listToJson", undefined] ? ListToJsonParser<undefined> : A extends readonly ["listToJson", ListToJsonParserOptions<infer S>] ? ListToJsonParser<S> : A extends readonly [
373
+ type CreateParserReturn<A extends readonly unknown[]> = A extends readonly ["string", ...unknown[]] ? StringParser : A extends readonly ["boolean", ...unknown[]] ? BooleanParser : A extends readonly ["number", ...unknown[]] ? NumberParser : A extends readonly ["listToArray", ...unknown[]] ? ListToArrayParser : A extends readonly ["listToKeyValue", ...unknown[]] ? ListToKeyValueParser : A extends readonly ["markdownCodeBlock", ...unknown[]] ? MarkdownCodeBlockParser : A extends readonly ["markdownCodeBlocks", ...unknown[]] ? MarkdownCodeBlocksParser : A extends readonly ["replaceStringTemplate", ...unknown[]] ? ReplaceStringTemplateParser : A extends readonly ["json"] | readonly ["json", undefined] ? JsonParser<undefined> : A extends readonly ["json", JsonParserOptions<infer S>] ? JsonParser<S> : A extends readonly ["listToJson"] | readonly ["listToJson", undefined] ? ListToJsonParser<undefined> : A extends readonly [
374
+ "listToJson",
375
+ ListToJsonParserOptions<infer S>
376
+ ] ? ListToJsonParser<S> : A extends readonly [
363
377
  "stringExtract",
364
378
  StringExtractParserOptions<infer E extends readonly string[]>
365
379
  ] ? StringExtractParser<E> : never;
@@ -1057,11 +1071,15 @@ interface LlmExecutorWithFunctionsOptions<T extends GenericFunctionCall = "auto"
1057
1071
  jsonSchema?: Record<string, any>;
1058
1072
  }
1059
1073
 
1060
- interface JsonParserOptions<S extends JSONSchema | undefined = undefined> {
1074
+ interface ParserSchemaOptions<S extends JSONSchema | undefined = undefined> {
1061
1075
  schema?: S;
1062
1076
  validateSchema?: boolean;
1063
1077
  }
1064
- interface ListToJsonParserOptions<S extends JSONSchema | undefined = undefined> extends JsonParserOptions<S> {
1078
+ type JsonParserMatch = "exact" | "extract";
1079
+ interface JsonParserOptions<S extends JSONSchema | undefined = undefined> extends ParserSchemaOptions<S> {
1080
+ match?: JsonParserMatch;
1081
+ }
1082
+ interface ListToJsonParserOptions<S extends JSONSchema | undefined = undefined> extends ParserSchemaOptions<S> {
1065
1083
  keyTransform?: "camelCase" | "preserve";
1066
1084
  }
1067
1085
 
@@ -2069,4 +2087,4 @@ declare function createEmbedding<T extends EmbeddingProviderKey>(provider: T, op
2069
2087
  };
2070
2088
  };
2071
2089
 
2072
- export { BaseExecutor, type BaseLlm, BaseParser, BasePrompt, BaseStateItem, ChatPrompt, CustomParser, DefaultState, DefaultStateItem, type EmbeddingProviderKey, type ErrorCategory, type ErrorCodes, type ErrorContextByCode, type ExecutionContext, type ExecutorContext, type ExecutorExecutionMetadata, type HookErrorRecord, type IChatMessages, LLM_EXE_ERROR_SYMBOL, LlmExeError, LlmExecutorOpenAiFunctions, LlmExecutorWithFunctions, LlmNativeFunctionParser, type LlmProvider, type LlmProviderKey, type NormalizedProviderError, type OpenAIModelName, OpenAiFunctionParser, type ProviderErrorContext, TextPrompt, type UseLlmKey, createCallableExecutor, createChatPrompt, createCoreExecutor, createCustomParser, createDialogue, createEmbedding, createLlmExecutor, createLlmFunctionExecutor, createOpenAiCompatibleConfiguration, createParser, createPrompt, createState, createStateItem, defineSchema, guards, isLlmExeError, registerHelpers, registerPartials, useExecutors, useLlm, useLlmConfiguration, index as utils };
2090
+ export { BaseExecutor, type BaseLlm, BaseParser, BasePrompt, BaseStateItem, type BooleanParserMatch, type BooleanParserOptions, ChatPrompt, CustomParser, DefaultState, DefaultStateItem, type EmbeddingProviderKey, type ErrorCategory, type ErrorCodes, type ErrorContextByCode, type ExecutionContext, type ExecutorContext, type ExecutorExecutionMetadata, type HookErrorRecord, type IChatMessages, type JsonParserMatch, type JsonParserOptions, LLM_EXE_ERROR_SYMBOL, LlmExeError, LlmExecutorOpenAiFunctions, LlmExecutorWithFunctions, LlmNativeFunctionParser, type LlmProvider, type LlmProviderKey, type NormalizedProviderError, type NumberParserMatch, type NumberParserOptions, type OpenAIModelName, OpenAiFunctionParser, type ProviderErrorContext, type StringExtractMatch, type StringExtractParserOptions, TextPrompt, type UseLlmKey, createCallableExecutor, createChatPrompt, createCoreExecutor, createCustomParser, createDialogue, createEmbedding, createLlmExecutor, createLlmFunctionExecutor, createOpenAiCompatibleConfiguration, createParser, createPrompt, createState, createStateItem, defineSchema, guards, isLlmExeError, registerHelpers, registerPartials, useExecutors, useLlm, useLlmConfiguration, index as utils };
package/dist/index.d.ts CHANGED
@@ -92,7 +92,7 @@ declare abstract class BaseParser<T = any, TInput = string> {
92
92
  declare abstract class BaseParserWithJson<S extends JSONSchema | undefined = undefined, T = S extends JSONSchema ? FromSchema<S> : Record<string, any>, TInput = string> extends BaseParser<T, TInput> {
93
93
  schema: S;
94
94
  validateSchema: boolean;
95
- constructor(name: string, options: JsonParserOptions<S>);
95
+ constructor(name: string, options: ParserSchemaOptions<S>);
96
96
  }
97
97
 
98
98
  /**
@@ -111,25 +111,31 @@ declare class StringParser extends BaseParser<string> {
111
111
  parse(text: string, _attributes?: Record<string, any>): string;
112
112
  }
113
113
 
114
+ type BooleanParserMatch = "exact" | "extract";
115
+ interface BooleanParserOptions {
116
+ match?: BooleanParserMatch;
117
+ }
114
118
  /**
115
119
  * v3 parser contract:
116
120
  * Category: strict
117
- * Mode: whole-output
121
+ * Mode: exact
118
122
  *
119
123
  * Accepts only documented boolean literals after trim/lowercase.
120
- * Returns true/false only when input is recognized.
121
- * Throws LlmExeError(parser.parse_failed) for empty, invalid-type, or
122
- * unrecognized input. Does not extract booleans from prose.
124
+ * Returns true/false only when input is recognized. Pass match: "extract" to
125
+ * extract one documented boolean literal from surrounding text.
126
+ * Throws LlmExeError(parser.parse_failed) for empty or unrecognized input.
127
+ * Invalid input types throw LlmExeError(parser.invalid_input).
123
128
  * Error context does not include input content unless LLM_EXE_DEBUG is enabled.
124
129
  *
125
130
  */
126
131
  declare class BooleanParser extends BaseParser<boolean> {
127
- constructor();
132
+ private match;
133
+ constructor(options?: BooleanParserOptions);
128
134
  private getInputErrorContext;
129
135
  parse(text: string, _attributes?: Record<string, any>): boolean;
130
136
  }
131
137
 
132
- type NumberParserMatch = "extract" | "whole";
138
+ type NumberParserMatch = "exact" | "extract";
133
139
  interface NumberParserOptions {
134
140
  match?: NumberParserMatch;
135
141
  }
@@ -138,7 +144,7 @@ interface NumberParserOptions {
138
144
  * Category: extractor
139
145
  * Mode: numeric token extraction
140
146
  *
141
- * Extracts one documented numeric token from text. Pass match: "whole" to
147
+ * Extracts one documented numeric token from text. Pass match: "exact" to
142
148
  * require the input to consist of exactly one numeric token (after trim) with
143
149
  * no surrounding prose.
144
150
  *
@@ -156,14 +162,16 @@ type JsonParserInput = string | Record<string, unknown> | unknown[];
156
162
  type JsonParserOutput<S extends JSONSchema | undefined> = S extends JSONSchema ? FromSchema<S> : Record<string, any>;
157
163
  declare class JsonParser<S extends JSONSchema | undefined = undefined> extends BaseParserWithJson<S, JsonParserOutput<S>, JsonParserInput> {
158
164
  private shouldValidateSchema;
165
+ private match;
159
166
  constructor(options?: JsonParserOptions<S>);
160
167
  /**
161
168
  * v3 parser contract:
162
169
  * Category: strict
163
- * Mode: whole-output
170
+ * Mode: exact
164
171
  *
165
- * Parses strict JSON object/array output only. Invalid JSON, empty input,
166
- * JSON primitives, and non-plain runtime objects throw typed parser errors.
172
+ * Parses strict JSON object/array output by default. Pass match: "extract"
173
+ * to extract one JSON object or array from surrounding text. Invalid JSON,
174
+ * empty input, JSON primitives, and non-plain runtime objects throw typed parser errors.
167
175
  * Schema validation is on by default when a schema is provided unless
168
176
  * validateSchema: false is explicitly set.
169
177
  *
@@ -314,7 +322,7 @@ declare class MarkdownCodeBlocksParser extends BaseParser<{
314
322
  }[];
315
323
  }
316
324
 
317
- type StringExtractMatch = "word" | "whole" | "substring";
325
+ type StringExtractMatch = "exact" | "word" | "substring";
318
326
  interface StringExtractParserOptions<E extends readonly string[] = readonly string[]> {
319
327
  enum: E;
320
328
  ignoreCase?: boolean;
@@ -331,14 +339,14 @@ declare class StringExtractParser<E extends readonly string[] = readonly string[
331
339
  * Mode: configured value extraction
332
340
  *
333
341
  * Returns the single configured enum value found in input. Matching is
334
- * word-bounded by default; pass match: "whole" to require exact input or
342
+ * word-bounded by default; pass match: "exact" to require exact input or
335
343
  * match: "substring" for legacy contains() behavior. Case-insensitive by
336
344
  * default.
337
345
  *
338
346
  */
339
347
  parse(text: string, _attributes?: Record<string, any>): E[number];
340
348
  private findMatches;
341
- private matchWhole;
349
+ private matchExact;
342
350
  private matchSubstring;
343
351
  private matchWord;
344
352
  }
@@ -350,16 +358,22 @@ declare class StringExtractParser<E extends readonly string[] = readonly string[
350
358
  * (e.g. "Source has 1 element(s) but target requires 2" when stringExtract
351
359
  * is called without options) instead of overload-resolution mystery.
352
360
  */
353
- type CreateParserArgs = [type: "string", options?: never] | [type: "boolean", options?: never] | [type: "listToArray", options?: never] | [type: "markdownCodeBlock", options?: never] | [type: "markdownCodeBlocks", options?: never] | [type: "replaceStringTemplate", options?: never] | [type: "number", options?: NumberParserOptions] | [type: "listToKeyValue", options?: ListToKeyValueParserOptions] | [type: "json", options?: JsonParserOptions<JSONSchema | undefined>] | [
361
+ type CreateParserArgs = [type: "string", options?: never] | [type: "boolean", options?: BooleanParserOptions] | [type: "listToArray", options?: never] | [type: "markdownCodeBlock", options?: never] | [type: "markdownCodeBlocks", options?: never] | [type: "replaceStringTemplate", options?: never] | [type: "number", options?: NumberParserOptions] | [type: "listToKeyValue", options?: ListToKeyValueParserOptions] | [type: "json", options?: JsonParserOptions<JSONSchema | undefined>] | [
354
362
  type: "listToJson",
355
363
  options?: ListToJsonParserOptions<JSONSchema | undefined>
356
- ] | [type: "stringExtract", options: StringExtractParserOptions<readonly string[]>];
364
+ ] | [
365
+ type: "stringExtract",
366
+ options: StringExtractParserOptions<readonly string[]>
367
+ ];
357
368
  /**
358
369
  * Maps a concrete argument tuple back to the parser instance type, preserving
359
370
  * schema inference for json/listToJson and enum literal narrowing for
360
371
  * stringExtract.
361
372
  */
362
- type CreateParserReturn<A extends readonly unknown[]> = A extends readonly ["string", ...unknown[]] ? StringParser : A extends readonly ["boolean", ...unknown[]] ? BooleanParser : A extends readonly ["number", ...unknown[]] ? NumberParser : A extends readonly ["listToArray", ...unknown[]] ? ListToArrayParser : A extends readonly ["listToKeyValue", ...unknown[]] ? ListToKeyValueParser : A extends readonly ["markdownCodeBlock", ...unknown[]] ? MarkdownCodeBlockParser : A extends readonly ["markdownCodeBlocks", ...unknown[]] ? MarkdownCodeBlocksParser : A extends readonly ["replaceStringTemplate", ...unknown[]] ? ReplaceStringTemplateParser : A extends readonly ["json"] | readonly ["json", undefined] ? JsonParser<undefined> : A extends readonly ["json", JsonParserOptions<infer S>] ? JsonParser<S> : A extends readonly ["listToJson"] | readonly ["listToJson", undefined] ? ListToJsonParser<undefined> : A extends readonly ["listToJson", ListToJsonParserOptions<infer S>] ? ListToJsonParser<S> : A extends readonly [
373
+ type CreateParserReturn<A extends readonly unknown[]> = A extends readonly ["string", ...unknown[]] ? StringParser : A extends readonly ["boolean", ...unknown[]] ? BooleanParser : A extends readonly ["number", ...unknown[]] ? NumberParser : A extends readonly ["listToArray", ...unknown[]] ? ListToArrayParser : A extends readonly ["listToKeyValue", ...unknown[]] ? ListToKeyValueParser : A extends readonly ["markdownCodeBlock", ...unknown[]] ? MarkdownCodeBlockParser : A extends readonly ["markdownCodeBlocks", ...unknown[]] ? MarkdownCodeBlocksParser : A extends readonly ["replaceStringTemplate", ...unknown[]] ? ReplaceStringTemplateParser : A extends readonly ["json"] | readonly ["json", undefined] ? JsonParser<undefined> : A extends readonly ["json", JsonParserOptions<infer S>] ? JsonParser<S> : A extends readonly ["listToJson"] | readonly ["listToJson", undefined] ? ListToJsonParser<undefined> : A extends readonly [
374
+ "listToJson",
375
+ ListToJsonParserOptions<infer S>
376
+ ] ? ListToJsonParser<S> : A extends readonly [
363
377
  "stringExtract",
364
378
  StringExtractParserOptions<infer E extends readonly string[]>
365
379
  ] ? StringExtractParser<E> : never;
@@ -1057,11 +1071,15 @@ interface LlmExecutorWithFunctionsOptions<T extends GenericFunctionCall = "auto"
1057
1071
  jsonSchema?: Record<string, any>;
1058
1072
  }
1059
1073
 
1060
- interface JsonParserOptions<S extends JSONSchema | undefined = undefined> {
1074
+ interface ParserSchemaOptions<S extends JSONSchema | undefined = undefined> {
1061
1075
  schema?: S;
1062
1076
  validateSchema?: boolean;
1063
1077
  }
1064
- interface ListToJsonParserOptions<S extends JSONSchema | undefined = undefined> extends JsonParserOptions<S> {
1078
+ type JsonParserMatch = "exact" | "extract";
1079
+ interface JsonParserOptions<S extends JSONSchema | undefined = undefined> extends ParserSchemaOptions<S> {
1080
+ match?: JsonParserMatch;
1081
+ }
1082
+ interface ListToJsonParserOptions<S extends JSONSchema | undefined = undefined> extends ParserSchemaOptions<S> {
1065
1083
  keyTransform?: "camelCase" | "preserve";
1066
1084
  }
1067
1085
 
@@ -2069,4 +2087,4 @@ declare function createEmbedding<T extends EmbeddingProviderKey>(provider: T, op
2069
2087
  };
2070
2088
  };
2071
2089
 
2072
- export { BaseExecutor, type BaseLlm, BaseParser, BasePrompt, BaseStateItem, ChatPrompt, CustomParser, DefaultState, DefaultStateItem, type EmbeddingProviderKey, type ErrorCategory, type ErrorCodes, type ErrorContextByCode, type ExecutionContext, type ExecutorContext, type ExecutorExecutionMetadata, type HookErrorRecord, type IChatMessages, LLM_EXE_ERROR_SYMBOL, LlmExeError, LlmExecutorOpenAiFunctions, LlmExecutorWithFunctions, LlmNativeFunctionParser, type LlmProvider, type LlmProviderKey, type NormalizedProviderError, type OpenAIModelName, OpenAiFunctionParser, type ProviderErrorContext, TextPrompt, type UseLlmKey, createCallableExecutor, createChatPrompt, createCoreExecutor, createCustomParser, createDialogue, createEmbedding, createLlmExecutor, createLlmFunctionExecutor, createOpenAiCompatibleConfiguration, createParser, createPrompt, createState, createStateItem, defineSchema, guards, isLlmExeError, registerHelpers, registerPartials, useExecutors, useLlm, useLlmConfiguration, index as utils };
2090
+ export { BaseExecutor, type BaseLlm, BaseParser, BasePrompt, BaseStateItem, type BooleanParserMatch, type BooleanParserOptions, ChatPrompt, CustomParser, DefaultState, DefaultStateItem, type EmbeddingProviderKey, type ErrorCategory, type ErrorCodes, type ErrorContextByCode, type ExecutionContext, type ExecutorContext, type ExecutorExecutionMetadata, type HookErrorRecord, type IChatMessages, type JsonParserMatch, type JsonParserOptions, LLM_EXE_ERROR_SYMBOL, LlmExeError, LlmExecutorOpenAiFunctions, LlmExecutorWithFunctions, LlmNativeFunctionParser, type LlmProvider, type LlmProviderKey, type NormalizedProviderError, type NumberParserMatch, type NumberParserOptions, type OpenAIModelName, OpenAiFunctionParser, type ProviderErrorContext, type StringExtractMatch, type StringExtractParserOptions, TextPrompt, type UseLlmKey, createCallableExecutor, createChatPrompt, createCoreExecutor, createCustomParser, createDialogue, createEmbedding, createLlmExecutor, createLlmFunctionExecutor, createOpenAiCompatibleConfiguration, createParser, createPrompt, createState, createStateItem, defineSchema, guards, isLlmExeError, registerHelpers, registerPartials, useExecutors, useLlm, useLlmConfiguration, index as utils };
package/dist/index.js CHANGED
@@ -1266,9 +1266,12 @@ var BOOLEAN_VALUES = ["true", "false", "yes", "no", "y", "n", "1", "0"];
1266
1266
  var TRUTHY_VALUES = /* @__PURE__ */ new Set(["true", "yes", "y", "1"]);
1267
1267
  var FALSY_VALUES = /* @__PURE__ */ new Set(["false", "no", "n", "0"]);
1268
1268
  var MAX_ERROR_INPUT_EXCERPT_LENGTH = 500;
1269
+ var BOOLEAN_TOKEN_PATTERN = /(?<![\p{L}\p{N}])(?:true|false|yes|no|y|n|1|0)(?![\p{L}\p{N}])/giu;
1269
1270
  var BooleanParser = class extends BaseParser {
1270
- constructor() {
1271
+ constructor(options) {
1271
1272
  super("boolean");
1273
+ __publicField(this, "match");
1274
+ this.match = options?.match ?? "exact";
1272
1275
  }
1273
1276
  getInputErrorContext(text) {
1274
1277
  const context = {
@@ -1316,6 +1319,36 @@ var BooleanParser = class extends BaseParser {
1316
1319
  if (FALSY_VALUES.has(clean)) {
1317
1320
  return false;
1318
1321
  }
1322
+ if (this.match === "extract") {
1323
+ const matches = Array.from(
1324
+ text.toLowerCase().matchAll(BOOLEAN_TOKEN_PATTERN)
1325
+ ).map((match) => match[0]);
1326
+ const values = Array.from(
1327
+ new Set(
1328
+ matches.map((match) => {
1329
+ if (TRUTHY_VALUES.has(match)) return true;
1330
+ return false;
1331
+ })
1332
+ )
1333
+ );
1334
+ if (values.length === 1) {
1335
+ return values[0];
1336
+ }
1337
+ if (values.length > 1) {
1338
+ throw new LlmExeError(`Multiple boolean values found in input.`, {
1339
+ code: "parser.parse_failed",
1340
+ context: {
1341
+ operation: "BooleanParser.parse",
1342
+ parser: "boolean",
1343
+ reason: "ambiguous_boolean",
1344
+ expected: "one boolean value",
1345
+ match: this.match,
1346
+ matchCount: values.length,
1347
+ ...this.getInputErrorContext(text)
1348
+ }
1349
+ });
1350
+ }
1351
+ }
1319
1352
  throw new LlmExeError(`No boolean value found in input.`, {
1320
1353
  code: "parser.parse_failed",
1321
1354
  context: {
@@ -1323,6 +1356,7 @@ var BooleanParser = class extends BaseParser {
1323
1356
  parser: "boolean",
1324
1357
  reason: "unrecognized_boolean",
1325
1358
  expected: BOOLEAN_VALUES,
1359
+ match: this.match,
1326
1360
  ...this.getInputErrorContext(text)
1327
1361
  }
1328
1362
  });
@@ -1347,7 +1381,7 @@ function toNumber(value) {
1347
1381
 
1348
1382
  // src/parser/parsers/NumberParser.ts
1349
1383
  var NUMERIC_TOKEN_PATTERN = /(^|[^\w.,])([+-]?(?:(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d+)?|\.\d+)(?:[eE][+-]?\d+)?)(?![\w,])/g;
1350
- var WHOLE_NUMERIC_PATTERN = /^[+-]?(?:(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d+)?|\.\d+)(?:[eE][+-]?\d+)?$/;
1384
+ var EXACT_NUMERIC_PATTERN = /^[+-]?(?:(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d+)?|\.\d+)(?:[eE][+-]?\d+)?$/;
1351
1385
  var NumberParser = class extends BaseParser {
1352
1386
  constructor(options) {
1353
1387
  super("number");
@@ -1382,16 +1416,16 @@ var NumberParser = class extends BaseParser {
1382
1416
  }
1383
1417
  });
1384
1418
  }
1385
- if (this.match === "whole") {
1419
+ if (this.match === "exact") {
1386
1420
  const trimmed = text.trim();
1387
- if (!WHOLE_NUMERIC_PATTERN.test(trimmed)) {
1388
- throw new LlmExeError(`Input is not a whole numeric value.`, {
1421
+ if (!EXACT_NUMERIC_PATTERN.test(trimmed)) {
1422
+ throw new LlmExeError(`Input is not an exact numeric value.`, {
1389
1423
  code: "parser.parse_failed",
1390
1424
  context: {
1391
1425
  operation: "NumberParser.parse",
1392
1426
  parser: "number",
1393
1427
  reason: "no_numeric_value",
1394
- expected: "whole number",
1428
+ expected: "exact number",
1395
1429
  match: this.match,
1396
1430
  inputLength: text.length
1397
1431
  }
@@ -1658,9 +1692,11 @@ function isPlainObject2(value) {
1658
1692
  const proto = Object.getPrototypeOf(value);
1659
1693
  return proto === Object.prototype || proto === null;
1660
1694
  }
1661
- function normalizeWholeResponseJsonText(input) {
1695
+ function normalizeExactResponseJsonText(input) {
1662
1696
  const trimmed = input.trim();
1663
- const fenceMatch = trimmed.match(/^```([a-zA-Z]*)[^\S\r\n]*\r?\n([\s\S]*)```$/);
1697
+ const fenceMatch = trimmed.match(
1698
+ /^```([a-zA-Z]*)[^\S\r\n]*\r?\n([\s\S]*)```$/
1699
+ );
1664
1700
  if (!fenceMatch) {
1665
1701
  return trimmed;
1666
1702
  }
@@ -1670,19 +1706,82 @@ function normalizeWholeResponseJsonText(input) {
1670
1706
  }
1671
1707
  return body.trim();
1672
1708
  }
1709
+ function findBalancedJsonEnd(input, start) {
1710
+ const first = input[start];
1711
+ const stack = first === "{" ? ["}"] : first === "[" ? ["]"] : [];
1712
+ let inString = false;
1713
+ let escaping = false;
1714
+ for (let index = start + 1; index < input.length; index += 1) {
1715
+ const char = input[index];
1716
+ if (inString) {
1717
+ if (escaping) {
1718
+ escaping = false;
1719
+ } else if (char === "\\") {
1720
+ escaping = true;
1721
+ } else if (char === '"') {
1722
+ inString = false;
1723
+ }
1724
+ continue;
1725
+ }
1726
+ if (char === '"') {
1727
+ inString = true;
1728
+ continue;
1729
+ }
1730
+ if (char === "{" || char === "[") {
1731
+ stack.push(char === "{" ? "}" : "]");
1732
+ continue;
1733
+ }
1734
+ if (char !== "}" && char !== "]") {
1735
+ continue;
1736
+ }
1737
+ if (stack[stack.length - 1] !== char) {
1738
+ return void 0;
1739
+ }
1740
+ stack.pop();
1741
+ if (stack.length === 0) {
1742
+ return index;
1743
+ }
1744
+ }
1745
+ return void 0;
1746
+ }
1747
+ function extractJsonCandidates(input) {
1748
+ const candidates = [];
1749
+ for (let index = 0; index < input.length; index += 1) {
1750
+ const char = input[index];
1751
+ if (char !== "{" && char !== "[") {
1752
+ continue;
1753
+ }
1754
+ const end = findBalancedJsonEnd(input, index);
1755
+ if (end === void 0) {
1756
+ continue;
1757
+ }
1758
+ const candidate = input.slice(index, end + 1);
1759
+ try {
1760
+ candidates.push({
1761
+ parsed: JSON.parse(candidate)
1762
+ });
1763
+ index = end;
1764
+ } catch {
1765
+ }
1766
+ }
1767
+ return candidates;
1768
+ }
1673
1769
  var JsonParser = class extends BaseParserWithJson {
1674
1770
  constructor(options = {}) {
1675
1771
  super("json", options);
1676
1772
  __publicField(this, "shouldValidateSchema");
1773
+ __publicField(this, "match");
1774
+ this.match = options.match ?? "exact";
1677
1775
  this.shouldValidateSchema = !!options.schema && options.validateSchema !== false;
1678
1776
  }
1679
1777
  /**
1680
1778
  * v3 parser contract:
1681
1779
  * Category: strict
1682
- * Mode: whole-output
1780
+ * Mode: exact
1683
1781
  *
1684
- * Parses strict JSON object/array output only. Invalid JSON, empty input,
1685
- * JSON primitives, and non-plain runtime objects throw typed parser errors.
1782
+ * Parses strict JSON object/array output by default. Pass match: "extract"
1783
+ * to extract one JSON object or array from surrounding text. Invalid JSON,
1784
+ * empty input, JSON primitives, and non-plain runtime objects throw typed parser errors.
1686
1785
  * Schema validation is on by default when a schema is provided unless
1687
1786
  * validateSchema: false is explicitly set.
1688
1787
  *
@@ -1705,19 +1804,52 @@ var JsonParser = class extends BaseParserWithJson {
1705
1804
  });
1706
1805
  }
1707
1806
  try {
1708
- parsed = JSON.parse(normalizeWholeResponseJsonText(text));
1807
+ parsed = JSON.parse(normalizeExactResponseJsonText(text));
1709
1808
  } catch (cause) {
1710
- throw new LlmExeError(`Invalid JSON input.`, {
1711
- code: "parser.parse_failed",
1712
- context: {
1713
- operation: "JsonParser.parse",
1714
- parser: "json",
1715
- reason: "invalid_json",
1716
- expected: "JSON object or array",
1717
- inputLength
1718
- },
1719
- cause
1720
- });
1809
+ if (this.match === "extract") {
1810
+ const candidates = extractJsonCandidates(text);
1811
+ if (candidates.length === 1) {
1812
+ parsed = candidates[0].parsed;
1813
+ } else if (candidates.length > 1) {
1814
+ throw new LlmExeError(`Multiple JSON values found in input.`, {
1815
+ code: "parser.parse_failed",
1816
+ context: {
1817
+ operation: "JsonParser.parse",
1818
+ parser: "json",
1819
+ reason: "ambiguous_json_match",
1820
+ expected: "one JSON object or array",
1821
+ match: this.match,
1822
+ inputLength,
1823
+ matchCount: candidates.length
1824
+ }
1825
+ });
1826
+ } else {
1827
+ throw new LlmExeError(`No JSON value found in input.`, {
1828
+ code: "parser.parse_failed",
1829
+ context: {
1830
+ operation: "JsonParser.parse",
1831
+ parser: "json",
1832
+ reason: "no_json_value",
1833
+ expected: "JSON object or array",
1834
+ match: this.match,
1835
+ inputLength
1836
+ },
1837
+ cause
1838
+ });
1839
+ }
1840
+ } else {
1841
+ throw new LlmExeError(`Invalid JSON input.`, {
1842
+ code: "parser.parse_failed",
1843
+ context: {
1844
+ operation: "JsonParser.parse",
1845
+ parser: "json",
1846
+ reason: "invalid_json",
1847
+ expected: "JSON object or array",
1848
+ inputLength
1849
+ },
1850
+ cause
1851
+ });
1852
+ }
1721
1853
  }
1722
1854
  } else if (Array.isArray(text) || isPlainObject2(text)) {
1723
1855
  parsed = text;
@@ -2988,7 +3120,7 @@ var StringExtractParser = class extends BaseParser {
2988
3120
  * Mode: configured value extraction
2989
3121
  *
2990
3122
  * Returns the single configured enum value found in input. Matching is
2991
- * word-bounded by default; pass match: "whole" to require exact input or
3123
+ * word-bounded by default; pass match: "exact" to require exact input or
2992
3124
  * match: "substring" for legacy contains() behavior. Case-insensitive by
2993
3125
  * default.
2994
3126
  *
@@ -3070,8 +3202,8 @@ var StringExtractParser = class extends BaseParser {
3070
3202
  }
3071
3203
  findMatches(text) {
3072
3204
  switch (this.match) {
3073
- case "whole":
3074
- return this.matchWhole(text);
3205
+ case "exact":
3206
+ return this.matchExact(text);
3075
3207
  case "substring":
3076
3208
  return this.matchSubstring(text);
3077
3209
  case "word":
@@ -3079,7 +3211,7 @@ var StringExtractParser = class extends BaseParser {
3079
3211
  return this.matchWord(text);
3080
3212
  }
3081
3213
  }
3082
- matchWhole(text) {
3214
+ matchExact(text) {
3083
3215
  const candidate = this.ignoreCase ? text.trim().toLowerCase() : text.trim();
3084
3216
  return this.enum.filter((option) => {
3085
3217
  if (option === "") return false;
@@ -3129,36 +3261,33 @@ function createParser(...args) {
3129
3261
  case "replaceStringTemplate":
3130
3262
  return new ReplaceStringTemplateParser();
3131
3263
  case "boolean":
3132
- return new BooleanParser();
3264
+ return new BooleanParser(options);
3133
3265
  case "number":
3134
3266
  return new NumberParser(options);
3135
3267
  case "string":
3136
3268
  return new StringParser();
3137
3269
  default:
3138
- throw new LlmExeError(
3139
- `Invalid parser type: "${type}"`,
3140
- {
3141
- code: "parser.invalid_type",
3142
- context: {
3143
- operation: "createParser",
3144
- parser: type,
3145
- availableParsers: [
3146
- "json",
3147
- "string",
3148
- "boolean",
3149
- "number",
3150
- "stringExtract",
3151
- "listToArray",
3152
- "listToJson",
3153
- "listToKeyValue",
3154
- "replaceStringTemplate",
3155
- "markdownCodeBlock",
3156
- "markdownCodeBlocks"
3157
- ],
3158
- resolution: "Use a registered parser type, or define a custom parser."
3159
- }
3270
+ throw new LlmExeError(`Invalid parser type: "${type}"`, {
3271
+ code: "parser.invalid_type",
3272
+ context: {
3273
+ operation: "createParser",
3274
+ parser: type,
3275
+ availableParsers: [
3276
+ "json",
3277
+ "string",
3278
+ "boolean",
3279
+ "number",
3280
+ "stringExtract",
3281
+ "listToArray",
3282
+ "listToJson",
3283
+ "listToKeyValue",
3284
+ "replaceStringTemplate",
3285
+ "markdownCodeBlock",
3286
+ "markdownCodeBlocks"
3287
+ ],
3288
+ resolution: "Use a registered parser type, or define a custom parser."
3160
3289
  }
3161
- );
3290
+ });
3162
3291
  }
3163
3292
  }
3164
3293
  function createCustomParser(name, parserFn) {
package/dist/index.mjs CHANGED
@@ -1200,9 +1200,12 @@ var BOOLEAN_VALUES = ["true", "false", "yes", "no", "y", "n", "1", "0"];
1200
1200
  var TRUTHY_VALUES = /* @__PURE__ */ new Set(["true", "yes", "y", "1"]);
1201
1201
  var FALSY_VALUES = /* @__PURE__ */ new Set(["false", "no", "n", "0"]);
1202
1202
  var MAX_ERROR_INPUT_EXCERPT_LENGTH = 500;
1203
+ var BOOLEAN_TOKEN_PATTERN = /(?<![\p{L}\p{N}])(?:true|false|yes|no|y|n|1|0)(?![\p{L}\p{N}])/giu;
1203
1204
  var BooleanParser = class extends BaseParser {
1204
- constructor() {
1205
+ constructor(options) {
1205
1206
  super("boolean");
1207
+ __publicField(this, "match");
1208
+ this.match = options?.match ?? "exact";
1206
1209
  }
1207
1210
  getInputErrorContext(text) {
1208
1211
  const context = {
@@ -1250,6 +1253,36 @@ var BooleanParser = class extends BaseParser {
1250
1253
  if (FALSY_VALUES.has(clean)) {
1251
1254
  return false;
1252
1255
  }
1256
+ if (this.match === "extract") {
1257
+ const matches = Array.from(
1258
+ text.toLowerCase().matchAll(BOOLEAN_TOKEN_PATTERN)
1259
+ ).map((match) => match[0]);
1260
+ const values = Array.from(
1261
+ new Set(
1262
+ matches.map((match) => {
1263
+ if (TRUTHY_VALUES.has(match)) return true;
1264
+ return false;
1265
+ })
1266
+ )
1267
+ );
1268
+ if (values.length === 1) {
1269
+ return values[0];
1270
+ }
1271
+ if (values.length > 1) {
1272
+ throw new LlmExeError(`Multiple boolean values found in input.`, {
1273
+ code: "parser.parse_failed",
1274
+ context: {
1275
+ operation: "BooleanParser.parse",
1276
+ parser: "boolean",
1277
+ reason: "ambiguous_boolean",
1278
+ expected: "one boolean value",
1279
+ match: this.match,
1280
+ matchCount: values.length,
1281
+ ...this.getInputErrorContext(text)
1282
+ }
1283
+ });
1284
+ }
1285
+ }
1253
1286
  throw new LlmExeError(`No boolean value found in input.`, {
1254
1287
  code: "parser.parse_failed",
1255
1288
  context: {
@@ -1257,6 +1290,7 @@ var BooleanParser = class extends BaseParser {
1257
1290
  parser: "boolean",
1258
1291
  reason: "unrecognized_boolean",
1259
1292
  expected: BOOLEAN_VALUES,
1293
+ match: this.match,
1260
1294
  ...this.getInputErrorContext(text)
1261
1295
  }
1262
1296
  });
@@ -1281,7 +1315,7 @@ function toNumber(value) {
1281
1315
 
1282
1316
  // src/parser/parsers/NumberParser.ts
1283
1317
  var NUMERIC_TOKEN_PATTERN = /(^|[^\w.,])([+-]?(?:(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d+)?|\.\d+)(?:[eE][+-]?\d+)?)(?![\w,])/g;
1284
- var WHOLE_NUMERIC_PATTERN = /^[+-]?(?:(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d+)?|\.\d+)(?:[eE][+-]?\d+)?$/;
1318
+ var EXACT_NUMERIC_PATTERN = /^[+-]?(?:(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d+)?|\.\d+)(?:[eE][+-]?\d+)?$/;
1285
1319
  var NumberParser = class extends BaseParser {
1286
1320
  constructor(options) {
1287
1321
  super("number");
@@ -1316,16 +1350,16 @@ var NumberParser = class extends BaseParser {
1316
1350
  }
1317
1351
  });
1318
1352
  }
1319
- if (this.match === "whole") {
1353
+ if (this.match === "exact") {
1320
1354
  const trimmed = text.trim();
1321
- if (!WHOLE_NUMERIC_PATTERN.test(trimmed)) {
1322
- throw new LlmExeError(`Input is not a whole numeric value.`, {
1355
+ if (!EXACT_NUMERIC_PATTERN.test(trimmed)) {
1356
+ throw new LlmExeError(`Input is not an exact numeric value.`, {
1323
1357
  code: "parser.parse_failed",
1324
1358
  context: {
1325
1359
  operation: "NumberParser.parse",
1326
1360
  parser: "number",
1327
1361
  reason: "no_numeric_value",
1328
- expected: "whole number",
1362
+ expected: "exact number",
1329
1363
  match: this.match,
1330
1364
  inputLength: text.length
1331
1365
  }
@@ -1592,9 +1626,11 @@ function isPlainObject2(value) {
1592
1626
  const proto = Object.getPrototypeOf(value);
1593
1627
  return proto === Object.prototype || proto === null;
1594
1628
  }
1595
- function normalizeWholeResponseJsonText(input) {
1629
+ function normalizeExactResponseJsonText(input) {
1596
1630
  const trimmed = input.trim();
1597
- const fenceMatch = trimmed.match(/^```([a-zA-Z]*)[^\S\r\n]*\r?\n([\s\S]*)```$/);
1631
+ const fenceMatch = trimmed.match(
1632
+ /^```([a-zA-Z]*)[^\S\r\n]*\r?\n([\s\S]*)```$/
1633
+ );
1598
1634
  if (!fenceMatch) {
1599
1635
  return trimmed;
1600
1636
  }
@@ -1604,19 +1640,82 @@ function normalizeWholeResponseJsonText(input) {
1604
1640
  }
1605
1641
  return body.trim();
1606
1642
  }
1643
+ function findBalancedJsonEnd(input, start) {
1644
+ const first = input[start];
1645
+ const stack = first === "{" ? ["}"] : first === "[" ? ["]"] : [];
1646
+ let inString = false;
1647
+ let escaping = false;
1648
+ for (let index = start + 1; index < input.length; index += 1) {
1649
+ const char = input[index];
1650
+ if (inString) {
1651
+ if (escaping) {
1652
+ escaping = false;
1653
+ } else if (char === "\\") {
1654
+ escaping = true;
1655
+ } else if (char === '"') {
1656
+ inString = false;
1657
+ }
1658
+ continue;
1659
+ }
1660
+ if (char === '"') {
1661
+ inString = true;
1662
+ continue;
1663
+ }
1664
+ if (char === "{" || char === "[") {
1665
+ stack.push(char === "{" ? "}" : "]");
1666
+ continue;
1667
+ }
1668
+ if (char !== "}" && char !== "]") {
1669
+ continue;
1670
+ }
1671
+ if (stack[stack.length - 1] !== char) {
1672
+ return void 0;
1673
+ }
1674
+ stack.pop();
1675
+ if (stack.length === 0) {
1676
+ return index;
1677
+ }
1678
+ }
1679
+ return void 0;
1680
+ }
1681
+ function extractJsonCandidates(input) {
1682
+ const candidates = [];
1683
+ for (let index = 0; index < input.length; index += 1) {
1684
+ const char = input[index];
1685
+ if (char !== "{" && char !== "[") {
1686
+ continue;
1687
+ }
1688
+ const end = findBalancedJsonEnd(input, index);
1689
+ if (end === void 0) {
1690
+ continue;
1691
+ }
1692
+ const candidate = input.slice(index, end + 1);
1693
+ try {
1694
+ candidates.push({
1695
+ parsed: JSON.parse(candidate)
1696
+ });
1697
+ index = end;
1698
+ } catch {
1699
+ }
1700
+ }
1701
+ return candidates;
1702
+ }
1607
1703
  var JsonParser = class extends BaseParserWithJson {
1608
1704
  constructor(options = {}) {
1609
1705
  super("json", options);
1610
1706
  __publicField(this, "shouldValidateSchema");
1707
+ __publicField(this, "match");
1708
+ this.match = options.match ?? "exact";
1611
1709
  this.shouldValidateSchema = !!options.schema && options.validateSchema !== false;
1612
1710
  }
1613
1711
  /**
1614
1712
  * v3 parser contract:
1615
1713
  * Category: strict
1616
- * Mode: whole-output
1714
+ * Mode: exact
1617
1715
  *
1618
- * Parses strict JSON object/array output only. Invalid JSON, empty input,
1619
- * JSON primitives, and non-plain runtime objects throw typed parser errors.
1716
+ * Parses strict JSON object/array output by default. Pass match: "extract"
1717
+ * to extract one JSON object or array from surrounding text. Invalid JSON,
1718
+ * empty input, JSON primitives, and non-plain runtime objects throw typed parser errors.
1620
1719
  * Schema validation is on by default when a schema is provided unless
1621
1720
  * validateSchema: false is explicitly set.
1622
1721
  *
@@ -1639,19 +1738,52 @@ var JsonParser = class extends BaseParserWithJson {
1639
1738
  });
1640
1739
  }
1641
1740
  try {
1642
- parsed = JSON.parse(normalizeWholeResponseJsonText(text));
1741
+ parsed = JSON.parse(normalizeExactResponseJsonText(text));
1643
1742
  } catch (cause) {
1644
- throw new LlmExeError(`Invalid JSON input.`, {
1645
- code: "parser.parse_failed",
1646
- context: {
1647
- operation: "JsonParser.parse",
1648
- parser: "json",
1649
- reason: "invalid_json",
1650
- expected: "JSON object or array",
1651
- inputLength
1652
- },
1653
- cause
1654
- });
1743
+ if (this.match === "extract") {
1744
+ const candidates = extractJsonCandidates(text);
1745
+ if (candidates.length === 1) {
1746
+ parsed = candidates[0].parsed;
1747
+ } else if (candidates.length > 1) {
1748
+ throw new LlmExeError(`Multiple JSON values found in input.`, {
1749
+ code: "parser.parse_failed",
1750
+ context: {
1751
+ operation: "JsonParser.parse",
1752
+ parser: "json",
1753
+ reason: "ambiguous_json_match",
1754
+ expected: "one JSON object or array",
1755
+ match: this.match,
1756
+ inputLength,
1757
+ matchCount: candidates.length
1758
+ }
1759
+ });
1760
+ } else {
1761
+ throw new LlmExeError(`No JSON value found in input.`, {
1762
+ code: "parser.parse_failed",
1763
+ context: {
1764
+ operation: "JsonParser.parse",
1765
+ parser: "json",
1766
+ reason: "no_json_value",
1767
+ expected: "JSON object or array",
1768
+ match: this.match,
1769
+ inputLength
1770
+ },
1771
+ cause
1772
+ });
1773
+ }
1774
+ } else {
1775
+ throw new LlmExeError(`Invalid JSON input.`, {
1776
+ code: "parser.parse_failed",
1777
+ context: {
1778
+ operation: "JsonParser.parse",
1779
+ parser: "json",
1780
+ reason: "invalid_json",
1781
+ expected: "JSON object or array",
1782
+ inputLength
1783
+ },
1784
+ cause
1785
+ });
1786
+ }
1655
1787
  }
1656
1788
  } else if (Array.isArray(text) || isPlainObject2(text)) {
1657
1789
  parsed = text;
@@ -2922,7 +3054,7 @@ var StringExtractParser = class extends BaseParser {
2922
3054
  * Mode: configured value extraction
2923
3055
  *
2924
3056
  * Returns the single configured enum value found in input. Matching is
2925
- * word-bounded by default; pass match: "whole" to require exact input or
3057
+ * word-bounded by default; pass match: "exact" to require exact input or
2926
3058
  * match: "substring" for legacy contains() behavior. Case-insensitive by
2927
3059
  * default.
2928
3060
  *
@@ -3004,8 +3136,8 @@ var StringExtractParser = class extends BaseParser {
3004
3136
  }
3005
3137
  findMatches(text) {
3006
3138
  switch (this.match) {
3007
- case "whole":
3008
- return this.matchWhole(text);
3139
+ case "exact":
3140
+ return this.matchExact(text);
3009
3141
  case "substring":
3010
3142
  return this.matchSubstring(text);
3011
3143
  case "word":
@@ -3013,7 +3145,7 @@ var StringExtractParser = class extends BaseParser {
3013
3145
  return this.matchWord(text);
3014
3146
  }
3015
3147
  }
3016
- matchWhole(text) {
3148
+ matchExact(text) {
3017
3149
  const candidate = this.ignoreCase ? text.trim().toLowerCase() : text.trim();
3018
3150
  return this.enum.filter((option) => {
3019
3151
  if (option === "") return false;
@@ -3063,36 +3195,33 @@ function createParser(...args) {
3063
3195
  case "replaceStringTemplate":
3064
3196
  return new ReplaceStringTemplateParser();
3065
3197
  case "boolean":
3066
- return new BooleanParser();
3198
+ return new BooleanParser(options);
3067
3199
  case "number":
3068
3200
  return new NumberParser(options);
3069
3201
  case "string":
3070
3202
  return new StringParser();
3071
3203
  default:
3072
- throw new LlmExeError(
3073
- `Invalid parser type: "${type}"`,
3074
- {
3075
- code: "parser.invalid_type",
3076
- context: {
3077
- operation: "createParser",
3078
- parser: type,
3079
- availableParsers: [
3080
- "json",
3081
- "string",
3082
- "boolean",
3083
- "number",
3084
- "stringExtract",
3085
- "listToArray",
3086
- "listToJson",
3087
- "listToKeyValue",
3088
- "replaceStringTemplate",
3089
- "markdownCodeBlock",
3090
- "markdownCodeBlocks"
3091
- ],
3092
- resolution: "Use a registered parser type, or define a custom parser."
3093
- }
3204
+ throw new LlmExeError(`Invalid parser type: "${type}"`, {
3205
+ code: "parser.invalid_type",
3206
+ context: {
3207
+ operation: "createParser",
3208
+ parser: type,
3209
+ availableParsers: [
3210
+ "json",
3211
+ "string",
3212
+ "boolean",
3213
+ "number",
3214
+ "stringExtract",
3215
+ "listToArray",
3216
+ "listToJson",
3217
+ "listToKeyValue",
3218
+ "replaceStringTemplate",
3219
+ "markdownCodeBlock",
3220
+ "markdownCodeBlocks"
3221
+ ],
3222
+ resolution: "Use a registered parser type, or define a custom parser."
3094
3223
  }
3095
- );
3224
+ });
3096
3225
  }
3097
3226
  }
3098
3227
  function createCustomParser(name, parserFn) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "llm-exe",
3
- "version": "3.0.0-beta.1",
3
+ "version": "3.0.0-beta.2",
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",
package/readme.md CHANGED
@@ -85,7 +85,7 @@ Welcome back!
85
85
  ```ts
86
86
  createParser("string"); // pass-through, returns string
87
87
  createParser("json", { schema }); // JSON with optional schema validation
88
- createParser("boolean"); // extracts boolean from response
88
+ createParser("boolean"); // parses a boolean token
89
89
  createParser("number"); // extracts number from response
90
90
  createParser("stringExtract", { enum: ["yes", "no"] }); // match one of the enum values
91
91
  createParser("listToArray"); // newline-separated list → string[]