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.
@@ -8,7 +8,7 @@ import {
8
8
  init_constants,
9
9
  init_gadget,
10
10
  init_logger
11
- } from "./chunk-KB7LMYC2.js";
11
+ } from "./chunk-ZFHFBEQ5.js";
12
12
 
13
13
  // src/gadgets/validation.ts
14
14
  function validateAndApplyDefaults(schema, params) {
@@ -900,4 +900,4 @@ export {
900
900
  MockGadgetBuilder,
901
901
  mockGadget
902
902
  };
903
- //# sourceMappingURL=chunk-YWJSGEYT.js.map
903
+ //# sourceMappingURL=chunk-CTC2WJZA.js.map
@@ -629,7 +629,9 @@ This content can contain:
629
629
  - Multiple paragraphs
630
630
  EOF
631
631
 
632
- The delimiter (EOF) can be any identifier. The closing delimiter must be on its own line.`);
632
+ The delimiter (EOF) can be any identifier. The closing delimiter must be on its own line.
633
+ IMPORTANT: Content inside heredoc is LITERAL - do NOT escape backticks, dollar signs, or any characters.
634
+ NEVER use TOML triple-quote strings ("""). ALWAYS use heredoc syntax (<<<EOF...EOF) for multiline content.`);
633
635
  }
634
636
  return parts.join("");
635
637
  }
@@ -677,9 +679,9 @@ ${this.endPrefix}`
677
679
  if (format === "toml") {
678
680
  return Object.entries(parameters).map(([key, value]) => {
679
681
  if (typeof value === "string" && value.includes("\n")) {
680
- return `${key} = """
682
+ return `${key} = <<<EOF
681
683
  ${value}
682
- """`;
684
+ EOF`;
683
685
  }
684
686
  return `${key} = ${JSON.stringify(value)}`;
685
687
  }).join("\n");
@@ -925,6 +927,10 @@ function formatParamsAsYaml(params) {
925
927
  }
926
928
  return lines.join("\n");
927
929
  }
930
+ function formatTomlInlineTable(obj) {
931
+ const entries = Object.entries(obj).map(([k, v]) => `${k} = ${formatTomlValue(v)}`);
932
+ return `{ ${entries.join(", ")} }`;
933
+ }
928
934
  function formatTomlValue(value) {
929
935
  if (typeof value === "string") {
930
936
  if (value.includes("\n")) {
@@ -942,10 +948,17 @@ ${delimiter}`;
942
948
  return '""';
943
949
  }
944
950
  if (Array.isArray(value)) {
945
- return JSON.stringify(value);
951
+ if (value.length === 0) return "[]";
952
+ const items = value.map((item) => {
953
+ if (typeof item === "object" && item !== null && !Array.isArray(item)) {
954
+ return formatTomlInlineTable(item);
955
+ }
956
+ return formatTomlValue(item);
957
+ });
958
+ return `[${items.join(", ")}]`;
946
959
  }
947
960
  if (typeof value === "object") {
948
- return JSON.stringify(value);
961
+ return formatTomlInlineTable(value);
949
962
  }
950
963
  return JSON.stringify(value);
951
964
  }
@@ -1499,7 +1512,8 @@ var init_executor = __esm({
1499
1512
  if (call.parseError || !call.parameters) {
1500
1513
  this.logger.error("Gadget parameter parse error", {
1501
1514
  gadgetName: call.gadgetName,
1502
- parseError: call.parseError
1515
+ parseError: call.parseError,
1516
+ rawParameters: call.parametersYaml
1503
1517
  });
1504
1518
  return {
1505
1519
  gadgetName: call.gadgetName,
@@ -1780,6 +1794,9 @@ function preprocessYaml(yamlStr) {
1780
1794
  }
1781
1795
  return result.join("\n");
1782
1796
  }
1797
+ function unescapeHeredocContent(content) {
1798
+ return content.replace(/\\`/g, "`").replace(/\\\$/g, "$").replace(/\\{/g, "{").replace(/\\}/g, "}");
1799
+ }
1783
1800
  function preprocessTomlHeredoc(tomlStr) {
1784
1801
  const lines = tomlStr.split("\n");
1785
1802
  const result = [];
@@ -1805,13 +1822,13 @@ function preprocessTomlHeredoc(tomlStr) {
1805
1822
  i++;
1806
1823
  }
1807
1824
  if (bodyLines.length === 0) {
1808
- result.push(`${indent}${key} = """"""`);
1825
+ result.push(`${indent}${key} = ''''''`);
1809
1826
  } else {
1810
- result.push(`${indent}${key} = """`);
1827
+ result.push(`${indent}${key} = '''`);
1811
1828
  for (let j = 0; j < bodyLines.length - 1; j++) {
1812
- result.push(bodyLines[j]);
1829
+ result.push(unescapeHeredocContent(bodyLines[j]));
1813
1830
  }
1814
- result.push(`${bodyLines[bodyLines.length - 1]}"""`);
1831
+ result.push(`${unescapeHeredocContent(bodyLines[bodyLines.length - 1])}'''`);
1815
1832
  }
1816
1833
  if (!foundClosing) {
1817
1834
  }
@@ -1822,6 +1839,14 @@ function preprocessTomlHeredoc(tomlStr) {
1822
1839
  }
1823
1840
  return result.join("\n");
1824
1841
  }
1842
+ function stripMarkdownFences(content) {
1843
+ let cleaned = content.trim();
1844
+ const openingFence = /^```(?:toml|yaml|json)?\s*\n/i;
1845
+ const closingFence = /\n?```\s*$/;
1846
+ cleaned = cleaned.replace(openingFence, "");
1847
+ cleaned = cleaned.replace(closingFence, "");
1848
+ return cleaned.trim();
1849
+ }
1825
1850
  var globalInvocationCounter, StreamParser;
1826
1851
  var init_parser = __esm({
1827
1852
  "src/gadgets/parser.ts"() {
@@ -1858,43 +1883,55 @@ var init_parser = __esm({
1858
1883
  }
1859
1884
  return { actualName: gadgetName, invocationId: `gadget_${++globalInvocationCounter}` };
1860
1885
  }
1886
+ /**
1887
+ * Truncate verbose parse errors to avoid context overflow.
1888
+ * Keeps first meaningful line and limits total length.
1889
+ */
1890
+ truncateParseError(error, format) {
1891
+ const message = error instanceof Error ? error.message : String(error);
1892
+ const firstLine = message.split("\n")[0];
1893
+ const maxLen = 200;
1894
+ if (firstLine.length <= maxLen) {
1895
+ return firstLine;
1896
+ }
1897
+ return `${firstLine.slice(0, maxLen)}... (${message.length} chars total)`;
1898
+ }
1861
1899
  /**
1862
1900
  * Parse parameter string according to configured format
1863
1901
  */
1864
1902
  parseParameters(raw) {
1903
+ const cleaned = stripMarkdownFences(raw);
1865
1904
  if (this.parameterFormat === "json") {
1866
1905
  try {
1867
- return { parameters: JSON.parse(raw) };
1906
+ return { parameters: JSON.parse(cleaned) };
1868
1907
  } catch (error) {
1869
- return { parseError: error instanceof Error ? error.message : "Failed to parse JSON" };
1908
+ return { parseError: this.truncateParseError(error, "JSON") };
1870
1909
  }
1871
1910
  }
1872
1911
  if (this.parameterFormat === "yaml") {
1873
1912
  try {
1874
- return { parameters: yaml2.load(preprocessYaml(raw)) };
1913
+ return { parameters: yaml2.load(preprocessYaml(cleaned)) };
1875
1914
  } catch (error) {
1876
- return { parseError: error instanceof Error ? error.message : "Failed to parse YAML" };
1915
+ return { parseError: this.truncateParseError(error, "YAML") };
1877
1916
  }
1878
1917
  }
1879
1918
  if (this.parameterFormat === "toml") {
1880
1919
  try {
1881
- return { parameters: parseToml(preprocessTomlHeredoc(raw)) };
1920
+ return { parameters: parseToml(preprocessTomlHeredoc(cleaned)) };
1882
1921
  } catch (error) {
1883
- return { parseError: error instanceof Error ? error.message : "Failed to parse TOML" };
1922
+ return { parseError: this.truncateParseError(error, "TOML") };
1884
1923
  }
1885
1924
  }
1886
1925
  try {
1887
- return { parameters: JSON.parse(raw) };
1926
+ return { parameters: JSON.parse(cleaned) };
1888
1927
  } catch {
1889
1928
  try {
1890
- return { parameters: parseToml(preprocessTomlHeredoc(raw)) };
1929
+ return { parameters: parseToml(preprocessTomlHeredoc(cleaned)) };
1891
1930
  } catch {
1892
1931
  try {
1893
- return { parameters: yaml2.load(preprocessYaml(raw)) };
1932
+ return { parameters: yaml2.load(preprocessYaml(cleaned)) };
1894
1933
  } catch (error) {
1895
- return {
1896
- parseError: error instanceof Error ? error.message : "Failed to parse as JSON, TOML, or YAML"
1897
- };
1934
+ return { parseError: this.truncateParseError(error, "auto") };
1898
1935
  }
1899
1936
  }
1900
1937
  }
@@ -2350,7 +2387,8 @@ var init_stream_processor = __esm({
2350
2387
  if (call.parseError) {
2351
2388
  this.logger.warn("Gadget has parse error", {
2352
2389
  gadgetName: call.gadgetName,
2353
- error: call.parseError
2390
+ error: call.parseError,
2391
+ rawParameters: call.parametersYaml
2354
2392
  });
2355
2393
  const shouldContinue = await this.checkContinueAfterError(
2356
2394
  call.parseError,
@@ -4050,6 +4088,7 @@ var init_agent = __esm({
4050
4088
  gadgetEndPrefix;
4051
4089
  onHumanInputRequired;
4052
4090
  textOnlyHandler;
4091
+ textWithGadgetsHandler;
4053
4092
  stopOnGadgetError;
4054
4093
  shouldContinueAfterError;
4055
4094
  defaultGadgetTimeoutMs;
@@ -4080,6 +4119,7 @@ var init_agent = __esm({
4080
4119
  this.gadgetEndPrefix = options.gadgetEndPrefix;
4081
4120
  this.onHumanInputRequired = options.onHumanInputRequired;
4082
4121
  this.textOnlyHandler = options.textOnlyHandler ?? "terminate";
4122
+ this.textWithGadgetsHandler = options.textWithGadgetsHandler;
4083
4123
  this.stopOnGadgetError = options.stopOnGadgetError ?? true;
4084
4124
  this.shouldContinueAfterError = options.shouldContinueAfterError;
4085
4125
  this.defaultGadgetTimeoutMs = options.defaultGadgetTimeoutMs;
@@ -4267,6 +4307,17 @@ var init_agent = __esm({
4267
4307
  }
4268
4308
  }
4269
4309
  if (result.didExecuteGadgets) {
4310
+ if (this.textWithGadgetsHandler) {
4311
+ const textContent = result.outputs.filter((output) => output.type === "text").map((output) => output.content).join("");
4312
+ if (textContent.trim()) {
4313
+ const { gadgetName, parameterMapping, resultMapping } = this.textWithGadgetsHandler;
4314
+ this.conversation.addGadgetCall(
4315
+ gadgetName,
4316
+ parameterMapping(textContent),
4317
+ resultMapping ? resultMapping(textContent) : textContent
4318
+ );
4319
+ }
4320
+ }
4270
4321
  for (const output of result.outputs) {
4271
4322
  if (output.type === "gadget_result") {
4272
4323
  const gadgetResult = output.result;
@@ -4278,7 +4329,13 @@ var init_agent = __esm({
4278
4329
  }
4279
4330
  }
4280
4331
  } else {
4281
- this.conversation.addAssistantMessage(finalMessage);
4332
+ if (finalMessage.trim()) {
4333
+ this.conversation.addGadgetCall(
4334
+ "TellUser",
4335
+ { message: finalMessage, done: false, type: "info" },
4336
+ `\u2139\uFE0F ${finalMessage}`
4337
+ );
4338
+ }
4282
4339
  const shouldBreak = await this.handleTextOnlyResponse(finalMessage);
4283
4340
  if (shouldBreak) {
4284
4341
  break;
@@ -4463,6 +4520,7 @@ var AgentBuilder;
4463
4520
  var init_builder = __esm({
4464
4521
  "src/agent/builder.ts"() {
4465
4522
  "use strict";
4523
+ init_constants();
4466
4524
  init_model_shortcuts();
4467
4525
  init_registry();
4468
4526
  init_agent();
@@ -4484,6 +4542,7 @@ var init_builder = __esm({
4484
4542
  gadgetStartPrefix;
4485
4543
  gadgetEndPrefix;
4486
4544
  textOnlyHandler;
4545
+ textWithGadgetsHandler;
4487
4546
  stopOnGadgetError;
4488
4547
  shouldContinueAfterError;
4489
4548
  defaultGadgetTimeoutMs;
@@ -4746,6 +4805,30 @@ var init_builder = __esm({
4746
4805
  this.textOnlyHandler = handler;
4747
4806
  return this;
4748
4807
  }
4808
+ /**
4809
+ * Set the handler for text content that appears alongside gadget calls.
4810
+ *
4811
+ * When set, text accompanying gadget responses will be wrapped as a
4812
+ * synthetic gadget call before the actual gadget results in the
4813
+ * conversation history.
4814
+ *
4815
+ * @param handler - Configuration for wrapping text
4816
+ * @returns This builder for chaining
4817
+ *
4818
+ * @example
4819
+ * ```typescript
4820
+ * // Wrap text as TellUser gadget
4821
+ * .withTextWithGadgetsHandler({
4822
+ * gadgetName: "TellUser",
4823
+ * parameterMapping: (text) => ({ message: text, done: false, type: "info" }),
4824
+ * resultMapping: (text) => `ℹ️ ${text}`,
4825
+ * })
4826
+ * ```
4827
+ */
4828
+ withTextWithGadgetsHandler(handler) {
4829
+ this.textWithGadgetsHandler = handler;
4830
+ return this;
4831
+ }
4749
4832
  /**
4750
4833
  * Set whether to stop gadget execution on first error.
4751
4834
  *
@@ -4860,6 +4943,69 @@ var init_builder = __esm({
4860
4943
  this.gadgetOutputLimitPercent = percent;
4861
4944
  return this;
4862
4945
  }
4946
+ /**
4947
+ * Add a synthetic gadget call to the conversation history.
4948
+ *
4949
+ * This is useful for in-context learning - showing the LLM what "past self"
4950
+ * did correctly so it mimics the pattern. The call is formatted with proper
4951
+ * markers and parameter format.
4952
+ *
4953
+ * @param gadgetName - Name of the gadget
4954
+ * @param parameters - Parameters passed to the gadget
4955
+ * @param result - Result returned by the gadget
4956
+ * @returns This builder for chaining
4957
+ *
4958
+ * @example
4959
+ * ```typescript
4960
+ * .withSyntheticGadgetCall(
4961
+ * 'TellUser',
4962
+ * {
4963
+ * message: '👋 Hello!\n\nHere\'s what I can do:\n- Analyze code\n- Run commands',
4964
+ * done: false,
4965
+ * type: 'info'
4966
+ * },
4967
+ * 'ℹ️ 👋 Hello!\n\nHere\'s what I can do:\n- Analyze code\n- Run commands'
4968
+ * )
4969
+ * ```
4970
+ */
4971
+ withSyntheticGadgetCall(gadgetName, parameters, result) {
4972
+ const startPrefix = this.gadgetStartPrefix ?? GADGET_START_PREFIX;
4973
+ const endPrefix = this.gadgetEndPrefix ?? GADGET_END_PREFIX;
4974
+ const format = this.parameterFormat ?? "yaml";
4975
+ const paramStr = this.formatSyntheticParameters(parameters, format);
4976
+ this.initialMessages.push({
4977
+ role: "assistant",
4978
+ content: `${startPrefix}${gadgetName}
4979
+ ${paramStr}
4980
+ ${endPrefix}`
4981
+ });
4982
+ this.initialMessages.push({
4983
+ role: "user",
4984
+ content: `Result: ${result}`
4985
+ });
4986
+ return this;
4987
+ }
4988
+ /**
4989
+ * Format parameters for synthetic gadget calls.
4990
+ * Uses heredoc for multiline string values.
4991
+ */
4992
+ formatSyntheticParameters(parameters, format) {
4993
+ if (format === "json" || format === "auto") {
4994
+ return JSON.stringify(parameters);
4995
+ }
4996
+ return Object.entries(parameters).map(([key, value]) => {
4997
+ if (typeof value === "string" && value.includes("\n")) {
4998
+ const separator = format === "yaml" ? ":" : " =";
4999
+ return `${key}${separator} <<<EOF
5000
+ ${value}
5001
+ EOF`;
5002
+ }
5003
+ if (format === "yaml") {
5004
+ return typeof value === "string" ? `${key}: ${value}` : `${key}: ${JSON.stringify(value)}`;
5005
+ }
5006
+ return `${key} = ${JSON.stringify(value)}`;
5007
+ }).join("\n");
5008
+ }
4863
5009
  /**
4864
5010
  * Build and create the agent with the given user prompt.
4865
5011
  * Returns the Agent instance ready to run.
@@ -4902,6 +5048,7 @@ var init_builder = __esm({
4902
5048
  gadgetStartPrefix: this.gadgetStartPrefix,
4903
5049
  gadgetEndPrefix: this.gadgetEndPrefix,
4904
5050
  textOnlyHandler: this.textOnlyHandler,
5051
+ textWithGadgetsHandler: this.textWithGadgetsHandler,
4905
5052
  stopOnGadgetError: this.stopOnGadgetError,
4906
5053
  shouldContinueAfterError: this.shouldContinueAfterError,
4907
5054
  defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
@@ -5003,6 +5150,7 @@ var init_builder = __esm({
5003
5150
  gadgetStartPrefix: this.gadgetStartPrefix,
5004
5151
  gadgetEndPrefix: this.gadgetEndPrefix,
5005
5152
  textOnlyHandler: this.textOnlyHandler,
5153
+ textWithGadgetsHandler: this.textWithGadgetsHandler,
5006
5154
  stopOnGadgetError: this.stopOnGadgetError,
5007
5155
  shouldContinueAfterError: this.shouldContinueAfterError,
5008
5156
  defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
@@ -5258,6 +5406,9 @@ var init_client = __esm({
5258
5406
  });
5259
5407
 
5260
5408
  export {
5409
+ GADGET_START_PREFIX,
5410
+ GADGET_END_PREFIX,
5411
+ init_constants,
5261
5412
  MODEL_ALIASES,
5262
5413
  resolveModel,
5263
5414
  hasProviderPrefix,
@@ -5266,9 +5417,6 @@ export {
5266
5417
  init_model_shortcuts,
5267
5418
  GadgetRegistry,
5268
5419
  init_registry,
5269
- GADGET_START_PREFIX,
5270
- GADGET_END_PREFIX,
5271
- init_constants,
5272
5420
  DEFAULT_PROMPTS,
5273
5421
  resolvePromptTemplate,
5274
5422
  resolveRulesTemplate,
@@ -5326,4 +5474,4 @@ export {
5326
5474
  AgentBuilder,
5327
5475
  init_builder
5328
5476
  };
5329
- //# sourceMappingURL=chunk-KB7LMYC2.js.map
5477
+ //# sourceMappingURL=chunk-ZFHFBEQ5.js.map