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.
- package/dist/{chunk-MH4TQ5AD.js → chunk-KB7LMYC2.js} +745 -287
- package/dist/chunk-KB7LMYC2.js.map +1 -0
- package/dist/{chunk-VF2WOCHM.js → chunk-YWJSGEYT.js} +4 -2
- package/dist/{chunk-VF2WOCHM.js.map → chunk-YWJSGEYT.js.map} +1 -1
- package/dist/cli.cjs +3167 -2686
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +94 -48
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +751 -304
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +112 -3
- package/dist/index.d.ts +112 -3
- package/dist/index.js +16 -5
- package/dist/index.js.map +1 -1
- package/dist/{mock-stream-C8mBXRzJ.d.cts → mock-stream-CCe8vISa.d.cts} +45 -1
- package/dist/{mock-stream-C8mBXRzJ.d.ts → mock-stream-CCe8vISa.d.ts} +45 -1
- package/dist/testing/index.cjs +740 -287
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.cts +2 -2
- package/dist/testing/index.d.ts +2 -2
- package/dist/testing/index.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-LKIBXQ5I.js +0 -23
- package/dist/chunk-LKIBXQ5I.js.map +0 -1
- package/dist/chunk-MH4TQ5AD.js.map +0 -1
|
@@ -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
|
|
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
|
-
|
|
558
|
-
|
|
559
|
-
|
|
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
|
|
597
|
-
For string values with
|
|
598
|
-
|
|
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
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
Please choose one.
|
|
608
|
+
This content can contain:
|
|
609
|
+
- Markdown lists
|
|
610
|
+
- Special characters: # : -
|
|
611
|
+
- Multiple paragraphs
|
|
612
|
+
EOF
|
|
606
613
|
|
|
607
|
-
|
|
608
|
-
|
|
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
|
|
616
|
-
For string values with multiple lines
|
|
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
|
-
|
|
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
|
|
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:
|
|
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:
|
|
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-
|
|
5329
|
+
//# sourceMappingURL=chunk-KB7LMYC2.js.map
|