llmist 0.5.1 → 0.6.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.
@@ -362,7 +362,7 @@ var init_prompt_config = __esm({
362
362
  criticalUsage: "INVOKE gadgets using the markers - do not describe what you want to do.",
363
363
  formatDescriptionYaml: "Parameters in YAML format (one per line)",
364
364
  formatDescriptionJson: "Parameters in JSON format (valid JSON object)",
365
- formatDescriptionToml: "Parameters in TOML format (key = value pairs, use triple-quotes for multiline)",
365
+ formatDescriptionToml: "Parameters in TOML format (key = value pairs, use heredoc for multiline: key = <<<EOF ... EOF)",
366
366
  rules: () => [
367
367
  "Output ONLY plain text with the exact markers - never use function/tool calling",
368
368
  "You can invoke multiple gadgets in a single response",
@@ -377,12 +377,16 @@ var init_prompt_config = __esm({
377
377
  });
378
378
 
379
379
  // src/core/constants.ts
380
- var GADGET_START_PREFIX, GADGET_END_PREFIX;
380
+ var GADGET_START_PREFIX, GADGET_END_PREFIX, DEFAULT_GADGET_OUTPUT_LIMIT, DEFAULT_GADGET_OUTPUT_LIMIT_PERCENT, CHARS_PER_TOKEN, FALLBACK_CONTEXT_WINDOW;
381
381
  var init_constants = __esm({
382
382
  "src/core/constants.ts"() {
383
383
  "use strict";
384
384
  GADGET_START_PREFIX = "!!!GADGET_START:";
385
385
  GADGET_END_PREFIX = "!!!GADGET_END";
386
+ DEFAULT_GADGET_OUTPUT_LIMIT = true;
387
+ DEFAULT_GADGET_OUTPUT_LIMIT_PERCENT = 15;
388
+ CHARS_PER_TOKEN = 4;
389
+ FALLBACK_CONTEXT_WINDOW = 128e3;
386
390
  }
387
391
  });
388
392
 
@@ -553,10 +557,11 @@ ${this.endPrefix}
553
557
  ${this.startPrefix}analyze
554
558
  type: economic_analysis
555
559
  matter: "Polish Economy"
556
- question: |
557
- Analyze the following:
558
- - Polish arms exports 2025
559
- - Economic implications
560
+ question: <<<EOF
561
+ Analyze the following:
562
+ - Polish arms exports 2025
563
+ - Economic implications
564
+ EOF
560
565
  ${this.endPrefix}`,
561
566
  json: `${this.startPrefix}translate
562
567
  {"from": "English", "to": "Polish", "content": "Paris is the capital of France: a beautiful city."}
@@ -572,11 +577,11 @@ ${this.endPrefix}
572
577
  ${this.startPrefix}analyze
573
578
  type = "economic_analysis"
574
579
  matter = "Polish Economy"
575
- question = """
580
+ question = <<<EOF
576
581
  Analyze the following:
577
582
  - Polish arms exports 2025
578
583
  - Economic implications
579
- """
584
+ EOF
580
585
  ${this.endPrefix}`,
581
586
  auto: `${this.startPrefix}translate
582
587
  {"from": "English", "to": "Polish", "content": "Paris is the capital of France: a beautiful city."}
@@ -593,37 +598,38 @@ ${multipleExamples[parameterFormat]}`);
593
598
  if (parameterFormat === "yaml") {
594
599
  parts.push(`
595
600
 
596
- YAML MULTILINE SYNTAX:
597
- For string values with special characters (colons, dashes, quotes) or multiple lines,
598
- use the pipe (|) syntax. ALL content lines MUST be indented with 2 spaces:
601
+ YAML HEREDOC SYNTAX:
602
+ For string values with multiple lines, use heredoc syntax (<<<DELIMITER...DELIMITER):
603
+
604
+ filePath: "README.md"
605
+ content: <<<EOF
606
+ # Project Title
599
607
 
600
- CORRECT - all lines indented:
601
- question: |
602
- Which option do you prefer?
603
- - Option A: fast processing
604
- - Option B: thorough analysis
605
- Please choose one.
608
+ This content can contain:
609
+ - Markdown lists
610
+ - Special characters: # : -
611
+ - Multiple paragraphs
612
+ EOF
606
613
 
607
- WRONG - inconsistent indentation breaks YAML:
608
- question: |
609
- Which option do you prefer?
610
- - Option A: fast
611
- Please choose one. <-- ERROR: not indented, breaks out of the block`);
614
+ The delimiter (EOF) can be any identifier. The closing delimiter must be on its own line.
615
+ No indentation is required for the content.`);
612
616
  } else if (parameterFormat === "toml") {
613
617
  parts.push(`
614
618
 
615
- TOML MULTILINE SYNTAX:
616
- For string values with multiple lines or special characters, use triple-quotes ("""):
619
+ TOML HEREDOC SYNTAX:
620
+ For string values with multiple lines, use heredoc syntax (<<<DELIMITER...DELIMITER):
617
621
 
618
622
  filePath = "README.md"
619
- content = """
623
+ content = <<<EOF
620
624
  # Project Title
621
625
 
622
626
  This content can contain:
623
627
  - Markdown lists
624
628
  - Special characters: # : -
625
629
  - Multiple paragraphs
626
- """`);
630
+ EOF
631
+
632
+ The delimiter (EOF) can be any identifier. The closing delimiter must be on its own line.`);
627
633
  }
628
634
  return parts.join("");
629
635
  }
@@ -705,18 +711,28 @@ function parseLogLevel(value) {
705
711
  }
706
712
  return LEVEL_NAME_TO_ID[normalized];
707
713
  }
714
+ function parseEnvBoolean(value) {
715
+ if (!value) return void 0;
716
+ const normalized = value.trim().toLowerCase();
717
+ if (normalized === "true" || normalized === "1") return true;
718
+ if (normalized === "false" || normalized === "0") return false;
719
+ return void 0;
720
+ }
708
721
  function createLogger(options = {}) {
709
722
  const envMinLevel = parseLogLevel(process.env.LLMIST_LOG_LEVEL);
710
723
  const envLogFile = process.env.LLMIST_LOG_FILE?.trim() ?? "";
724
+ const envLogReset = parseEnvBoolean(process.env.LLMIST_LOG_RESET);
711
725
  const minLevel = options.minLevel ?? envMinLevel ?? 4;
712
726
  const defaultType = options.type ?? "pretty";
713
727
  const name = options.name ?? "llmist";
728
+ const logReset = options.logReset ?? envLogReset ?? false;
714
729
  let logFileStream;
715
730
  let finalType = defaultType;
716
731
  if (envLogFile) {
717
732
  try {
718
733
  mkdirSync(dirname(envLogFile), { recursive: true });
719
- logFileStream = createWriteStream(envLogFile, { flags: "a" });
734
+ const flags = logReset ? "w" : "a";
735
+ logFileStream = createWriteStream(envLogFile, { flags });
720
736
  finalType = "hidden";
721
737
  } catch (error) {
722
738
  console.error("Failed to initialize LLMIST_LOG_FILE output:", error);
@@ -756,6 +772,531 @@ var init_logger = __esm({
756
772
  }
757
773
  });
758
774
 
775
+ // src/gadgets/schema-to-json.ts
776
+ import * as z2 from "zod";
777
+ function schemaToJSONSchema(schema, options) {
778
+ const jsonSchema = z2.toJSONSchema(schema, options ?? { target: "draft-7" });
779
+ const mismatches = detectDescriptionMismatch(schema, jsonSchema);
780
+ if (mismatches.length > 0) {
781
+ defaultLogger.warn(
782
+ `Zod instance mismatch detected: ${mismatches.length} description(s) lost. For best results, use: import { z } from "llmist"`
783
+ );
784
+ return mergeDescriptions(schema, jsonSchema);
785
+ }
786
+ return jsonSchema;
787
+ }
788
+ function detectDescriptionMismatch(schema, jsonSchema) {
789
+ const mismatches = [];
790
+ function checkSchema(zodSchema, json, path) {
791
+ if (!zodSchema || typeof zodSchema !== "object") return;
792
+ const def = zodSchema._def;
793
+ const jsonObj = json;
794
+ if (def?.description && !jsonObj?.description) {
795
+ mismatches.push(path || "root");
796
+ }
797
+ if (def?.typeName === "ZodObject" && def?.shape) {
798
+ const shape = typeof def.shape === "function" ? def.shape() : def.shape;
799
+ for (const [key, fieldSchema] of Object.entries(shape)) {
800
+ const properties = jsonObj?.properties;
801
+ const jsonProp = properties?.[key];
802
+ checkSchema(fieldSchema, jsonProp, path ? `${path}.${key}` : key);
803
+ }
804
+ }
805
+ if (def?.typeName === "ZodArray" && def?.type) {
806
+ checkSchema(def.type, jsonObj?.items, path ? `${path}[]` : "[]");
807
+ }
808
+ if ((def?.typeName === "ZodOptional" || def?.typeName === "ZodNullable") && def?.innerType) {
809
+ checkSchema(def.innerType, json, path);
810
+ }
811
+ if (def?.typeName === "ZodDefault" && def?.innerType) {
812
+ checkSchema(def.innerType, json, path);
813
+ }
814
+ }
815
+ checkSchema(schema, jsonSchema, "");
816
+ return mismatches;
817
+ }
818
+ function mergeDescriptions(schema, jsonSchema) {
819
+ function merge(zodSchema, json) {
820
+ if (!json || typeof json !== "object") return json;
821
+ const def = zodSchema._def;
822
+ const jsonObj = json;
823
+ const merged = { ...jsonObj };
824
+ if (def?.description && !jsonObj.description) {
825
+ merged.description = def.description;
826
+ }
827
+ if (def?.typeName === "ZodObject" && def?.shape && jsonObj.properties) {
828
+ const shape = typeof def.shape === "function" ? def.shape() : def.shape;
829
+ const properties = jsonObj.properties;
830
+ merged.properties = { ...properties };
831
+ for (const [key, fieldSchema] of Object.entries(shape)) {
832
+ if (properties[key]) {
833
+ merged.properties[key] = merge(fieldSchema, properties[key]);
834
+ }
835
+ }
836
+ }
837
+ if (def?.typeName === "ZodArray" && def?.type && jsonObj.items) {
838
+ merged.items = merge(def.type, jsonObj.items);
839
+ }
840
+ if ((def?.typeName === "ZodOptional" || def?.typeName === "ZodNullable") && def?.innerType) {
841
+ return merge(def.innerType, json);
842
+ }
843
+ if (def?.typeName === "ZodDefault" && def?.innerType) {
844
+ return merge(def.innerType, json);
845
+ }
846
+ return merged;
847
+ }
848
+ return merge(schema, jsonSchema);
849
+ }
850
+ var init_schema_to_json = __esm({
851
+ "src/gadgets/schema-to-json.ts"() {
852
+ "use strict";
853
+ init_logger();
854
+ }
855
+ });
856
+
857
+ // src/gadgets/gadget.ts
858
+ import * as yaml from "js-yaml";
859
+ function findSafeDelimiter(content) {
860
+ const lines = content.split("\n");
861
+ for (const delimiter of HEREDOC_DELIMITERS) {
862
+ const regex = new RegExp(`^${delimiter}\\s*$`);
863
+ const isUsed = lines.some((line) => regex.test(line));
864
+ if (!isUsed) {
865
+ return delimiter;
866
+ }
867
+ }
868
+ let counter = 1;
869
+ while (counter < 1e3) {
870
+ const delimiter = `HEREDOC_${counter}`;
871
+ const regex = new RegExp(`^${delimiter}\\s*$`);
872
+ const isUsed = lines.some((line) => regex.test(line));
873
+ if (!isUsed) {
874
+ return delimiter;
875
+ }
876
+ counter++;
877
+ }
878
+ return "HEREDOC_FALLBACK";
879
+ }
880
+ function formatYamlValue(value, indent = "") {
881
+ if (typeof value === "string") {
882
+ const lines = value.split("\n");
883
+ if (lines.length === 1 && !value.includes(":") && !value.startsWith("-")) {
884
+ return value;
885
+ }
886
+ const delimiter = findSafeDelimiter(value);
887
+ return `<<<${delimiter}
888
+ ${value}
889
+ ${delimiter}`;
890
+ }
891
+ if (typeof value === "number" || typeof value === "boolean") {
892
+ return String(value);
893
+ }
894
+ if (value === null || value === void 0) {
895
+ return "null";
896
+ }
897
+ if (Array.isArray(value)) {
898
+ if (value.length === 0) return "[]";
899
+ const items = value.map((item) => `${indent}- ${formatYamlValue(item, indent + " ")}`);
900
+ return "\n" + items.join("\n");
901
+ }
902
+ if (typeof value === "object") {
903
+ const entries = Object.entries(value);
904
+ if (entries.length === 0) return "{}";
905
+ const lines = entries.map(([k, v]) => {
906
+ const formattedValue = formatYamlValue(v, indent + " ");
907
+ if (formattedValue.startsWith("\n") || formattedValue.startsWith("|")) {
908
+ return `${indent}${k}: ${formattedValue}`;
909
+ }
910
+ return `${indent}${k}: ${formattedValue}`;
911
+ });
912
+ return "\n" + lines.join("\n");
913
+ }
914
+ return yaml.dump(value).trimEnd();
915
+ }
916
+ function formatParamsAsYaml(params) {
917
+ const lines = [];
918
+ for (const [key, value] of Object.entries(params)) {
919
+ const formattedValue = formatYamlValue(value, "");
920
+ if (formattedValue.startsWith("\n")) {
921
+ lines.push(`${key}:${formattedValue}`);
922
+ } else {
923
+ lines.push(`${key}: ${formattedValue}`);
924
+ }
925
+ }
926
+ return lines.join("\n");
927
+ }
928
+ function formatTomlValue(value) {
929
+ if (typeof value === "string") {
930
+ if (value.includes("\n")) {
931
+ const delimiter = findSafeDelimiter(value);
932
+ return `<<<${delimiter}
933
+ ${value}
934
+ ${delimiter}`;
935
+ }
936
+ return JSON.stringify(value);
937
+ }
938
+ if (typeof value === "number" || typeof value === "boolean") {
939
+ return String(value);
940
+ }
941
+ if (value === null || value === void 0) {
942
+ return '""';
943
+ }
944
+ if (Array.isArray(value)) {
945
+ return JSON.stringify(value);
946
+ }
947
+ if (typeof value === "object") {
948
+ return JSON.stringify(value);
949
+ }
950
+ return JSON.stringify(value);
951
+ }
952
+ function formatParamsAsToml(params) {
953
+ const lines = [];
954
+ for (const [key, value] of Object.entries(params)) {
955
+ lines.push(`${key} = ${formatTomlValue(value)}`);
956
+ }
957
+ return lines.join("\n");
958
+ }
959
+ var HEREDOC_DELIMITERS, BaseGadget;
960
+ var init_gadget = __esm({
961
+ "src/gadgets/gadget.ts"() {
962
+ "use strict";
963
+ init_schema_to_json();
964
+ init_schema_validator();
965
+ HEREDOC_DELIMITERS = ["EOF", "END", "DOC", "CONTENT", "TEXT", "HEREDOC", "DATA", "BLOCK"];
966
+ BaseGadget = class {
967
+ /**
968
+ * The name of the gadget. Used for identification when LLM calls it.
969
+ * If not provided, defaults to the class name.
970
+ */
971
+ name;
972
+ /**
973
+ * Optional Zod schema describing the expected input payload. When provided,
974
+ * it will be validated before execution and transformed into a JSON Schema
975
+ * representation that is surfaced to the LLM as part of the instructions.
976
+ */
977
+ parameterSchema;
978
+ /**
979
+ * Optional timeout in milliseconds for gadget execution.
980
+ * If execution exceeds this timeout, a TimeoutException will be thrown.
981
+ * If not set, the global defaultGadgetTimeoutMs from runtime options will be used.
982
+ * Set to 0 or undefined to disable timeout for this gadget.
983
+ */
984
+ timeoutMs;
985
+ /**
986
+ * Optional usage examples to help LLMs understand proper invocation.
987
+ * Examples are rendered in getInstruction() alongside the schema.
988
+ *
989
+ * Note: Uses broader `unknown` type to allow typed examples from subclasses
990
+ * while maintaining runtime compatibility.
991
+ */
992
+ examples;
993
+ /**
994
+ * Auto-generated instruction text for the LLM.
995
+ * Combines name, description, and parameter schema into a formatted instruction.
996
+ * @deprecated Use getInstruction(format) instead for format-specific schemas
997
+ */
998
+ get instruction() {
999
+ return this.getInstruction("yaml");
1000
+ }
1001
+ /**
1002
+ * Generate instruction text for the LLM with format-specific schema.
1003
+ * Combines name, description, and parameter schema into a formatted instruction.
1004
+ *
1005
+ * @param format - Format for the schema representation ('json' | 'yaml' | 'toml' | 'auto')
1006
+ * @returns Formatted instruction string
1007
+ */
1008
+ getInstruction(format = "json") {
1009
+ const parts = [];
1010
+ parts.push(this.description);
1011
+ if (this.parameterSchema) {
1012
+ const gadgetName = this.name ?? this.constructor.name;
1013
+ validateGadgetSchema(this.parameterSchema, gadgetName);
1014
+ const jsonSchema = schemaToJSONSchema(this.parameterSchema, {
1015
+ target: "draft-7"
1016
+ });
1017
+ if (format === "json" || format === "auto") {
1018
+ parts.push("\n\nInput Schema (JSON):");
1019
+ parts.push(JSON.stringify(jsonSchema, null, 2));
1020
+ } else if (format === "toml") {
1021
+ parts.push("\n\nInput Schema (TOML):");
1022
+ parts.push(JSON.stringify(jsonSchema, null, 2));
1023
+ } else {
1024
+ const yamlSchema = yaml.dump(jsonSchema).trimEnd();
1025
+ parts.push("\n\nInput Schema (YAML):");
1026
+ parts.push(yamlSchema);
1027
+ }
1028
+ }
1029
+ if (this.examples && this.examples.length > 0) {
1030
+ parts.push("\n\nExamples:");
1031
+ this.examples.forEach((example, index) => {
1032
+ if (index > 0) {
1033
+ parts.push("");
1034
+ }
1035
+ if (example.comment) {
1036
+ parts.push(`# ${example.comment}`);
1037
+ }
1038
+ parts.push("Input:");
1039
+ if (format === "json" || format === "auto") {
1040
+ parts.push(JSON.stringify(example.params, null, 2));
1041
+ } else if (format === "toml") {
1042
+ parts.push(formatParamsAsToml(example.params));
1043
+ } else {
1044
+ parts.push(formatParamsAsYaml(example.params));
1045
+ }
1046
+ if (example.output !== void 0) {
1047
+ parts.push("Output:");
1048
+ parts.push(example.output);
1049
+ }
1050
+ });
1051
+ }
1052
+ return parts.join("\n");
1053
+ }
1054
+ };
1055
+ }
1056
+ });
1057
+
1058
+ // src/gadgets/create-gadget.ts
1059
+ function createGadget(config) {
1060
+ class DynamicGadget extends BaseGadget {
1061
+ name = config.name;
1062
+ description = config.description;
1063
+ parameterSchema = config.schema;
1064
+ timeoutMs = config.timeoutMs;
1065
+ examples = config.examples;
1066
+ execute(params) {
1067
+ return config.execute(params);
1068
+ }
1069
+ }
1070
+ return new DynamicGadget();
1071
+ }
1072
+ var init_create_gadget = __esm({
1073
+ "src/gadgets/create-gadget.ts"() {
1074
+ "use strict";
1075
+ init_gadget();
1076
+ }
1077
+ });
1078
+
1079
+ // src/gadgets/output-viewer.ts
1080
+ import { z as z3 } from "zod";
1081
+ function applyPattern(lines, pattern) {
1082
+ const regex = new RegExp(pattern.regex);
1083
+ if (!pattern.include) {
1084
+ return lines.filter((line) => !regex.test(line));
1085
+ }
1086
+ const matchIndices = /* @__PURE__ */ new Set();
1087
+ for (let i = 0; i < lines.length; i++) {
1088
+ if (regex.test(lines[i])) {
1089
+ const start = Math.max(0, i - pattern.before);
1090
+ const end = Math.min(lines.length - 1, i + pattern.after);
1091
+ for (let j = start; j <= end; j++) {
1092
+ matchIndices.add(j);
1093
+ }
1094
+ }
1095
+ }
1096
+ return lines.filter((_, index) => matchIndices.has(index));
1097
+ }
1098
+ function applyPatterns(lines, patterns) {
1099
+ let result = lines;
1100
+ for (const pattern of patterns) {
1101
+ result = applyPattern(result, pattern);
1102
+ }
1103
+ return result;
1104
+ }
1105
+ function applyLineLimit(lines, limit) {
1106
+ const trimmed = limit.trim();
1107
+ if (trimmed.endsWith("-") && !trimmed.startsWith("-")) {
1108
+ const n = parseInt(trimmed.slice(0, -1), 10);
1109
+ if (!isNaN(n) && n > 0) {
1110
+ return lines.slice(0, n);
1111
+ }
1112
+ }
1113
+ if (trimmed.startsWith("-") && !trimmed.includes("-", 1)) {
1114
+ const n = parseInt(trimmed, 10);
1115
+ if (!isNaN(n) && n < 0) {
1116
+ return lines.slice(n);
1117
+ }
1118
+ }
1119
+ const rangeMatch = trimmed.match(/^(\d+)-(\d+)$/);
1120
+ if (rangeMatch) {
1121
+ const start = parseInt(rangeMatch[1], 10);
1122
+ const end = parseInt(rangeMatch[2], 10);
1123
+ if (!isNaN(start) && !isNaN(end) && start > 0 && end >= start) {
1124
+ return lines.slice(start - 1, end);
1125
+ }
1126
+ }
1127
+ return lines;
1128
+ }
1129
+ function createGadgetOutputViewer(store) {
1130
+ return createGadget({
1131
+ name: "GadgetOutputViewer",
1132
+ description: "View stored output from gadgets that returned too much data. Use patterns to filter lines (like grep) and limit to control output size. Patterns are applied first in order, then the limit is applied to the result.",
1133
+ schema: z3.object({
1134
+ id: z3.string().describe("ID of the stored output (from the truncation message)"),
1135
+ patterns: z3.array(patternSchema).optional().describe(
1136
+ "Filter patterns applied in order (like piping through grep). Each pattern can include or exclude lines with optional before/after context."
1137
+ ),
1138
+ limit: z3.string().optional().describe(
1139
+ "Line range to return after filtering. Formats: '100-' (first 100), '-25' (last 25), '50-100' (lines 50-100)"
1140
+ )
1141
+ }),
1142
+ examples: [
1143
+ {
1144
+ comment: "View first 50 lines of stored output",
1145
+ params: { id: "Search_abc12345", limit: "50-" }
1146
+ },
1147
+ {
1148
+ comment: "Filter for error lines with context",
1149
+ params: {
1150
+ id: "Search_abc12345",
1151
+ patterns: [{ regex: "error|Error|ERROR", include: true, before: 2, after: 5 }]
1152
+ }
1153
+ },
1154
+ {
1155
+ comment: "Exclude blank lines, then show first 100",
1156
+ params: {
1157
+ id: "Search_abc12345",
1158
+ patterns: [{ regex: "^\\s*$", include: false, before: 0, after: 0 }],
1159
+ limit: "100-"
1160
+ }
1161
+ },
1162
+ {
1163
+ comment: "Chain filters: find TODOs, exclude tests, limit to 50 lines",
1164
+ params: {
1165
+ id: "Search_abc12345",
1166
+ patterns: [
1167
+ { regex: "TODO", include: true, before: 1, after: 1 },
1168
+ { regex: "test|spec", include: false, before: 0, after: 0 }
1169
+ ],
1170
+ limit: "50-"
1171
+ }
1172
+ }
1173
+ ],
1174
+ execute: ({ id, patterns, limit }) => {
1175
+ const stored = store.get(id);
1176
+ if (!stored) {
1177
+ return `Error: No stored output with id "${id}". Available IDs: ${store.getIds().join(", ") || "(none)"}`;
1178
+ }
1179
+ let lines = stored.content.split("\n");
1180
+ if (patterns && patterns.length > 0) {
1181
+ lines = applyPatterns(
1182
+ lines,
1183
+ patterns.map((p) => ({
1184
+ regex: p.regex,
1185
+ include: p.include ?? true,
1186
+ before: p.before ?? 0,
1187
+ after: p.after ?? 0
1188
+ }))
1189
+ );
1190
+ }
1191
+ if (limit) {
1192
+ lines = applyLineLimit(lines, limit);
1193
+ }
1194
+ const totalLines = stored.lineCount;
1195
+ const returnedLines = lines.length;
1196
+ if (returnedLines === 0) {
1197
+ return `No lines matched the filters. Original output had ${totalLines} lines.`;
1198
+ }
1199
+ const header = returnedLines < totalLines ? `[Showing ${returnedLines} of ${totalLines} lines]
1200
+ ` : `[Showing all ${totalLines} lines]
1201
+ `;
1202
+ return header + lines.join("\n");
1203
+ }
1204
+ });
1205
+ }
1206
+ var patternSchema;
1207
+ var init_output_viewer = __esm({
1208
+ "src/gadgets/output-viewer.ts"() {
1209
+ "use strict";
1210
+ init_create_gadget();
1211
+ patternSchema = z3.object({
1212
+ regex: z3.string().describe("Regular expression to match"),
1213
+ include: z3.boolean().default(true).describe("true = keep matching lines, false = exclude matching lines"),
1214
+ before: z3.number().int().min(0).default(0).describe("Context lines before each match (like grep -B)"),
1215
+ after: z3.number().int().min(0).default(0).describe("Context lines after each match (like grep -A)")
1216
+ });
1217
+ }
1218
+ });
1219
+
1220
+ // src/agent/gadget-output-store.ts
1221
+ import { randomBytes } from "node:crypto";
1222
+ var GadgetOutputStore;
1223
+ var init_gadget_output_store = __esm({
1224
+ "src/agent/gadget-output-store.ts"() {
1225
+ "use strict";
1226
+ GadgetOutputStore = class {
1227
+ outputs = /* @__PURE__ */ new Map();
1228
+ /**
1229
+ * Store a gadget output and return its ID.
1230
+ *
1231
+ * @param gadgetName - Name of the gadget that produced the output
1232
+ * @param content - Full output content to store
1233
+ * @returns Generated ID for retrieving the output later
1234
+ */
1235
+ store(gadgetName, content) {
1236
+ const id = this.generateId(gadgetName);
1237
+ const encoder = new TextEncoder();
1238
+ const stored = {
1239
+ id,
1240
+ gadgetName,
1241
+ content,
1242
+ byteSize: encoder.encode(content).length,
1243
+ lineCount: content.split("\n").length,
1244
+ timestamp: /* @__PURE__ */ new Date()
1245
+ };
1246
+ this.outputs.set(id, stored);
1247
+ return id;
1248
+ }
1249
+ /**
1250
+ * Retrieve a stored output by ID.
1251
+ *
1252
+ * @param id - The output ID (e.g., "Search_d34db33f")
1253
+ * @returns The stored output or undefined if not found
1254
+ */
1255
+ get(id) {
1256
+ return this.outputs.get(id);
1257
+ }
1258
+ /**
1259
+ * Check if an output exists.
1260
+ *
1261
+ * @param id - The output ID to check
1262
+ * @returns True if the output exists
1263
+ */
1264
+ has(id) {
1265
+ return this.outputs.has(id);
1266
+ }
1267
+ /**
1268
+ * Get all stored output IDs.
1269
+ *
1270
+ * @returns Array of output IDs
1271
+ */
1272
+ getIds() {
1273
+ return Array.from(this.outputs.keys());
1274
+ }
1275
+ /**
1276
+ * Get the number of stored outputs.
1277
+ */
1278
+ get size() {
1279
+ return this.outputs.size;
1280
+ }
1281
+ /**
1282
+ * Clear all stored outputs.
1283
+ * Called when the agent run completes.
1284
+ */
1285
+ clear() {
1286
+ this.outputs.clear();
1287
+ }
1288
+ /**
1289
+ * Generate a unique ID for a stored output.
1290
+ * Format: {GadgetName}_{8 hex chars}
1291
+ */
1292
+ generateId(gadgetName) {
1293
+ const hex = randomBytes(4).toString("hex");
1294
+ return `${gadgetName}_${hex}`;
1295
+ }
1296
+ };
1297
+ }
1298
+ });
1299
+
759
1300
  // src/agent/conversation-manager.ts
760
1301
  var ConversationManager;
761
1302
  var init_conversation_manager = __esm({
@@ -1121,7 +1662,7 @@ var init_executor = __esm({
1121
1662
  });
1122
1663
 
1123
1664
  // src/gadgets/parser.ts
1124
- import * as yaml from "js-yaml";
1665
+ import * as yaml2 from "js-yaml";
1125
1666
  import { load as parseToml } from "js-toml";
1126
1667
  function preprocessYaml(yamlStr) {
1127
1668
  const lines = yamlStr.split("\n");
@@ -1129,6 +1670,25 @@ function preprocessYaml(yamlStr) {
1129
1670
  let i = 0;
1130
1671
  while (i < lines.length) {
1131
1672
  const line = lines[i];
1673
+ const heredocMatch = line.match(/^(\s*)([\w-]+):\s*<<<([A-Za-z_][A-Za-z0-9_]*)\s*$/);
1674
+ if (heredocMatch) {
1675
+ const [, indent, key, delimiter] = heredocMatch;
1676
+ const bodyLines = [];
1677
+ i++;
1678
+ const closingRegex = new RegExp(`^${delimiter}\\s*$`);
1679
+ while (i < lines.length && !closingRegex.test(lines[i])) {
1680
+ bodyLines.push(lines[i]);
1681
+ i++;
1682
+ }
1683
+ if (i < lines.length) {
1684
+ i++;
1685
+ }
1686
+ result.push(`${indent}${key}: |`);
1687
+ for (const bodyLine of bodyLines) {
1688
+ result.push(`${indent} ${bodyLine}`);
1689
+ }
1690
+ continue;
1691
+ }
1132
1692
  const match = line.match(/^(\s*)([\w-]+):\s+(.+)$/);
1133
1693
  if (match) {
1134
1694
  const [, indent, key, value] = match;
@@ -1220,6 +1780,48 @@ function preprocessYaml(yamlStr) {
1220
1780
  }
1221
1781
  return result.join("\n");
1222
1782
  }
1783
+ function preprocessTomlHeredoc(tomlStr) {
1784
+ const lines = tomlStr.split("\n");
1785
+ const result = [];
1786
+ let i = 0;
1787
+ const heredocStartRegex = /^(\s*)([\w-]+)\s*=\s*<<<([A-Za-z_][A-Za-z0-9_]*)\s*$/;
1788
+ while (i < lines.length) {
1789
+ const line = lines[i];
1790
+ const match = line.match(heredocStartRegex);
1791
+ if (match) {
1792
+ const [, indent, key, delimiter] = match;
1793
+ const bodyLines = [];
1794
+ i++;
1795
+ const closingRegex = new RegExp(`^${delimiter}\\s*$`);
1796
+ let foundClosing = false;
1797
+ while (i < lines.length) {
1798
+ const bodyLine = lines[i];
1799
+ if (closingRegex.test(bodyLine)) {
1800
+ foundClosing = true;
1801
+ i++;
1802
+ break;
1803
+ }
1804
+ bodyLines.push(bodyLine);
1805
+ i++;
1806
+ }
1807
+ if (bodyLines.length === 0) {
1808
+ result.push(`${indent}${key} = """"""`);
1809
+ } else {
1810
+ result.push(`${indent}${key} = """`);
1811
+ for (let j = 0; j < bodyLines.length - 1; j++) {
1812
+ result.push(bodyLines[j]);
1813
+ }
1814
+ result.push(`${bodyLines[bodyLines.length - 1]}"""`);
1815
+ }
1816
+ if (!foundClosing) {
1817
+ }
1818
+ continue;
1819
+ }
1820
+ result.push(line);
1821
+ i++;
1822
+ }
1823
+ return result.join("\n");
1824
+ }
1223
1825
  var globalInvocationCounter, StreamParser;
1224
1826
  var init_parser = __esm({
1225
1827
  "src/gadgets/parser.ts"() {
@@ -1269,14 +1871,14 @@ var init_parser = __esm({
1269
1871
  }
1270
1872
  if (this.parameterFormat === "yaml") {
1271
1873
  try {
1272
- return { parameters: yaml.load(preprocessYaml(raw)) };
1874
+ return { parameters: yaml2.load(preprocessYaml(raw)) };
1273
1875
  } catch (error) {
1274
1876
  return { parseError: error instanceof Error ? error.message : "Failed to parse YAML" };
1275
1877
  }
1276
1878
  }
1277
1879
  if (this.parameterFormat === "toml") {
1278
1880
  try {
1279
- return { parameters: parseToml(raw) };
1881
+ return { parameters: parseToml(preprocessTomlHeredoc(raw)) };
1280
1882
  } catch (error) {
1281
1883
  return { parseError: error instanceof Error ? error.message : "Failed to parse TOML" };
1282
1884
  }
@@ -1285,10 +1887,10 @@ var init_parser = __esm({
1285
1887
  return { parameters: JSON.parse(raw) };
1286
1888
  } catch {
1287
1889
  try {
1288
- return { parameters: parseToml(raw) };
1890
+ return { parameters: parseToml(preprocessTomlHeredoc(raw)) };
1289
1891
  } catch {
1290
1892
  try {
1291
- return { parameters: yaml.load(preprocessYaml(raw)) };
1893
+ return { parameters: yaml2.load(preprocessYaml(raw)) };
1292
1894
  } catch (error) {
1293
1895
  return {
1294
1896
  parseError: error instanceof Error ? error.message : "Failed to parse as JSON, TOML, or YAML"
@@ -3423,9 +4025,12 @@ var Agent;
3423
4025
  var init_agent = __esm({
3424
4026
  "src/agent/agent.ts"() {
3425
4027
  "use strict";
4028
+ init_constants();
3426
4029
  init_messages();
3427
4030
  init_model_shortcuts();
4031
+ init_output_viewer();
3428
4032
  init_logger();
4033
+ init_gadget_output_store();
3429
4034
  init_agent_internal_key();
3430
4035
  init_conversation_manager();
3431
4036
  init_event_handlers();
@@ -3450,6 +4055,10 @@ var init_agent = __esm({
3450
4055
  defaultGadgetTimeoutMs;
3451
4056
  defaultMaxTokens;
3452
4057
  userPromptProvided;
4058
+ // Gadget output limiting
4059
+ outputStore;
4060
+ outputLimitEnabled;
4061
+ outputLimitCharLimit;
3453
4062
  /**
3454
4063
  * Creates a new Agent instance.
3455
4064
  * @internal This constructor is private. Use LLMist.createAgent() or AgentBuilder instead.
@@ -3465,7 +4074,6 @@ var init_agent = __esm({
3465
4074
  this.maxIterations = options.maxIterations ?? 10;
3466
4075
  this.temperature = options.temperature;
3467
4076
  this.logger = options.logger ?? createLogger({ name: "llmist:agent" });
3468
- this.hooks = options.hooks ?? {};
3469
4077
  this.registry = options.registry;
3470
4078
  this.parameterFormat = options.parameterFormat ?? "json";
3471
4079
  this.gadgetStartPrefix = options.gadgetStartPrefix;
@@ -3476,6 +4084,16 @@ var init_agent = __esm({
3476
4084
  this.shouldContinueAfterError = options.shouldContinueAfterError;
3477
4085
  this.defaultGadgetTimeoutMs = options.defaultGadgetTimeoutMs;
3478
4086
  this.defaultMaxTokens = this.resolveMaxTokensFromCatalog(options.model);
4087
+ this.outputLimitEnabled = options.gadgetOutputLimit ?? DEFAULT_GADGET_OUTPUT_LIMIT;
4088
+ this.outputStore = new GadgetOutputStore();
4089
+ const limitPercent = options.gadgetOutputLimitPercent ?? DEFAULT_GADGET_OUTPUT_LIMIT_PERCENT;
4090
+ const limits = this.client.modelRegistry.getModelLimits(this.model);
4091
+ const contextWindow = limits?.contextWindow ?? FALLBACK_CONTEXT_WINDOW;
4092
+ this.outputLimitCharLimit = Math.floor(contextWindow * (limitPercent / 100) * CHARS_PER_TOKEN);
4093
+ if (this.outputLimitEnabled) {
4094
+ this.registry.register("GadgetOutputViewer", createGadgetOutputViewer(this.outputStore));
4095
+ }
4096
+ this.hooks = this.mergeOutputLimiterHook(options.hooks);
3479
4097
  const baseBuilder = new LLMMessageBuilder(options.promptConfig);
3480
4098
  if (options.systemPrompt) {
3481
4099
  baseBuilder.addSystem(options.systemPrompt);
@@ -3780,6 +4398,43 @@ var init_agent = __esm({
3780
4398
  }
3781
4399
  return this.client.modelRegistry.getModelLimits(unprefixedModelId)?.maxOutputTokens;
3782
4400
  }
4401
+ /**
4402
+ * Merge the output limiter interceptor into user-provided hooks.
4403
+ * The limiter runs first, then chains to any user interceptor.
4404
+ */
4405
+ mergeOutputLimiterHook(userHooks) {
4406
+ if (!this.outputLimitEnabled) {
4407
+ return userHooks ?? {};
4408
+ }
4409
+ const limiterInterceptor = (result, ctx) => {
4410
+ if (ctx.gadgetName === "GadgetOutputViewer") {
4411
+ return result;
4412
+ }
4413
+ if (result.length > this.outputLimitCharLimit) {
4414
+ const id = this.outputStore.store(ctx.gadgetName, result);
4415
+ const lines = result.split("\n").length;
4416
+ const bytes = new TextEncoder().encode(result).length;
4417
+ this.logger.info("Gadget output exceeded limit, stored for browsing", {
4418
+ gadgetName: ctx.gadgetName,
4419
+ outputId: id,
4420
+ bytes,
4421
+ lines,
4422
+ charLimit: this.outputLimitCharLimit
4423
+ });
4424
+ return `[Gadget "${ctx.gadgetName}" returned too much data: ${bytes.toLocaleString()} bytes, ${lines.toLocaleString()} lines. Use GadgetOutputViewer with id "${id}" to read it]`;
4425
+ }
4426
+ return result;
4427
+ };
4428
+ const userInterceptor = userHooks?.interceptors?.interceptGadgetResult;
4429
+ const chainedInterceptor = userInterceptor ? (result, ctx) => userInterceptor(limiterInterceptor(result, ctx), ctx) : limiterInterceptor;
4430
+ return {
4431
+ ...userHooks,
4432
+ interceptors: {
4433
+ ...userHooks?.interceptors,
4434
+ interceptGadgetResult: chainedInterceptor
4435
+ }
4436
+ };
4437
+ }
3783
4438
  /**
3784
4439
  * Run agent with named event handlers (syntactic sugar).
3785
4440
  *
@@ -3832,6 +4487,8 @@ var init_builder = __esm({
3832
4487
  stopOnGadgetError;
3833
4488
  shouldContinueAfterError;
3834
4489
  defaultGadgetTimeoutMs;
4490
+ gadgetOutputLimit;
4491
+ gadgetOutputLimitPercent;
3835
4492
  constructor(client) {
3836
4493
  this.client = client;
3837
4494
  }
@@ -4164,6 +4821,45 @@ var init_builder = __esm({
4164
4821
  this.defaultGadgetTimeoutMs = timeoutMs;
4165
4822
  return this;
4166
4823
  }
4824
+ /**
4825
+ * Enable or disable gadget output limiting.
4826
+ *
4827
+ * When enabled, gadget outputs exceeding the configured limit are stored
4828
+ * and can be browsed using the GadgetOutputViewer gadget.
4829
+ *
4830
+ * @param enabled - Whether to enable output limiting (default: true)
4831
+ * @returns This builder for chaining
4832
+ *
4833
+ * @example
4834
+ * ```typescript
4835
+ * .withGadgetOutputLimit(false) // Disable output limiting
4836
+ * ```
4837
+ */
4838
+ withGadgetOutputLimit(enabled) {
4839
+ this.gadgetOutputLimit = enabled;
4840
+ return this;
4841
+ }
4842
+ /**
4843
+ * Set the maximum gadget output as a percentage of the model's context window.
4844
+ *
4845
+ * Outputs exceeding this limit are stored for later browsing with GadgetOutputViewer.
4846
+ *
4847
+ * @param percent - Percentage of context window (1-100, default: 15)
4848
+ * @returns This builder for chaining
4849
+ * @throws {Error} If percent is not between 1 and 100
4850
+ *
4851
+ * @example
4852
+ * ```typescript
4853
+ * .withGadgetOutputLimitPercent(25) // 25% of context window
4854
+ * ```
4855
+ */
4856
+ withGadgetOutputLimitPercent(percent) {
4857
+ if (percent < 1 || percent > 100) {
4858
+ throw new Error("Output limit percent must be between 1 and 100");
4859
+ }
4860
+ this.gadgetOutputLimitPercent = percent;
4861
+ return this;
4862
+ }
4167
4863
  /**
4168
4864
  * Build and create the agent with the given user prompt.
4169
4865
  * Returns the Agent instance ready to run.
@@ -4208,7 +4904,9 @@ var init_builder = __esm({
4208
4904
  textOnlyHandler: this.textOnlyHandler,
4209
4905
  stopOnGadgetError: this.stopOnGadgetError,
4210
4906
  shouldContinueAfterError: this.shouldContinueAfterError,
4211
- defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs
4907
+ defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
4908
+ gadgetOutputLimit: this.gadgetOutputLimit,
4909
+ gadgetOutputLimitPercent: this.gadgetOutputLimitPercent
4212
4910
  };
4213
4911
  return new Agent(AGENT_INTERNAL_KEY, options);
4214
4912
  }
@@ -4307,7 +5005,9 @@ var init_builder = __esm({
4307
5005
  textOnlyHandler: this.textOnlyHandler,
4308
5006
  stopOnGadgetError: this.stopOnGadgetError,
4309
5007
  shouldContinueAfterError: this.shouldContinueAfterError,
4310
- defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs
5008
+ defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
5009
+ gadgetOutputLimit: this.gadgetOutputLimit,
5010
+ gadgetOutputLimitPercent: this.gadgetOutputLimitPercent
4311
5011
  };
4312
5012
  return new Agent(AGENT_INTERNAL_KEY, options);
4313
5013
  }
@@ -4557,255 +5257,6 @@ var init_client = __esm({
4557
5257
  }
4558
5258
  });
4559
5259
 
4560
- // src/gadgets/gadget.ts
4561
- import * as yaml2 from "js-yaml";
4562
-
4563
- // src/gadgets/schema-to-json.ts
4564
- init_logger();
4565
- import * as z2 from "zod";
4566
- function schemaToJSONSchema(schema, options) {
4567
- const jsonSchema = z2.toJSONSchema(schema, options ?? { target: "draft-7" });
4568
- const mismatches = detectDescriptionMismatch(schema, jsonSchema);
4569
- if (mismatches.length > 0) {
4570
- defaultLogger.warn(
4571
- `Zod instance mismatch detected: ${mismatches.length} description(s) lost. For best results, use: import { z } from "llmist"`
4572
- );
4573
- return mergeDescriptions(schema, jsonSchema);
4574
- }
4575
- return jsonSchema;
4576
- }
4577
- function detectDescriptionMismatch(schema, jsonSchema) {
4578
- const mismatches = [];
4579
- function checkSchema(zodSchema, json, path) {
4580
- if (!zodSchema || typeof zodSchema !== "object") return;
4581
- const def = zodSchema._def;
4582
- const jsonObj = json;
4583
- if (def?.description && !jsonObj?.description) {
4584
- mismatches.push(path || "root");
4585
- }
4586
- if (def?.typeName === "ZodObject" && def?.shape) {
4587
- const shape = typeof def.shape === "function" ? def.shape() : def.shape;
4588
- for (const [key, fieldSchema] of Object.entries(shape)) {
4589
- const properties = jsonObj?.properties;
4590
- const jsonProp = properties?.[key];
4591
- checkSchema(fieldSchema, jsonProp, path ? `${path}.${key}` : key);
4592
- }
4593
- }
4594
- if (def?.typeName === "ZodArray" && def?.type) {
4595
- checkSchema(def.type, jsonObj?.items, path ? `${path}[]` : "[]");
4596
- }
4597
- if ((def?.typeName === "ZodOptional" || def?.typeName === "ZodNullable") && def?.innerType) {
4598
- checkSchema(def.innerType, json, path);
4599
- }
4600
- if (def?.typeName === "ZodDefault" && def?.innerType) {
4601
- checkSchema(def.innerType, json, path);
4602
- }
4603
- }
4604
- checkSchema(schema, jsonSchema, "");
4605
- return mismatches;
4606
- }
4607
- function mergeDescriptions(schema, jsonSchema) {
4608
- function merge(zodSchema, json) {
4609
- if (!json || typeof json !== "object") return json;
4610
- const def = zodSchema._def;
4611
- const jsonObj = json;
4612
- const merged = { ...jsonObj };
4613
- if (def?.description && !jsonObj.description) {
4614
- merged.description = def.description;
4615
- }
4616
- if (def?.typeName === "ZodObject" && def?.shape && jsonObj.properties) {
4617
- const shape = typeof def.shape === "function" ? def.shape() : def.shape;
4618
- const properties = jsonObj.properties;
4619
- merged.properties = { ...properties };
4620
- for (const [key, fieldSchema] of Object.entries(shape)) {
4621
- if (properties[key]) {
4622
- merged.properties[key] = merge(fieldSchema, properties[key]);
4623
- }
4624
- }
4625
- }
4626
- if (def?.typeName === "ZodArray" && def?.type && jsonObj.items) {
4627
- merged.items = merge(def.type, jsonObj.items);
4628
- }
4629
- if ((def?.typeName === "ZodOptional" || def?.typeName === "ZodNullable") && def?.innerType) {
4630
- return merge(def.innerType, json);
4631
- }
4632
- if (def?.typeName === "ZodDefault" && def?.innerType) {
4633
- return merge(def.innerType, json);
4634
- }
4635
- return merged;
4636
- }
4637
- return merge(schema, jsonSchema);
4638
- }
4639
-
4640
- // src/gadgets/gadget.ts
4641
- init_schema_validator();
4642
- function formatYamlValue(value, indent = "") {
4643
- if (typeof value === "string") {
4644
- const lines = value.split("\n");
4645
- if (lines.length === 1 && !value.includes(":") && !value.startsWith("-")) {
4646
- return value;
4647
- }
4648
- const indentedLines = lines.map((line) => `${indent} ${line}`).join("\n");
4649
- return `|
4650
- ${indentedLines}`;
4651
- }
4652
- if (typeof value === "number" || typeof value === "boolean") {
4653
- return String(value);
4654
- }
4655
- if (value === null || value === void 0) {
4656
- return "null";
4657
- }
4658
- if (Array.isArray(value)) {
4659
- if (value.length === 0) return "[]";
4660
- const items = value.map((item) => `${indent}- ${formatYamlValue(item, indent + " ")}`);
4661
- return "\n" + items.join("\n");
4662
- }
4663
- if (typeof value === "object") {
4664
- const entries = Object.entries(value);
4665
- if (entries.length === 0) return "{}";
4666
- const lines = entries.map(([k, v]) => {
4667
- const formattedValue = formatYamlValue(v, indent + " ");
4668
- if (formattedValue.startsWith("\n") || formattedValue.startsWith("|")) {
4669
- return `${indent}${k}: ${formattedValue}`;
4670
- }
4671
- return `${indent}${k}: ${formattedValue}`;
4672
- });
4673
- return "\n" + lines.join("\n");
4674
- }
4675
- return yaml2.dump(value).trimEnd();
4676
- }
4677
- function formatParamsAsYaml(params) {
4678
- const lines = [];
4679
- for (const [key, value] of Object.entries(params)) {
4680
- const formattedValue = formatYamlValue(value, "");
4681
- if (formattedValue.startsWith("\n")) {
4682
- lines.push(`${key}:${formattedValue}`);
4683
- } else {
4684
- lines.push(`${key}: ${formattedValue}`);
4685
- }
4686
- }
4687
- return lines.join("\n");
4688
- }
4689
- function formatTomlValue(value) {
4690
- if (typeof value === "string") {
4691
- if (value.includes("\n")) {
4692
- return `"""
4693
- ${value}
4694
- """`;
4695
- }
4696
- return JSON.stringify(value);
4697
- }
4698
- if (typeof value === "number" || typeof value === "boolean") {
4699
- return String(value);
4700
- }
4701
- if (value === null || value === void 0) {
4702
- return '""';
4703
- }
4704
- if (Array.isArray(value)) {
4705
- return JSON.stringify(value);
4706
- }
4707
- if (typeof value === "object") {
4708
- return JSON.stringify(value);
4709
- }
4710
- return JSON.stringify(value);
4711
- }
4712
- function formatParamsAsToml(params) {
4713
- const lines = [];
4714
- for (const [key, value] of Object.entries(params)) {
4715
- lines.push(`${key} = ${formatTomlValue(value)}`);
4716
- }
4717
- return lines.join("\n");
4718
- }
4719
- var BaseGadget = class {
4720
- /**
4721
- * The name of the gadget. Used for identification when LLM calls it.
4722
- * If not provided, defaults to the class name.
4723
- */
4724
- name;
4725
- /**
4726
- * Optional Zod schema describing the expected input payload. When provided,
4727
- * it will be validated before execution and transformed into a JSON Schema
4728
- * representation that is surfaced to the LLM as part of the instructions.
4729
- */
4730
- parameterSchema;
4731
- /**
4732
- * Optional timeout in milliseconds for gadget execution.
4733
- * If execution exceeds this timeout, a TimeoutException will be thrown.
4734
- * If not set, the global defaultGadgetTimeoutMs from runtime options will be used.
4735
- * Set to 0 or undefined to disable timeout for this gadget.
4736
- */
4737
- timeoutMs;
4738
- /**
4739
- * Optional usage examples to help LLMs understand proper invocation.
4740
- * Examples are rendered in getInstruction() alongside the schema.
4741
- *
4742
- * Note: Uses broader `unknown` type to allow typed examples from subclasses
4743
- * while maintaining runtime compatibility.
4744
- */
4745
- examples;
4746
- /**
4747
- * Auto-generated instruction text for the LLM.
4748
- * Combines name, description, and parameter schema into a formatted instruction.
4749
- * @deprecated Use getInstruction(format) instead for format-specific schemas
4750
- */
4751
- get instruction() {
4752
- return this.getInstruction("yaml");
4753
- }
4754
- /**
4755
- * Generate instruction text for the LLM with format-specific schema.
4756
- * Combines name, description, and parameter schema into a formatted instruction.
4757
- *
4758
- * @param format - Format for the schema representation ('json' | 'yaml' | 'toml' | 'auto')
4759
- * @returns Formatted instruction string
4760
- */
4761
- getInstruction(format = "json") {
4762
- const parts = [];
4763
- parts.push(this.description);
4764
- if (this.parameterSchema) {
4765
- const gadgetName = this.name ?? this.constructor.name;
4766
- validateGadgetSchema(this.parameterSchema, gadgetName);
4767
- const jsonSchema = schemaToJSONSchema(this.parameterSchema, {
4768
- target: "draft-7"
4769
- });
4770
- if (format === "json" || format === "auto") {
4771
- parts.push("\n\nInput Schema (JSON):");
4772
- parts.push(JSON.stringify(jsonSchema, null, 2));
4773
- } else if (format === "toml") {
4774
- parts.push("\n\nInput Schema (TOML):");
4775
- parts.push(JSON.stringify(jsonSchema, null, 2));
4776
- } else {
4777
- const yamlSchema = yaml2.dump(jsonSchema).trimEnd();
4778
- parts.push("\n\nInput Schema (YAML):");
4779
- parts.push(yamlSchema);
4780
- }
4781
- }
4782
- if (this.examples && this.examples.length > 0) {
4783
- parts.push("\n\nExamples:");
4784
- this.examples.forEach((example, index) => {
4785
- if (index > 0) {
4786
- parts.push("");
4787
- }
4788
- if (example.comment) {
4789
- parts.push(`# ${example.comment}`);
4790
- }
4791
- parts.push("Input:");
4792
- if (format === "json" || format === "auto") {
4793
- parts.push(JSON.stringify(example.params, null, 2));
4794
- } else if (format === "toml") {
4795
- parts.push(formatParamsAsToml(example.params));
4796
- } else {
4797
- parts.push(formatParamsAsYaml(example.params));
4798
- }
4799
- if (example.output !== void 0) {
4800
- parts.push("Output:");
4801
- parts.push(example.output);
4802
- }
4803
- });
4804
- }
4805
- return parts.join("\n");
4806
- }
4807
- };
4808
-
4809
5260
  export {
4810
5261
  MODEL_ALIASES,
4811
5262
  resolveModel,
@@ -4827,6 +5278,14 @@ export {
4827
5278
  createLogger,
4828
5279
  defaultLogger,
4829
5280
  init_logger,
5281
+ BaseGadget,
5282
+ init_gadget,
5283
+ createGadget,
5284
+ init_create_gadget,
5285
+ createGadgetOutputViewer,
5286
+ init_output_viewer,
5287
+ GadgetOutputStore,
5288
+ init_gadget_output_store,
4830
5289
  ConversationManager,
4831
5290
  init_conversation_manager,
4832
5291
  runWithHandlers,
@@ -4865,7 +5324,6 @@ export {
4865
5324
  LLMist,
4866
5325
  init_client,
4867
5326
  AgentBuilder,
4868
- init_builder,
4869
- BaseGadget
5327
+ init_builder
4870
5328
  };
4871
- //# sourceMappingURL=chunk-MH4TQ5AD.js.map
5329
+ //# sourceMappingURL=chunk-KB7LMYC2.js.map