llmist 0.6.1 → 0.7.0

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.cjs CHANGED
@@ -30,6 +30,20 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
30
30
  ));
31
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
32
 
33
+ // src/core/constants.ts
34
+ var GADGET_START_PREFIX, GADGET_END_PREFIX, DEFAULT_GADGET_OUTPUT_LIMIT, DEFAULT_GADGET_OUTPUT_LIMIT_PERCENT, CHARS_PER_TOKEN, FALLBACK_CONTEXT_WINDOW;
35
+ var init_constants = __esm({
36
+ "src/core/constants.ts"() {
37
+ "use strict";
38
+ GADGET_START_PREFIX = "!!!GADGET_START:";
39
+ GADGET_END_PREFIX = "!!!GADGET_END";
40
+ DEFAULT_GADGET_OUTPUT_LIMIT = true;
41
+ DEFAULT_GADGET_OUTPUT_LIMIT_PERCENT = 15;
42
+ CHARS_PER_TOKEN = 4;
43
+ FALLBACK_CONTEXT_WINDOW = 128e3;
44
+ }
45
+ });
46
+
33
47
  // src/core/model-shortcuts.ts
34
48
  function isKnownModelPattern(model) {
35
49
  const normalized = model.toLowerCase();
@@ -344,20 +358,6 @@ var init_registry = __esm({
344
358
  }
345
359
  });
346
360
 
347
- // src/core/constants.ts
348
- var GADGET_START_PREFIX, GADGET_END_PREFIX, DEFAULT_GADGET_OUTPUT_LIMIT, DEFAULT_GADGET_OUTPUT_LIMIT_PERCENT, CHARS_PER_TOKEN, FALLBACK_CONTEXT_WINDOW;
349
- var init_constants = __esm({
350
- "src/core/constants.ts"() {
351
- "use strict";
352
- GADGET_START_PREFIX = "!!!GADGET_START:";
353
- GADGET_END_PREFIX = "!!!GADGET_END";
354
- DEFAULT_GADGET_OUTPUT_LIMIT = true;
355
- DEFAULT_GADGET_OUTPUT_LIMIT_PERCENT = 15;
356
- CHARS_PER_TOKEN = 4;
357
- FALLBACK_CONTEXT_WINDOW = 128e3;
358
- }
359
- });
360
-
361
361
  // src/core/prompt-config.ts
362
362
  function resolvePromptTemplate(template, defaultValue, context) {
363
363
  const resolved = template ?? defaultValue;
@@ -641,7 +641,9 @@ This content can contain:
641
641
  - Multiple paragraphs
642
642
  EOF
643
643
 
644
- The delimiter (EOF) can be any identifier. The closing delimiter must be on its own line.`);
644
+ The delimiter (EOF) can be any identifier. The closing delimiter must be on its own line.
645
+ IMPORTANT: Content inside heredoc is LITERAL - do NOT escape backticks, dollar signs, or any characters.
646
+ NEVER use TOML triple-quote strings ("""). ALWAYS use heredoc syntax (<<<EOF...EOF) for multiline content.`);
645
647
  }
646
648
  return parts.join("");
647
649
  }
@@ -689,9 +691,9 @@ ${this.endPrefix}`
689
691
  if (format === "toml") {
690
692
  return Object.entries(parameters).map(([key, value]) => {
691
693
  if (typeof value === "string" && value.includes("\n")) {
692
- return `${key} = """
694
+ return `${key} = <<<EOF
693
695
  ${value}
694
- """`;
696
+ EOF`;
695
697
  }
696
698
  return `${key} = ${JSON.stringify(value)}`;
697
699
  }).join("\n");
@@ -937,6 +939,10 @@ function formatParamsAsYaml(params) {
937
939
  }
938
940
  return lines.join("\n");
939
941
  }
942
+ function formatTomlInlineTable(obj) {
943
+ const entries = Object.entries(obj).map(([k, v]) => `${k} = ${formatTomlValue(v)}`);
944
+ return `{ ${entries.join(", ")} }`;
945
+ }
940
946
  function formatTomlValue(value) {
941
947
  if (typeof value === "string") {
942
948
  if (value.includes("\n")) {
@@ -954,10 +960,17 @@ ${delimiter}`;
954
960
  return '""';
955
961
  }
956
962
  if (Array.isArray(value)) {
957
- return JSON.stringify(value);
963
+ if (value.length === 0) return "[]";
964
+ const items = value.map((item) => {
965
+ if (typeof item === "object" && item !== null && !Array.isArray(item)) {
966
+ return formatTomlInlineTable(item);
967
+ }
968
+ return formatTomlValue(item);
969
+ });
970
+ return `[${items.join(", ")}]`;
958
971
  }
959
972
  if (typeof value === "object") {
960
- return JSON.stringify(value);
973
+ return formatTomlInlineTable(value);
961
974
  }
962
975
  return JSON.stringify(value);
963
976
  }
@@ -1678,7 +1691,8 @@ var init_executor = __esm({
1678
1691
  if (call.parseError || !call.parameters) {
1679
1692
  this.logger.error("Gadget parameter parse error", {
1680
1693
  gadgetName: call.gadgetName,
1681
- parseError: call.parseError
1694
+ parseError: call.parseError,
1695
+ rawParameters: call.parametersYaml
1682
1696
  });
1683
1697
  return {
1684
1698
  gadgetName: call.gadgetName,
@@ -1957,6 +1971,9 @@ function preprocessYaml(yamlStr) {
1957
1971
  }
1958
1972
  return result.join("\n");
1959
1973
  }
1974
+ function unescapeHeredocContent(content) {
1975
+ return content.replace(/\\`/g, "`").replace(/\\\$/g, "$").replace(/\\{/g, "{").replace(/\\}/g, "}");
1976
+ }
1960
1977
  function preprocessTomlHeredoc(tomlStr) {
1961
1978
  const lines = tomlStr.split("\n");
1962
1979
  const result = [];
@@ -1982,13 +1999,13 @@ function preprocessTomlHeredoc(tomlStr) {
1982
1999
  i++;
1983
2000
  }
1984
2001
  if (bodyLines.length === 0) {
1985
- result.push(`${indent}${key} = """"""`);
2002
+ result.push(`${indent}${key} = ''''''`);
1986
2003
  } else {
1987
- result.push(`${indent}${key} = """`);
2004
+ result.push(`${indent}${key} = '''`);
1988
2005
  for (let j = 0; j < bodyLines.length - 1; j++) {
1989
- result.push(bodyLines[j]);
2006
+ result.push(unescapeHeredocContent(bodyLines[j]));
1990
2007
  }
1991
- result.push(`${bodyLines[bodyLines.length - 1]}"""`);
2008
+ result.push(`${unescapeHeredocContent(bodyLines[bodyLines.length - 1])}'''`);
1992
2009
  }
1993
2010
  if (!foundClosing) {
1994
2011
  }
@@ -1999,6 +2016,14 @@ function preprocessTomlHeredoc(tomlStr) {
1999
2016
  }
2000
2017
  return result.join("\n");
2001
2018
  }
2019
+ function stripMarkdownFences(content) {
2020
+ let cleaned = content.trim();
2021
+ const openingFence = /^```(?:toml|yaml|json)?\s*\n/i;
2022
+ const closingFence = /\n?```\s*$/;
2023
+ cleaned = cleaned.replace(openingFence, "");
2024
+ cleaned = cleaned.replace(closingFence, "");
2025
+ return cleaned.trim();
2026
+ }
2002
2027
  var yaml2, import_js_toml, globalInvocationCounter, StreamParser;
2003
2028
  var init_parser = __esm({
2004
2029
  "src/gadgets/parser.ts"() {
@@ -2037,43 +2062,55 @@ var init_parser = __esm({
2037
2062
  }
2038
2063
  return { actualName: gadgetName, invocationId: `gadget_${++globalInvocationCounter}` };
2039
2064
  }
2065
+ /**
2066
+ * Truncate verbose parse errors to avoid context overflow.
2067
+ * Keeps first meaningful line and limits total length.
2068
+ */
2069
+ truncateParseError(error, format) {
2070
+ const message = error instanceof Error ? error.message : String(error);
2071
+ const firstLine = message.split("\n")[0];
2072
+ const maxLen = 200;
2073
+ if (firstLine.length <= maxLen) {
2074
+ return firstLine;
2075
+ }
2076
+ return `${firstLine.slice(0, maxLen)}... (${message.length} chars total)`;
2077
+ }
2040
2078
  /**
2041
2079
  * Parse parameter string according to configured format
2042
2080
  */
2043
2081
  parseParameters(raw) {
2082
+ const cleaned = stripMarkdownFences(raw);
2044
2083
  if (this.parameterFormat === "json") {
2045
2084
  try {
2046
- return { parameters: JSON.parse(raw) };
2085
+ return { parameters: JSON.parse(cleaned) };
2047
2086
  } catch (error) {
2048
- return { parseError: error instanceof Error ? error.message : "Failed to parse JSON" };
2087
+ return { parseError: this.truncateParseError(error, "JSON") };
2049
2088
  }
2050
2089
  }
2051
2090
  if (this.parameterFormat === "yaml") {
2052
2091
  try {
2053
- return { parameters: yaml2.load(preprocessYaml(raw)) };
2092
+ return { parameters: yaml2.load(preprocessYaml(cleaned)) };
2054
2093
  } catch (error) {
2055
- return { parseError: error instanceof Error ? error.message : "Failed to parse YAML" };
2094
+ return { parseError: this.truncateParseError(error, "YAML") };
2056
2095
  }
2057
2096
  }
2058
2097
  if (this.parameterFormat === "toml") {
2059
2098
  try {
2060
- return { parameters: (0, import_js_toml.load)(preprocessTomlHeredoc(raw)) };
2099
+ return { parameters: (0, import_js_toml.load)(preprocessTomlHeredoc(cleaned)) };
2061
2100
  } catch (error) {
2062
- return { parseError: error instanceof Error ? error.message : "Failed to parse TOML" };
2101
+ return { parseError: this.truncateParseError(error, "TOML") };
2063
2102
  }
2064
2103
  }
2065
2104
  try {
2066
- return { parameters: JSON.parse(raw) };
2105
+ return { parameters: JSON.parse(cleaned) };
2067
2106
  } catch {
2068
2107
  try {
2069
- return { parameters: (0, import_js_toml.load)(preprocessTomlHeredoc(raw)) };
2108
+ return { parameters: (0, import_js_toml.load)(preprocessTomlHeredoc(cleaned)) };
2070
2109
  } catch {
2071
2110
  try {
2072
- return { parameters: yaml2.load(preprocessYaml(raw)) };
2111
+ return { parameters: yaml2.load(preprocessYaml(cleaned)) };
2073
2112
  } catch (error) {
2074
- return {
2075
- parseError: error instanceof Error ? error.message : "Failed to parse as JSON, TOML, or YAML"
2076
- };
2113
+ return { parseError: this.truncateParseError(error, "auto") };
2077
2114
  }
2078
2115
  }
2079
2116
  }
@@ -2375,7 +2412,8 @@ var init_stream_processor = __esm({
2375
2412
  if (call.parseError) {
2376
2413
  this.logger.warn("Gadget has parse error", {
2377
2414
  gadgetName: call.gadgetName,
2378
- error: call.parseError
2415
+ error: call.parseError,
2416
+ rawParameters: call.parametersYaml
2379
2417
  });
2380
2418
  const shouldContinue = await this.checkContinueAfterError(
2381
2419
  call.parseError,
@@ -2616,6 +2654,7 @@ var init_agent = __esm({
2616
2654
  gadgetEndPrefix;
2617
2655
  onHumanInputRequired;
2618
2656
  textOnlyHandler;
2657
+ textWithGadgetsHandler;
2619
2658
  stopOnGadgetError;
2620
2659
  shouldContinueAfterError;
2621
2660
  defaultGadgetTimeoutMs;
@@ -2646,6 +2685,7 @@ var init_agent = __esm({
2646
2685
  this.gadgetEndPrefix = options.gadgetEndPrefix;
2647
2686
  this.onHumanInputRequired = options.onHumanInputRequired;
2648
2687
  this.textOnlyHandler = options.textOnlyHandler ?? "terminate";
2688
+ this.textWithGadgetsHandler = options.textWithGadgetsHandler;
2649
2689
  this.stopOnGadgetError = options.stopOnGadgetError ?? true;
2650
2690
  this.shouldContinueAfterError = options.shouldContinueAfterError;
2651
2691
  this.defaultGadgetTimeoutMs = options.defaultGadgetTimeoutMs;
@@ -2833,6 +2873,17 @@ var init_agent = __esm({
2833
2873
  }
2834
2874
  }
2835
2875
  if (result.didExecuteGadgets) {
2876
+ if (this.textWithGadgetsHandler) {
2877
+ const textContent = result.outputs.filter((output) => output.type === "text").map((output) => output.content).join("");
2878
+ if (textContent.trim()) {
2879
+ const { gadgetName, parameterMapping, resultMapping } = this.textWithGadgetsHandler;
2880
+ this.conversation.addGadgetCall(
2881
+ gadgetName,
2882
+ parameterMapping(textContent),
2883
+ resultMapping ? resultMapping(textContent) : textContent
2884
+ );
2885
+ }
2886
+ }
2836
2887
  for (const output of result.outputs) {
2837
2888
  if (output.type === "gadget_result") {
2838
2889
  const gadgetResult = output.result;
@@ -2844,7 +2895,13 @@ var init_agent = __esm({
2844
2895
  }
2845
2896
  }
2846
2897
  } else {
2847
- this.conversation.addAssistantMessage(finalMessage);
2898
+ if (finalMessage.trim()) {
2899
+ this.conversation.addGadgetCall(
2900
+ "TellUser",
2901
+ { message: finalMessage, done: false, type: "info" },
2902
+ `\u2139\uFE0F ${finalMessage}`
2903
+ );
2904
+ }
2848
2905
  const shouldBreak = await this.handleTextOnlyResponse(finalMessage);
2849
2906
  if (shouldBreak) {
2850
2907
  break;
@@ -4718,6 +4775,7 @@ var AgentBuilder;
4718
4775
  var init_builder = __esm({
4719
4776
  "src/agent/builder.ts"() {
4720
4777
  "use strict";
4778
+ init_constants();
4721
4779
  init_model_shortcuts();
4722
4780
  init_registry();
4723
4781
  init_agent();
@@ -4739,6 +4797,7 @@ var init_builder = __esm({
4739
4797
  gadgetStartPrefix;
4740
4798
  gadgetEndPrefix;
4741
4799
  textOnlyHandler;
4800
+ textWithGadgetsHandler;
4742
4801
  stopOnGadgetError;
4743
4802
  shouldContinueAfterError;
4744
4803
  defaultGadgetTimeoutMs;
@@ -5001,6 +5060,30 @@ var init_builder = __esm({
5001
5060
  this.textOnlyHandler = handler;
5002
5061
  return this;
5003
5062
  }
5063
+ /**
5064
+ * Set the handler for text content that appears alongside gadget calls.
5065
+ *
5066
+ * When set, text accompanying gadget responses will be wrapped as a
5067
+ * synthetic gadget call before the actual gadget results in the
5068
+ * conversation history.
5069
+ *
5070
+ * @param handler - Configuration for wrapping text
5071
+ * @returns This builder for chaining
5072
+ *
5073
+ * @example
5074
+ * ```typescript
5075
+ * // Wrap text as TellUser gadget
5076
+ * .withTextWithGadgetsHandler({
5077
+ * gadgetName: "TellUser",
5078
+ * parameterMapping: (text) => ({ message: text, done: false, type: "info" }),
5079
+ * resultMapping: (text) => `ℹ️ ${text}`,
5080
+ * })
5081
+ * ```
5082
+ */
5083
+ withTextWithGadgetsHandler(handler) {
5084
+ this.textWithGadgetsHandler = handler;
5085
+ return this;
5086
+ }
5004
5087
  /**
5005
5088
  * Set whether to stop gadget execution on first error.
5006
5089
  *
@@ -5115,6 +5198,69 @@ var init_builder = __esm({
5115
5198
  this.gadgetOutputLimitPercent = percent;
5116
5199
  return this;
5117
5200
  }
5201
+ /**
5202
+ * Add a synthetic gadget call to the conversation history.
5203
+ *
5204
+ * This is useful for in-context learning - showing the LLM what "past self"
5205
+ * did correctly so it mimics the pattern. The call is formatted with proper
5206
+ * markers and parameter format.
5207
+ *
5208
+ * @param gadgetName - Name of the gadget
5209
+ * @param parameters - Parameters passed to the gadget
5210
+ * @param result - Result returned by the gadget
5211
+ * @returns This builder for chaining
5212
+ *
5213
+ * @example
5214
+ * ```typescript
5215
+ * .withSyntheticGadgetCall(
5216
+ * 'TellUser',
5217
+ * {
5218
+ * message: '👋 Hello!\n\nHere\'s what I can do:\n- Analyze code\n- Run commands',
5219
+ * done: false,
5220
+ * type: 'info'
5221
+ * },
5222
+ * 'ℹ️ 👋 Hello!\n\nHere\'s what I can do:\n- Analyze code\n- Run commands'
5223
+ * )
5224
+ * ```
5225
+ */
5226
+ withSyntheticGadgetCall(gadgetName, parameters, result) {
5227
+ const startPrefix = this.gadgetStartPrefix ?? GADGET_START_PREFIX;
5228
+ const endPrefix = this.gadgetEndPrefix ?? GADGET_END_PREFIX;
5229
+ const format = this.parameterFormat ?? "yaml";
5230
+ const paramStr = this.formatSyntheticParameters(parameters, format);
5231
+ this.initialMessages.push({
5232
+ role: "assistant",
5233
+ content: `${startPrefix}${gadgetName}
5234
+ ${paramStr}
5235
+ ${endPrefix}`
5236
+ });
5237
+ this.initialMessages.push({
5238
+ role: "user",
5239
+ content: `Result: ${result}`
5240
+ });
5241
+ return this;
5242
+ }
5243
+ /**
5244
+ * Format parameters for synthetic gadget calls.
5245
+ * Uses heredoc for multiline string values.
5246
+ */
5247
+ formatSyntheticParameters(parameters, format) {
5248
+ if (format === "json" || format === "auto") {
5249
+ return JSON.stringify(parameters);
5250
+ }
5251
+ return Object.entries(parameters).map(([key, value]) => {
5252
+ if (typeof value === "string" && value.includes("\n")) {
5253
+ const separator = format === "yaml" ? ":" : " =";
5254
+ return `${key}${separator} <<<EOF
5255
+ ${value}
5256
+ EOF`;
5257
+ }
5258
+ if (format === "yaml") {
5259
+ return typeof value === "string" ? `${key}: ${value}` : `${key}: ${JSON.stringify(value)}`;
5260
+ }
5261
+ return `${key} = ${JSON.stringify(value)}`;
5262
+ }).join("\n");
5263
+ }
5118
5264
  /**
5119
5265
  * Build and create the agent with the given user prompt.
5120
5266
  * Returns the Agent instance ready to run.
@@ -5157,6 +5303,7 @@ var init_builder = __esm({
5157
5303
  gadgetStartPrefix: this.gadgetStartPrefix,
5158
5304
  gadgetEndPrefix: this.gadgetEndPrefix,
5159
5305
  textOnlyHandler: this.textOnlyHandler,
5306
+ textWithGadgetsHandler: this.textWithGadgetsHandler,
5160
5307
  stopOnGadgetError: this.stopOnGadgetError,
5161
5308
  shouldContinueAfterError: this.shouldContinueAfterError,
5162
5309
  defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
@@ -5258,6 +5405,7 @@ var init_builder = __esm({
5258
5405
  gadgetStartPrefix: this.gadgetStartPrefix,
5259
5406
  gadgetEndPrefix: this.gadgetEndPrefix,
5260
5407
  textOnlyHandler: this.textOnlyHandler,
5408
+ textWithGadgetsHandler: this.textWithGadgetsHandler,
5261
5409
  stopOnGadgetError: this.stopOnGadgetError,
5262
5410
  shouldContinueAfterError: this.shouldContinueAfterError,
5263
5411
  defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,