llm-exe 2.3.4 → 2.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -494,6 +494,21 @@ function toNumber(value) {
494
494
  return NaN;
495
495
  }
496
496
 
497
+ // src/utils/modules/errors.ts
498
+ var LlmExeError = class extends Error {
499
+ constructor(message, code, context) {
500
+ super(message ?? "");
501
+ __publicField(this, "code");
502
+ __publicField(this, "context");
503
+ this.name = this.constructor.name;
504
+ this.code = code ?? "unknown";
505
+ this.context = context;
506
+ if (Error.captureStackTrace) {
507
+ Error.captureStackTrace(this, this.constructor);
508
+ }
509
+ }
510
+ };
511
+
497
512
  // src/parser/parsers/NumberParser.ts
498
513
  var NumberParser = class extends BaseParser {
499
514
  constructor(options) {
@@ -501,7 +516,18 @@ var NumberParser = class extends BaseParser {
501
516
  }
502
517
  parse(text) {
503
518
  const match = text.match(/-?\d+(\.\d+)?/);
504
- return match && isFinite(toNumber(match[0])) ? toNumber(match[0]) : -1;
519
+ if (match && isFinite(toNumber(match[0]))) {
520
+ return toNumber(match[0]);
521
+ }
522
+ throw new LlmExeError(
523
+ `No numeric value found in input.`,
524
+ "parser",
525
+ {
526
+ parser: "number",
527
+ output: text,
528
+ error: `No numeric value found in input.`
529
+ }
530
+ );
505
531
  }
506
532
  };
507
533
 
@@ -1398,7 +1424,7 @@ var asyncCallWithTimeout = async (asyncPromise, timeLimit = 1e4) => {
1398
1424
  const timeoutPromise = new Promise((_resolve, reject) => {
1399
1425
  timeoutHandle = setTimeout(() => {
1400
1426
  return reject(
1401
- new Error("Unable to perform action. Try again, or use another action.")
1427
+ new Error(`LLM call timed out after ${timeLimit}ms`)
1402
1428
  );
1403
1429
  }, timeLimit);
1404
1430
  });
@@ -1486,21 +1512,6 @@ function validateParserSchema(schema, parsed) {
1486
1512
  return null;
1487
1513
  }
1488
1514
 
1489
- // src/utils/modules/errors.ts
1490
- var LlmExeError = class extends Error {
1491
- constructor(message, code, context) {
1492
- super(message ?? "");
1493
- __publicField(this, "code");
1494
- __publicField(this, "context");
1495
- this.name = this.constructor.name;
1496
- this.code = code ?? "unknown";
1497
- this.context = context;
1498
- if (Error.captureStackTrace) {
1499
- Error.captureStackTrace(this, this.constructor);
1500
- }
1501
- }
1502
- };
1503
-
1504
1515
  // src/parser/parsers/JsonParser.ts
1505
1516
  var JsonParser = class extends BaseParserWithJson {
1506
1517
  constructor(options = {}) {
@@ -1544,6 +1555,8 @@ function camelCase(input) {
1544
1555
  var ListToJsonParser = class extends BaseParserWithJson {
1545
1556
  constructor(options = {}) {
1546
1557
  super("listToJson", options);
1558
+ __publicField(this, "keyTransform");
1559
+ this.keyTransform = options.keyTransform ?? "camelCase";
1547
1560
  }
1548
1561
  parse(text) {
1549
1562
  const lines = text.split("\n");
@@ -1554,7 +1567,8 @@ var ListToJsonParser = class extends BaseParserWithJson {
1554
1567
  const key = line.slice(0, colonIndex);
1555
1568
  const value = line.slice(colonIndex + 1).trim();
1556
1569
  if (value) {
1557
- output[camelCase(key)] = value;
1570
+ const transformedKey = this.keyTransform === "preserve" ? key.trim() : camelCase(key);
1571
+ output[transformedKey] = value;
1558
1572
  }
1559
1573
  }
1560
1574
  });
@@ -1727,7 +1741,15 @@ var StringExtractParser = class extends BaseParser {
1727
1741
  return option;
1728
1742
  }
1729
1743
  }
1730
- return "";
1744
+ throw new LlmExeError(
1745
+ `No matching enum value found in input.`,
1746
+ "parser",
1747
+ {
1748
+ parser: "stringExtract",
1749
+ output: text,
1750
+ error: `No matching enum value found in input. Expected one of: ${this.enum.join(", ")}`
1751
+ }
1752
+ );
1731
1753
  }
1732
1754
  };
1733
1755
 
@@ -2244,6 +2266,7 @@ function cleanJsonSchemaFor(schema = {}, provider) {
2244
2266
  // src/llm/config/openai/compatible.ts
2245
2267
  function createOpenAiCompatibleConfiguration(overrides) {
2246
2268
  const [apiKeyPropertyKey, apiKeyPropertyValue] = overrides.apiKeyMapping;
2269
+ const isReasoningModel = overrides.isReasoningModel ?? (() => false);
2247
2270
  const config = {
2248
2271
  key: overrides.key,
2249
2272
  provider: overrides.provider,
@@ -2251,7 +2274,12 @@ function createOpenAiCompatibleConfiguration(overrides) {
2251
2274
  options: {
2252
2275
  prompt: {},
2253
2276
  effort: {},
2277
+ temperature: {},
2254
2278
  topP: {},
2279
+ maxTokens: {},
2280
+ stopSequences: {},
2281
+ frequencyPenalty: {},
2282
+ logitBias: {},
2255
2283
  useJson: {},
2256
2284
  [apiKeyPropertyKey]: {
2257
2285
  default: getEnvironmentVariable(apiKeyPropertyValue)
@@ -2267,9 +2295,24 @@ function createOpenAiCompatibleConfiguration(overrides) {
2267
2295
  model: {
2268
2296
  key: "model"
2269
2297
  },
2298
+ temperature: {
2299
+ key: "temperature"
2300
+ },
2270
2301
  topP: {
2271
2302
  key: "top_p"
2272
2303
  },
2304
+ maxTokens: {
2305
+ key: "max_tokens"
2306
+ },
2307
+ stopSequences: {
2308
+ key: "stop"
2309
+ },
2310
+ frequencyPenalty: {
2311
+ key: "frequency_penalty"
2312
+ },
2313
+ logitBias: {
2314
+ key: "logit_bias"
2315
+ },
2273
2316
  useJson: {
2274
2317
  key: "response_format.type",
2275
2318
  transform: (v) => v ? "json_object" : "text"
@@ -2277,10 +2320,7 @@ function createOpenAiCompatibleConfiguration(overrides) {
2277
2320
  effort: {
2278
2321
  key: "reasoning_effort",
2279
2322
  transform: (v, _s) => {
2280
- if (
2281
- // only supported reasoning models
2282
- ["gpt-5"].includes(_s.model) && typeof v === "string" && ["minimal", "low", "medium", "high"].includes(v)
2283
- ) {
2323
+ if (typeof _s.model === "string" && isReasoningModel(_s.model) && typeof v === "string" && ["minimal", "low", "medium", "high"].includes(v)) {
2284
2324
  return v;
2285
2325
  }
2286
2326
  return void 0;
@@ -2327,7 +2367,8 @@ var openAiChatV1 = createOpenAiCompatibleConfiguration({
2327
2367
  key: "openai.chat.v1",
2328
2368
  provider: "openai.chat",
2329
2369
  endpoint: `https://api.openai.com/v1/chat/completions`,
2330
- apiKeyMapping: ["openAiApiKey", "OPENAI_API_KEY"]
2370
+ apiKeyMapping: ["openAiApiKey", "OPENAI_API_KEY"],
2371
+ isReasoningModel: (model) => model.startsWith("gpt-5") || model.startsWith("o3") || model.startsWith("o4")
2331
2372
  });
2332
2373
  var openAiChatMockV1 = {
2333
2374
  key: "openai.chat-mock.v1",
@@ -2373,10 +2414,12 @@ var openai = {
2373
2414
  "openai.gpt-4.1-nano": withDefaultModel(openAiChatV1, "gpt-4.1-nano"),
2374
2415
  // Reasoning models
2375
2416
  "openai.o3": withDefaultModel(openAiChatV1, "o3"),
2376
- "openai.o4-mini": withDefaultModel(openAiChatV1, "o4-mini"),
2377
2417
  // GPT-4o family
2418
+ "openai.gpt-4": withDefaultModel(openAiChatV1, "gpt-4"),
2378
2419
  "openai.gpt-4o": withDefaultModel(openAiChatV1, "gpt-4o"),
2379
- "openai.gpt-4o-mini": withDefaultModel(openAiChatV1, "gpt-4o-mini")
2420
+ "openai.gpt-4o-mini": withDefaultModel(openAiChatV1, "gpt-4o-mini"),
2421
+ // Deprecated
2422
+ "openai.o4-mini": withDefaultModel(openAiChatV1, "o4-mini")
2380
2423
  };
2381
2424
 
2382
2425
  // src/llm/config/anthropic/promptSanitizeMessageCallback.ts
@@ -2636,6 +2679,14 @@ var bedrock = {
2636
2679
 
2637
2680
  // src/llm/config/anthropic/index.ts
2638
2681
  var ANTHROPIC_VERSION = "2023-06-01";
2682
+ var MODELS_REJECTING_SAMPLING_PARAMS = ["claude-opus-4-7"];
2683
+ var isClaude4x = (model) => /^claude-(opus|sonnet|haiku)-4-/.test(model);
2684
+ var dropIfModelRejectsSamplingParams = (v, body) => MODELS_REJECTING_SAMPLING_PARAMS.includes(body.model) ? void 0 : v;
2685
+ var topPTransform = (v, body) => {
2686
+ if (MODELS_REJECTING_SAMPLING_PARAMS.includes(body.model)) return void 0;
2687
+ if (isClaude4x(body.model) && body.temperature !== void 0) return void 0;
2688
+ return v;
2689
+ };
2639
2690
  var anthropicChatV1 = {
2640
2691
  key: "anthropic.chat.v1",
2641
2692
  provider: "anthropic.chat",
@@ -2668,13 +2719,16 @@ var anthropicChatV1 = {
2668
2719
  transform: anthropicPromptSanitize
2669
2720
  },
2670
2721
  temperature: {
2671
- key: "temperature"
2722
+ key: "temperature",
2723
+ transform: dropIfModelRejectsSamplingParams
2672
2724
  },
2673
2725
  topP: {
2674
- key: "top_p"
2726
+ key: "top_p",
2727
+ transform: topPTransform
2675
2728
  },
2676
2729
  topK: {
2677
- key: "top_k"
2730
+ key: "top_k",
2731
+ transform: dropIfModelRejectsSamplingParams
2678
2732
  },
2679
2733
  stopSequences: {
2680
2734
  key: "stop_sequences"
@@ -2710,6 +2764,11 @@ var anthropicChatV1 = {
2710
2764
  };
2711
2765
  var anthropic = {
2712
2766
  "anthropic.chat.v1": anthropicChatV1,
2767
+ // Claude 4.7 models
2768
+ "anthropic.claude-opus-4-7": withDefaultModel(
2769
+ anthropicChatV1,
2770
+ "claude-opus-4-7"
2771
+ ),
2713
2772
  // Claude 4.6 models
2714
2773
  "anthropic.claude-opus-4-6": withDefaultModel(
2715
2774
  anthropicChatV1,
@@ -2719,7 +2778,20 @@ var anthropic = {
2719
2778
  anthropicChatV1,
2720
2779
  "claude-sonnet-4-6"
2721
2780
  ),
2722
- // Claude 4 models
2781
+ // Claude 4.5 models
2782
+ "anthropic.claude-haiku-4-5": withDefaultModel(
2783
+ anthropicChatV1,
2784
+ "claude-haiku-4-5"
2785
+ ),
2786
+ "anthropic.claude-sonnet-4-5": withDefaultModel(
2787
+ anthropicChatV1,
2788
+ "claude-sonnet-4-5"
2789
+ ),
2790
+ // Deprecated
2791
+ "anthropic.claude-opus-4-1": withDefaultModel(
2792
+ anthropicChatV1,
2793
+ "claude-opus-4-1-20250805"
2794
+ ),
2723
2795
  "anthropic.claude-sonnet-4": withDefaultModel(
2724
2796
  anthropicChatV1,
2725
2797
  "claude-sonnet-4-0"
@@ -2732,7 +2804,6 @@ var anthropic = {
2732
2804
  anthropicChatV1,
2733
2805
  "claude-3-7-sonnet-20250219"
2734
2806
  ),
2735
- // Claude 3.5 models
2736
2807
  "anthropic.claude-3-5-sonnet": withDefaultModel(
2737
2808
  anthropicChatV1,
2738
2809
  "claude-3-5-sonnet-latest"
@@ -2741,14 +2812,9 @@ var anthropic = {
2741
2812
  anthropicChatV1,
2742
2813
  "claude-3-5-haiku-latest"
2743
2814
  ),
2744
- // Deprecated
2745
2815
  "anthropic.claude-3-opus": withDefaultModel(
2746
2816
  anthropicChatV1,
2747
2817
  "claude-3-opus-20240229"
2748
- ),
2749
- "anthropic.claude-3-haiku": withDefaultModel(
2750
- anthropicChatV1,
2751
- "claude-3-haiku-20240307"
2752
2818
  )
2753
2819
  };
2754
2820
 
@@ -2757,7 +2823,13 @@ var xaiChatV1 = createOpenAiCompatibleConfiguration({
2757
2823
  key: "xai.chat.v1",
2758
2824
  provider: "xai.chat",
2759
2825
  endpoint: `https://api.x.ai/v1/chat/completions`,
2760
- apiKeyMapping: ["xAiApiKey", "XAI_API_KEY"]
2826
+ apiKeyMapping: ["xAiApiKey", "XAI_API_KEY"],
2827
+ // Per xAI docs (checked 2026-05-13), grok-4 errors if `reasoning_effort` is
2828
+ // sent; grok-3-mini and the fast-non-reasoning variants don't accept it
2829
+ // either. Only grok-4.3 and grok-4.20-multi-agent support it, and neither
2830
+ // has a shorthand here yet. Leave the predicate empty so effort is dropped
2831
+ // for every currently-shipped xAI shorthand.
2832
+ isReasoningModel: () => false
2761
2833
  });
2762
2834
  var xai = {
2763
2835
  "xai.chat.v1": xaiChatV1,
@@ -2765,7 +2837,8 @@ var xai = {
2765
2837
  "xai.grok-3": withDefaultModel(xaiChatV1, "grok-3"),
2766
2838
  "xai.grok-3-mini": withDefaultModel(xaiChatV1, "grok-3-mini"),
2767
2839
  "xai.grok-4": withDefaultModel(xaiChatV1, "grok-4"),
2768
- "xai.grok-4-fast": withDefaultModel(xaiChatV1, "grok-4-fast-non-reasoning")
2840
+ "xai.grok-4-fast": withDefaultModel(xaiChatV1, "grok-4-fast-non-reasoning"),
2841
+ "xai.grok-4-1-fast": withDefaultModel(xaiChatV1, "grok-4-1-fast-non-reasoning")
2769
2842
  };
2770
2843
 
2771
2844
  // src/llm/output/_utils/combineJsonl.ts
@@ -2872,7 +2945,11 @@ var ollama = {
2872
2945
  "ollama.llama3.3": withDefaultModel(ollamaChatV1, "llama3.3"),
2873
2946
  "ollama.llama3.2": withDefaultModel(ollamaChatV1, "llama3.2"),
2874
2947
  "ollama.llama3.1": withDefaultModel(ollamaChatV1, "llama3.1"),
2875
- "ollama.qwq": withDefaultModel(ollamaChatV1, "qwq")
2948
+ "ollama.qwq": withDefaultModel(ollamaChatV1, "qwq"),
2949
+ "ollama.gemma3": withDefaultModel(ollamaChatV1, "gemma3"),
2950
+ "ollama.mistral": withDefaultModel(ollamaChatV1, "mistral"),
2951
+ "ollama.qwen2.5": withDefaultModel(ollamaChatV1, "qwen2.5"),
2952
+ "ollama.qwen3": withDefaultModel(ollamaChatV1, "qwen3")
2876
2953
  };
2877
2954
 
2878
2955
  // src/llm/config/google/promptSanitizeMessageCallback.ts
@@ -3089,14 +3166,6 @@ var googleGeminiChatV1 = {
3089
3166
  };
3090
3167
  var google = {
3091
3168
  "google.chat.v1": googleGeminiChatV1,
3092
- "google.gemini-2.0-flash": withDefaultModel(
3093
- googleGeminiChatV1,
3094
- "gemini-2.0-flash"
3095
- ),
3096
- "google.gemini-2.0-flash-lite": withDefaultModel(
3097
- googleGeminiChatV1,
3098
- "gemini-2.0-flash-lite"
3099
- ),
3100
3169
  "google.gemini-2.5-flash": withDefaultModel(
3101
3170
  googleGeminiChatV1,
3102
3171
  "gemini-2.5-flash"
@@ -3105,13 +3174,22 @@ var google = {
3105
3174
  googleGeminiChatV1,
3106
3175
  "gemini-2.5-flash-lite"
3107
3176
  ),
3108
- "google.gemini-1.5-pro": withDefaultModel(
3109
- googleGeminiChatV1,
3110
- "gemini-1.5-pro"
3111
- ),
3112
3177
  "google.gemini-2.5-pro": withDefaultModel(
3113
3178
  googleGeminiChatV1,
3114
3179
  "gemini-2.5-pro"
3180
+ ),
3181
+ // Deprecated
3182
+ "google.gemini-2.0-flash": withDefaultModel(
3183
+ googleGeminiChatV1,
3184
+ "gemini-2.0-flash"
3185
+ ),
3186
+ "google.gemini-2.0-flash-lite": withDefaultModel(
3187
+ googleGeminiChatV1,
3188
+ "gemini-2.0-flash-lite"
3189
+ ),
3190
+ "google.gemini-1.5-pro": withDefaultModel(
3191
+ googleGeminiChatV1,
3192
+ "gemini-1.5-pro"
3115
3193
  )
3116
3194
  };
3117
3195
 
@@ -3124,7 +3202,9 @@ var deepseekChatV1 = createOpenAiCompatibleConfiguration({
3124
3202
  });
3125
3203
  var deepseek = {
3126
3204
  "deepseek.chat.v1": deepseekChatV1,
3127
- "deepseek.chat": withDefaultModel(deepseekChatV1, "deepseek-chat")
3205
+ "deepseek.chat": withDefaultModel(deepseekChatV1, "deepseek-chat"),
3206
+ "deepseek.v4-flash": withDefaultModel(deepseekChatV1, "deepseek-v4-flash"),
3207
+ "deepseek.v4-pro": withDefaultModel(deepseekChatV1, "deepseek-v4-pro")
3128
3208
  };
3129
3209
 
3130
3210
  // src/llm/config.ts
@@ -3239,12 +3319,19 @@ async function apiRequest(url, options) {
3239
3319
  const response = await fetch(url, finalOptions);
3240
3320
  if (!response.ok) {
3241
3321
  let message = `HTTP error. Status: ${response.status}. Error Message: ${response?.statusText || "Unknown error."}`;
3242
- if (url.startsWith("https://api.openai.com/")) {
3243
- try {
3244
- const body = await response.json();
3245
- message = `HTTP error. Status Code: ${response.status}. Error Message: ${body?.error?.message || "No further details provided."}`;
3246
- } catch (error) {
3322
+ try {
3323
+ const text = await response.text();
3324
+ if (text) {
3325
+ let detail = text;
3326
+ try {
3327
+ const body = JSON.parse(text);
3328
+ detail = body?.error?.message || body?.error || body?.message || text;
3329
+ if (typeof detail !== "string") detail = JSON.stringify(detail);
3330
+ } catch {
3331
+ }
3332
+ message = `HTTP error. Status Code: ${response.status}. Error Message: ${detail}`;
3247
3333
  }
3334
+ } catch {
3248
3335
  }
3249
3336
  throw new Error(message);
3250
3337
  }
@@ -4076,6 +4163,11 @@ var BasePrompt = class {
4076
4163
  return promptValue;
4077
4164
  }
4078
4165
  getReplacements(values) {
4166
+ if (values === void 0 || values === null) {
4167
+ throw new Error(
4168
+ "format() requires an input object. Did you forget to pass arguments?"
4169
+ );
4170
+ }
4079
4171
  const { input = "", ...restOfValues } = values;
4080
4172
  const replacements = Object.assign(
4081
4173
  {},
@@ -4088,11 +4180,11 @@ var BasePrompt = class {
4088
4180
  return replacements;
4089
4181
  }
4090
4182
  /**
4091
- * validate description
4092
- * @return {boolean} Returns false if the template is not valid.
4183
+ * Validates the prompt structure.
4184
+ * @return {boolean} Returns false if the prompt has no messages defined.
4093
4185
  */
4094
4186
  validate() {
4095
- return true;
4187
+ return this.messages.length > 0;
4096
4188
  }
4097
4189
  };
4098
4190
 
@@ -4689,14 +4781,6 @@ var ChatPrompt = class extends BasePrompt {
4689
4781
  }
4690
4782
  return messagesOut;
4691
4783
  }
4692
- /**
4693
- * validate Ensures there are not unresolved tokens in prompt.
4694
- * @TODO Make this work!
4695
- * @return Returns false if the template is not valid.
4696
- */
4697
- validate() {
4698
- return true;
4699
- }
4700
4784
  };
4701
4785
 
4702
4786
  // src/prompt/_functions.ts
@@ -4723,10 +4807,12 @@ var BaseStateItem = class {
4723
4807
  this.initialValue = initialValue;
4724
4808
  }
4725
4809
  setValue(value) {
4726
- assert(
4727
- typeof value === typeof this.value,
4728
- `Invalid value type. Expected ${typeof this.value}, received ${typeof value}`
4729
- );
4810
+ if (this.value !== void 0 && this.value !== null) {
4811
+ assert(
4812
+ typeof value === typeof this.value,
4813
+ `Invalid value type. Expected ${typeof this.value}, received ${typeof value}`
4814
+ );
4815
+ }
4730
4816
  this.value = value;
4731
4817
  }
4732
4818
  getKey() {
@@ -4862,11 +4948,42 @@ var Dialogue = class extends BaseStateItem {
4862
4948
  return this;
4863
4949
  }
4864
4950
  setMessageTurn(userMessage, assistantMessage, systemMessage = "") {
4951
+ this.setSystemMessage(systemMessage);
4865
4952
  this.setUserMessage(userMessage);
4866
4953
  this.setAssistantMessage(assistantMessage);
4867
- this.setSystemMessage(systemMessage);
4868
4954
  return this;
4869
4955
  }
4956
+ /**
4957
+ * Aliases using `add*` naming to match ChatPrompt's API.
4958
+ * These delegate to the corresponding `set*` methods.
4959
+ */
4960
+ addUserMessage(content, name) {
4961
+ return this.setUserMessage(content, name);
4962
+ }
4963
+ addAssistantMessage(content) {
4964
+ return this.setAssistantMessage(content);
4965
+ }
4966
+ addSystemMessage(content) {
4967
+ return this.setSystemMessage(content);
4968
+ }
4969
+ addToolMessage(content, name, id) {
4970
+ return this.setToolMessage(content, name, id);
4971
+ }
4972
+ addToolCallMessage(input) {
4973
+ return this.setToolCallMessage(input);
4974
+ }
4975
+ addFunctionMessage(content, name, id) {
4976
+ return this.setFunctionMessage(content, name, id);
4977
+ }
4978
+ addFunctionCallMessage(input) {
4979
+ return this.setFunctionCallMessage(input);
4980
+ }
4981
+ addMessageTurn(userMessage, assistantMessage, systemMessage = "") {
4982
+ return this.setMessageTurn(userMessage, assistantMessage, systemMessage);
4983
+ }
4984
+ addHistory(messages) {
4985
+ return this.setHistory(messages);
4986
+ }
4870
4987
  setHistory(messages) {
4871
4988
  for (const message of messages) {
4872
4989
  switch (message?.role) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "llm-exe",
3
- "version": "2.3.4",
3
+ "version": "2.3.6",
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
@@ -104,11 +104,34 @@ const parser = createCustomParser("MyUppercaseParser", (output, input) => {
104
104
 
105
105
  #### State
106
106
 
107
+ Manage conversation history and structured data across LLM calls:
108
+
107
109
  ```ts
110
+ import { createState, createDialogue, createStateItem } from "llm-exe";
111
+
112
+ // Create a state container
113
+ const state = createState();
114
+
115
+ // Dialogues — store conversation history
116
+ const chat = state.createDialogue("chat");
117
+ chat.setUserMessage("Hi");
118
+ chat.setAssistantMessage("Hello!");
119
+ chat.getHistory(); // returns message array
120
+
121
+ // Standalone dialogue (without state)
108
122
  const dialogue = createDialogue("chat");
109
123
  dialogue.setUserMessage("Hi");
110
- dialogue.setAssistantMessage("Hello!");
111
- dialogue.getHistory(); // returns chat array
124
+
125
+ // Context items — typed values with get/set/reset
126
+ const intent = createStateItem("userIntent", "unknown");
127
+ state.createContextItem(intent);
128
+ intent.setValue("booking");
129
+ intent.getValue(); // "booking"
130
+ intent.resetValue(); // resets to "unknown"
131
+
132
+ // Attributes — simple key-value metadata
133
+ state.setAttribute("userId", "abc-123");
134
+ state.attributes["userId"]; // "abc-123"
112
135
  ```
113
136
 
114
137
  #### Hooks