llm-exe 3.0.0 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -14,11 +14,18 @@ interface Serializable {
14
14
  }
15
15
 
16
16
  type IChatMessageRole = "system" | "model" | "assistant" | "user" | "function" | "function_call";
17
+ /**
18
+ * Loose content-block shape accepted everywhere content blocks are taken.
19
+ * Prefer `IChatMessageContent`; this stays loose (`type: string`) for
20
+ * backwards compatibility with previously-accepted shapes like
21
+ * `{ type: "image", image_url: {...} }`, which providers normalize.
22
+ */
17
23
  interface IChatMessageContentDetailed {
18
24
  type: string;
19
25
  text?: string;
20
26
  image_url?: {
21
27
  url: string;
28
+ detail?: "low" | "high" | "auto";
22
29
  };
23
30
  }
24
31
  interface IChatMessageBase {
@@ -670,7 +677,7 @@ declare function createChatPrompt<I extends Record<string, any>>(initialSystemPr
670
677
  * @template O - Output type.
671
678
  * @template H - Hooks type.
672
679
  */
673
- declare abstract class BaseExecutor<I extends PlainObject, O = any, H extends BaseExecutorHooks = BaseExecutorHooks> {
680
+ declare abstract class BaseExecutor<I extends PlainObject, O = any, H extends BaseExecutorHooks = BaseExecutorHooks, R = any, HI = any> {
674
681
  /**
675
682
  * @property id - internal id of the executor
676
683
  */
@@ -701,7 +708,7 @@ declare abstract class BaseExecutor<I extends PlainObject, O = any, H extends Ba
701
708
  * @property maxHooksPerEvent - Maximum number of hooks allowed per event
702
709
  */
703
710
  readonly maxHooksPerEvent: number;
704
- constructor(name: string, type: string, options?: CoreExecutorExecuteOptions<H>);
711
+ constructor(name: string, type: string, options?: CoreExecutorExecuteOptions<I, O, R, HI, H>);
705
712
  abstract handler(input: I, _options?: any, _context?: ExecutionContext<I, O>): Promise<any>;
706
713
  /**
707
714
  * Build a per-call execution context snapshot. Captures the current
@@ -745,7 +752,7 @@ declare abstract class BaseExecutor<I extends PlainObject, O = any, H extends Ba
745
752
  metadata(): Record<string, any>;
746
753
  getMetadata(metadata?: Record<string, any>): ExecutorMetadata;
747
754
  runHook(hook: keyof H, _metadata: ExecutorExecutionMetadata): HookErrorRecord[];
748
- setHooks(hooks?: CoreExecutorHookInput<H>): this;
755
+ setHooks(hooks?: CoreExecutorHookInput<I, O, R, HI, H>): this;
749
756
  removeHook(eventName: keyof H, fn: ListenerFunction): this;
750
757
  on(eventName: keyof H, fn: ListenerFunction): this;
751
758
  off(eventName: keyof H, fn: ListenerFunction): this;
@@ -770,9 +777,9 @@ declare abstract class BaseExecutor<I extends PlainObject, O = any, H extends Ba
770
777
  * Core Function Executor
771
778
  */
772
779
  declare class CoreExecutor<I extends PlainObject, O> extends BaseExecutor<I, O> {
773
- _handler: (input: I) => Promise<any> | any;
774
- constructor(fn: CoreExecutorInput<I, O>, options?: CoreExecutorExecuteOptions);
775
- handler(_input: I): Promise<O>;
780
+ _handler: (input: I, context?: ExecutionContext<I, O>) => Promise<any> | any;
781
+ constructor(fn: CoreExecutorInput<I, O>, options?: CoreExecutorExecuteOptions<I, O>);
782
+ handler(_input: I, _options?: any, _context?: ExecutionContext<I, O>): Promise<O>;
776
783
  }
777
784
 
778
785
  declare abstract class BaseStateItem<T> implements Serializable {
@@ -903,12 +910,12 @@ declare function createStateItem<T>(name: string, defaultValue: T): DefaultState
903
910
  /**
904
911
  * Core Executor With LLM
905
912
  */
906
- declare class LlmExecutor<Llm extends BaseLlm<any>, Prompt extends BasePrompt<Record<string, any>>, Parser extends BaseParser<any, any>, State extends BaseState> extends BaseExecutor<PromptInput<Prompt>, ParserOutput<Parser>, LlmExecutorHooks> {
913
+ declare class LlmExecutor<Llm extends BaseLlm<any>, Prompt extends BasePrompt<Record<string, any>>, Parser extends BaseParser<any, any>, State extends BaseState> extends BaseExecutor<PromptInput<Prompt>, ParserOutput<Parser>, LlmExecutorHooks, BaseLlCall, ReturnType<Prompt["format"]>> {
907
914
  llm: Llm;
908
915
  prompt: Prompt | undefined;
909
916
  promptFn: any;
910
917
  parser: StringParser | Parser;
911
- constructor(llmConfiguration: ExecutorWithLlmOptions<Llm, Prompt, Parser, State>, options?: CoreExecutorExecuteOptions<LlmExecutorHooks>);
918
+ constructor(llmConfiguration: ExecutorWithLlmOptions<Llm, Prompt, Parser, State>, options?: CoreExecutorExecuteOptions<PromptInput<Prompt>, ParserOutput<Parser>, BaseLlCall, ReturnType<Prompt["format"]>, LlmExecutorHooks>);
912
919
  /**
913
920
  * Runs the executor against the configured LLM and prompt.
914
921
  *
@@ -931,14 +938,14 @@ declare class LlmExecutor<Llm extends BaseLlm<any>, Prompt extends BasePrompt<Re
931
938
  * Core Executor With LLM
932
939
  */
933
940
  declare class LlmExecutorWithFunctions<Llm extends BaseLlm, Prompt extends BasePrompt<Record<string, any>>, Parser extends BaseParser, State extends BaseState = BaseState> extends LlmExecutor<Llm, Prompt, LlmFunctionParser<Parser>, State> {
934
- constructor(llmConfiguration: ExecutorWithLlmOptions<Llm, Prompt, Parser, State>, options?: CoreExecutorExecuteOptions<LlmExecutorHooks>);
941
+ constructor(llmConfiguration: ExecutorWithLlmOptions<Llm, Prompt, Parser, State>, options?: CoreExecutorExecuteOptions<PromptInput<Prompt>, ParserOutput<LlmFunctionParser<Parser>>, BaseLlCall, ReturnType<Prompt["format"]>, LlmExecutorHooks>);
935
942
  execute<T extends GenericFunctionCall>(_input: PromptInput<Prompt>, _options: LlmExecutorWithFunctionsOptions<T>): Promise<OutputResultContent[] | ParserOutput<Parser>>;
936
943
  }
937
944
  /**
938
945
  * @deprecated Use `LlmExecutorWithFunctions` instead.
939
946
  */
940
947
  declare class LlmExecutorOpenAiFunctions<Llm extends BaseLlm, Prompt extends BasePrompt<Record<string, any>>, Parser extends BaseParser, State extends BaseState = BaseState> extends LlmExecutor<Llm, Prompt, LlmNativeFunctionParser<Parser>, State> {
941
- constructor(llmConfiguration: ExecutorWithLlmOptions<Llm, Prompt, Parser, State>, options?: CoreExecutorExecuteOptions<LlmExecutorHooks>);
948
+ constructor(llmConfiguration: ExecutorWithLlmOptions<Llm, Prompt, Parser, State>, options?: CoreExecutorExecuteOptions<PromptInput<Prompt>, ParserOutput<LlmNativeFunctionParser<Parser>>, BaseLlCall, ReturnType<Prompt["format"]>, LlmExecutorHooks>);
942
949
  execute<T extends GenericFunctionCall>(_input: PromptInput<Prompt>, _options: LlmExecutorWithFunctionsOptions<T>): Promise<ParserOutput<Parser> | {
943
950
  name: string;
944
951
  arguments: any;
@@ -952,7 +959,7 @@ declare class LlmExecutorOpenAiFunctions<Llm extends BaseLlm, Prompt extends Bas
952
959
  * @param handler - The handler function.
953
960
  * @returns - A new CoreExecutor instance.
954
961
  */
955
- declare function createCoreExecutor<I extends PlainObject, O>(handler: (input: I) => Promise<O> | O, options?: CoreExecutorExecuteOptions): CoreExecutor<I, O>;
962
+ declare function createCoreExecutor<I extends PlainObject, O>(handler: (input: I, context?: ExecutionContext<I, O>) => Promise<O> | O, options?: CoreExecutorExecuteOptions<I, O>): CoreExecutor<I, O>;
956
963
  /**
957
964
  * Function to create a core executor with Llm.
958
965
  * @template Llm - Llm type.
@@ -962,8 +969,8 @@ declare function createCoreExecutor<I extends PlainObject, O>(handler: (input: I
962
969
  * @param options - Options for BaseExecutorV3.
963
970
  * @returns - A new LlmExecutor instance.
964
971
  */
965
- declare function createLlmExecutor<Llm extends BaseLlm<any>, Prompt extends BasePrompt<any>, Parser extends BaseParser, State extends BaseState>(llmConfiguration: ExecutorWithLlmOptions<Llm, Prompt, Parser, State>, options?: CoreExecutorExecuteOptions<LlmExecutorHooks>): LlmExecutor<Llm, Prompt, Parser, State>;
966
- declare function createLlmFunctionExecutor<Llm extends BaseLlm, Prompt extends BasePrompt<Record<string, any>>, Parser extends BaseParser, State extends BaseState>(llmConfiguration: ExecutorWithLlmOptions<Llm, Prompt, Parser, State>, options?: CoreExecutorExecuteOptions<LlmExecutorHooks>): LlmExecutorWithFunctions<Llm, Prompt, Parser, State>;
972
+ declare function createLlmExecutor<Llm extends BaseLlm<any>, Prompt extends BasePrompt<any>, Parser extends BaseParser, State extends BaseState>(llmConfiguration: ExecutorWithLlmOptions<Llm, Prompt, Parser, State>, options?: CoreExecutorExecuteOptions<PromptInput<Prompt>, ParserOutput<Parser>, BaseLlCall, ReturnType<Prompt["format"]>, LlmExecutorHooks>): LlmExecutor<Llm, Prompt, Parser, State>;
973
+ declare function createLlmFunctionExecutor<Llm extends BaseLlm, Prompt extends BasePrompt<Record<string, any>>, Parser extends BaseParser, State extends BaseState>(llmConfiguration: ExecutorWithLlmOptions<Llm, Prompt, Parser, State>, options?: CoreExecutorExecuteOptions<PromptInput<Prompt>, ParserOutput<LlmFunctionParser<Parser>>, BaseLlCall, ReturnType<Prompt["format"]>, LlmExecutorHooks>): LlmExecutorWithFunctions<Llm, Prompt, Parser, State>;
967
974
 
968
975
  declare const hookOnComplete = "onComplete";
969
976
  declare const hookOnError = "onError";
@@ -982,7 +989,7 @@ interface ExecutorWithLlmOptions<Llm, Prompt, Parser, State> {
982
989
  }
983
990
  interface CoreExecutorInput<I, O> {
984
991
  name?: string;
985
- handler: (input: I) => Promise<O> | O;
992
+ handler: (input: I, context?: ExecutionContext<I, O>) => Promise<O> | O;
986
993
  getHandlerInput?(input: I): Promise<any>;
987
994
  getHandlerOutput?(out: any): O;
988
995
  }
@@ -1006,12 +1013,12 @@ interface HookErrorRecord {
1006
1013
  errorContext?: unknown;
1007
1014
  errorCause?: unknown;
1008
1015
  }
1009
- interface ExecutorExecutionMetadata<I = any, O = any> {
1016
+ interface ExecutorExecutionMetadata<I = any, O = any, R = any, HI = any> {
1010
1017
  start: null | number;
1011
1018
  end: null | number;
1012
1019
  input: I;
1013
- handlerInput?: any;
1014
- handlerOutput?: any;
1020
+ handlerInput?: HI;
1021
+ handlerOutput?: R;
1015
1022
  output?: O;
1016
1023
  errorMessage?: string;
1017
1024
  error?: Error;
@@ -1045,11 +1052,20 @@ interface BaseExecutorHooks {
1045
1052
  }
1046
1053
  interface LlmExecutorHooks extends BaseExecutorHooks {
1047
1054
  }
1048
- type CoreExecutorHookInput<H = BaseExecutorHooks> = {
1049
- [key in keyof H]?: ListenerFunction | ListenerFunction[];
1055
+ /**
1056
+ * A single executor hook callback. Receives the per-run execution metadata
1057
+ * (input/output/error fields typed via I/O) followed by the executor's own
1058
+ * identity metadata. This is the shape fired for onSuccess / onError /
1059
+ * onComplete — the metadata fields that are populated differ per event
1060
+ * (`output` on success, `error` on failure), but all are optional on
1061
+ * {@link ExecutorExecutionMetadata}, so one signature covers every hook.
1062
+ */
1063
+ type ExecutorHookFunction<I = any, O = any, R = any, HI = any> = (metadata: ExecutorExecutionMetadata<I, O, R, HI>, executor: ExecutorMetadata) => void;
1064
+ type CoreExecutorHookInput<I = any, O = any, R = any, HI = any, H = BaseExecutorHooks> = {
1065
+ [key in keyof H]?: ExecutorHookFunction<I, O, R, HI> | ExecutorHookFunction<I, O, R, HI>[];
1050
1066
  };
1051
- interface CoreExecutorExecuteOptions<T = BaseExecutorHooks> {
1052
- hooks?: CoreExecutorHookInput<T>;
1067
+ interface CoreExecutorExecuteOptions<I = any, O = any, R = any, HI = any, T = BaseExecutorHooks> {
1068
+ hooks?: CoreExecutorHookInput<I, O, R, HI, T>;
1053
1069
  }
1054
1070
  interface CallableExecutorCore {
1055
1071
  name: string;
@@ -1073,6 +1089,18 @@ interface LlmExecutorWithFunctionsOptions<T extends GenericFunctionCall = "auto"
1073
1089
 
1074
1090
  interface ParserSchemaOptions<S extends JSONSchema | undefined = undefined> {
1075
1091
  schema?: S;
1092
+ /**
1093
+ * Controls schema enforcement when `schema` is provided. Validation —
1094
+ * including `required` fields and type/constraint checks — is **on by
1095
+ * default** whenever a schema is set; invalid or incomplete input throws a
1096
+ * `parser.schema_validation_failed` error.
1097
+ *
1098
+ * Set `validateSchema: false` to opt out into the legacy filter/default-only
1099
+ * behavior: unknown keys are stripped and defaults applied, but `required`
1100
+ * fields and constraints are NOT checked. Has no effect when no schema is set.
1101
+ *
1102
+ * @default true (when `schema` is provided)
1103
+ */
1076
1104
  validateSchema?: boolean;
1077
1105
  }
1078
1106
  type JsonParserMatch = "exact" | "extract";
@@ -1771,6 +1799,9 @@ type LlmExeErrorJson<C extends ErrorCodes = ErrorCodes> = {
1771
1799
  cause?: SerializableCause;
1772
1800
  truncated?: boolean;
1773
1801
  };
1802
+ type SerializeOptions = {
1803
+ includeStack?: boolean;
1804
+ };
1774
1805
 
1775
1806
  declare function enforceResultAttributes<O>(input: any): {
1776
1807
  result: O;
@@ -1910,6 +1941,8 @@ declare function importHelpers(_helpers: {
1910
1941
 
1911
1942
  declare function filterObjectOnSchema(schema: any, doc: any, detach?: any, property?: string): any;
1912
1943
 
1944
+ declare function escapeTemplateString(input: string): string;
1945
+
1913
1946
  declare const asyncCallWithTimeout: <T = any>(asyncPromise: Promise<T>, timeLimit?: number) => Promise<T>;
1914
1947
 
1915
1948
  declare function guessProviderFromModel(payload: {
@@ -1929,6 +1962,7 @@ declare const index_LlmExeError: typeof LlmExeError;
1929
1962
  declare const index_assert: typeof assert;
1930
1963
  declare const index_asyncCallWithTimeout: typeof asyncCallWithTimeout;
1931
1964
  declare const index_defineSchema: typeof defineSchema;
1965
+ declare const index_escapeTemplateString: typeof escapeTemplateString;
1932
1966
  declare const index_filterObjectOnSchema: typeof filterObjectOnSchema;
1933
1967
  declare const index_guessProviderFromModel: typeof guessProviderFromModel;
1934
1968
  declare const index_importHelpers: typeof importHelpers;
@@ -1942,7 +1976,7 @@ declare const index_registerPartials: typeof registerPartials;
1942
1976
  declare const index_replaceTemplateString: typeof replaceTemplateString;
1943
1977
  declare const index_replaceTemplateStringAsync: typeof replaceTemplateStringAsync;
1944
1978
  declare namespace index {
1945
- export { index_LLM_EXE_ERROR_SYMBOL as LLM_EXE_ERROR_SYMBOL, index_LlmExeError as LlmExeError, index_assert as assert, index_asyncCallWithTimeout as asyncCallWithTimeout, index_defineSchema as defineSchema, index_filterObjectOnSchema as filterObjectOnSchema, index_guessProviderFromModel as guessProviderFromModel, index_importHelpers as importHelpers, index_importPartials as importPartials, index_isLlmExeError as isLlmExeError, index_isObjectStringified as isObjectStringified, index_maybeParseJSON as maybeParseJSON, index_maybeStringifyJSON as maybeStringifyJSON, index_registerHelpers as registerHelpers, index_registerPartials as registerPartials, index_replaceTemplateString as replaceTemplateString, index_replaceTemplateStringAsync as replaceTemplateStringAsync };
1979
+ export { index_LLM_EXE_ERROR_SYMBOL as LLM_EXE_ERROR_SYMBOL, index_LlmExeError as LlmExeError, index_assert as assert, index_asyncCallWithTimeout as asyncCallWithTimeout, index_defineSchema as defineSchema, index_escapeTemplateString as escapeTemplateString, index_filterObjectOnSchema as filterObjectOnSchema, index_guessProviderFromModel as guessProviderFromModel, index_importHelpers as importHelpers, index_importPartials as importPartials, index_isLlmExeError as isLlmExeError, index_isObjectStringified as isObjectStringified, index_maybeParseJSON as maybeParseJSON, index_maybeStringifyJSON as maybeStringifyJSON, index_registerHelpers as registerHelpers, index_registerPartials as registerPartials, index_replaceTemplateString as replaceTemplateString, index_replaceTemplateStringAsync as replaceTemplateStringAsync };
1946
1980
  }
1947
1981
 
1948
1982
  declare function isOutputResult(obj: any): obj is OutputResult;
@@ -2092,4 +2126,8 @@ declare function createEmbedding<T extends EmbeddingProviderKey>(provider: T, op
2092
2126
  };
2093
2127
  };
2094
2128
 
2095
- 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 };
2129
+ declare function serializeLlmExeError(error: unknown, options?: SerializeOptions): JsonSafe;
2130
+
2131
+ declare function formatLlmExeErrorForLog(error: unknown): string;
2132
+
2133
+ 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, formatLlmExeErrorForLog, guards, isLlmExeError, registerHelpers, registerPartials, serializeLlmExeError, useExecutors, useLlm, useLlmConfiguration, index as utils };
package/dist/index.d.ts CHANGED
@@ -14,11 +14,18 @@ interface Serializable {
14
14
  }
15
15
 
16
16
  type IChatMessageRole = "system" | "model" | "assistant" | "user" | "function" | "function_call";
17
+ /**
18
+ * Loose content-block shape accepted everywhere content blocks are taken.
19
+ * Prefer `IChatMessageContent`; this stays loose (`type: string`) for
20
+ * backwards compatibility with previously-accepted shapes like
21
+ * `{ type: "image", image_url: {...} }`, which providers normalize.
22
+ */
17
23
  interface IChatMessageContentDetailed {
18
24
  type: string;
19
25
  text?: string;
20
26
  image_url?: {
21
27
  url: string;
28
+ detail?: "low" | "high" | "auto";
22
29
  };
23
30
  }
24
31
  interface IChatMessageBase {
@@ -670,7 +677,7 @@ declare function createChatPrompt<I extends Record<string, any>>(initialSystemPr
670
677
  * @template O - Output type.
671
678
  * @template H - Hooks type.
672
679
  */
673
- declare abstract class BaseExecutor<I extends PlainObject, O = any, H extends BaseExecutorHooks = BaseExecutorHooks> {
680
+ declare abstract class BaseExecutor<I extends PlainObject, O = any, H extends BaseExecutorHooks = BaseExecutorHooks, R = any, HI = any> {
674
681
  /**
675
682
  * @property id - internal id of the executor
676
683
  */
@@ -701,7 +708,7 @@ declare abstract class BaseExecutor<I extends PlainObject, O = any, H extends Ba
701
708
  * @property maxHooksPerEvent - Maximum number of hooks allowed per event
702
709
  */
703
710
  readonly maxHooksPerEvent: number;
704
- constructor(name: string, type: string, options?: CoreExecutorExecuteOptions<H>);
711
+ constructor(name: string, type: string, options?: CoreExecutorExecuteOptions<I, O, R, HI, H>);
705
712
  abstract handler(input: I, _options?: any, _context?: ExecutionContext<I, O>): Promise<any>;
706
713
  /**
707
714
  * Build a per-call execution context snapshot. Captures the current
@@ -745,7 +752,7 @@ declare abstract class BaseExecutor<I extends PlainObject, O = any, H extends Ba
745
752
  metadata(): Record<string, any>;
746
753
  getMetadata(metadata?: Record<string, any>): ExecutorMetadata;
747
754
  runHook(hook: keyof H, _metadata: ExecutorExecutionMetadata): HookErrorRecord[];
748
- setHooks(hooks?: CoreExecutorHookInput<H>): this;
755
+ setHooks(hooks?: CoreExecutorHookInput<I, O, R, HI, H>): this;
749
756
  removeHook(eventName: keyof H, fn: ListenerFunction): this;
750
757
  on(eventName: keyof H, fn: ListenerFunction): this;
751
758
  off(eventName: keyof H, fn: ListenerFunction): this;
@@ -770,9 +777,9 @@ declare abstract class BaseExecutor<I extends PlainObject, O = any, H extends Ba
770
777
  * Core Function Executor
771
778
  */
772
779
  declare class CoreExecutor<I extends PlainObject, O> extends BaseExecutor<I, O> {
773
- _handler: (input: I) => Promise<any> | any;
774
- constructor(fn: CoreExecutorInput<I, O>, options?: CoreExecutorExecuteOptions);
775
- handler(_input: I): Promise<O>;
780
+ _handler: (input: I, context?: ExecutionContext<I, O>) => Promise<any> | any;
781
+ constructor(fn: CoreExecutorInput<I, O>, options?: CoreExecutorExecuteOptions<I, O>);
782
+ handler(_input: I, _options?: any, _context?: ExecutionContext<I, O>): Promise<O>;
776
783
  }
777
784
 
778
785
  declare abstract class BaseStateItem<T> implements Serializable {
@@ -903,12 +910,12 @@ declare function createStateItem<T>(name: string, defaultValue: T): DefaultState
903
910
  /**
904
911
  * Core Executor With LLM
905
912
  */
906
- declare class LlmExecutor<Llm extends BaseLlm<any>, Prompt extends BasePrompt<Record<string, any>>, Parser extends BaseParser<any, any>, State extends BaseState> extends BaseExecutor<PromptInput<Prompt>, ParserOutput<Parser>, LlmExecutorHooks> {
913
+ declare class LlmExecutor<Llm extends BaseLlm<any>, Prompt extends BasePrompt<Record<string, any>>, Parser extends BaseParser<any, any>, State extends BaseState> extends BaseExecutor<PromptInput<Prompt>, ParserOutput<Parser>, LlmExecutorHooks, BaseLlCall, ReturnType<Prompt["format"]>> {
907
914
  llm: Llm;
908
915
  prompt: Prompt | undefined;
909
916
  promptFn: any;
910
917
  parser: StringParser | Parser;
911
- constructor(llmConfiguration: ExecutorWithLlmOptions<Llm, Prompt, Parser, State>, options?: CoreExecutorExecuteOptions<LlmExecutorHooks>);
918
+ constructor(llmConfiguration: ExecutorWithLlmOptions<Llm, Prompt, Parser, State>, options?: CoreExecutorExecuteOptions<PromptInput<Prompt>, ParserOutput<Parser>, BaseLlCall, ReturnType<Prompt["format"]>, LlmExecutorHooks>);
912
919
  /**
913
920
  * Runs the executor against the configured LLM and prompt.
914
921
  *
@@ -931,14 +938,14 @@ declare class LlmExecutor<Llm extends BaseLlm<any>, Prompt extends BasePrompt<Re
931
938
  * Core Executor With LLM
932
939
  */
933
940
  declare class LlmExecutorWithFunctions<Llm extends BaseLlm, Prompt extends BasePrompt<Record<string, any>>, Parser extends BaseParser, State extends BaseState = BaseState> extends LlmExecutor<Llm, Prompt, LlmFunctionParser<Parser>, State> {
934
- constructor(llmConfiguration: ExecutorWithLlmOptions<Llm, Prompt, Parser, State>, options?: CoreExecutorExecuteOptions<LlmExecutorHooks>);
941
+ constructor(llmConfiguration: ExecutorWithLlmOptions<Llm, Prompt, Parser, State>, options?: CoreExecutorExecuteOptions<PromptInput<Prompt>, ParserOutput<LlmFunctionParser<Parser>>, BaseLlCall, ReturnType<Prompt["format"]>, LlmExecutorHooks>);
935
942
  execute<T extends GenericFunctionCall>(_input: PromptInput<Prompt>, _options: LlmExecutorWithFunctionsOptions<T>): Promise<OutputResultContent[] | ParserOutput<Parser>>;
936
943
  }
937
944
  /**
938
945
  * @deprecated Use `LlmExecutorWithFunctions` instead.
939
946
  */
940
947
  declare class LlmExecutorOpenAiFunctions<Llm extends BaseLlm, Prompt extends BasePrompt<Record<string, any>>, Parser extends BaseParser, State extends BaseState = BaseState> extends LlmExecutor<Llm, Prompt, LlmNativeFunctionParser<Parser>, State> {
941
- constructor(llmConfiguration: ExecutorWithLlmOptions<Llm, Prompt, Parser, State>, options?: CoreExecutorExecuteOptions<LlmExecutorHooks>);
948
+ constructor(llmConfiguration: ExecutorWithLlmOptions<Llm, Prompt, Parser, State>, options?: CoreExecutorExecuteOptions<PromptInput<Prompt>, ParserOutput<LlmNativeFunctionParser<Parser>>, BaseLlCall, ReturnType<Prompt["format"]>, LlmExecutorHooks>);
942
949
  execute<T extends GenericFunctionCall>(_input: PromptInput<Prompt>, _options: LlmExecutorWithFunctionsOptions<T>): Promise<ParserOutput<Parser> | {
943
950
  name: string;
944
951
  arguments: any;
@@ -952,7 +959,7 @@ declare class LlmExecutorOpenAiFunctions<Llm extends BaseLlm, Prompt extends Bas
952
959
  * @param handler - The handler function.
953
960
  * @returns - A new CoreExecutor instance.
954
961
  */
955
- declare function createCoreExecutor<I extends PlainObject, O>(handler: (input: I) => Promise<O> | O, options?: CoreExecutorExecuteOptions): CoreExecutor<I, O>;
962
+ declare function createCoreExecutor<I extends PlainObject, O>(handler: (input: I, context?: ExecutionContext<I, O>) => Promise<O> | O, options?: CoreExecutorExecuteOptions<I, O>): CoreExecutor<I, O>;
956
963
  /**
957
964
  * Function to create a core executor with Llm.
958
965
  * @template Llm - Llm type.
@@ -962,8 +969,8 @@ declare function createCoreExecutor<I extends PlainObject, O>(handler: (input: I
962
969
  * @param options - Options for BaseExecutorV3.
963
970
  * @returns - A new LlmExecutor instance.
964
971
  */
965
- declare function createLlmExecutor<Llm extends BaseLlm<any>, Prompt extends BasePrompt<any>, Parser extends BaseParser, State extends BaseState>(llmConfiguration: ExecutorWithLlmOptions<Llm, Prompt, Parser, State>, options?: CoreExecutorExecuteOptions<LlmExecutorHooks>): LlmExecutor<Llm, Prompt, Parser, State>;
966
- declare function createLlmFunctionExecutor<Llm extends BaseLlm, Prompt extends BasePrompt<Record<string, any>>, Parser extends BaseParser, State extends BaseState>(llmConfiguration: ExecutorWithLlmOptions<Llm, Prompt, Parser, State>, options?: CoreExecutorExecuteOptions<LlmExecutorHooks>): LlmExecutorWithFunctions<Llm, Prompt, Parser, State>;
972
+ declare function createLlmExecutor<Llm extends BaseLlm<any>, Prompt extends BasePrompt<any>, Parser extends BaseParser, State extends BaseState>(llmConfiguration: ExecutorWithLlmOptions<Llm, Prompt, Parser, State>, options?: CoreExecutorExecuteOptions<PromptInput<Prompt>, ParserOutput<Parser>, BaseLlCall, ReturnType<Prompt["format"]>, LlmExecutorHooks>): LlmExecutor<Llm, Prompt, Parser, State>;
973
+ declare function createLlmFunctionExecutor<Llm extends BaseLlm, Prompt extends BasePrompt<Record<string, any>>, Parser extends BaseParser, State extends BaseState>(llmConfiguration: ExecutorWithLlmOptions<Llm, Prompt, Parser, State>, options?: CoreExecutorExecuteOptions<PromptInput<Prompt>, ParserOutput<LlmFunctionParser<Parser>>, BaseLlCall, ReturnType<Prompt["format"]>, LlmExecutorHooks>): LlmExecutorWithFunctions<Llm, Prompt, Parser, State>;
967
974
 
968
975
  declare const hookOnComplete = "onComplete";
969
976
  declare const hookOnError = "onError";
@@ -982,7 +989,7 @@ interface ExecutorWithLlmOptions<Llm, Prompt, Parser, State> {
982
989
  }
983
990
  interface CoreExecutorInput<I, O> {
984
991
  name?: string;
985
- handler: (input: I) => Promise<O> | O;
992
+ handler: (input: I, context?: ExecutionContext<I, O>) => Promise<O> | O;
986
993
  getHandlerInput?(input: I): Promise<any>;
987
994
  getHandlerOutput?(out: any): O;
988
995
  }
@@ -1006,12 +1013,12 @@ interface HookErrorRecord {
1006
1013
  errorContext?: unknown;
1007
1014
  errorCause?: unknown;
1008
1015
  }
1009
- interface ExecutorExecutionMetadata<I = any, O = any> {
1016
+ interface ExecutorExecutionMetadata<I = any, O = any, R = any, HI = any> {
1010
1017
  start: null | number;
1011
1018
  end: null | number;
1012
1019
  input: I;
1013
- handlerInput?: any;
1014
- handlerOutput?: any;
1020
+ handlerInput?: HI;
1021
+ handlerOutput?: R;
1015
1022
  output?: O;
1016
1023
  errorMessage?: string;
1017
1024
  error?: Error;
@@ -1045,11 +1052,20 @@ interface BaseExecutorHooks {
1045
1052
  }
1046
1053
  interface LlmExecutorHooks extends BaseExecutorHooks {
1047
1054
  }
1048
- type CoreExecutorHookInput<H = BaseExecutorHooks> = {
1049
- [key in keyof H]?: ListenerFunction | ListenerFunction[];
1055
+ /**
1056
+ * A single executor hook callback. Receives the per-run execution metadata
1057
+ * (input/output/error fields typed via I/O) followed by the executor's own
1058
+ * identity metadata. This is the shape fired for onSuccess / onError /
1059
+ * onComplete — the metadata fields that are populated differ per event
1060
+ * (`output` on success, `error` on failure), but all are optional on
1061
+ * {@link ExecutorExecutionMetadata}, so one signature covers every hook.
1062
+ */
1063
+ type ExecutorHookFunction<I = any, O = any, R = any, HI = any> = (metadata: ExecutorExecutionMetadata<I, O, R, HI>, executor: ExecutorMetadata) => void;
1064
+ type CoreExecutorHookInput<I = any, O = any, R = any, HI = any, H = BaseExecutorHooks> = {
1065
+ [key in keyof H]?: ExecutorHookFunction<I, O, R, HI> | ExecutorHookFunction<I, O, R, HI>[];
1050
1066
  };
1051
- interface CoreExecutorExecuteOptions<T = BaseExecutorHooks> {
1052
- hooks?: CoreExecutorHookInput<T>;
1067
+ interface CoreExecutorExecuteOptions<I = any, O = any, R = any, HI = any, T = BaseExecutorHooks> {
1068
+ hooks?: CoreExecutorHookInput<I, O, R, HI, T>;
1053
1069
  }
1054
1070
  interface CallableExecutorCore {
1055
1071
  name: string;
@@ -1073,6 +1089,18 @@ interface LlmExecutorWithFunctionsOptions<T extends GenericFunctionCall = "auto"
1073
1089
 
1074
1090
  interface ParserSchemaOptions<S extends JSONSchema | undefined = undefined> {
1075
1091
  schema?: S;
1092
+ /**
1093
+ * Controls schema enforcement when `schema` is provided. Validation —
1094
+ * including `required` fields and type/constraint checks — is **on by
1095
+ * default** whenever a schema is set; invalid or incomplete input throws a
1096
+ * `parser.schema_validation_failed` error.
1097
+ *
1098
+ * Set `validateSchema: false` to opt out into the legacy filter/default-only
1099
+ * behavior: unknown keys are stripped and defaults applied, but `required`
1100
+ * fields and constraints are NOT checked. Has no effect when no schema is set.
1101
+ *
1102
+ * @default true (when `schema` is provided)
1103
+ */
1076
1104
  validateSchema?: boolean;
1077
1105
  }
1078
1106
  type JsonParserMatch = "exact" | "extract";
@@ -1771,6 +1799,9 @@ type LlmExeErrorJson<C extends ErrorCodes = ErrorCodes> = {
1771
1799
  cause?: SerializableCause;
1772
1800
  truncated?: boolean;
1773
1801
  };
1802
+ type SerializeOptions = {
1803
+ includeStack?: boolean;
1804
+ };
1774
1805
 
1775
1806
  declare function enforceResultAttributes<O>(input: any): {
1776
1807
  result: O;
@@ -1910,6 +1941,8 @@ declare function importHelpers(_helpers: {
1910
1941
 
1911
1942
  declare function filterObjectOnSchema(schema: any, doc: any, detach?: any, property?: string): any;
1912
1943
 
1944
+ declare function escapeTemplateString(input: string): string;
1945
+
1913
1946
  declare const asyncCallWithTimeout: <T = any>(asyncPromise: Promise<T>, timeLimit?: number) => Promise<T>;
1914
1947
 
1915
1948
  declare function guessProviderFromModel(payload: {
@@ -1929,6 +1962,7 @@ declare const index_LlmExeError: typeof LlmExeError;
1929
1962
  declare const index_assert: typeof assert;
1930
1963
  declare const index_asyncCallWithTimeout: typeof asyncCallWithTimeout;
1931
1964
  declare const index_defineSchema: typeof defineSchema;
1965
+ declare const index_escapeTemplateString: typeof escapeTemplateString;
1932
1966
  declare const index_filterObjectOnSchema: typeof filterObjectOnSchema;
1933
1967
  declare const index_guessProviderFromModel: typeof guessProviderFromModel;
1934
1968
  declare const index_importHelpers: typeof importHelpers;
@@ -1942,7 +1976,7 @@ declare const index_registerPartials: typeof registerPartials;
1942
1976
  declare const index_replaceTemplateString: typeof replaceTemplateString;
1943
1977
  declare const index_replaceTemplateStringAsync: typeof replaceTemplateStringAsync;
1944
1978
  declare namespace index {
1945
- export { index_LLM_EXE_ERROR_SYMBOL as LLM_EXE_ERROR_SYMBOL, index_LlmExeError as LlmExeError, index_assert as assert, index_asyncCallWithTimeout as asyncCallWithTimeout, index_defineSchema as defineSchema, index_filterObjectOnSchema as filterObjectOnSchema, index_guessProviderFromModel as guessProviderFromModel, index_importHelpers as importHelpers, index_importPartials as importPartials, index_isLlmExeError as isLlmExeError, index_isObjectStringified as isObjectStringified, index_maybeParseJSON as maybeParseJSON, index_maybeStringifyJSON as maybeStringifyJSON, index_registerHelpers as registerHelpers, index_registerPartials as registerPartials, index_replaceTemplateString as replaceTemplateString, index_replaceTemplateStringAsync as replaceTemplateStringAsync };
1979
+ export { index_LLM_EXE_ERROR_SYMBOL as LLM_EXE_ERROR_SYMBOL, index_LlmExeError as LlmExeError, index_assert as assert, index_asyncCallWithTimeout as asyncCallWithTimeout, index_defineSchema as defineSchema, index_escapeTemplateString as escapeTemplateString, index_filterObjectOnSchema as filterObjectOnSchema, index_guessProviderFromModel as guessProviderFromModel, index_importHelpers as importHelpers, index_importPartials as importPartials, index_isLlmExeError as isLlmExeError, index_isObjectStringified as isObjectStringified, index_maybeParseJSON as maybeParseJSON, index_maybeStringifyJSON as maybeStringifyJSON, index_registerHelpers as registerHelpers, index_registerPartials as registerPartials, index_replaceTemplateString as replaceTemplateString, index_replaceTemplateStringAsync as replaceTemplateStringAsync };
1946
1980
  }
1947
1981
 
1948
1982
  declare function isOutputResult(obj: any): obj is OutputResult;
@@ -2092,4 +2126,8 @@ declare function createEmbedding<T extends EmbeddingProviderKey>(provider: T, op
2092
2126
  };
2093
2127
  };
2094
2128
 
2095
- 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 };
2129
+ declare function serializeLlmExeError(error: unknown, options?: SerializeOptions): JsonSafe;
2130
+
2131
+ declare function formatLlmExeErrorForLog(error: unknown): string;
2132
+
2133
+ 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, formatLlmExeErrorForLog, guards, isLlmExeError, registerHelpers, registerPartials, serializeLlmExeError, useExecutors, useLlm, useLlmConfiguration, index as utils };
package/dist/index.js CHANGED
@@ -67,10 +67,12 @@ __export(index_exports, {
67
67
  createState: () => createState,
68
68
  createStateItem: () => createStateItem,
69
69
  defineSchema: () => defineSchema,
70
+ formatLlmExeErrorForLog: () => formatLlmExeErrorForLog,
70
71
  guards: () => guards_exports,
71
72
  isLlmExeError: () => isLlmExeError,
72
73
  registerHelpers: () => registerHelpers,
73
74
  registerPartials: () => registerPartials,
75
+ serializeLlmExeError: () => serializeLlmExeError,
74
76
  useExecutors: () => useExecutors,
75
77
  useLlm: () => useLlm,
76
78
  useLlmConfiguration: () => useLlmConfiguration,
@@ -530,6 +532,48 @@ function formatErrorList(values, options) {
530
532
  }
531
533
  return parts.join(", ");
532
534
  }
535
+ function formatLlmExeErrorForLog(error) {
536
+ if (!error || typeof error !== "object") {
537
+ return formatErrorValue(error);
538
+ }
539
+ const e = error;
540
+ const name = typeof e.name === "string" && e.name ? e.name : "Error";
541
+ const message = typeof e.message === "string" ? e.message : "";
542
+ const code = typeof e.code === "string" ? e.code : void 0;
543
+ const category = typeof e.category === "string" ? e.category : void 0;
544
+ let header;
545
+ if (code) {
546
+ header = `${name} [${code}]: ${message}`;
547
+ } else if (category) {
548
+ header = `${name} [${category}]: ${message}`;
549
+ } else {
550
+ header = `${name}: ${message}`;
551
+ }
552
+ const chain = [];
553
+ let current = e.cause;
554
+ let depth = 0;
555
+ const seen = /* @__PURE__ */ new WeakSet();
556
+ while (current && depth < 5) {
557
+ if (typeof current === "object") {
558
+ if (seen.has(current)) {
559
+ chain.push("Caused by: [Circular]");
560
+ break;
561
+ }
562
+ seen.add(current);
563
+ }
564
+ const c = current;
565
+ const cName = typeof c.name === "string" && c.name ? c.name : "Error";
566
+ const cMsg = typeof c.message === "string" ? c.message : String(current);
567
+ const cCode = typeof c.code === "string" ? c.code : void 0;
568
+ chain.push(
569
+ cCode ? `Caused by: ${cName} [${cCode}]: ${cMsg}` : `Caused by: ${cName}: ${cMsg}`
570
+ );
571
+ current = c.cause;
572
+ depth++;
573
+ }
574
+ return chain.length > 0 ? `${header}
575
+ ${chain.join("\n")}` : header;
576
+ }
533
577
 
534
578
  // src/errors/createLlmExeError.ts
535
579
  var DOCS_BASE_URL = "https://llm-exe.com";
@@ -1051,7 +1095,9 @@ var BaseExecutor = class {
1051
1095
  return this;
1052
1096
  }
1053
1097
  on(eventName, fn) {
1054
- return this.setHooks({ [eventName]: fn });
1098
+ return this.setHooks({
1099
+ [eventName]: fn
1100
+ });
1055
1101
  }
1056
1102
  off(eventName, fn) {
1057
1103
  return this.removeHook(eventName, fn);
@@ -1149,8 +1195,8 @@ var CoreExecutor = class extends BaseExecutor {
1149
1195
  __publicField(this, "_handler");
1150
1196
  this._handler = fn.handler.bind(null);
1151
1197
  }
1152
- async handler(_input) {
1153
- return this._handler.call(null, _input);
1198
+ async handler(_input, _options, _context) {
1199
+ return this._handler.call(null, _input, _context);
1154
1200
  }
1155
1201
  };
1156
1202
 
@@ -3302,6 +3348,7 @@ __export(utils_exports, {
3302
3348
  assert: () => assert,
3303
3349
  asyncCallWithTimeout: () => asyncCallWithTimeout,
3304
3350
  defineSchema: () => defineSchema,
3351
+ escapeTemplateString: () => escapeTemplateString,
3305
3352
  filterObjectOnSchema: () => filterObjectOnSchema,
3306
3353
  guessProviderFromModel: () => guessProviderFromModel,
3307
3354
  importHelpers: () => importHelpers,
@@ -3374,6 +3421,12 @@ function importHelpers(_helpers) {
3374
3421
  return helpers;
3375
3422
  }
3376
3423
 
3424
+ // src/utils/modules/escapeTemplateString.ts
3425
+ function escapeTemplateString(input) {
3426
+ if (typeof input !== "string") return input;
3427
+ return input.replace(/\{\{/g, "\\{{");
3428
+ }
3429
+
3377
3430
  // src/utils/modules/replaceTemplateStringAsync.ts
3378
3431
  async function replaceTemplateStringAsync(templateString, substitutions = {}, configuration = {
3379
3432
  helpers: [],
@@ -4039,9 +4092,53 @@ function OutputOpenAIChat(result, _config) {
4039
4092
  };
4040
4093
  }
4041
4094
 
4095
+ // src/llm/config/_utils/imageContent.ts
4096
+ function isImageUrlContentBlock(block) {
4097
+ if (typeof block !== "object" || block === null) {
4098
+ return false;
4099
+ }
4100
+ const imageUrl = block.image_url;
4101
+ return typeof imageUrl === "object" && imageUrl !== null && typeof imageUrl.url === "string";
4102
+ }
4103
+ var DATA_URI_PATTERN = /^data:([^;,]+);base64,(.+)$/;
4104
+ function parseImageUrl(url, context) {
4105
+ if (typeof url !== "string" || url.trim() === "") {
4106
+ throw new LlmExeError("Image content block has an empty url", {
4107
+ code: "prompt.invalid_messages",
4108
+ context: {
4109
+ ...context,
4110
+ received: url,
4111
+ expected: "an https URL or a data: URI",
4112
+ resolution: "Set image_url.url to an https URL or a base64 data: URI (data:image/png;base64,...)."
4113
+ }
4114
+ });
4115
+ }
4116
+ if (url.startsWith("data:")) {
4117
+ const match = url.match(DATA_URI_PATTERN);
4118
+ if (!match) {
4119
+ throw new LlmExeError("Malformed data: URI in image content block", {
4120
+ code: "prompt.invalid_messages",
4121
+ context: {
4122
+ ...context,
4123
+ received: `${url.slice(0, 48)}...`,
4124
+ expected: "data:<media-type>;base64,<data>",
4125
+ resolution: "Images must be base64-encoded with an explicit media type, e.g. data:image/png;base64,iVBOR..."
4126
+ }
4127
+ });
4128
+ }
4129
+ return { kind: "base64", mediaType: match[1], data: match[2] };
4130
+ }
4131
+ return { kind: "url", url };
4132
+ }
4133
+
4042
4134
  // src/llm/config/openai/promptSanitizeMessageCallback.ts
4043
4135
  function openaiPromptMessageCallback(_message) {
4044
4136
  let message = { ..._message };
4137
+ if (Array.isArray(message.content)) {
4138
+ message.content = message.content.map(
4139
+ (block) => isImageUrlContentBlock(block) && block.type !== "image_url" ? { ...block, type: "image_url" } : block
4140
+ );
4141
+ }
4045
4142
  if (message.role === "function") {
4046
4143
  message.role = "tool";
4047
4144
  message.tool_call_id = message.id;
@@ -4268,8 +4365,46 @@ var openai = {
4268
4365
  };
4269
4366
 
4270
4367
  // src/llm/config/anthropic/promptSanitizeMessageCallback.ts
4271
- function anthropicPromptMessageCallback(_message) {
4368
+ function anthropicPromptMessageCallback(_message, options = {}) {
4369
+ const { provider = "anthropic.chat", allowImageUrlSources = true } = options;
4272
4370
  let message = { ..._message };
4371
+ if (Array.isArray(message.content)) {
4372
+ message.content = message.content.map((block) => {
4373
+ if (!isImageUrlContentBlock(block)) {
4374
+ return block;
4375
+ }
4376
+ const parsed = parseImageUrl(block.image_url.url, {
4377
+ operation: "anthropicPromptMessageCallback",
4378
+ provider
4379
+ });
4380
+ if (parsed.kind === "base64") {
4381
+ return {
4382
+ type: "image",
4383
+ source: {
4384
+ type: "base64",
4385
+ media_type: parsed.mediaType,
4386
+ data: parsed.data
4387
+ }
4388
+ };
4389
+ }
4390
+ if (!allowImageUrlSources) {
4391
+ throw new LlmExeError("Image URLs are not supported by this provider", {
4392
+ code: "prompt.invalid_messages",
4393
+ context: {
4394
+ operation: "anthropicPromptMessageCallback",
4395
+ provider,
4396
+ received: parsed.url,
4397
+ expected: "a base64 data: URI",
4398
+ resolution: "Bedrock does not fetch remote images. Base64-encode the image and pass it as a data: URI (data:image/png;base64,...)."
4399
+ }
4400
+ });
4401
+ }
4402
+ return {
4403
+ type: "image",
4404
+ source: { type: "url", url: parsed.url }
4405
+ };
4406
+ });
4407
+ }
4273
4408
  if (message.role === "function") {
4274
4409
  message.role = "user";
4275
4410
  message.content = [
@@ -4315,10 +4450,11 @@ function mergeConsecutiveSameRole(messages) {
4315
4450
  }
4316
4451
  return merged;
4317
4452
  }
4318
- function anthropicPromptSanitize(_messages, _inputBodyObj, _outputObj) {
4453
+ function anthropicPromptSanitize(_messages, _inputBodyObj, _outputObj, _options = {}) {
4454
+ const toAnthropicMessage = (m) => anthropicPromptMessageCallback(m, _options);
4319
4455
  if (typeof _messages === "string") {
4320
4456
  return [{ role: "user", content: _messages }].map(
4321
- anthropicPromptMessageCallback
4457
+ toAnthropicMessage
4322
4458
  );
4323
4459
  }
4324
4460
  const [first, ...messages] = [
@@ -4328,7 +4464,7 @@ function anthropicPromptSanitize(_messages, _inputBodyObj, _outputObj) {
4328
4464
  return [
4329
4465
  { role: "user", content: first.content },
4330
4466
  ...messages
4331
- ].map(anthropicPromptMessageCallback);
4467
+ ].map(toAnthropicMessage);
4332
4468
  }
4333
4469
  if (first.role === "system" && messages.length > 0) {
4334
4470
  _outputObj.system = first.content;
@@ -4337,7 +4473,7 @@ function anthropicPromptSanitize(_messages, _inputBodyObj, _outputObj) {
4337
4473
  return { ...m, role: "user" };
4338
4474
  }
4339
4475
  return m;
4340
- }).map(anthropicPromptMessageCallback);
4476
+ }).map(toAnthropicMessage);
4341
4477
  return mergeConsecutiveSameRole(result2);
4342
4478
  }
4343
4479
  const result = [
@@ -4348,7 +4484,7 @@ function anthropicPromptSanitize(_messages, _inputBodyObj, _outputObj) {
4348
4484
  }
4349
4485
  return m;
4350
4486
  })
4351
- ].map(anthropicPromptMessageCallback);
4487
+ ].map(toAnthropicMessage);
4352
4488
  return mergeConsecutiveSameRole(result);
4353
4489
  }
4354
4490
 
@@ -4461,7 +4597,11 @@ var amazonAnthropicChatV1 = {
4461
4597
  mapBody: {
4462
4598
  prompt: {
4463
4599
  key: "messages",
4464
- transform: anthropicPromptSanitize
4600
+ transform: (v, i, o) => anthropicPromptSanitize(v, i, o, {
4601
+ provider: "amazon:anthropic.chat",
4602
+ // Bedrock's invoke API only accepts base64 image sources
4603
+ allowImageUrlSources: false
4604
+ })
4465
4605
  },
4466
4606
  topP: {
4467
4607
  key: "top_p"
@@ -4517,6 +4657,21 @@ var amazonMetaChatV1 = {
4517
4657
  if (typeof messages === "string") {
4518
4658
  return messages;
4519
4659
  } else {
4660
+ const hasImageContent = messages.some(
4661
+ (message) => Array.isArray(message?.content) && message.content.some(isImageUrlContentBlock)
4662
+ );
4663
+ if (hasImageContent) {
4664
+ throw new LlmExeError("Image content is not supported", {
4665
+ code: "prompt.invalid_messages",
4666
+ context: {
4667
+ operation: "amazonMetaChatV1.prompt.transform",
4668
+ provider: "amazon:meta.chat",
4669
+ received: "a message with image content",
4670
+ expected: "text-only messages",
4671
+ resolution: "This model accepts a flattened text prompt and cannot receive images."
4672
+ }
4673
+ });
4674
+ }
4520
4675
  return replaceTemplateString(`{{>DialogueHistory key='messages'}}`, {
4521
4676
  messages
4522
4677
  });
@@ -4811,6 +4966,60 @@ function OutputOllamaChat(result, _config) {
4811
4966
  };
4812
4967
  }
4813
4968
 
4969
+ // src/llm/config/ollama/promptSanitize.ts
4970
+ function ollamaPromptSanitize(_messages) {
4971
+ if (typeof _messages === "string") {
4972
+ return [{ role: "user", content: _messages }];
4973
+ }
4974
+ return _messages.map((_message) => {
4975
+ if (!Array.isArray(_message.content)) {
4976
+ return _message;
4977
+ }
4978
+ const message = { ..._message };
4979
+ const textParts = [];
4980
+ const images = [];
4981
+ for (const block of message.content) {
4982
+ if (isImageUrlContentBlock(block)) {
4983
+ const parsed = parseImageUrl(block.image_url.url, {
4984
+ operation: "ollamaPromptSanitize",
4985
+ provider: "ollama.chat"
4986
+ });
4987
+ if (parsed.kind === "url") {
4988
+ throw new LlmExeError("Image URLs are not supported by ollama", {
4989
+ code: "prompt.invalid_messages",
4990
+ context: {
4991
+ operation: "ollamaPromptSanitize",
4992
+ provider: "ollama.chat",
4993
+ received: parsed.url,
4994
+ expected: "a base64 data: URI",
4995
+ resolution: "Ollama does not fetch remote images. Base64-encode the image and pass it as a data: URI (data:image/png;base64,...)."
4996
+ }
4997
+ });
4998
+ }
4999
+ images.push(parsed.data);
5000
+ } else if (typeof block?.text === "string") {
5001
+ textParts.push(block.text);
5002
+ } else {
5003
+ throw new LlmExeError("Unsupported content block for ollama", {
5004
+ code: "prompt.invalid_messages",
5005
+ context: {
5006
+ operation: "ollamaPromptSanitize",
5007
+ provider: "ollama.chat",
5008
+ received: block,
5009
+ expected: "text or image_url content blocks",
5010
+ resolution: "Ollama messages only support text and base64 images."
5011
+ }
5012
+ });
5013
+ }
5014
+ }
5015
+ message.content = textParts.join("\n");
5016
+ if (images.length > 0) {
5017
+ message.images = images;
5018
+ }
5019
+ return message;
5020
+ });
5021
+ }
5022
+
4814
5023
  // src/llm/config/ollama/index.ts
4815
5024
  var ollamaChatV1 = {
4816
5025
  key: "ollama.chat.v1",
@@ -4828,12 +5037,7 @@ var ollamaChatV1 = {
4828
5037
  mapBody: {
4829
5038
  prompt: {
4830
5039
  key: "messages",
4831
- transform: (v) => {
4832
- if (typeof v === "string") {
4833
- return [{ role: "user", content: v }];
4834
- }
4835
- return v;
4836
- }
5040
+ transform: (v) => ollamaPromptSanitize(v)
4837
5041
  },
4838
5042
  model: {
4839
5043
  key: "model"
@@ -4870,6 +5074,37 @@ var ollama = {
4870
5074
  };
4871
5075
 
4872
5076
  // src/llm/config/google/promptSanitizeMessageCallback.ts
5077
+ var GOOGLE_SUPPORTED_FILE_URI = /^(gs:\/\/|https:\/\/generativelanguage\.googleapis\.com\/)/;
5078
+ function googleGeminiContentBlockToPart(block) {
5079
+ if (isImageUrlContentBlock(block)) {
5080
+ const parsed = parseImageUrl(block.image_url.url, {
5081
+ operation: "googleGeminiPromptMessageCallback",
5082
+ provider: "google.chat"
5083
+ });
5084
+ if (parsed.kind === "base64") {
5085
+ return {
5086
+ inlineData: { mimeType: parsed.mediaType, data: parsed.data }
5087
+ };
5088
+ }
5089
+ if (GOOGLE_SUPPORTED_FILE_URI.test(parsed.url)) {
5090
+ return { fileData: { fileUri: parsed.url } };
5091
+ }
5092
+ throw new LlmExeError("Gemini cannot load images from arbitrary URLs", {
5093
+ code: "prompt.invalid_messages",
5094
+ context: {
5095
+ operation: "googleGeminiPromptMessageCallback",
5096
+ provider: "google.chat",
5097
+ received: parsed.url,
5098
+ expected: "a base64 data: URI, a Files API URI, or a gs:// URI",
5099
+ resolution: "Pass the image as a data: URI (data:image/png;base64,...), or upload it with the Gemini Files API and pass the returned file URI."
5100
+ }
5101
+ });
5102
+ }
5103
+ if (typeof block?.text === "string") {
5104
+ return { text: block.text };
5105
+ }
5106
+ return block;
5107
+ }
4873
5108
  function googleGeminiPromptMessageCallback(_message) {
4874
5109
  let message = { ..._message };
4875
5110
  const parts = [];
@@ -4883,6 +5118,9 @@ function googleGeminiPromptMessageCallback(_message) {
4883
5118
  if (typeof payload.content === "string" && message.role !== "function") {
4884
5119
  parts.push({ text: message.content });
4885
5120
  }
5121
+ if (Array.isArray(payload.content) && message.role !== "function") {
5122
+ parts.push(...payload.content.map(googleGeminiContentBlockToPart));
5123
+ }
4886
5124
  if (message.role === "function") {
4887
5125
  role = "user";
4888
5126
  parts.push({
@@ -7700,10 +7938,12 @@ function createStateItem(name, defaultValue) {
7700
7938
  createState,
7701
7939
  createStateItem,
7702
7940
  defineSchema,
7941
+ formatLlmExeErrorForLog,
7703
7942
  guards,
7704
7943
  isLlmExeError,
7705
7944
  registerHelpers,
7706
7945
  registerPartials,
7946
+ serializeLlmExeError,
7707
7947
  useExecutors,
7708
7948
  useLlm,
7709
7949
  useLlmConfiguration,
package/dist/index.mjs CHANGED
@@ -464,6 +464,48 @@ function formatErrorList(values, options) {
464
464
  }
465
465
  return parts.join(", ");
466
466
  }
467
+ function formatLlmExeErrorForLog(error) {
468
+ if (!error || typeof error !== "object") {
469
+ return formatErrorValue(error);
470
+ }
471
+ const e = error;
472
+ const name = typeof e.name === "string" && e.name ? e.name : "Error";
473
+ const message = typeof e.message === "string" ? e.message : "";
474
+ const code = typeof e.code === "string" ? e.code : void 0;
475
+ const category = typeof e.category === "string" ? e.category : void 0;
476
+ let header;
477
+ if (code) {
478
+ header = `${name} [${code}]: ${message}`;
479
+ } else if (category) {
480
+ header = `${name} [${category}]: ${message}`;
481
+ } else {
482
+ header = `${name}: ${message}`;
483
+ }
484
+ const chain = [];
485
+ let current = e.cause;
486
+ let depth = 0;
487
+ const seen = /* @__PURE__ */ new WeakSet();
488
+ while (current && depth < 5) {
489
+ if (typeof current === "object") {
490
+ if (seen.has(current)) {
491
+ chain.push("Caused by: [Circular]");
492
+ break;
493
+ }
494
+ seen.add(current);
495
+ }
496
+ const c = current;
497
+ const cName = typeof c.name === "string" && c.name ? c.name : "Error";
498
+ const cMsg = typeof c.message === "string" ? c.message : String(current);
499
+ const cCode = typeof c.code === "string" ? c.code : void 0;
500
+ chain.push(
501
+ cCode ? `Caused by: ${cName} [${cCode}]: ${cMsg}` : `Caused by: ${cName}: ${cMsg}`
502
+ );
503
+ current = c.cause;
504
+ depth++;
505
+ }
506
+ return chain.length > 0 ? `${header}
507
+ ${chain.join("\n")}` : header;
508
+ }
467
509
 
468
510
  // src/errors/createLlmExeError.ts
469
511
  var DOCS_BASE_URL = "https://llm-exe.com";
@@ -985,7 +1027,9 @@ var BaseExecutor = class {
985
1027
  return this;
986
1028
  }
987
1029
  on(eventName, fn) {
988
- return this.setHooks({ [eventName]: fn });
1030
+ return this.setHooks({
1031
+ [eventName]: fn
1032
+ });
989
1033
  }
990
1034
  off(eventName, fn) {
991
1035
  return this.removeHook(eventName, fn);
@@ -1083,8 +1127,8 @@ var CoreExecutor = class extends BaseExecutor {
1083
1127
  __publicField(this, "_handler");
1084
1128
  this._handler = fn.handler.bind(null);
1085
1129
  }
1086
- async handler(_input) {
1087
- return this._handler.call(null, _input);
1130
+ async handler(_input, _options, _context) {
1131
+ return this._handler.call(null, _input, _context);
1088
1132
  }
1089
1133
  };
1090
1134
 
@@ -3236,6 +3280,7 @@ __export(utils_exports, {
3236
3280
  assert: () => assert,
3237
3281
  asyncCallWithTimeout: () => asyncCallWithTimeout,
3238
3282
  defineSchema: () => defineSchema,
3283
+ escapeTemplateString: () => escapeTemplateString,
3239
3284
  filterObjectOnSchema: () => filterObjectOnSchema,
3240
3285
  guessProviderFromModel: () => guessProviderFromModel,
3241
3286
  importHelpers: () => importHelpers,
@@ -3308,6 +3353,12 @@ function importHelpers(_helpers) {
3308
3353
  return helpers;
3309
3354
  }
3310
3355
 
3356
+ // src/utils/modules/escapeTemplateString.ts
3357
+ function escapeTemplateString(input) {
3358
+ if (typeof input !== "string") return input;
3359
+ return input.replace(/\{\{/g, "\\{{");
3360
+ }
3361
+
3311
3362
  // src/utils/modules/replaceTemplateStringAsync.ts
3312
3363
  async function replaceTemplateStringAsync(templateString, substitutions = {}, configuration = {
3313
3364
  helpers: [],
@@ -3973,9 +4024,53 @@ function OutputOpenAIChat(result, _config) {
3973
4024
  };
3974
4025
  }
3975
4026
 
4027
+ // src/llm/config/_utils/imageContent.ts
4028
+ function isImageUrlContentBlock(block) {
4029
+ if (typeof block !== "object" || block === null) {
4030
+ return false;
4031
+ }
4032
+ const imageUrl = block.image_url;
4033
+ return typeof imageUrl === "object" && imageUrl !== null && typeof imageUrl.url === "string";
4034
+ }
4035
+ var DATA_URI_PATTERN = /^data:([^;,]+);base64,(.+)$/;
4036
+ function parseImageUrl(url, context) {
4037
+ if (typeof url !== "string" || url.trim() === "") {
4038
+ throw new LlmExeError("Image content block has an empty url", {
4039
+ code: "prompt.invalid_messages",
4040
+ context: {
4041
+ ...context,
4042
+ received: url,
4043
+ expected: "an https URL or a data: URI",
4044
+ resolution: "Set image_url.url to an https URL or a base64 data: URI (data:image/png;base64,...)."
4045
+ }
4046
+ });
4047
+ }
4048
+ if (url.startsWith("data:")) {
4049
+ const match = url.match(DATA_URI_PATTERN);
4050
+ if (!match) {
4051
+ throw new LlmExeError("Malformed data: URI in image content block", {
4052
+ code: "prompt.invalid_messages",
4053
+ context: {
4054
+ ...context,
4055
+ received: `${url.slice(0, 48)}...`,
4056
+ expected: "data:<media-type>;base64,<data>",
4057
+ resolution: "Images must be base64-encoded with an explicit media type, e.g. data:image/png;base64,iVBOR..."
4058
+ }
4059
+ });
4060
+ }
4061
+ return { kind: "base64", mediaType: match[1], data: match[2] };
4062
+ }
4063
+ return { kind: "url", url };
4064
+ }
4065
+
3976
4066
  // src/llm/config/openai/promptSanitizeMessageCallback.ts
3977
4067
  function openaiPromptMessageCallback(_message) {
3978
4068
  let message = { ..._message };
4069
+ if (Array.isArray(message.content)) {
4070
+ message.content = message.content.map(
4071
+ (block) => isImageUrlContentBlock(block) && block.type !== "image_url" ? { ...block, type: "image_url" } : block
4072
+ );
4073
+ }
3979
4074
  if (message.role === "function") {
3980
4075
  message.role = "tool";
3981
4076
  message.tool_call_id = message.id;
@@ -4202,8 +4297,46 @@ var openai = {
4202
4297
  };
4203
4298
 
4204
4299
  // src/llm/config/anthropic/promptSanitizeMessageCallback.ts
4205
- function anthropicPromptMessageCallback(_message) {
4300
+ function anthropicPromptMessageCallback(_message, options = {}) {
4301
+ const { provider = "anthropic.chat", allowImageUrlSources = true } = options;
4206
4302
  let message = { ..._message };
4303
+ if (Array.isArray(message.content)) {
4304
+ message.content = message.content.map((block) => {
4305
+ if (!isImageUrlContentBlock(block)) {
4306
+ return block;
4307
+ }
4308
+ const parsed = parseImageUrl(block.image_url.url, {
4309
+ operation: "anthropicPromptMessageCallback",
4310
+ provider
4311
+ });
4312
+ if (parsed.kind === "base64") {
4313
+ return {
4314
+ type: "image",
4315
+ source: {
4316
+ type: "base64",
4317
+ media_type: parsed.mediaType,
4318
+ data: parsed.data
4319
+ }
4320
+ };
4321
+ }
4322
+ if (!allowImageUrlSources) {
4323
+ throw new LlmExeError("Image URLs are not supported by this provider", {
4324
+ code: "prompt.invalid_messages",
4325
+ context: {
4326
+ operation: "anthropicPromptMessageCallback",
4327
+ provider,
4328
+ received: parsed.url,
4329
+ expected: "a base64 data: URI",
4330
+ resolution: "Bedrock does not fetch remote images. Base64-encode the image and pass it as a data: URI (data:image/png;base64,...)."
4331
+ }
4332
+ });
4333
+ }
4334
+ return {
4335
+ type: "image",
4336
+ source: { type: "url", url: parsed.url }
4337
+ };
4338
+ });
4339
+ }
4207
4340
  if (message.role === "function") {
4208
4341
  message.role = "user";
4209
4342
  message.content = [
@@ -4249,10 +4382,11 @@ function mergeConsecutiveSameRole(messages) {
4249
4382
  }
4250
4383
  return merged;
4251
4384
  }
4252
- function anthropicPromptSanitize(_messages, _inputBodyObj, _outputObj) {
4385
+ function anthropicPromptSanitize(_messages, _inputBodyObj, _outputObj, _options = {}) {
4386
+ const toAnthropicMessage = (m) => anthropicPromptMessageCallback(m, _options);
4253
4387
  if (typeof _messages === "string") {
4254
4388
  return [{ role: "user", content: _messages }].map(
4255
- anthropicPromptMessageCallback
4389
+ toAnthropicMessage
4256
4390
  );
4257
4391
  }
4258
4392
  const [first, ...messages] = [
@@ -4262,7 +4396,7 @@ function anthropicPromptSanitize(_messages, _inputBodyObj, _outputObj) {
4262
4396
  return [
4263
4397
  { role: "user", content: first.content },
4264
4398
  ...messages
4265
- ].map(anthropicPromptMessageCallback);
4399
+ ].map(toAnthropicMessage);
4266
4400
  }
4267
4401
  if (first.role === "system" && messages.length > 0) {
4268
4402
  _outputObj.system = first.content;
@@ -4271,7 +4405,7 @@ function anthropicPromptSanitize(_messages, _inputBodyObj, _outputObj) {
4271
4405
  return { ...m, role: "user" };
4272
4406
  }
4273
4407
  return m;
4274
- }).map(anthropicPromptMessageCallback);
4408
+ }).map(toAnthropicMessage);
4275
4409
  return mergeConsecutiveSameRole(result2);
4276
4410
  }
4277
4411
  const result = [
@@ -4282,7 +4416,7 @@ function anthropicPromptSanitize(_messages, _inputBodyObj, _outputObj) {
4282
4416
  }
4283
4417
  return m;
4284
4418
  })
4285
- ].map(anthropicPromptMessageCallback);
4419
+ ].map(toAnthropicMessage);
4286
4420
  return mergeConsecutiveSameRole(result);
4287
4421
  }
4288
4422
 
@@ -4395,7 +4529,11 @@ var amazonAnthropicChatV1 = {
4395
4529
  mapBody: {
4396
4530
  prompt: {
4397
4531
  key: "messages",
4398
- transform: anthropicPromptSanitize
4532
+ transform: (v, i, o) => anthropicPromptSanitize(v, i, o, {
4533
+ provider: "amazon:anthropic.chat",
4534
+ // Bedrock's invoke API only accepts base64 image sources
4535
+ allowImageUrlSources: false
4536
+ })
4399
4537
  },
4400
4538
  topP: {
4401
4539
  key: "top_p"
@@ -4451,6 +4589,21 @@ var amazonMetaChatV1 = {
4451
4589
  if (typeof messages === "string") {
4452
4590
  return messages;
4453
4591
  } else {
4592
+ const hasImageContent = messages.some(
4593
+ (message) => Array.isArray(message?.content) && message.content.some(isImageUrlContentBlock)
4594
+ );
4595
+ if (hasImageContent) {
4596
+ throw new LlmExeError("Image content is not supported", {
4597
+ code: "prompt.invalid_messages",
4598
+ context: {
4599
+ operation: "amazonMetaChatV1.prompt.transform",
4600
+ provider: "amazon:meta.chat",
4601
+ received: "a message with image content",
4602
+ expected: "text-only messages",
4603
+ resolution: "This model accepts a flattened text prompt and cannot receive images."
4604
+ }
4605
+ });
4606
+ }
4454
4607
  return replaceTemplateString(`{{>DialogueHistory key='messages'}}`, {
4455
4608
  messages
4456
4609
  });
@@ -4745,6 +4898,60 @@ function OutputOllamaChat(result, _config) {
4745
4898
  };
4746
4899
  }
4747
4900
 
4901
+ // src/llm/config/ollama/promptSanitize.ts
4902
+ function ollamaPromptSanitize(_messages) {
4903
+ if (typeof _messages === "string") {
4904
+ return [{ role: "user", content: _messages }];
4905
+ }
4906
+ return _messages.map((_message) => {
4907
+ if (!Array.isArray(_message.content)) {
4908
+ return _message;
4909
+ }
4910
+ const message = { ..._message };
4911
+ const textParts = [];
4912
+ const images = [];
4913
+ for (const block of message.content) {
4914
+ if (isImageUrlContentBlock(block)) {
4915
+ const parsed = parseImageUrl(block.image_url.url, {
4916
+ operation: "ollamaPromptSanitize",
4917
+ provider: "ollama.chat"
4918
+ });
4919
+ if (parsed.kind === "url") {
4920
+ throw new LlmExeError("Image URLs are not supported by ollama", {
4921
+ code: "prompt.invalid_messages",
4922
+ context: {
4923
+ operation: "ollamaPromptSanitize",
4924
+ provider: "ollama.chat",
4925
+ received: parsed.url,
4926
+ expected: "a base64 data: URI",
4927
+ resolution: "Ollama does not fetch remote images. Base64-encode the image and pass it as a data: URI (data:image/png;base64,...)."
4928
+ }
4929
+ });
4930
+ }
4931
+ images.push(parsed.data);
4932
+ } else if (typeof block?.text === "string") {
4933
+ textParts.push(block.text);
4934
+ } else {
4935
+ throw new LlmExeError("Unsupported content block for ollama", {
4936
+ code: "prompt.invalid_messages",
4937
+ context: {
4938
+ operation: "ollamaPromptSanitize",
4939
+ provider: "ollama.chat",
4940
+ received: block,
4941
+ expected: "text or image_url content blocks",
4942
+ resolution: "Ollama messages only support text and base64 images."
4943
+ }
4944
+ });
4945
+ }
4946
+ }
4947
+ message.content = textParts.join("\n");
4948
+ if (images.length > 0) {
4949
+ message.images = images;
4950
+ }
4951
+ return message;
4952
+ });
4953
+ }
4954
+
4748
4955
  // src/llm/config/ollama/index.ts
4749
4956
  var ollamaChatV1 = {
4750
4957
  key: "ollama.chat.v1",
@@ -4762,12 +4969,7 @@ var ollamaChatV1 = {
4762
4969
  mapBody: {
4763
4970
  prompt: {
4764
4971
  key: "messages",
4765
- transform: (v) => {
4766
- if (typeof v === "string") {
4767
- return [{ role: "user", content: v }];
4768
- }
4769
- return v;
4770
- }
4972
+ transform: (v) => ollamaPromptSanitize(v)
4771
4973
  },
4772
4974
  model: {
4773
4975
  key: "model"
@@ -4804,6 +5006,37 @@ var ollama = {
4804
5006
  };
4805
5007
 
4806
5008
  // src/llm/config/google/promptSanitizeMessageCallback.ts
5009
+ var GOOGLE_SUPPORTED_FILE_URI = /^(gs:\/\/|https:\/\/generativelanguage\.googleapis\.com\/)/;
5010
+ function googleGeminiContentBlockToPart(block) {
5011
+ if (isImageUrlContentBlock(block)) {
5012
+ const parsed = parseImageUrl(block.image_url.url, {
5013
+ operation: "googleGeminiPromptMessageCallback",
5014
+ provider: "google.chat"
5015
+ });
5016
+ if (parsed.kind === "base64") {
5017
+ return {
5018
+ inlineData: { mimeType: parsed.mediaType, data: parsed.data }
5019
+ };
5020
+ }
5021
+ if (GOOGLE_SUPPORTED_FILE_URI.test(parsed.url)) {
5022
+ return { fileData: { fileUri: parsed.url } };
5023
+ }
5024
+ throw new LlmExeError("Gemini cannot load images from arbitrary URLs", {
5025
+ code: "prompt.invalid_messages",
5026
+ context: {
5027
+ operation: "googleGeminiPromptMessageCallback",
5028
+ provider: "google.chat",
5029
+ received: parsed.url,
5030
+ expected: "a base64 data: URI, a Files API URI, or a gs:// URI",
5031
+ resolution: "Pass the image as a data: URI (data:image/png;base64,...), or upload it with the Gemini Files API and pass the returned file URI."
5032
+ }
5033
+ });
5034
+ }
5035
+ if (typeof block?.text === "string") {
5036
+ return { text: block.text };
5037
+ }
5038
+ return block;
5039
+ }
4807
5040
  function googleGeminiPromptMessageCallback(_message) {
4808
5041
  let message = { ..._message };
4809
5042
  const parts = [];
@@ -4817,6 +5050,9 @@ function googleGeminiPromptMessageCallback(_message) {
4817
5050
  if (typeof payload.content === "string" && message.role !== "function") {
4818
5051
  parts.push({ text: message.content });
4819
5052
  }
5053
+ if (Array.isArray(payload.content) && message.role !== "function") {
5054
+ parts.push(...payload.content.map(googleGeminiContentBlockToPart));
5055
+ }
4820
5056
  if (message.role === "function") {
4821
5057
  role = "user";
4822
5058
  parts.push({
@@ -7633,10 +7869,12 @@ export {
7633
7869
  createState,
7634
7870
  createStateItem,
7635
7871
  defineSchema,
7872
+ formatLlmExeErrorForLog,
7636
7873
  guards_exports as guards,
7637
7874
  isLlmExeError,
7638
7875
  registerHelpers,
7639
7876
  registerPartials,
7877
+ serializeLlmExeError,
7640
7878
  useExecutors,
7641
7879
  useLlm,
7642
7880
  useLlmConfiguration,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "llm-exe",
3
- "version": "3.0.0",
3
+ "version": "3.0.1",
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
@@ -14,7 +14,7 @@ A package that provides simplified base components to make building and maintain
14
14
  - Allow LLM's to call functions (or call other LLM executors).
15
15
  - Not very opinionated. You have control on how you use it.
16
16
 
17
- ![llm-exe](https://assets.llm-exe.com/llm-exe-featured-2025.png)
17
+ ![llm-exe project logo](https://assets.llm-exe.com/llm-exe-featured-2025.png)
18
18
 
19
19
  See full docs here: [https://llm-exe.com](https://llm-exe.com)
20
20