llmist 0.8.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -32,12 +32,13 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
32
32
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
33
33
 
34
34
  // src/core/constants.ts
35
- var GADGET_START_PREFIX, GADGET_END_PREFIX, DEFAULT_GADGET_OUTPUT_LIMIT, DEFAULT_GADGET_OUTPUT_LIMIT_PERCENT, CHARS_PER_TOKEN, FALLBACK_CONTEXT_WINDOW;
35
+ var GADGET_START_PREFIX, GADGET_END_PREFIX, GADGET_ARG_PREFIX, DEFAULT_GADGET_OUTPUT_LIMIT, DEFAULT_GADGET_OUTPUT_LIMIT_PERCENT, CHARS_PER_TOKEN, FALLBACK_CONTEXT_WINDOW;
36
36
  var init_constants = __esm({
37
37
  "src/core/constants.ts"() {
38
38
  "use strict";
39
39
  GADGET_START_PREFIX = "!!!GADGET_START:";
40
40
  GADGET_END_PREFIX = "!!!GADGET_END";
41
+ GADGET_ARG_PREFIX = "!!!ARG:";
41
42
  DEFAULT_GADGET_OUTPUT_LIMIT = true;
42
43
  DEFAULT_GADGET_OUTPUT_LIMIT_PERCENT = 15;
43
44
  CHARS_PER_TOKEN = 4;
@@ -370,17 +371,12 @@ var init_prompt_config = __esm({
370
371
  "EACH MARKER MUST START WITH A NEWLINE."
371
372
  ].join("\n"),
372
373
  criticalUsage: "INVOKE gadgets using the markers - do not describe what you want to do.",
373
- formatDescriptionYaml: "Parameters in YAML format (one per line)",
374
- formatDescriptionJson: "Parameters in JSON format (valid JSON object)",
375
- formatDescriptionToml: "Parameters in TOML format (key = value pairs, use heredoc for multiline: key = <<<EOF ... EOF)",
374
+ formatDescription: (ctx) => `Parameters using ${ctx.argPrefix}name markers (value on next line(s), no escaping needed)`,
376
375
  rules: () => [
377
376
  "Output ONLY plain text with the exact markers - never use function/tool calling",
378
377
  "You can invoke multiple gadgets in a single response",
379
378
  "For dependent gadgets, invoke the first one and wait for the result"
380
379
  ],
381
- schemaLabelJson: "\n\nInput Schema (JSON):",
382
- schemaLabelYaml: "\n\nInput Schema (YAML):",
383
- schemaLabelToml: "\n\nInput Schema (TOML):",
384
380
  customExamples: null
385
381
  };
386
382
  }
@@ -397,6 +393,7 @@ var init_messages = __esm({
397
393
  messages = [];
398
394
  startPrefix = GADGET_START_PREFIX;
399
395
  endPrefix = GADGET_END_PREFIX;
396
+ argPrefix = GADGET_ARG_PREFIX;
400
397
  promptConfig;
401
398
  constructor(promptConfig) {
402
399
  this.promptConfig = promptConfig ?? {};
@@ -405,26 +402,32 @@ var init_messages = __esm({
405
402
  * Set custom prefixes for gadget markers.
406
403
  * Used to configure history builder to match system prompt markers.
407
404
  */
408
- withPrefixes(startPrefix, endPrefix) {
405
+ withPrefixes(startPrefix, endPrefix, argPrefix) {
409
406
  this.startPrefix = startPrefix;
410
407
  this.endPrefix = endPrefix;
408
+ if (argPrefix) {
409
+ this.argPrefix = argPrefix;
410
+ }
411
411
  return this;
412
412
  }
413
413
  addSystem(content, metadata) {
414
414
  this.messages.push({ role: "system", content, metadata });
415
415
  return this;
416
416
  }
417
- addGadgets(gadgets, parameterFormat = "json", options) {
417
+ addGadgets(gadgets, options) {
418
418
  if (options?.startPrefix) {
419
419
  this.startPrefix = options.startPrefix;
420
420
  }
421
421
  if (options?.endPrefix) {
422
422
  this.endPrefix = options.endPrefix;
423
423
  }
424
+ if (options?.argPrefix) {
425
+ this.argPrefix = options.argPrefix;
426
+ }
424
427
  const context = {
425
- parameterFormat,
426
428
  startPrefix: this.startPrefix,
427
429
  endPrefix: this.endPrefix,
430
+ argPrefix: this.argPrefix,
428
431
  gadgetCount: gadgets.length,
429
432
  gadgetNames: gadgets.map((g) => g.name ?? g.constructor.name)
430
433
  };
@@ -435,26 +438,19 @@ var init_messages = __esm({
435
438
  context
436
439
  );
437
440
  parts.push(mainInstruction);
438
- parts.push(this.buildGadgetsSection(gadgets, parameterFormat));
439
- parts.push(this.buildUsageSection(parameterFormat, context));
441
+ parts.push(this.buildGadgetsSection(gadgets));
442
+ parts.push(this.buildUsageSection(context));
440
443
  this.messages.push({ role: "system", content: parts.join("") });
441
444
  return this;
442
445
  }
443
- buildGadgetsSection(gadgets, parameterFormat) {
446
+ buildGadgetsSection(gadgets) {
444
447
  const parts = [];
445
448
  parts.push("\n\nAVAILABLE GADGETS");
446
449
  parts.push("\n=================\n");
447
450
  for (const gadget of gadgets) {
448
451
  const gadgetName = gadget.name ?? gadget.constructor.name;
449
- const instruction = gadget.getInstruction(parameterFormat);
450
- const schemaMarkers = {
451
- yaml: "\n\nInput Schema (YAML):",
452
- json: "\n\nInput Schema (JSON):",
453
- toml: "\n\nInput Schema (TOML):",
454
- auto: "\n\nInput Schema (JSON):"
455
- // auto defaults to JSON schema display
456
- };
457
- const schemaMarker = schemaMarkers[parameterFormat];
452
+ const instruction = gadget.getInstruction(this.argPrefix);
453
+ const schemaMarker = "\n\nInput Schema (BLOCK):";
458
454
  const schemaIndex = instruction.indexOf(schemaMarker);
459
455
  const description = (schemaIndex !== -1 ? instruction.substring(0, schemaIndex) : instruction).trim();
460
456
  const schema = schemaIndex !== -1 ? instruction.substring(schemaIndex + schemaMarker.length).trim() : "";
@@ -465,35 +461,20 @@ ${description}`);
465
461
  if (schema) {
466
462
  parts.push(`
467
463
 
468
- PARAMETERS (${parameterFormat.toUpperCase()}):
464
+ PARAMETERS (BLOCK):
469
465
  ${schema}`);
470
466
  }
471
467
  parts.push("\n\n---");
472
468
  }
473
469
  return parts.join("");
474
470
  }
475
- buildUsageSection(parameterFormat, context) {
471
+ buildUsageSection(context) {
476
472
  const parts = [];
477
- const formatDescriptionMap = {
478
- yaml: {
479
- config: this.promptConfig.formatDescriptionYaml,
480
- defaultValue: DEFAULT_PROMPTS.formatDescriptionYaml
481
- },
482
- json: {
483
- config: this.promptConfig.formatDescriptionJson,
484
- defaultValue: DEFAULT_PROMPTS.formatDescriptionJson
485
- },
486
- toml: {
487
- config: this.promptConfig.formatDescriptionToml,
488
- defaultValue: DEFAULT_PROMPTS.formatDescriptionToml
489
- },
490
- auto: {
491
- config: this.promptConfig.formatDescriptionJson,
492
- defaultValue: DEFAULT_PROMPTS.formatDescriptionJson
493
- }
494
- };
495
- const { config, defaultValue } = formatDescriptionMap[parameterFormat];
496
- const formatDescription = resolvePromptTemplate(config, defaultValue, context);
473
+ const formatDescription = resolvePromptTemplate(
474
+ this.promptConfig.formatDescription,
475
+ DEFAULT_PROMPTS.formatDescription,
476
+ context
477
+ );
497
478
  parts.push("\n\nHOW TO INVOKE GADGETS");
498
479
  parts.push("\n=====================\n");
499
480
  const criticalUsage = resolvePromptTemplate(
@@ -511,124 +492,90 @@ CRITICAL: ${criticalUsage}
511
492
  2. ${formatDescription}`);
512
493
  parts.push(`
513
494
  3. End marker: ${this.endPrefix}`);
514
- parts.push(this.buildExamplesSection(parameterFormat, context));
495
+ parts.push(this.buildExamplesSection(context));
515
496
  parts.push(this.buildRulesSection(context));
516
497
  parts.push("\n");
517
498
  return parts.join("");
518
499
  }
519
- buildExamplesSection(parameterFormat, context) {
500
+ buildExamplesSection(context) {
520
501
  if (this.promptConfig.customExamples) {
521
502
  return this.promptConfig.customExamples(context);
522
503
  }
523
504
  const parts = [];
524
- const singleExamples = {
525
- yaml: `${this.startPrefix}translate
526
- from: English
527
- to: Polish
528
- content: "Paris is the capital of France: a beautiful city."
529
- ${this.endPrefix}`,
530
- json: `${this.startPrefix}translate
531
- {"from": "English", "to": "Polish", "content": "Paris is the capital of France: a beautiful city."}
532
- ${this.endPrefix}`,
533
- toml: `${this.startPrefix}translate
534
- from = "English"
535
- to = "Polish"
536
- content = "Paris is the capital of France: a beautiful city."
537
- ${this.endPrefix}`,
538
- auto: `${this.startPrefix}translate
539
- {"from": "English", "to": "Polish", "content": "Paris is the capital of France: a beautiful city."}
540
- ${this.endPrefix}`
541
- };
505
+ const singleExample = `${this.startPrefix}translate
506
+ ${this.argPrefix}from
507
+ English
508
+ ${this.argPrefix}to
509
+ Polish
510
+ ${this.argPrefix}content
511
+ Paris is the capital of France: a beautiful city.
512
+ ${this.endPrefix}`;
542
513
  parts.push(`
543
514
 
544
515
  EXAMPLE (Single Gadget):
545
516
 
546
- ${singleExamples[parameterFormat]}`);
547
- const multipleExamples = {
548
- yaml: `${this.startPrefix}translate
549
- from: English
550
- to: Polish
551
- content: "Paris is the capital of France: a beautiful city."
517
+ ${singleExample}`);
518
+ const multipleExample = `${this.startPrefix}translate
519
+ ${this.argPrefix}from
520
+ English
521
+ ${this.argPrefix}to
522
+ Polish
523
+ ${this.argPrefix}content
524
+ Paris is the capital of France: a beautiful city.
552
525
  ${this.endPrefix}
553
526
  ${this.startPrefix}analyze
554
- type: economic_analysis
555
- matter: "Polish Economy"
556
- question: <<<EOF
527
+ ${this.argPrefix}type
528
+ economic_analysis
529
+ ${this.argPrefix}matter
530
+ Polish Economy
531
+ ${this.argPrefix}question
557
532
  Analyze the following:
558
533
  - Polish arms exports 2025
559
534
  - Economic implications
560
- EOF
561
- ${this.endPrefix}`,
562
- json: `${this.startPrefix}translate
563
- {"from": "English", "to": "Polish", "content": "Paris is the capital of France: a beautiful city."}
564
- ${this.endPrefix}
565
- ${this.startPrefix}analyze
566
- {"type": "economic_analysis", "matter": "Polish Economy", "question": "Analyze the following: Polish arms exports 2025, economic implications"}
567
- ${this.endPrefix}`,
568
- toml: `${this.startPrefix}translate
569
- from = "English"
570
- to = "Polish"
571
- content = "Paris is the capital of France: a beautiful city."
572
- ${this.endPrefix}
573
- ${this.startPrefix}analyze
574
- type = "economic_analysis"
575
- matter = "Polish Economy"
576
- question = <<<EOF
577
- Analyze the following:
578
- - Polish arms exports 2025
579
- - Economic implications
580
- EOF
581
- ${this.endPrefix}`,
582
- auto: `${this.startPrefix}translate
583
- {"from": "English", "to": "Polish", "content": "Paris is the capital of France: a beautiful city."}
584
- ${this.endPrefix}
585
- ${this.startPrefix}analyze
586
- {"type": "economic_analysis", "matter": "Polish Economy", "question": "Analyze the following: Polish arms exports 2025, economic implications"}
587
- ${this.endPrefix}`
588
- };
535
+ ${this.endPrefix}`;
589
536
  parts.push(`
590
537
 
591
538
  EXAMPLE (Multiple Gadgets):
592
539
 
593
- ${multipleExamples[parameterFormat]}`);
594
- if (parameterFormat === "yaml") {
595
- parts.push(`
596
-
597
- YAML HEREDOC SYNTAX:
598
- For string values with multiple lines, use heredoc syntax (<<<DELIMITER...DELIMITER):
599
-
600
- filePath: "README.md"
601
- content: <<<EOF
602
- # Project Title
540
+ ${multipleExample}`);
541
+ parts.push(`
603
542
 
604
- This content can contain:
605
- - Markdown lists
606
- - Special characters: # : -
607
- - Multiple paragraphs
608
- EOF
543
+ BLOCK FORMAT SYNTAX:
544
+ Block format uses ${this.argPrefix}name markers. Values are captured verbatim until the next marker.
609
545
 
610
- The delimiter (EOF) can be any identifier. The closing delimiter must be on its own line.
611
- No indentation is required for the content.`);
612
- } else if (parameterFormat === "toml") {
613
- parts.push(`
546
+ ${this.argPrefix}filename
547
+ calculator.ts
548
+ ${this.argPrefix}code
549
+ class Calculator {
550
+ private history: string[] = [];
614
551
 
615
- TOML HEREDOC SYNTAX:
616
- For string values with multiple lines, use heredoc syntax (<<<DELIMITER...DELIMITER):
552
+ add(a: number, b: number): number {
553
+ const result = a + b;
554
+ this.history.push(\`\${a} + \${b} = \${result}\`);
555
+ return result;
556
+ }
557
+ }
617
558
 
618
- filePath = "README.md"
619
- content = <<<EOF
620
- # Project Title
559
+ BLOCK FORMAT RULES:
560
+ - Each parameter starts with ${this.argPrefix}parameterName on its own line
561
+ - The value starts on the NEXT line after the marker
562
+ - Value ends when the next ${this.argPrefix} or ${this.endPrefix} appears
563
+ - NO escaping needed - write values exactly as they should appear
564
+ - Perfect for code, JSON, markdown, or any content with special characters
621
565
 
622
- This content can contain:
623
- - Markdown lists
624
- - Special characters: # : -
625
- - Multiple paragraphs
626
- EOF
566
+ NESTED OBJECTS (use / separator):
567
+ ${this.argPrefix}config/timeout
568
+ 30
569
+ ${this.argPrefix}config/retries
570
+ 3
571
+ Produces: { "config": { "timeout": "30", "retries": "3" } }
627
572
 
628
- The delimiter (EOF) can be any identifier. The closing delimiter must be on its own line.
629
- IMPORTANT: Content inside heredoc is LITERAL - do NOT escape backticks, dollar signs, or any characters.
630
- NEVER use TOML triple-quote strings ("""). ALWAYS use heredoc syntax (<<<EOF...EOF) for multiline content.`);
631
- }
573
+ ARRAYS (use numeric indices):
574
+ ${this.argPrefix}items/0
575
+ first
576
+ ${this.argPrefix}items/1
577
+ second
578
+ Produces: { "items": ["first", "second"] }`);
632
579
  return parts.join("");
633
580
  }
634
581
  buildRulesSection(context) {
@@ -649,8 +596,8 @@ NEVER use TOML triple-quote strings ("""). ALWAYS use heredoc syntax (<<<EOF...E
649
596
  this.messages.push({ role: "assistant", content, metadata });
650
597
  return this;
651
598
  }
652
- addGadgetCall(gadget, parameters, result, parameterFormat = "json") {
653
- const paramStr = this.formatParameters(parameters, parameterFormat);
599
+ addGadgetCall(gadget, parameters, result) {
600
+ const paramStr = this.formatBlockParameters(parameters, "");
654
601
  this.messages.push({
655
602
  role: "assistant",
656
603
  content: `${this.startPrefix}${gadget}
@@ -663,26 +610,32 @@ ${this.endPrefix}`
663
610
  });
664
611
  return this;
665
612
  }
666
- formatParameters(parameters, format) {
667
- if (format === "yaml") {
668
- return Object.entries(parameters).map(([key, value]) => {
669
- if (typeof value === "string") {
670
- return `${key}: ${value}`;
671
- }
672
- return `${key}: ${JSON.stringify(value)}`;
673
- }).join("\n");
674
- }
675
- if (format === "toml") {
676
- return Object.entries(parameters).map(([key, value]) => {
677
- if (typeof value === "string" && value.includes("\n")) {
678
- return `${key} = <<<EOF
679
- ${value}
680
- EOF`;
681
- }
682
- return `${key} = ${JSON.stringify(value)}`;
683
- }).join("\n");
613
+ /**
614
+ * Format parameters as Block format with JSON Pointer paths.
615
+ * Uses the configured argPrefix for consistency with system prompt.
616
+ */
617
+ formatBlockParameters(params, prefix) {
618
+ const lines = [];
619
+ for (const [key, value] of Object.entries(params)) {
620
+ const fullPath = prefix ? `${prefix}/${key}` : key;
621
+ if (Array.isArray(value)) {
622
+ value.forEach((item, index) => {
623
+ const itemPath = `${fullPath}/${index}`;
624
+ if (typeof item === "object" && item !== null) {
625
+ lines.push(this.formatBlockParameters(item, itemPath));
626
+ } else {
627
+ lines.push(`${this.argPrefix}${itemPath}`);
628
+ lines.push(String(item));
629
+ }
630
+ });
631
+ } else if (typeof value === "object" && value !== null) {
632
+ lines.push(this.formatBlockParameters(value, fullPath));
633
+ } else {
634
+ lines.push(`${this.argPrefix}${fullPath}`);
635
+ lines.push(String(value));
636
+ }
684
637
  }
685
- return JSON.stringify(parameters);
638
+ return lines.join("\n");
686
639
  }
687
640
  build() {
688
641
  return [...this.messages];
@@ -854,134 +807,72 @@ var init_schema_to_json = __esm({
854
807
  });
855
808
 
856
809
  // src/gadgets/gadget.ts
857
- function findSafeDelimiter(content) {
858
- const lines = content.split("\n");
859
- for (const delimiter of HEREDOC_DELIMITERS) {
860
- const regex = new RegExp(`^${delimiter}\\s*$`);
861
- const isUsed = lines.some((line) => regex.test(line));
862
- if (!isUsed) {
863
- return delimiter;
864
- }
865
- }
866
- let counter = 1;
867
- while (counter < 1e3) {
868
- const delimiter = `__GADGET_PARAM_${counter}__`;
869
- const regex = new RegExp(`^${delimiter}\\s*$`);
870
- const isUsed = lines.some((line) => regex.test(line));
871
- if (!isUsed) {
872
- return delimiter;
873
- }
874
- counter++;
875
- }
876
- return "HEREDOC_FALLBACK";
877
- }
878
- function formatYamlValue(value, indent = "") {
879
- if (typeof value === "string") {
880
- const lines = value.split("\n");
881
- if (lines.length === 1 && !value.includes(":") && !value.startsWith("-")) {
882
- return value;
883
- }
884
- const delimiter = findSafeDelimiter(value);
885
- return `<<<${delimiter}
886
- ${value}
887
- ${delimiter}`;
888
- }
889
- if (typeof value === "number" || typeof value === "boolean") {
890
- return String(value);
891
- }
892
- if (value === null || value === void 0) {
893
- return "null";
894
- }
895
- if (Array.isArray(value)) {
896
- if (value.length === 0) return "[]";
897
- const items = value.map((item) => `${indent}- ${formatYamlValue(item, indent + " ")}`);
898
- return "\n" + items.join("\n");
899
- }
900
- if (typeof value === "object") {
901
- const entries = Object.entries(value);
902
- if (entries.length === 0) return "{}";
903
- const lines = entries.map(([k, v]) => {
904
- const formattedValue = formatYamlValue(v, indent + " ");
905
- if (formattedValue.startsWith("\n") || formattedValue.startsWith("|")) {
906
- return `${indent}${k}: ${formattedValue}`;
907
- }
908
- return `${indent}${k}: ${formattedValue}`;
909
- });
910
- return "\n" + lines.join("\n");
911
- }
912
- return yaml.dump(value).trimEnd();
913
- }
914
- function formatParamsAsYaml(params) {
810
+ function formatParamsAsBlock(params, prefix = "", argPrefix = GADGET_ARG_PREFIX) {
915
811
  const lines = [];
916
812
  for (const [key, value] of Object.entries(params)) {
917
- const formattedValue = formatYamlValue(value, "");
918
- if (formattedValue.startsWith("\n")) {
919
- lines.push(`${key}:${formattedValue}`);
813
+ const fullPath = prefix ? `${prefix}/${key}` : key;
814
+ if (Array.isArray(value)) {
815
+ value.forEach((item, index) => {
816
+ const itemPath = `${fullPath}/${index}`;
817
+ if (typeof item === "object" && item !== null) {
818
+ lines.push(formatParamsAsBlock(item, itemPath, argPrefix));
819
+ } else {
820
+ lines.push(`${argPrefix}${itemPath}`);
821
+ lines.push(String(item));
822
+ }
823
+ });
824
+ } else if (typeof value === "object" && value !== null) {
825
+ lines.push(formatParamsAsBlock(value, fullPath, argPrefix));
920
826
  } else {
921
- lines.push(`${key}: ${formattedValue}`);
827
+ lines.push(`${argPrefix}${fullPath}`);
828
+ lines.push(String(value));
922
829
  }
923
830
  }
924
831
  return lines.join("\n");
925
832
  }
926
- function formatTomlInlineTable(obj) {
927
- const entries = Object.entries(obj).map(([k, v]) => `${k} = ${formatTomlValue(v)}`);
928
- return `{ ${entries.join(", ")} }`;
929
- }
930
- function formatTomlValue(value) {
931
- if (typeof value === "string") {
932
- if (value.includes("\n")) {
933
- const delimiter = findSafeDelimiter(value);
934
- return `<<<${delimiter}
935
- ${value}
936
- ${delimiter}`;
937
- }
938
- return JSON.stringify(value);
939
- }
940
- if (typeof value === "number" || typeof value === "boolean") {
941
- return String(value);
942
- }
943
- if (value === null || value === void 0) {
944
- return '""';
945
- }
946
- if (Array.isArray(value)) {
947
- if (value.length === 0) return "[]";
948
- const items = value.map((item) => {
949
- if (typeof item === "object" && item !== null && !Array.isArray(item)) {
950
- return formatTomlInlineTable(item);
951
- }
952
- return formatTomlValue(item);
953
- });
954
- return `[${items.join(", ")}]`;
955
- }
956
- if (typeof value === "object") {
957
- return formatTomlInlineTable(value);
958
- }
959
- return JSON.stringify(value);
960
- }
961
- function formatParamsAsToml(params) {
833
+ function formatSchemaAsPlainText(schema, indent = "") {
962
834
  const lines = [];
963
- for (const [key, value] of Object.entries(params)) {
964
- lines.push(`${key} = ${formatTomlValue(value)}`);
835
+ const properties = schema.properties || {};
836
+ const required = schema.required || [];
837
+ for (const [key, prop] of Object.entries(properties)) {
838
+ const propObj = prop;
839
+ const type = propObj.type;
840
+ const description = propObj.description;
841
+ const isRequired = required.includes(key);
842
+ const enumValues = propObj.enum;
843
+ let line = `${indent}- ${key}`;
844
+ if (type === "array") {
845
+ const items = propObj.items;
846
+ const itemType = items?.type || "any";
847
+ line += ` (array of ${itemType})`;
848
+ } else if (type === "object" && propObj.properties) {
849
+ line += " (object)";
850
+ } else {
851
+ line += ` (${type})`;
852
+ }
853
+ if (isRequired) {
854
+ line += " [required]";
855
+ }
856
+ if (description) {
857
+ line += `: ${description}`;
858
+ }
859
+ if (enumValues) {
860
+ line += ` - one of: ${enumValues.map((v) => `"${v}"`).join(", ")}`;
861
+ }
862
+ lines.push(line);
863
+ if (type === "object" && propObj.properties) {
864
+ lines.push(formatSchemaAsPlainText(propObj, indent + " "));
865
+ }
965
866
  }
966
867
  return lines.join("\n");
967
868
  }
968
- var yaml, HEREDOC_DELIMITERS, BaseGadget;
869
+ var BaseGadget;
969
870
  var init_gadget = __esm({
970
871
  "src/gadgets/gadget.ts"() {
971
872
  "use strict";
972
- yaml = __toESM(require("js-yaml"), 1);
873
+ init_constants();
973
874
  init_schema_to_json();
974
875
  init_schema_validator();
975
- HEREDOC_DELIMITERS = [
976
- "__GADGET_PARAM_EOF__",
977
- "__GADGET_PARAM_END__",
978
- "__GADGET_PARAM_DOC__",
979
- "__GADGET_PARAM_CONTENT__",
980
- "__GADGET_PARAM_TEXT__",
981
- "__GADGET_PARAM_HEREDOC__",
982
- "__GADGET_PARAM_DATA__",
983
- "__GADGET_PARAM_BLOCK__"
984
- ];
985
876
  BaseGadget = class {
986
877
  /**
987
878
  * The name of the gadget. Used for identification when LLM calls it.
@@ -1012,19 +903,19 @@ var init_gadget = __esm({
1012
903
  /**
1013
904
  * Auto-generated instruction text for the LLM.
1014
905
  * Combines name, description, and parameter schema into a formatted instruction.
1015
- * @deprecated Use getInstruction(format) instead for format-specific schemas
906
+ * @deprecated Use getInstruction() instead
1016
907
  */
1017
908
  get instruction() {
1018
- return this.getInstruction("yaml");
909
+ return this.getInstruction();
1019
910
  }
1020
911
  /**
1021
- * Generate instruction text for the LLM with format-specific schema.
912
+ * Generate instruction text for the LLM.
1022
913
  * Combines name, description, and parameter schema into a formatted instruction.
1023
914
  *
1024
- * @param format - Format for the schema representation ('json' | 'yaml' | 'toml' | 'auto')
915
+ * @param argPrefix - Optional custom argument prefix for block format examples
1025
916
  * @returns Formatted instruction string
1026
917
  */
1027
- getInstruction(format = "json") {
918
+ getInstruction(argPrefix) {
1028
919
  const parts = [];
1029
920
  parts.push(this.description);
1030
921
  if (this.parameterSchema) {
@@ -1033,20 +924,12 @@ var init_gadget = __esm({
1033
924
  const jsonSchema = schemaToJSONSchema(this.parameterSchema, {
1034
925
  target: "draft-7"
1035
926
  });
1036
- if (format === "json" || format === "auto") {
1037
- parts.push("\n\nInput Schema (JSON):");
1038
- parts.push(JSON.stringify(jsonSchema, null, 2));
1039
- } else if (format === "toml") {
1040
- parts.push("\n\nInput Schema (TOML):");
1041
- parts.push(JSON.stringify(jsonSchema, null, 2));
1042
- } else {
1043
- const yamlSchema = yaml.dump(jsonSchema).trimEnd();
1044
- parts.push("\n\nInput Schema (YAML):");
1045
- parts.push(yamlSchema);
1046
- }
927
+ parts.push("\n\nParameters:");
928
+ parts.push(formatSchemaAsPlainText(jsonSchema));
1047
929
  }
1048
930
  if (this.examples && this.examples.length > 0) {
1049
931
  parts.push("\n\nExamples:");
932
+ const effectiveArgPrefix = argPrefix ?? GADGET_ARG_PREFIX;
1050
933
  this.examples.forEach((example, index) => {
1051
934
  if (index > 0) {
1052
935
  parts.push("");
@@ -1055,13 +938,7 @@ var init_gadget = __esm({
1055
938
  parts.push(`# ${example.comment}`);
1056
939
  }
1057
940
  parts.push("Input:");
1058
- if (format === "json" || format === "auto") {
1059
- parts.push(JSON.stringify(example.params, null, 2));
1060
- } else if (format === "toml") {
1061
- parts.push(formatParamsAsToml(example.params));
1062
- } else {
1063
- parts.push(formatParamsAsYaml(example.params));
1064
- }
941
+ parts.push(formatParamsAsBlock(example.params, "", effectiveArgPrefix));
1065
942
  if (example.output !== void 0) {
1066
943
  parts.push("Output:");
1067
944
  parts.push(example.output);
@@ -1338,14 +1215,12 @@ var init_conversation_manager = __esm({
1338
1215
  baseMessages;
1339
1216
  initialMessages;
1340
1217
  historyBuilder;
1341
- parameterFormat;
1342
1218
  constructor(baseMessages, initialMessages, options = {}) {
1343
1219
  this.baseMessages = baseMessages;
1344
1220
  this.initialMessages = initialMessages;
1345
- this.parameterFormat = options.parameterFormat ?? "json";
1346
1221
  this.historyBuilder = new LLMMessageBuilder();
1347
1222
  if (options.startPrefix && options.endPrefix) {
1348
- this.historyBuilder.withPrefixes(options.startPrefix, options.endPrefix);
1223
+ this.historyBuilder.withPrefixes(options.startPrefix, options.endPrefix, options.argPrefix);
1349
1224
  }
1350
1225
  }
1351
1226
  addUserMessage(content) {
@@ -1355,7 +1230,7 @@ var init_conversation_manager = __esm({
1355
1230
  this.historyBuilder.addAssistant(content);
1356
1231
  }
1357
1232
  addGadgetCall(gadgetName, parameters, result) {
1358
- this.historyBuilder.addGadgetCall(gadgetName, parameters, result, this.parameterFormat);
1233
+ this.historyBuilder.addGadgetCall(gadgetName, parameters, result);
1359
1234
  }
1360
1235
  getMessages() {
1361
1236
  return [...this.baseMessages, ...this.initialMessages, ...this.historyBuilder.build()];
@@ -1378,7 +1253,7 @@ async function runWithHandlers(agentGenerator, handlers) {
1378
1253
  await handlers.onGadgetCall({
1379
1254
  gadgetName: event.call.gadgetName,
1380
1255
  parameters: event.call.parameters,
1381
- parametersYaml: event.call.parametersYaml
1256
+ parametersRaw: event.call.parametersRaw
1382
1257
  });
1383
1258
  }
1384
1259
  break;
@@ -1572,6 +1447,89 @@ var init_hook_validators = __esm({
1572
1447
  }
1573
1448
  });
1574
1449
 
1450
+ // src/gadgets/error-formatter.ts
1451
+ var GadgetErrorFormatter;
1452
+ var init_error_formatter = __esm({
1453
+ "src/gadgets/error-formatter.ts"() {
1454
+ "use strict";
1455
+ init_constants();
1456
+ GadgetErrorFormatter = class {
1457
+ argPrefix;
1458
+ startPrefix;
1459
+ endPrefix;
1460
+ constructor(options = {}) {
1461
+ this.argPrefix = options.argPrefix ?? GADGET_ARG_PREFIX;
1462
+ this.startPrefix = options.startPrefix ?? GADGET_START_PREFIX;
1463
+ this.endPrefix = options.endPrefix ?? GADGET_END_PREFIX;
1464
+ }
1465
+ /**
1466
+ * Format a Zod validation error with full gadget instructions.
1467
+ *
1468
+ * @param gadgetName - Name of the gadget that was called
1469
+ * @param zodError - The Zod validation error
1470
+ * @param gadget - The gadget instance (for generating instructions)
1471
+ * @returns Formatted error message with usage instructions
1472
+ */
1473
+ formatValidationError(gadgetName, zodError, gadget) {
1474
+ const parts = [];
1475
+ parts.push(`Error: Invalid parameters for '${gadgetName}':`);
1476
+ for (const issue of zodError.issues) {
1477
+ const path2 = issue.path.join(".") || "root";
1478
+ parts.push(` - ${path2}: ${issue.message}`);
1479
+ }
1480
+ parts.push("");
1481
+ parts.push("Gadget Usage:");
1482
+ parts.push(gadget.getInstruction(this.argPrefix));
1483
+ return parts.join("\n");
1484
+ }
1485
+ /**
1486
+ * Format a parse error with block format reference.
1487
+ *
1488
+ * @param gadgetName - Name of the gadget that was called
1489
+ * @param parseError - The parse error message
1490
+ * @param gadget - The gadget instance if found (for generating instructions)
1491
+ * @returns Formatted error message with format reference
1492
+ */
1493
+ formatParseError(gadgetName, parseError, gadget) {
1494
+ const parts = [];
1495
+ parts.push(`Error: Failed to parse parameters for '${gadgetName}':`);
1496
+ parts.push(` ${parseError}`);
1497
+ if (gadget) {
1498
+ parts.push("");
1499
+ parts.push("Gadget Usage:");
1500
+ parts.push(gadget.getInstruction(this.argPrefix));
1501
+ }
1502
+ parts.push("");
1503
+ parts.push("Block Format Reference:");
1504
+ parts.push(` ${this.startPrefix}${gadgetName}`);
1505
+ parts.push(` ${this.argPrefix}parameterName`);
1506
+ parts.push(" parameter value here");
1507
+ parts.push(` ${this.endPrefix}`);
1508
+ return parts.join("\n");
1509
+ }
1510
+ /**
1511
+ * Format a registry error (gadget not found) with available gadgets list.
1512
+ *
1513
+ * @param gadgetName - Name of the gadget that was not found
1514
+ * @param availableGadgets - List of available gadget names
1515
+ * @returns Formatted error message with available gadgets
1516
+ */
1517
+ formatRegistryError(gadgetName, availableGadgets) {
1518
+ const parts = [];
1519
+ parts.push(`Error: Gadget '${gadgetName}' not found.`);
1520
+ if (availableGadgets.length > 0) {
1521
+ parts.push("");
1522
+ parts.push(`Available gadgets: ${availableGadgets.join(", ")}`);
1523
+ } else {
1524
+ parts.push("");
1525
+ parts.push("No gadgets are currently registered.");
1526
+ }
1527
+ return parts.join("\n");
1528
+ }
1529
+ };
1530
+ }
1531
+ });
1532
+
1575
1533
  // src/gadgets/exceptions.ts
1576
1534
  var BreakLoopException, HumanInputException, TimeoutException;
1577
1535
  var init_exceptions = __esm({
@@ -1610,15 +1568,18 @@ var init_executor = __esm({
1610
1568
  "src/gadgets/executor.ts"() {
1611
1569
  "use strict";
1612
1570
  init_logger();
1571
+ init_error_formatter();
1613
1572
  init_exceptions();
1614
1573
  GadgetExecutor = class {
1615
- constructor(registry, onHumanInputRequired, logger, defaultGadgetTimeoutMs) {
1574
+ constructor(registry, onHumanInputRequired, logger, defaultGadgetTimeoutMs, errorFormatterOptions) {
1616
1575
  this.registry = registry;
1617
1576
  this.onHumanInputRequired = onHumanInputRequired;
1618
1577
  this.defaultGadgetTimeoutMs = defaultGadgetTimeoutMs;
1619
1578
  this.logger = logger ?? createLogger({ name: "llmist:executor" });
1579
+ this.errorFormatter = new GadgetErrorFormatter(errorFormatterOptions);
1620
1580
  }
1621
1581
  logger;
1582
+ errorFormatter;
1622
1583
  /**
1623
1584
  * Creates a promise that rejects with a TimeoutException after the specified timeout.
1624
1585
  */
@@ -1643,11 +1604,12 @@ var init_executor = __esm({
1643
1604
  const gadget = this.registry.get(call.gadgetName);
1644
1605
  if (!gadget) {
1645
1606
  this.logger.error("Gadget not found", { gadgetName: call.gadgetName });
1607
+ const availableGadgets = this.registry.getNames();
1646
1608
  return {
1647
1609
  gadgetName: call.gadgetName,
1648
1610
  invocationId: call.invocationId,
1649
1611
  parameters: call.parameters ?? {},
1650
- error: `Gadget '${call.gadgetName}' not found in registry`,
1612
+ error: this.errorFormatter.formatRegistryError(call.gadgetName, availableGadgets),
1651
1613
  executionTimeMs: Date.now() - startTime
1652
1614
  };
1653
1615
  }
@@ -1655,27 +1617,28 @@ var init_executor = __esm({
1655
1617
  this.logger.error("Gadget parameter parse error", {
1656
1618
  gadgetName: call.gadgetName,
1657
1619
  parseError: call.parseError,
1658
- rawParameters: call.parametersYaml
1620
+ rawParameters: call.parametersRaw
1659
1621
  });
1622
+ const parseErrorMessage = call.parseError ?? "Failed to parse parameters";
1660
1623
  return {
1661
1624
  gadgetName: call.gadgetName,
1662
1625
  invocationId: call.invocationId,
1663
1626
  parameters: {},
1664
- error: call.parseError ?? "Failed to parse parameters",
1627
+ error: this.errorFormatter.formatParseError(call.gadgetName, parseErrorMessage, gadget),
1665
1628
  executionTimeMs: Date.now() - startTime
1666
1629
  };
1667
1630
  }
1668
1631
  if (gadget.parameterSchema) {
1669
1632
  const validationResult = gadget.parameterSchema.safeParse(rawParameters);
1670
1633
  if (!validationResult.success) {
1671
- const formattedIssues = validationResult.error.issues.map((issue) => {
1672
- const path2 = issue.path.join(".") || "root";
1673
- return `${path2}: ${issue.message}`;
1674
- }).join("; ");
1675
- const validationError = `Invalid parameters: ${formattedIssues}`;
1634
+ const validationError = this.errorFormatter.formatValidationError(
1635
+ call.gadgetName,
1636
+ validationResult.error,
1637
+ gadget
1638
+ );
1676
1639
  this.logger.error("Gadget parameter validation failed", {
1677
1640
  gadgetName: call.gadgetName,
1678
- error: validationError
1641
+ issueCount: validationResult.error.issues.length
1679
1642
  });
1680
1643
  return {
1681
1644
  gadgetName: call.gadgetName,
@@ -1817,168 +1780,107 @@ var init_executor = __esm({
1817
1780
  }
1818
1781
  });
1819
1782
 
1820
- // src/gadgets/parser.ts
1821
- function preprocessYaml(yamlStr) {
1822
- const lines = yamlStr.split("\n");
1823
- const result = [];
1824
- let i = 0;
1825
- while (i < lines.length) {
1826
- const line = lines[i];
1827
- const heredocMatch = line.match(/^(\s*)([\w-]+):\s*<<<([A-Za-z_][A-Za-z0-9_]*)\s*$/);
1828
- if (heredocMatch) {
1829
- const [, indent, key, delimiter] = heredocMatch;
1830
- const bodyLines = [];
1831
- i++;
1832
- const closingRegex = new RegExp(`^${delimiter}\\s*$`);
1833
- while (i < lines.length && !closingRegex.test(lines[i])) {
1834
- bodyLines.push(lines[i]);
1835
- i++;
1836
- }
1837
- if (i < lines.length) {
1838
- i++;
1839
- }
1840
- result.push(`${indent}${key}: |`);
1841
- for (const bodyLine of bodyLines) {
1842
- result.push(`${indent} ${bodyLine}`);
1783
+ // src/gadgets/block-params.ts
1784
+ function parseBlockParams(content, options) {
1785
+ const argPrefix = options?.argPrefix ?? GADGET_ARG_PREFIX;
1786
+ const result = {};
1787
+ const seenPointers = /* @__PURE__ */ new Set();
1788
+ const parts = content.split(argPrefix);
1789
+ for (let i = 1; i < parts.length; i++) {
1790
+ const part = parts[i];
1791
+ const newlineIndex = part.indexOf("\n");
1792
+ if (newlineIndex === -1) {
1793
+ const pointer2 = part.trim();
1794
+ if (pointer2) {
1795
+ if (seenPointers.has(pointer2)) {
1796
+ throw new Error(`Duplicate pointer: ${pointer2}`);
1797
+ }
1798
+ seenPointers.add(pointer2);
1799
+ setByPointer(result, pointer2, "");
1843
1800
  }
1844
1801
  continue;
1845
1802
  }
1846
- const match = line.match(/^(\s*)([\w-]+):\s+(.+)$/);
1847
- if (match) {
1848
- const [, indent, key, value] = match;
1849
- if (value === "|" || value === ">" || value === "|-" || value === ">-") {
1850
- result.push(line);
1851
- i++;
1852
- const keyIndentLen2 = indent.length;
1853
- const blockLines = [];
1854
- let minContentIndent = Infinity;
1855
- while (i < lines.length) {
1856
- const blockLine = lines[i];
1857
- const blockIndentMatch = blockLine.match(/^(\s*)/);
1858
- const blockIndentLen = blockIndentMatch ? blockIndentMatch[1].length : 0;
1859
- if (blockLine.trim() === "") {
1860
- blockLines.push({ content: "", originalIndent: 0 });
1861
- i++;
1862
- continue;
1863
- }
1864
- if (blockIndentLen > keyIndentLen2) {
1865
- const content = blockLine.substring(blockIndentLen);
1866
- blockLines.push({ content, originalIndent: blockIndentLen });
1867
- if (content.trim().length > 0) {
1868
- minContentIndent = Math.min(minContentIndent, blockIndentLen);
1869
- }
1870
- i++;
1871
- } else {
1872
- break;
1873
- }
1874
- }
1875
- const targetIndent = keyIndentLen2 + 2;
1876
- for (const blockLine of blockLines) {
1877
- if (blockLine.content === "") {
1878
- result.push("");
1879
- } else {
1880
- result.push(" ".repeat(targetIndent) + blockLine.content);
1881
- }
1882
- }
1883
- continue;
1884
- }
1885
- if (value.startsWith('"') || value.startsWith("'") || value === "true" || value === "false" || /^-?\d+(\.\d+)?$/.test(value)) {
1886
- result.push(line);
1887
- i++;
1888
- continue;
1889
- }
1890
- const keyIndentLen = indent.length;
1891
- const continuationLines = [];
1892
- let j = i + 1;
1893
- while (j < lines.length) {
1894
- const nextLine = lines[j];
1895
- if (nextLine.trim() === "") {
1896
- continuationLines.push(nextLine);
1897
- j++;
1898
- continue;
1899
- }
1900
- const nextIndentMatch = nextLine.match(/^(\s*)/);
1901
- const nextIndentLen = nextIndentMatch ? nextIndentMatch[1].length : 0;
1902
- if (nextIndentLen > keyIndentLen) {
1903
- continuationLines.push(nextLine);
1904
- j++;
1905
- } else {
1906
- break;
1907
- }
1908
- }
1909
- if (continuationLines.length > 0 && continuationLines.some((l) => l.trim().length > 0)) {
1910
- result.push(`${indent}${key}: |`);
1911
- result.push(`${indent} ${value}`);
1912
- for (const contLine of continuationLines) {
1913
- if (contLine.trim() === "") {
1914
- result.push("");
1915
- } else {
1916
- const contIndentMatch = contLine.match(/^(\s*)/);
1917
- const contIndent = contIndentMatch ? contIndentMatch[1] : "";
1918
- const contContent = contLine.substring(contIndent.length);
1919
- result.push(`${indent} ${contContent}`);
1920
- }
1921
- }
1922
- i = j;
1923
- continue;
1924
- }
1925
- if (value.includes(": ") || value.endsWith(":")) {
1926
- const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
1927
- result.push(`${indent}${key}: "${escaped}"`);
1928
- i++;
1929
- continue;
1930
- }
1803
+ const pointer = part.substring(0, newlineIndex).trim();
1804
+ let value = part.substring(newlineIndex + 1);
1805
+ if (value.endsWith("\n")) {
1806
+ value = value.slice(0, -1);
1931
1807
  }
1932
- result.push(line);
1933
- i++;
1934
- }
1935
- return result.join("\n");
1936
- }
1937
- function unescapeHeredocContent(content) {
1938
- return content.replace(/\\`/g, "`").replace(/\\\$/g, "$").replace(/\\{/g, "{").replace(/\\}/g, "}");
1939
- }
1940
- function preprocessTomlHeredoc(tomlStr) {
1941
- const lines = tomlStr.split("\n");
1942
- const result = [];
1943
- let i = 0;
1944
- const heredocStartRegex = /^(\s*)([\w-]+)\s*=\s*<<<([A-Za-z_][A-Za-z0-9_]*)\s*$/;
1945
- while (i < lines.length) {
1946
- const line = lines[i];
1947
- const match = line.match(heredocStartRegex);
1948
- if (match) {
1949
- const [, indent, key, delimiter] = match;
1950
- const bodyLines = [];
1951
- i++;
1952
- const closingRegex = new RegExp(`^${delimiter}\\s*$`);
1953
- let foundClosing = false;
1954
- while (i < lines.length) {
1955
- const bodyLine = lines[i];
1956
- if (closingRegex.test(bodyLine)) {
1957
- foundClosing = true;
1958
- i++;
1959
- break;
1960
- }
1961
- bodyLines.push(bodyLine);
1962
- i++;
1963
- }
1964
- if (bodyLines.length === 0) {
1965
- result.push(`${indent}${key} = ''''''`);
1966
- } else {
1967
- result.push(`${indent}${key} = '''`);
1968
- for (let j = 0; j < bodyLines.length - 1; j++) {
1969
- result.push(unescapeHeredocContent(bodyLines[j]));
1970
- }
1971
- result.push(`${unescapeHeredocContent(bodyLines[bodyLines.length - 1])}'''`);
1972
- }
1973
- if (!foundClosing) {
1974
- }
1808
+ if (!pointer) {
1975
1809
  continue;
1976
1810
  }
1977
- result.push(line);
1978
- i++;
1811
+ if (seenPointers.has(pointer)) {
1812
+ throw new Error(`Duplicate pointer: ${pointer}`);
1813
+ }
1814
+ seenPointers.add(pointer);
1815
+ setByPointer(result, pointer, value);
1816
+ }
1817
+ return result;
1818
+ }
1819
+ function coerceValue(value) {
1820
+ if (value.includes("\n")) {
1821
+ return value;
1822
+ }
1823
+ const trimmed = value.trim();
1824
+ if (trimmed === "true") return true;
1825
+ if (trimmed === "false") return false;
1826
+ if (trimmed !== "" && /^-?\d+(\.\d+)?$/.test(trimmed)) {
1827
+ const num = Number(trimmed);
1828
+ if (!isNaN(num) && isFinite(num)) {
1829
+ return num;
1830
+ }
1831
+ }
1832
+ return value;
1833
+ }
1834
+ function setByPointer(obj, pointer, value) {
1835
+ const segments = pointer.split("/");
1836
+ let current = obj;
1837
+ for (let i = 0; i < segments.length - 1; i++) {
1838
+ const segment = segments[i];
1839
+ const nextSegment = segments[i + 1];
1840
+ const nextIsArrayIndex = /^\d+$/.test(nextSegment);
1841
+ if (Array.isArray(current)) {
1842
+ const index = parseInt(segment, 10);
1843
+ if (isNaN(index) || index < 0) {
1844
+ throw new Error(`Invalid array index: ${segment}`);
1845
+ }
1846
+ if (index > current.length) {
1847
+ throw new Error(`Array index gap: expected ${current.length}, got ${index}`);
1848
+ }
1849
+ if (current[index] === void 0) {
1850
+ current[index] = nextIsArrayIndex ? [] : {};
1851
+ }
1852
+ current = current[index];
1853
+ } else {
1854
+ const rec = current;
1855
+ if (rec[segment] === void 0) {
1856
+ rec[segment] = nextIsArrayIndex ? [] : {};
1857
+ }
1858
+ current = rec[segment];
1859
+ }
1860
+ }
1861
+ const lastSegment = segments[segments.length - 1];
1862
+ const coercedValue = coerceValue(value);
1863
+ if (Array.isArray(current)) {
1864
+ const index = parseInt(lastSegment, 10);
1865
+ if (isNaN(index) || index < 0) {
1866
+ throw new Error(`Invalid array index: ${lastSegment}`);
1867
+ }
1868
+ if (index > current.length) {
1869
+ throw new Error(`Array index gap: expected ${current.length}, got ${index}`);
1870
+ }
1871
+ current[index] = coercedValue;
1872
+ } else {
1873
+ current[lastSegment] = coercedValue;
1979
1874
  }
1980
- return result.join("\n");
1981
1875
  }
1876
+ var init_block_params = __esm({
1877
+ "src/gadgets/block-params.ts"() {
1878
+ "use strict";
1879
+ init_constants();
1880
+ }
1881
+ });
1882
+
1883
+ // src/gadgets/parser.ts
1982
1884
  function stripMarkdownFences(content) {
1983
1885
  let cleaned = content.trim();
1984
1886
  const openingFence = /^```(?:toml|yaml|json)?\s*\n/i;
@@ -1987,24 +1889,23 @@ function stripMarkdownFences(content) {
1987
1889
  cleaned = cleaned.replace(closingFence, "");
1988
1890
  return cleaned.trim();
1989
1891
  }
1990
- var yaml2, import_js_toml, globalInvocationCounter, StreamParser;
1892
+ var globalInvocationCounter, StreamParser;
1991
1893
  var init_parser = __esm({
1992
1894
  "src/gadgets/parser.ts"() {
1993
1895
  "use strict";
1994
- yaml2 = __toESM(require("js-yaml"), 1);
1995
- import_js_toml = require("js-toml");
1996
1896
  init_constants();
1897
+ init_block_params();
1997
1898
  globalInvocationCounter = 0;
1998
1899
  StreamParser = class {
1999
1900
  buffer = "";
2000
1901
  lastReportedTextLength = 0;
2001
1902
  startPrefix;
2002
1903
  endPrefix;
2003
- parameterFormat;
1904
+ argPrefix;
2004
1905
  constructor(options = {}) {
2005
1906
  this.startPrefix = options.startPrefix ?? GADGET_START_PREFIX;
2006
1907
  this.endPrefix = options.endPrefix ?? GADGET_END_PREFIX;
2007
- this.parameterFormat = options.parameterFormat ?? "json";
1908
+ this.argPrefix = options.argPrefix ?? GADGET_ARG_PREFIX;
2008
1909
  }
2009
1910
  takeTextUntil(index) {
2010
1911
  if (index <= this.lastReportedTextLength) {
@@ -2026,56 +1927,22 @@ var init_parser = __esm({
2026
1927
  return { actualName: gadgetName, invocationId: `gadget_${++globalInvocationCounter}` };
2027
1928
  }
2028
1929
  /**
2029
- * Truncate verbose parse errors to avoid context overflow.
2030
- * Keeps first meaningful line and limits total length.
1930
+ * Extract the error message from a parse error.
1931
+ * Preserves full message since the error formatter adds contextual help
1932
+ * that benefits from precise, detailed error information.
2031
1933
  */
2032
- truncateParseError(error, format) {
2033
- const message = error instanceof Error ? error.message : String(error);
2034
- const firstLine = message.split("\n")[0];
2035
- const maxLen = 200;
2036
- if (firstLine.length <= maxLen) {
2037
- return firstLine;
2038
- }
2039
- return `${firstLine.slice(0, maxLen)}... (${message.length} chars total)`;
1934
+ extractParseError(error) {
1935
+ return error instanceof Error ? error.message : String(error);
2040
1936
  }
2041
1937
  /**
2042
- * Parse parameter string according to configured format
1938
+ * Parse parameter string using block format
2043
1939
  */
2044
1940
  parseParameters(raw) {
2045
1941
  const cleaned = stripMarkdownFences(raw);
2046
- if (this.parameterFormat === "json") {
2047
- try {
2048
- return { parameters: JSON.parse(cleaned) };
2049
- } catch (error) {
2050
- return { parseError: this.truncateParseError(error, "JSON") };
2051
- }
2052
- }
2053
- if (this.parameterFormat === "yaml") {
2054
- try {
2055
- return { parameters: yaml2.load(preprocessYaml(cleaned)) };
2056
- } catch (error) {
2057
- return { parseError: this.truncateParseError(error, "YAML") };
2058
- }
2059
- }
2060
- if (this.parameterFormat === "toml") {
2061
- try {
2062
- return { parameters: (0, import_js_toml.load)(preprocessTomlHeredoc(cleaned)) };
2063
- } catch (error) {
2064
- return { parseError: this.truncateParseError(error, "TOML") };
2065
- }
2066
- }
2067
1942
  try {
2068
- return { parameters: JSON.parse(cleaned) };
2069
- } catch {
2070
- try {
2071
- return { parameters: (0, import_js_toml.load)(preprocessTomlHeredoc(cleaned)) };
2072
- } catch {
2073
- try {
2074
- return { parameters: yaml2.load(preprocessYaml(cleaned)) };
2075
- } catch (error) {
2076
- return { parseError: this.truncateParseError(error, "auto") };
2077
- }
2078
- }
1943
+ return { parameters: parseBlockParams(cleaned, { argPrefix: this.argPrefix }) };
1944
+ } catch (error) {
1945
+ return { parseError: this.extractParseError(error) };
2079
1946
  }
2080
1947
  }
2081
1948
  // Feed a chunk of text and get parsed events
@@ -2134,8 +2001,7 @@ var init_parser = __esm({
2134
2001
  call: {
2135
2002
  gadgetName: actualGadgetName,
2136
2003
  invocationId,
2137
- parametersYaml: parametersRaw,
2138
- // Keep property name for backward compatibility
2004
+ parametersRaw,
2139
2005
  parameters,
2140
2006
  parseError
2141
2007
  }
@@ -2169,7 +2035,7 @@ var init_parser = __esm({
2169
2035
  call: {
2170
2036
  gadgetName: actualGadgetName,
2171
2037
  invocationId,
2172
- parametersYaml: parametersRaw,
2038
+ parametersRaw,
2173
2039
  parameters,
2174
2040
  parseError
2175
2041
  }
@@ -2220,9 +2086,9 @@ var init_stream_processor = __esm({
2220
2086
  this.stopOnGadgetError = options.stopOnGadgetError ?? true;
2221
2087
  this.shouldContinueAfterError = options.shouldContinueAfterError;
2222
2088
  this.parser = new StreamParser({
2223
- parameterFormat: options.parameterFormat,
2224
2089
  startPrefix: options.gadgetStartPrefix,
2225
- endPrefix: options.gadgetEndPrefix
2090
+ endPrefix: options.gadgetEndPrefix,
2091
+ argPrefix: options.gadgetArgPrefix
2226
2092
  });
2227
2093
  this.executor = new GadgetExecutor(
2228
2094
  options.registry,
@@ -2376,7 +2242,7 @@ var init_stream_processor = __esm({
2376
2242
  this.logger.warn("Gadget has parse error", {
2377
2243
  gadgetName: call.gadgetName,
2378
2244
  error: call.parseError,
2379
- rawParameters: call.parametersYaml
2245
+ rawParameters: call.parametersRaw
2380
2246
  });
2381
2247
  const shouldContinue = await this.checkContinueAfterError(
2382
2248
  call.parseError,
@@ -2612,9 +2478,9 @@ var init_agent = __esm({
2612
2478
  hooks;
2613
2479
  conversation;
2614
2480
  registry;
2615
- parameterFormat;
2616
2481
  gadgetStartPrefix;
2617
2482
  gadgetEndPrefix;
2483
+ gadgetArgPrefix;
2618
2484
  onHumanInputRequired;
2619
2485
  textOnlyHandler;
2620
2486
  textWithGadgetsHandler;
@@ -2643,9 +2509,9 @@ var init_agent = __esm({
2643
2509
  this.temperature = options.temperature;
2644
2510
  this.logger = options.logger ?? createLogger({ name: "llmist:agent" });
2645
2511
  this.registry = options.registry;
2646
- this.parameterFormat = options.parameterFormat ?? "json";
2647
2512
  this.gadgetStartPrefix = options.gadgetStartPrefix;
2648
2513
  this.gadgetEndPrefix = options.gadgetEndPrefix;
2514
+ this.gadgetArgPrefix = options.gadgetArgPrefix;
2649
2515
  this.onHumanInputRequired = options.onHumanInputRequired;
2650
2516
  this.textOnlyHandler = options.textOnlyHandler ?? "terminate";
2651
2517
  this.textWithGadgetsHandler = options.textWithGadgetsHandler;
@@ -2667,9 +2533,10 @@ var init_agent = __esm({
2667
2533
  if (options.systemPrompt) {
2668
2534
  baseBuilder.addSystem(options.systemPrompt);
2669
2535
  }
2670
- baseBuilder.addGadgets(this.registry.getAll(), this.parameterFormat, {
2536
+ baseBuilder.addGadgets(this.registry.getAll(), {
2671
2537
  startPrefix: options.gadgetStartPrefix,
2672
- endPrefix: options.gadgetEndPrefix
2538
+ endPrefix: options.gadgetEndPrefix,
2539
+ argPrefix: options.gadgetArgPrefix
2673
2540
  });
2674
2541
  const baseMessages = baseBuilder.build();
2675
2542
  const initialMessages = (options.initialMessages ?? []).map((message) => ({
@@ -2677,9 +2544,9 @@ var init_agent = __esm({
2677
2544
  content: message.content
2678
2545
  }));
2679
2546
  this.conversation = new ConversationManager(baseMessages, initialMessages, {
2680
- parameterFormat: this.parameterFormat,
2681
2547
  startPrefix: options.gadgetStartPrefix,
2682
- endPrefix: options.gadgetEndPrefix
2548
+ endPrefix: options.gadgetEndPrefix,
2549
+ argPrefix: options.gadgetArgPrefix
2683
2550
  });
2684
2551
  this.userPromptProvided = !!options.userPrompt;
2685
2552
  if (options.userPrompt) {
@@ -2772,9 +2639,9 @@ var init_agent = __esm({
2772
2639
  const processor = new StreamProcessor({
2773
2640
  iteration: currentIteration,
2774
2641
  registry: this.registry,
2775
- parameterFormat: this.parameterFormat,
2776
2642
  gadgetStartPrefix: this.gadgetStartPrefix,
2777
2643
  gadgetEndPrefix: this.gadgetEndPrefix,
2644
+ gadgetArgPrefix: this.gadgetArgPrefix,
2778
2645
  hooks: this.hooks,
2779
2646
  logger: this.logger.getSubLogger({ name: "stream-processor" }),
2780
2647
  onHumanInputRequired: this.onHumanInputRequired,
@@ -5040,9 +4907,9 @@ var init_builder = __esm({
5040
4907
  gadgets = [];
5041
4908
  initialMessages = [];
5042
4909
  onHumanInputRequired;
5043
- parameterFormat;
5044
4910
  gadgetStartPrefix;
5045
4911
  gadgetEndPrefix;
4912
+ gadgetArgPrefix;
5046
4913
  textOnlyHandler;
5047
4914
  textWithGadgetsHandler;
5048
4915
  stopOnGadgetError;
@@ -5229,21 +5096,6 @@ var init_builder = __esm({
5229
5096
  this.onHumanInputRequired = handler;
5230
5097
  return this;
5231
5098
  }
5232
- /**
5233
- * Set the parameter format for gadget calls.
5234
- *
5235
- * @param format - Parameter format ("json" or "xml")
5236
- * @returns This builder for chaining
5237
- *
5238
- * @example
5239
- * ```typescript
5240
- * .withParameterFormat("xml")
5241
- * ```
5242
- */
5243
- withParameterFormat(format) {
5244
- this.parameterFormat = format;
5245
- return this;
5246
- }
5247
5099
  /**
5248
5100
  * Set custom gadget marker prefix.
5249
5101
  *
@@ -5274,6 +5126,21 @@ var init_builder = __esm({
5274
5126
  this.gadgetEndPrefix = suffix;
5275
5127
  return this;
5276
5128
  }
5129
+ /**
5130
+ * Set custom argument prefix for block format parameters.
5131
+ *
5132
+ * @param prefix - Custom prefix for argument markers (default: "!!!ARG:")
5133
+ * @returns This builder for chaining
5134
+ *
5135
+ * @example
5136
+ * ```typescript
5137
+ * .withGadgetArgPrefix("<<ARG>>")
5138
+ * ```
5139
+ */
5140
+ withGadgetArgPrefix(prefix) {
5141
+ this.gadgetArgPrefix = prefix;
5142
+ return this;
5143
+ }
5277
5144
  /**
5278
5145
  * Set the text-only handler strategy.
5279
5146
  *
@@ -5473,8 +5340,7 @@ var init_builder = __esm({
5473
5340
  withSyntheticGadgetCall(gadgetName, parameters, result) {
5474
5341
  const startPrefix = this.gadgetStartPrefix ?? GADGET_START_PREFIX;
5475
5342
  const endPrefix = this.gadgetEndPrefix ?? GADGET_END_PREFIX;
5476
- const format = this.parameterFormat ?? "yaml";
5477
- const paramStr = this.formatSyntheticParameters(parameters, format);
5343
+ const paramStr = this.formatBlockParameters(parameters, "");
5478
5344
  this.initialMessages.push({
5479
5345
  role: "assistant",
5480
5346
  content: `${startPrefix}${gadgetName}
@@ -5488,25 +5354,31 @@ ${endPrefix}`
5488
5354
  return this;
5489
5355
  }
5490
5356
  /**
5491
- * Format parameters for synthetic gadget calls.
5492
- * Uses heredoc for multiline string values.
5357
+ * Format parameters as block format with JSON Pointer paths.
5493
5358
  */
5494
- formatSyntheticParameters(parameters, format) {
5495
- if (format === "json" || format === "auto") {
5496
- return JSON.stringify(parameters);
5497
- }
5498
- return Object.entries(parameters).map(([key, value]) => {
5499
- if (typeof value === "string" && value.includes("\n")) {
5500
- const separator = format === "yaml" ? ":" : " =";
5501
- return `${key}${separator} <<<EOF
5502
- ${value}
5503
- EOF`;
5504
- }
5505
- if (format === "yaml") {
5506
- return typeof value === "string" ? `${key}: ${value}` : `${key}: ${JSON.stringify(value)}`;
5359
+ formatBlockParameters(params, prefix) {
5360
+ const lines = [];
5361
+ const argPrefix = this.gadgetArgPrefix ?? GADGET_ARG_PREFIX;
5362
+ for (const [key, value] of Object.entries(params)) {
5363
+ const fullPath = prefix ? `${prefix}/${key}` : key;
5364
+ if (Array.isArray(value)) {
5365
+ value.forEach((item, index) => {
5366
+ const itemPath = `${fullPath}/${index}`;
5367
+ if (typeof item === "object" && item !== null) {
5368
+ lines.push(this.formatBlockParameters(item, itemPath));
5369
+ } else {
5370
+ lines.push(`${argPrefix}${itemPath}`);
5371
+ lines.push(String(item));
5372
+ }
5373
+ });
5374
+ } else if (typeof value === "object" && value !== null) {
5375
+ lines.push(this.formatBlockParameters(value, fullPath));
5376
+ } else {
5377
+ lines.push(`${argPrefix}${fullPath}`);
5378
+ lines.push(String(value));
5507
5379
  }
5508
- return `${key} = ${JSON.stringify(value)}`;
5509
- }).join("\n");
5380
+ }
5381
+ return lines.join("\n");
5510
5382
  }
5511
5383
  /**
5512
5384
  * Build and create the agent with the given user prompt.
@@ -5546,9 +5418,9 @@ EOF`;
5546
5418
  promptConfig: this.promptConfig,
5547
5419
  initialMessages: this.initialMessages,
5548
5420
  onHumanInputRequired: this.onHumanInputRequired,
5549
- parameterFormat: this.parameterFormat,
5550
5421
  gadgetStartPrefix: this.gadgetStartPrefix,
5551
5422
  gadgetEndPrefix: this.gadgetEndPrefix,
5423
+ gadgetArgPrefix: this.gadgetArgPrefix,
5552
5424
  textOnlyHandler: this.textOnlyHandler,
5553
5425
  textWithGadgetsHandler: this.textWithGadgetsHandler,
5554
5426
  stopOnGadgetError: this.stopOnGadgetError,
@@ -5648,9 +5520,9 @@ EOF`;
5648
5520
  promptConfig: this.promptConfig,
5649
5521
  initialMessages: this.initialMessages,
5650
5522
  onHumanInputRequired: this.onHumanInputRequired,
5651
- parameterFormat: this.parameterFormat,
5652
5523
  gadgetStartPrefix: this.gadgetStartPrefix,
5653
5524
  gadgetEndPrefix: this.gadgetEndPrefix,
5525
+ gadgetArgPrefix: this.gadgetArgPrefix,
5654
5526
  textOnlyHandler: this.textOnlyHandler,
5655
5527
  textWithGadgetsHandler: this.textWithGadgetsHandler,
5656
5528
  stopOnGadgetError: this.stopOnGadgetError,
@@ -5671,11 +5543,11 @@ var CLI_DESCRIPTION = "Command line utilities for llmist agents and direct LLM a
5671
5543
  var COMMANDS = {
5672
5544
  complete: "complete",
5673
5545
  agent: "agent",
5674
- models: "models"
5546
+ models: "models",
5547
+ gadget: "gadget"
5675
5548
  };
5676
5549
  var LOG_LEVELS = ["silly", "trace", "debug", "info", "warn", "error", "fatal"];
5677
5550
  var DEFAULT_MODEL = "openai:gpt-5-nano";
5678
- var DEFAULT_PARAMETER_FORMAT = "toml";
5679
5551
  var OPTION_FLAGS = {
5680
5552
  model: "-m, --model <identifier>",
5681
5553
  systemPrompt: "-s, --system <prompt>",
@@ -5683,10 +5555,11 @@ var OPTION_FLAGS = {
5683
5555
  maxTokens: "--max-tokens <count>",
5684
5556
  maxIterations: "-i, --max-iterations <count>",
5685
5557
  gadgetModule: "-g, --gadget <module>",
5686
- parameterFormat: "--parameter-format <format>",
5687
5558
  logLevel: "--log-level <level>",
5688
5559
  logFile: "--log-file <path>",
5689
5560
  logReset: "--log-reset",
5561
+ logLlmRequests: "--log-llm-requests [dir]",
5562
+ logLlmResponses: "--log-llm-responses [dir]",
5690
5563
  noBuiltins: "--no-builtins",
5691
5564
  noBuiltinInteraction: "--no-builtin-interaction",
5692
5565
  quiet: "-q, --quiet"
@@ -5698,10 +5571,11 @@ var OPTION_DESCRIPTIONS = {
5698
5571
  maxTokens: "Maximum number of output tokens requested from the model.",
5699
5572
  maxIterations: "Maximum number of agent loop iterations before exiting.",
5700
5573
  gadgetModule: "Path or module specifier for a gadget export. Repeat to register multiple gadgets.",
5701
- parameterFormat: "Format for gadget parameter schemas: 'json', 'yaml', 'toml', or 'auto'.",
5702
5574
  logLevel: "Log level: silly, trace, debug, info, warn, error, fatal.",
5703
5575
  logFile: "Path to log file. When set, logs are written to file instead of stderr.",
5704
5576
  logReset: "Reset (truncate) the log file at session start instead of appending.",
5577
+ logLlmRequests: "Save raw LLM requests as plain text. Optional dir, defaults to ~/.llmist/logs/requests/",
5578
+ logLlmResponses: "Save raw LLM responses as plain text. Optional dir, defaults to ~/.llmist/logs/responses/",
5705
5579
  noBuiltins: "Disable built-in gadgets (AskUser, TellUser).",
5706
5580
  noBuiltinInteraction: "Disable interactive gadgets (AskUser) while keeping TellUser.",
5707
5581
  quiet: "Suppress all output except content (text and TellUser messages)."
@@ -5709,12 +5583,12 @@ var OPTION_DESCRIPTIONS = {
5709
5583
  var SUMMARY_PREFIX = "[llmist]";
5710
5584
 
5711
5585
  // src/cli/program.ts
5712
- var import_commander3 = require("commander");
5586
+ var import_commander2 = require("commander");
5713
5587
 
5714
5588
  // package.json
5715
5589
  var package_default = {
5716
5590
  name: "llmist",
5717
- version: "0.7.0",
5591
+ version: "1.0.0",
5718
5592
  description: "Universal TypeScript LLM client with streaming-first agent framework. Works with any model - no structured outputs or native tool calling required. Implements its own flexible grammar for function calling.",
5719
5593
  type: "module",
5720
5594
  main: "dist/index.cjs",
@@ -5827,7 +5701,7 @@ var package_default = {
5827
5701
  };
5828
5702
 
5829
5703
  // src/cli/agent-command.ts
5830
- var import_promises = require("readline/promises");
5704
+ var import_promises2 = require("readline/promises");
5831
5705
  var import_chalk3 = __toESM(require("chalk"), 1);
5832
5706
  init_builder();
5833
5707
  init_registry();
@@ -6016,8 +5890,33 @@ async function loadGadgets(specifiers, cwd, importer = (specifier) => import(spe
6016
5890
  return gadgets;
6017
5891
  }
6018
5892
 
6019
- // src/cli/option-helpers.ts
6020
- var import_commander2 = require("commander");
5893
+ // src/cli/llm-logging.ts
5894
+ var import_promises = require("fs/promises");
5895
+ var import_node_os = require("os");
5896
+ var import_node_path3 = require("path");
5897
+ var DEFAULT_LLM_LOG_DIR = (0, import_node_path3.join)((0, import_node_os.homedir)(), ".llmist", "logs");
5898
+ function resolveLogDir(option, subdir) {
5899
+ if (option === true) {
5900
+ return (0, import_node_path3.join)(DEFAULT_LLM_LOG_DIR, subdir);
5901
+ }
5902
+ if (typeof option === "string") {
5903
+ return option;
5904
+ }
5905
+ return void 0;
5906
+ }
5907
+ function formatLlmRequest(messages) {
5908
+ const lines = [];
5909
+ for (const msg of messages) {
5910
+ lines.push(`=== ${msg.role.toUpperCase()} ===`);
5911
+ lines.push(msg.content ?? "");
5912
+ lines.push("");
5913
+ }
5914
+ return lines.join("\n");
5915
+ }
5916
+ async function writeLogFile(dir, filename, content) {
5917
+ await (0, import_promises.mkdir)(dir, { recursive: true });
5918
+ await (0, import_promises.writeFile)((0, import_node_path3.join)(dir, filename), content, "utf-8");
5919
+ }
6021
5920
 
6022
5921
  // src/cli/utils.ts
6023
5922
  var import_chalk2 = __toESM(require("chalk"), 1);
@@ -6061,9 +5960,29 @@ function ensureMarkedConfigured() {
6061
5960
  }
6062
5961
  function renderMarkdown(text) {
6063
5962
  ensureMarkedConfigured();
6064
- const rendered = import_marked.marked.parse(text);
5963
+ let rendered = import_marked.marked.parse(text);
5964
+ rendered = rendered.replace(/\*\*(.+?)\*\*/g, (_, content) => import_chalk.default.bold(content)).replace(/(?<!\*)\*(\S[^*]*)\*(?!\*)/g, (_, content) => import_chalk.default.italic(content));
6065
5965
  return rendered.trimEnd();
6066
5966
  }
5967
+ function createRainbowSeparator() {
5968
+ const colors = [import_chalk.default.red, import_chalk.default.yellow, import_chalk.default.green, import_chalk.default.cyan, import_chalk.default.blue, import_chalk.default.magenta];
5969
+ const char = "\u2500";
5970
+ const width = process.stdout.columns || 80;
5971
+ let result = "";
5972
+ for (let i = 0; i < width; i++) {
5973
+ result += colors[i % colors.length](char);
5974
+ }
5975
+ return result;
5976
+ }
5977
+ function renderMarkdownWithSeparators(text) {
5978
+ const rendered = renderMarkdown(text);
5979
+ const separator = createRainbowSeparator();
5980
+ return `
5981
+ ${separator}
5982
+ ${rendered}
5983
+ ${separator}
5984
+ `;
5985
+ }
6067
5986
  function formatTokens(tokens) {
6068
5987
  return tokens >= 1e3 ? `${(tokens / 1e3).toFixed(1)}k` : `${tokens}`;
6069
5988
  }
@@ -6183,7 +6102,7 @@ function formatGadgetSummary(result) {
6183
6102
  const summaryLine = `${icon} ${gadgetLabel}${paramsLabel} ${import_chalk.default.dim("\u2192")} ${outputLabel} ${timeLabel}`;
6184
6103
  if (result.gadgetName === "TellUser" && result.parameters?.message) {
6185
6104
  const message = String(result.parameters.message);
6186
- const rendered = renderMarkdown(message);
6105
+ const rendered = renderMarkdownWithSeparators(message);
6187
6106
  return `${summaryLine}
6188
6107
  ${rendered}`;
6189
6108
  }
@@ -6490,7 +6409,7 @@ var StreamProgress = class {
6490
6409
  }
6491
6410
  this.isRunning = false;
6492
6411
  if (this.hasRendered) {
6493
- this.target.write("\r\x1B[K");
6412
+ this.target.write("\r\x1B[K\x1B[0G");
6494
6413
  this.hasRendered = false;
6495
6414
  }
6496
6415
  }
@@ -6583,16 +6502,6 @@ async function executeAction(action, env) {
6583
6502
  }
6584
6503
 
6585
6504
  // src/cli/option-helpers.ts
6586
- var PARAMETER_FORMAT_VALUES = ["json", "yaml", "toml", "auto"];
6587
- function parseParameterFormat(value) {
6588
- const normalized = value.toLowerCase();
6589
- if (!PARAMETER_FORMAT_VALUES.includes(normalized)) {
6590
- throw new import_commander2.InvalidArgumentError(
6591
- `Parameter format must be one of: ${PARAMETER_FORMAT_VALUES.join(", ")}`
6592
- );
6593
- }
6594
- return normalized;
6595
- }
6596
6505
  function addCompleteOptions(cmd, defaults) {
6597
6506
  return cmd.option(OPTION_FLAGS.model, OPTION_DESCRIPTIONS.model, defaults?.model ?? DEFAULT_MODEL).option(OPTION_FLAGS.systemPrompt, OPTION_DESCRIPTIONS.systemPrompt, defaults?.system).option(
6598
6507
  OPTION_FLAGS.temperature,
@@ -6604,7 +6513,7 @@ function addCompleteOptions(cmd, defaults) {
6604
6513
  OPTION_DESCRIPTIONS.maxTokens,
6605
6514
  createNumericParser({ label: "Max tokens", integer: true, min: 1 }),
6606
6515
  defaults?.["max-tokens"]
6607
- ).option(OPTION_FLAGS.quiet, OPTION_DESCRIPTIONS.quiet, defaults?.quiet);
6516
+ ).option(OPTION_FLAGS.quiet, OPTION_DESCRIPTIONS.quiet, defaults?.quiet).option(OPTION_FLAGS.logLlmRequests, OPTION_DESCRIPTIONS.logLlmRequests, defaults?.["log-llm-requests"]).option(OPTION_FLAGS.logLlmResponses, OPTION_DESCRIPTIONS.logLlmResponses, defaults?.["log-llm-responses"]);
6608
6517
  }
6609
6518
  function addAgentOptions(cmd, defaults) {
6610
6519
  const gadgetAccumulator = (value, previous = []) => [
@@ -6624,16 +6533,11 @@ function addAgentOptions(cmd, defaults) {
6624
6533
  defaults?.["max-iterations"]
6625
6534
  ).option(OPTION_FLAGS.gadgetModule, OPTION_DESCRIPTIONS.gadgetModule, gadgetAccumulator, [
6626
6535
  ...defaultGadgets
6627
- ]).option(
6628
- OPTION_FLAGS.parameterFormat,
6629
- OPTION_DESCRIPTIONS.parameterFormat,
6630
- parseParameterFormat,
6631
- defaults?.["parameter-format"] ?? DEFAULT_PARAMETER_FORMAT
6632
- ).option(OPTION_FLAGS.noBuiltins, OPTION_DESCRIPTIONS.noBuiltins, defaults?.builtins !== false).option(
6536
+ ]).option(OPTION_FLAGS.noBuiltins, OPTION_DESCRIPTIONS.noBuiltins, defaults?.builtins !== false).option(
6633
6537
  OPTION_FLAGS.noBuiltinInteraction,
6634
6538
  OPTION_DESCRIPTIONS.noBuiltinInteraction,
6635
6539
  defaults?.["builtin-interaction"] !== false
6636
- ).option(OPTION_FLAGS.quiet, OPTION_DESCRIPTIONS.quiet, defaults?.quiet);
6540
+ ).option(OPTION_FLAGS.quiet, OPTION_DESCRIPTIONS.quiet, defaults?.quiet).option(OPTION_FLAGS.logLlmRequests, OPTION_DESCRIPTIONS.logLlmRequests, defaults?.["log-llm-requests"]).option(OPTION_FLAGS.logLlmResponses, OPTION_DESCRIPTIONS.logLlmResponses, defaults?.["log-llm-responses"]);
6637
6541
  }
6638
6542
  function configToCompleteOptions(config) {
6639
6543
  const result = {};
@@ -6642,6 +6546,8 @@ function configToCompleteOptions(config) {
6642
6546
  if (config.temperature !== void 0) result.temperature = config.temperature;
6643
6547
  if (config["max-tokens"] !== void 0) result.maxTokens = config["max-tokens"];
6644
6548
  if (config.quiet !== void 0) result.quiet = config.quiet;
6549
+ if (config["log-llm-requests"] !== void 0) result.logLlmRequests = config["log-llm-requests"];
6550
+ if (config["log-llm-responses"] !== void 0) result.logLlmResponses = config["log-llm-responses"];
6645
6551
  return result;
6646
6552
  }
6647
6553
  function configToAgentOptions(config) {
@@ -6651,7 +6557,6 @@ function configToAgentOptions(config) {
6651
6557
  if (config.temperature !== void 0) result.temperature = config.temperature;
6652
6558
  if (config["max-iterations"] !== void 0) result.maxIterations = config["max-iterations"];
6653
6559
  if (config.gadget !== void 0) result.gadget = config.gadget;
6654
- if (config["parameter-format"] !== void 0) result.parameterFormat = config["parameter-format"];
6655
6560
  if (config.builtins !== void 0) result.builtins = config.builtins;
6656
6561
  if (config["builtin-interaction"] !== void 0)
6657
6562
  result.builtinInteraction = config["builtin-interaction"];
@@ -6659,13 +6564,17 @@ function configToAgentOptions(config) {
6659
6564
  result.gadgetStartPrefix = config["gadget-start-prefix"];
6660
6565
  if (config["gadget-end-prefix"] !== void 0)
6661
6566
  result.gadgetEndPrefix = config["gadget-end-prefix"];
6567
+ if (config["gadget-arg-prefix"] !== void 0)
6568
+ result.gadgetArgPrefix = config["gadget-arg-prefix"];
6662
6569
  if (config.quiet !== void 0) result.quiet = config.quiet;
6570
+ if (config["log-llm-requests"] !== void 0) result.logLlmRequests = config["log-llm-requests"];
6571
+ if (config["log-llm-responses"] !== void 0) result.logLlmResponses = config["log-llm-responses"];
6663
6572
  return result;
6664
6573
  }
6665
6574
 
6666
6575
  // src/cli/agent-command.ts
6667
6576
  async function promptApproval(env, prompt) {
6668
- const rl = (0, import_promises.createInterface)({ input: env.stdin, output: env.stderr });
6577
+ const rl = (0, import_promises2.createInterface)({ input: env.stdin, output: env.stderr });
6669
6578
  try {
6670
6579
  const answer = await rl.question(prompt);
6671
6580
  return answer.trim();
@@ -6680,10 +6589,10 @@ function createHumanInputHandler(env, progress) {
6680
6589
  }
6681
6590
  return async (question) => {
6682
6591
  progress.pause();
6683
- const rl = (0, import_promises.createInterface)({ input: env.stdin, output: env.stdout });
6592
+ const rl = (0, import_promises2.createInterface)({ input: env.stdin, output: env.stdout });
6684
6593
  try {
6685
6594
  const questionLine = question.trim() ? `
6686
- ${renderMarkdown(question.trim())}` : "";
6595
+ ${renderMarkdownWithSeparators(question.trim())}` : "";
6687
6596
  let isFirst = true;
6688
6597
  while (true) {
6689
6598
  const statsPrompt = progress.formatPrompt();
@@ -6726,6 +6635,9 @@ async function executeAgent(promptArg, options, env) {
6726
6635
  const progress = new StreamProgress(env.stderr, stderrTTY, client.modelRegistry);
6727
6636
  let usage;
6728
6637
  let iterations = 0;
6638
+ const llmRequestsDir = resolveLogDir(options.logLlmRequests, "requests");
6639
+ const llmResponsesDir = resolveLogDir(options.logLlmResponses, "responses");
6640
+ let llmCallCounter = 0;
6729
6641
  const countMessagesTokens = async (model, messages) => {
6730
6642
  try {
6731
6643
  return await client.countTokens(model, messages);
@@ -6748,12 +6660,18 @@ async function executeAgent(promptArg, options, env) {
6748
6660
  // onLLMCallStart: Start progress indicator for each LLM call
6749
6661
  // This showcases how to react to agent lifecycle events
6750
6662
  onLLMCallStart: async (context) => {
6663
+ llmCallCounter++;
6751
6664
  const inputTokens = await countMessagesTokens(
6752
6665
  context.options.model,
6753
6666
  context.options.messages
6754
6667
  );
6755
6668
  progress.startCall(context.options.model, inputTokens);
6756
6669
  progress.setInputTokens(inputTokens, false);
6670
+ if (llmRequestsDir) {
6671
+ const filename = `${Date.now()}_call_${llmCallCounter}.request.txt`;
6672
+ const content = formatLlmRequest(context.options.messages);
6673
+ await writeLogFile(llmRequestsDir, filename, content);
6674
+ }
6757
6675
  },
6758
6676
  // onStreamChunk: Real-time updates as LLM generates tokens
6759
6677
  // This enables responsive UIs that show progress during generation
@@ -6816,6 +6734,10 @@ async function executeAgent(promptArg, options, env) {
6816
6734
  `);
6817
6735
  }
6818
6736
  }
6737
+ if (llmResponsesDir) {
6738
+ const filename = `${Date.now()}_call_${llmCallCounter}.response.txt`;
6739
+ await writeLogFile(llmResponsesDir, filename, context.rawResponse);
6740
+ }
6819
6741
  }
6820
6742
  },
6821
6743
  // SHOWCASE: Controller-based approval gating for dangerous gadgets
@@ -6880,13 +6802,15 @@ Command rejected by user with message: "${response}"`
6880
6802
  if (gadgets.length > 0) {
6881
6803
  builder.withGadgets(...gadgets);
6882
6804
  }
6883
- builder.withParameterFormat(options.parameterFormat);
6884
6805
  if (options.gadgetStartPrefix) {
6885
6806
  builder.withGadgetStartPrefix(options.gadgetStartPrefix);
6886
6807
  }
6887
6808
  if (options.gadgetEndPrefix) {
6888
6809
  builder.withGadgetEndPrefix(options.gadgetEndPrefix);
6889
6810
  }
6811
+ if (options.gadgetArgPrefix) {
6812
+ builder.withGadgetArgPrefix(options.gadgetArgPrefix);
6813
+ }
6890
6814
  builder.withSyntheticGadgetCall(
6891
6815
  "TellUser",
6892
6816
  {
@@ -6903,17 +6827,25 @@ Command rejected by user with message: "${response}"`
6903
6827
  resultMapping: (text) => `\u2139\uFE0F ${text}`
6904
6828
  });
6905
6829
  const agent = builder.ask(prompt);
6830
+ let textBuffer = "";
6831
+ const flushTextBuffer = () => {
6832
+ if (textBuffer) {
6833
+ const output = options.quiet ? textBuffer : renderMarkdownWithSeparators(textBuffer);
6834
+ printer.write(output);
6835
+ textBuffer = "";
6836
+ }
6837
+ };
6906
6838
  for await (const event of agent.run()) {
6907
6839
  if (event.type === "text") {
6908
6840
  progress.pause();
6909
- printer.write(event.content);
6841
+ textBuffer += event.content;
6910
6842
  } else if (event.type === "gadget_result") {
6843
+ flushTextBuffer();
6911
6844
  progress.pause();
6912
6845
  if (options.quiet) {
6913
6846
  if (event.result.gadgetName === "TellUser" && event.result.parameters?.message) {
6914
6847
  const message = String(event.result.parameters.message);
6915
- const rendered = renderMarkdown(message);
6916
- env.stdout.write(`${rendered}
6848
+ env.stdout.write(`${message}
6917
6849
  `);
6918
6850
  }
6919
6851
  } else {
@@ -6923,6 +6855,7 @@ Command rejected by user with message: "${response}"`
6923
6855
  }
6924
6856
  }
6925
6857
  }
6858
+ flushTextBuffer();
6926
6859
  progress.complete();
6927
6860
  printer.ensureNewline();
6928
6861
  if (!options.quiet && iterations > 1) {
@@ -6961,9 +6894,18 @@ async function executeComplete(promptArg, options, env) {
6961
6894
  builder.addSystem(options.system);
6962
6895
  }
6963
6896
  builder.addUser(prompt);
6897
+ const messages = builder.build();
6898
+ const llmRequestsDir = resolveLogDir(options.logLlmRequests, "requests");
6899
+ const llmResponsesDir = resolveLogDir(options.logLlmResponses, "responses");
6900
+ const timestamp = Date.now();
6901
+ if (llmRequestsDir) {
6902
+ const filename = `${timestamp}_complete.request.txt`;
6903
+ const content = formatLlmRequest(messages);
6904
+ await writeLogFile(llmRequestsDir, filename, content);
6905
+ }
6964
6906
  const stream2 = client.stream({
6965
6907
  model,
6966
- messages: builder.build(),
6908
+ messages,
6967
6909
  temperature: options.temperature,
6968
6910
  maxTokens: options.maxTokens
6969
6911
  });
@@ -6974,7 +6916,7 @@ async function executeComplete(promptArg, options, env) {
6974
6916
  progress.startCall(model, estimatedInputTokens);
6975
6917
  let finishReason;
6976
6918
  let usage;
6977
- let totalChars = 0;
6919
+ let accumulatedResponse = "";
6978
6920
  for await (const chunk of stream2) {
6979
6921
  if (chunk.usage) {
6980
6922
  usage = chunk.usage;
@@ -6987,8 +6929,8 @@ async function executeComplete(promptArg, options, env) {
6987
6929
  }
6988
6930
  if (chunk.text) {
6989
6931
  progress.pause();
6990
- totalChars += chunk.text.length;
6991
- progress.update(totalChars);
6932
+ accumulatedResponse += chunk.text;
6933
+ progress.update(accumulatedResponse.length);
6992
6934
  printer.write(chunk.text);
6993
6935
  }
6994
6936
  if (chunk.finishReason !== void 0) {
@@ -6998,6 +6940,10 @@ async function executeComplete(promptArg, options, env) {
6998
6940
  progress.endCall(usage);
6999
6941
  progress.complete();
7000
6942
  printer.ensureNewline();
6943
+ if (llmResponsesDir) {
6944
+ const filename = `${timestamp}_complete.response.txt`;
6945
+ await writeLogFile(llmResponsesDir, filename, accumulatedResponse);
6946
+ }
7001
6947
  if (stderrTTY && !options.quiet) {
7002
6948
  const summary = renderSummary({ finishReason, usage, cost: progress.getTotalCost() });
7003
6949
  if (summary) {
@@ -7016,9 +6962,9 @@ function registerCompleteCommand(program, env, config) {
7016
6962
 
7017
6963
  // src/cli/config.ts
7018
6964
  var import_node_fs3 = require("fs");
7019
- var import_node_os = require("os");
7020
- var import_node_path3 = require("path");
7021
- var import_js_toml2 = require("js-toml");
6965
+ var import_node_os2 = require("os");
6966
+ var import_node_path4 = require("path");
6967
+ var import_js_toml = require("js-toml");
7022
6968
 
7023
6969
  // src/cli/templates.ts
7024
6970
  var import_eta = require("eta");
@@ -7112,6 +7058,8 @@ var COMPLETE_CONFIG_KEYS = /* @__PURE__ */ new Set([
7112
7058
  "log-level",
7113
7059
  "log-file",
7114
7060
  "log-reset",
7061
+ "log-llm-requests",
7062
+ "log-llm-responses",
7115
7063
  "type"
7116
7064
  // Allowed for inheritance compatibility, ignored for built-in commands
7117
7065
  ]);
@@ -7121,16 +7069,18 @@ var AGENT_CONFIG_KEYS = /* @__PURE__ */ new Set([
7121
7069
  "temperature",
7122
7070
  "max-iterations",
7123
7071
  "gadget",
7124
- "parameter-format",
7125
7072
  "builtins",
7126
7073
  "builtin-interaction",
7127
7074
  "gadget-start-prefix",
7128
7075
  "gadget-end-prefix",
7076
+ "gadget-arg-prefix",
7129
7077
  "quiet",
7130
7078
  "inherits",
7131
7079
  "log-level",
7132
7080
  "log-file",
7133
7081
  "log-reset",
7082
+ "log-llm-requests",
7083
+ "log-llm-responses",
7134
7084
  "type"
7135
7085
  // Allowed for inheritance compatibility, ignored for built-in commands
7136
7086
  ]);
@@ -7140,9 +7090,8 @@ var CUSTOM_CONFIG_KEYS = /* @__PURE__ */ new Set([
7140
7090
  "type",
7141
7091
  "description"
7142
7092
  ]);
7143
- var VALID_PARAMETER_FORMATS = ["json", "yaml", "toml", "auto"];
7144
7093
  function getConfigPath() {
7145
- return (0, import_node_path3.join)((0, import_node_os.homedir)(), ".llmist", "cli.toml");
7094
+ return (0, import_node_path4.join)((0, import_node_os2.homedir)(), ".llmist", "cli.toml");
7146
7095
  }
7147
7096
  var ConfigError = class extends Error {
7148
7097
  constructor(message, path2) {
@@ -7276,6 +7225,20 @@ function validateCompleteConfig(raw, section) {
7276
7225
  if ("quiet" in rawObj) {
7277
7226
  result.quiet = validateBoolean(rawObj.quiet, "quiet", section);
7278
7227
  }
7228
+ if ("log-llm-requests" in rawObj) {
7229
+ result["log-llm-requests"] = validateStringOrBoolean(
7230
+ rawObj["log-llm-requests"],
7231
+ "log-llm-requests",
7232
+ section
7233
+ );
7234
+ }
7235
+ if ("log-llm-responses" in rawObj) {
7236
+ result["log-llm-responses"] = validateStringOrBoolean(
7237
+ rawObj["log-llm-responses"],
7238
+ "log-llm-responses",
7239
+ section
7240
+ );
7241
+ }
7279
7242
  return result;
7280
7243
  }
7281
7244
  function validateAgentConfig(raw, section) {
@@ -7301,15 +7264,6 @@ function validateAgentConfig(raw, section) {
7301
7264
  if ("gadget" in rawObj) {
7302
7265
  result.gadget = validateStringArray(rawObj.gadget, "gadget", section);
7303
7266
  }
7304
- if ("parameter-format" in rawObj) {
7305
- const format = validateString(rawObj["parameter-format"], "parameter-format", section);
7306
- if (!VALID_PARAMETER_FORMATS.includes(format)) {
7307
- throw new ConfigError(
7308
- `[${section}].parameter-format must be one of: ${VALID_PARAMETER_FORMATS.join(", ")}`
7309
- );
7310
- }
7311
- result["parameter-format"] = format;
7312
- }
7313
7267
  if ("builtins" in rawObj) {
7314
7268
  result.builtins = validateBoolean(rawObj.builtins, "builtins", section);
7315
7269
  }
@@ -7334,11 +7288,38 @@ function validateAgentConfig(raw, section) {
7334
7288
  section
7335
7289
  );
7336
7290
  }
7291
+ if ("gadget-arg-prefix" in rawObj) {
7292
+ result["gadget-arg-prefix"] = validateString(
7293
+ rawObj["gadget-arg-prefix"],
7294
+ "gadget-arg-prefix",
7295
+ section
7296
+ );
7297
+ }
7337
7298
  if ("quiet" in rawObj) {
7338
7299
  result.quiet = validateBoolean(rawObj.quiet, "quiet", section);
7339
7300
  }
7301
+ if ("log-llm-requests" in rawObj) {
7302
+ result["log-llm-requests"] = validateStringOrBoolean(
7303
+ rawObj["log-llm-requests"],
7304
+ "log-llm-requests",
7305
+ section
7306
+ );
7307
+ }
7308
+ if ("log-llm-responses" in rawObj) {
7309
+ result["log-llm-responses"] = validateStringOrBoolean(
7310
+ rawObj["log-llm-responses"],
7311
+ "log-llm-responses",
7312
+ section
7313
+ );
7314
+ }
7340
7315
  return result;
7341
7316
  }
7317
+ function validateStringOrBoolean(value, field, section) {
7318
+ if (typeof value === "string" || typeof value === "boolean") {
7319
+ return value;
7320
+ }
7321
+ throw new ConfigError(`[${section}].${field} must be a string or boolean`);
7322
+ }
7342
7323
  function validateCustomConfig(raw, section) {
7343
7324
  if (typeof raw !== "object" || raw === null) {
7344
7325
  throw new ConfigError(`[${section}] must be a table`);
@@ -7373,15 +7354,6 @@ function validateCustomConfig(raw, section) {
7373
7354
  if ("gadget" in rawObj) {
7374
7355
  result.gadget = validateStringArray(rawObj.gadget, "gadget", section);
7375
7356
  }
7376
- if ("parameter-format" in rawObj) {
7377
- const format = validateString(rawObj["parameter-format"], "parameter-format", section);
7378
- if (!VALID_PARAMETER_FORMATS.includes(format)) {
7379
- throw new ConfigError(
7380
- `[${section}].parameter-format must be one of: ${VALID_PARAMETER_FORMATS.join(", ")}`
7381
- );
7382
- }
7383
- result["parameter-format"] = format;
7384
- }
7385
7357
  if ("builtins" in rawObj) {
7386
7358
  result.builtins = validateBoolean(rawObj.builtins, "builtins", section);
7387
7359
  }
@@ -7406,6 +7378,13 @@ function validateCustomConfig(raw, section) {
7406
7378
  section
7407
7379
  );
7408
7380
  }
7381
+ if ("gadget-arg-prefix" in rawObj) {
7382
+ result["gadget-arg-prefix"] = validateString(
7383
+ rawObj["gadget-arg-prefix"],
7384
+ "gadget-arg-prefix",
7385
+ section
7386
+ );
7387
+ }
7409
7388
  if ("max-tokens" in rawObj) {
7410
7389
  result["max-tokens"] = validateNumber(rawObj["max-tokens"], "max-tokens", section, {
7411
7390
  integer: true,
@@ -7475,7 +7454,7 @@ function loadConfig() {
7475
7454
  }
7476
7455
  let raw;
7477
7456
  try {
7478
- raw = (0, import_js_toml2.load)(content);
7457
+ raw = (0, import_js_toml.load)(content);
7479
7458
  } catch (error) {
7480
7459
  throw new ConfigError(
7481
7460
  `Invalid TOML syntax: ${error instanceof Error ? error.message : "Unknown error"}`,
@@ -7596,8 +7575,439 @@ function resolveInheritance(config, configPath) {
7596
7575
  return resolved;
7597
7576
  }
7598
7577
 
7599
- // src/cli/models-command.ts
7578
+ // src/cli/gadget-command.ts
7579
+ var import_chalk5 = __toESM(require("chalk"), 1);
7580
+ init_schema_to_json();
7581
+ init_schema_validator();
7582
+
7583
+ // src/cli/gadget-prompts.ts
7584
+ var import_promises3 = require("readline/promises");
7600
7585
  var import_chalk4 = __toESM(require("chalk"), 1);
7586
+ init_schema_to_json();
7587
+ async function promptForParameters(schema, ctx) {
7588
+ if (!schema) {
7589
+ return {};
7590
+ }
7591
+ const jsonSchema = schemaToJSONSchema(schema, { target: "draft-7" });
7592
+ if (!jsonSchema.properties || Object.keys(jsonSchema.properties).length === 0) {
7593
+ return {};
7594
+ }
7595
+ const rl = (0, import_promises3.createInterface)({ input: ctx.stdin, output: ctx.stdout });
7596
+ const params = {};
7597
+ try {
7598
+ for (const [key, prop] of Object.entries(jsonSchema.properties)) {
7599
+ const value = await promptForField(rl, key, prop, jsonSchema.required ?? []);
7600
+ if (value !== void 0) {
7601
+ params[key] = value;
7602
+ }
7603
+ }
7604
+ } finally {
7605
+ rl.close();
7606
+ }
7607
+ const result = schema.safeParse(params);
7608
+ if (!result.success) {
7609
+ const issues = result.error.issues.map((i) => ` ${i.path.join(".")}: ${i.message}`).join("\n");
7610
+ throw new Error(`Invalid parameters:
7611
+ ${issues}`);
7612
+ }
7613
+ return result.data;
7614
+ }
7615
+ async function promptForField(rl, key, prop, required) {
7616
+ const isRequired = required.includes(key);
7617
+ const typeHint = formatTypeHint(prop);
7618
+ const defaultHint = prop.default !== void 0 ? import_chalk4.default.dim(` [default: ${JSON.stringify(prop.default)}]`) : "";
7619
+ const requiredMarker = isRequired ? import_chalk4.default.red("*") : "";
7620
+ let prompt = `
7621
+ ${import_chalk4.default.cyan.bold(key)}${requiredMarker}`;
7622
+ if (prop.description) {
7623
+ prompt += import_chalk4.default.dim(` - ${prop.description}`);
7624
+ }
7625
+ prompt += `
7626
+ ${typeHint}${defaultHint}
7627
+ ${import_chalk4.default.green(">")} `;
7628
+ const answer = await rl.question(prompt);
7629
+ const trimmed = answer.trim();
7630
+ if (!trimmed) {
7631
+ if (prop.default !== void 0) {
7632
+ return void 0;
7633
+ }
7634
+ if (!isRequired) {
7635
+ return void 0;
7636
+ }
7637
+ throw new Error(`Parameter '${key}' is required.`);
7638
+ }
7639
+ return parseValue(trimmed, prop, key);
7640
+ }
7641
+ function formatTypeHint(prop) {
7642
+ if (prop.enum) {
7643
+ return import_chalk4.default.yellow(`(${prop.enum.join(" | ")})`);
7644
+ }
7645
+ if (prop.type === "array") {
7646
+ const items = prop.items;
7647
+ if (items?.enum) {
7648
+ return import_chalk4.default.yellow(`(${items.enum.join(" | ")})[] comma-separated`);
7649
+ }
7650
+ const itemType = items?.type ?? "any";
7651
+ return import_chalk4.default.yellow(`(${itemType}[]) comma-separated`);
7652
+ }
7653
+ if (prop.type === "object" && prop.properties) {
7654
+ return import_chalk4.default.yellow("(object) enter as JSON");
7655
+ }
7656
+ return import_chalk4.default.yellow(`(${prop.type ?? "any"})`);
7657
+ }
7658
+ function parseValue(input, prop, key) {
7659
+ const type = prop.type;
7660
+ if (type === "number" || type === "integer") {
7661
+ const num = Number(input);
7662
+ if (Number.isNaN(num)) {
7663
+ throw new Error(`Invalid number for '${key}': ${input}`);
7664
+ }
7665
+ if (type === "integer" && !Number.isInteger(num)) {
7666
+ throw new Error(`Expected integer for '${key}', got: ${input}`);
7667
+ }
7668
+ return num;
7669
+ }
7670
+ if (type === "boolean") {
7671
+ const lower = input.toLowerCase();
7672
+ if (["true", "yes", "1", "y"].includes(lower)) return true;
7673
+ if (["false", "no", "0", "n"].includes(lower)) return false;
7674
+ throw new Error(`Invalid boolean for '${key}': ${input} (use true/false, yes/no, 1/0)`);
7675
+ }
7676
+ if (type === "array") {
7677
+ const items = input.split(",").map((s) => s.trim()).filter(Boolean);
7678
+ const itemType = prop.items?.type;
7679
+ if (itemType === "number" || itemType === "integer") {
7680
+ return items.map((item) => {
7681
+ const num = Number(item);
7682
+ if (Number.isNaN(num)) throw new Error(`Invalid number in '${key}' array: ${item}`);
7683
+ return num;
7684
+ });
7685
+ }
7686
+ if (itemType === "boolean") {
7687
+ return items.map((item) => {
7688
+ const lower = item.toLowerCase();
7689
+ if (["true", "yes", "1", "y"].includes(lower)) return true;
7690
+ if (["false", "no", "0", "n"].includes(lower)) return false;
7691
+ throw new Error(`Invalid boolean in '${key}' array: ${item}`);
7692
+ });
7693
+ }
7694
+ return items;
7695
+ }
7696
+ if (type === "object") {
7697
+ try {
7698
+ return JSON.parse(input);
7699
+ } catch {
7700
+ throw new Error(`Invalid JSON for '${key}': ${input}`);
7701
+ }
7702
+ }
7703
+ return input;
7704
+ }
7705
+ async function readStdinJson(stdin) {
7706
+ const chunks = [];
7707
+ for await (const chunk of stdin) {
7708
+ if (typeof chunk === "string") {
7709
+ chunks.push(chunk);
7710
+ } else {
7711
+ chunks.push(chunk.toString("utf8"));
7712
+ }
7713
+ }
7714
+ const content = chunks.join("").trim();
7715
+ if (!content) {
7716
+ return {};
7717
+ }
7718
+ try {
7719
+ const parsed = JSON.parse(content);
7720
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
7721
+ throw new Error("Stdin must contain a JSON object, not an array or primitive.");
7722
+ }
7723
+ return parsed;
7724
+ } catch (error) {
7725
+ if (error instanceof SyntaxError) {
7726
+ throw new Error(`Invalid JSON from stdin: ${error.message}`);
7727
+ }
7728
+ throw error;
7729
+ }
7730
+ }
7731
+
7732
+ // src/cli/gadget-command.ts
7733
+ async function selectGadget(file, nameOption, cwd) {
7734
+ const gadgets = await loadGadgets([file], cwd);
7735
+ if (gadgets.length === 0) {
7736
+ throw new Error(
7737
+ `No gadgets found in '${file}'.
7738
+ Ensure the file exports a Gadget class or instance.`
7739
+ );
7740
+ }
7741
+ if (gadgets.length === 1) {
7742
+ const gadget = gadgets[0];
7743
+ const name = gadget.name ?? gadget.constructor.name;
7744
+ return { gadget, name };
7745
+ }
7746
+ const names = gadgets.map((g) => g.name ?? g.constructor.name);
7747
+ if (!nameOption) {
7748
+ throw new Error(
7749
+ `File '${file}' exports ${gadgets.length} gadgets.
7750
+ Use --name to select one:
7751
+ ` + names.map((n) => ` - ${n}`).join("\n")
7752
+ );
7753
+ }
7754
+ const found = gadgets.find((g) => (g.name ?? g.constructor.name) === nameOption);
7755
+ if (!found) {
7756
+ throw new Error(
7757
+ `Gadget '${nameOption}' not found in '${file}'.
7758
+ Available gadgets:
7759
+ ` + names.map((n) => ` - ${n}`).join("\n")
7760
+ );
7761
+ }
7762
+ return { gadget: found, name: nameOption };
7763
+ }
7764
+ async function executeGadgetRun(file, options, env) {
7765
+ const cwd = process.cwd();
7766
+ const { gadget, name } = await selectGadget(file, options.name, cwd);
7767
+ env.stderr.write(import_chalk5.default.cyan.bold(`
7768
+ \u{1F527} Running gadget: ${name}
7769
+ `));
7770
+ let params;
7771
+ if (env.isTTY) {
7772
+ params = await promptForParameters(gadget.parameterSchema, {
7773
+ stdin: env.stdin,
7774
+ stdout: env.stderr
7775
+ // Prompts go to stderr to keep stdout clean
7776
+ });
7777
+ } else {
7778
+ env.stderr.write(import_chalk5.default.dim("Reading parameters from stdin...\n"));
7779
+ const stdinParams = await readStdinJson(env.stdin);
7780
+ if (gadget.parameterSchema) {
7781
+ const result2 = gadget.parameterSchema.safeParse(stdinParams);
7782
+ if (!result2.success) {
7783
+ const issues = result2.error.issues.map((i) => ` ${i.path.join(".")}: ${i.message}`).join("\n");
7784
+ throw new Error(`Invalid parameters:
7785
+ ${issues}`);
7786
+ }
7787
+ params = result2.data;
7788
+ } else {
7789
+ params = stdinParams;
7790
+ }
7791
+ }
7792
+ env.stderr.write(import_chalk5.default.dim("\nExecuting...\n"));
7793
+ const startTime = Date.now();
7794
+ let result;
7795
+ try {
7796
+ if (gadget.timeoutMs && gadget.timeoutMs > 0) {
7797
+ result = await Promise.race([
7798
+ Promise.resolve(gadget.execute(params)),
7799
+ new Promise(
7800
+ (_, reject) => setTimeout(
7801
+ () => reject(new Error(`Gadget timed out after ${gadget.timeoutMs}ms`)),
7802
+ gadget.timeoutMs
7803
+ )
7804
+ )
7805
+ ]);
7806
+ } else {
7807
+ result = await Promise.resolve(gadget.execute(params));
7808
+ }
7809
+ } catch (error) {
7810
+ const message = error instanceof Error ? error.message : String(error);
7811
+ throw new Error(`Execution failed: ${message}`);
7812
+ }
7813
+ const elapsed = Date.now() - startTime;
7814
+ env.stderr.write(import_chalk5.default.green(`
7815
+ \u2713 Completed in ${elapsed}ms
7816
+
7817
+ `));
7818
+ formatOutput(result, options, env.stdout);
7819
+ }
7820
+ function formatOutput(result, options, stdout) {
7821
+ if (options.raw) {
7822
+ stdout.write(result);
7823
+ if (!result.endsWith("\n")) stdout.write("\n");
7824
+ return;
7825
+ }
7826
+ if (options.json || looksLikeJson(result)) {
7827
+ try {
7828
+ const parsed = JSON.parse(result);
7829
+ stdout.write(JSON.stringify(parsed, null, 2) + "\n");
7830
+ return;
7831
+ } catch {
7832
+ }
7833
+ }
7834
+ stdout.write(result);
7835
+ if (!result.endsWith("\n")) stdout.write("\n");
7836
+ }
7837
+ function looksLikeJson(str) {
7838
+ const trimmed = str.trim();
7839
+ return trimmed.startsWith("{") && trimmed.endsWith("}") || trimmed.startsWith("[") && trimmed.endsWith("]");
7840
+ }
7841
+ async function executeGadgetInfo(file, options, env) {
7842
+ const cwd = process.cwd();
7843
+ const { gadget, name } = await selectGadget(file, options.name, cwd);
7844
+ if (options.json) {
7845
+ const info = buildGadgetInfo(gadget, name);
7846
+ env.stdout.write(JSON.stringify(info, null, 2) + "\n");
7847
+ return;
7848
+ }
7849
+ env.stdout.write("\n");
7850
+ env.stdout.write(import_chalk5.default.cyan.bold(`${name}
7851
+ `));
7852
+ env.stdout.write(import_chalk5.default.cyan("\u2550".repeat(name.length)) + "\n\n");
7853
+ env.stdout.write(import_chalk5.default.bold("Description:\n"));
7854
+ env.stdout.write(` ${gadget.description}
7855
+
7856
+ `);
7857
+ if (gadget.parameterSchema) {
7858
+ env.stdout.write(import_chalk5.default.bold("Parameters:\n"));
7859
+ const jsonSchema = schemaToJSONSchema(gadget.parameterSchema, { target: "draft-7" });
7860
+ env.stdout.write(formatSchemaAsText(jsonSchema, " ") + "\n\n");
7861
+ } else {
7862
+ env.stdout.write(import_chalk5.default.dim("No parameters required.\n\n"));
7863
+ }
7864
+ if (gadget.timeoutMs) {
7865
+ env.stdout.write(import_chalk5.default.bold("Timeout:\n"));
7866
+ env.stdout.write(` ${gadget.timeoutMs}ms
7867
+
7868
+ `);
7869
+ }
7870
+ if (gadget.examples && gadget.examples.length > 0) {
7871
+ env.stdout.write(import_chalk5.default.bold("Examples:\n"));
7872
+ for (const example of gadget.examples) {
7873
+ if (example.comment) {
7874
+ env.stdout.write(import_chalk5.default.dim(` # ${example.comment}
7875
+ `));
7876
+ }
7877
+ env.stdout.write(` Input: ${import_chalk5.default.cyan(JSON.stringify(example.params))}
7878
+ `);
7879
+ if (example.output !== void 0) {
7880
+ env.stdout.write(` Output: ${import_chalk5.default.green(example.output)}
7881
+ `);
7882
+ }
7883
+ env.stdout.write("\n");
7884
+ }
7885
+ }
7886
+ }
7887
+ function buildGadgetInfo(gadget, name) {
7888
+ const info = {
7889
+ name,
7890
+ description: gadget.description
7891
+ };
7892
+ if (gadget.parameterSchema) {
7893
+ info.schema = schemaToJSONSchema(gadget.parameterSchema, { target: "draft-7" });
7894
+ }
7895
+ if (gadget.timeoutMs) {
7896
+ info.timeoutMs = gadget.timeoutMs;
7897
+ }
7898
+ if (gadget.examples && gadget.examples.length > 0) {
7899
+ info.examples = gadget.examples;
7900
+ }
7901
+ return info;
7902
+ }
7903
+ function formatSchemaAsText(schema, indent = "") {
7904
+ const lines = [];
7905
+ const properties = schema.properties || {};
7906
+ const required = schema.required || [];
7907
+ for (const [key, prop] of Object.entries(properties)) {
7908
+ const type = prop.type;
7909
+ const description = prop.description;
7910
+ const isRequired = required.includes(key);
7911
+ const enumValues = prop.enum;
7912
+ const defaultValue = prop.default;
7913
+ let line = `${indent}${import_chalk5.default.cyan(key)}`;
7914
+ if (isRequired) {
7915
+ line += import_chalk5.default.red("*");
7916
+ }
7917
+ if (type === "array") {
7918
+ const items = prop.items;
7919
+ const itemType = items?.type || "any";
7920
+ line += import_chalk5.default.dim(` (${itemType}[])`);
7921
+ } else if (type === "object" && prop.properties) {
7922
+ line += import_chalk5.default.dim(" (object)");
7923
+ } else {
7924
+ line += import_chalk5.default.dim(` (${type})`);
7925
+ }
7926
+ if (defaultValue !== void 0) {
7927
+ line += import_chalk5.default.dim(` [default: ${JSON.stringify(defaultValue)}]`);
7928
+ }
7929
+ if (description) {
7930
+ line += `: ${description}`;
7931
+ }
7932
+ if (enumValues) {
7933
+ line += import_chalk5.default.yellow(` - one of: ${enumValues.join(", ")}`);
7934
+ }
7935
+ lines.push(line);
7936
+ if (type === "object" && prop.properties) {
7937
+ lines.push(formatSchemaAsText(prop, indent + " "));
7938
+ }
7939
+ }
7940
+ return lines.join("\n");
7941
+ }
7942
+ async function executeGadgetValidate(file, env) {
7943
+ const cwd = process.cwd();
7944
+ try {
7945
+ const gadgets = await loadGadgets([file], cwd);
7946
+ if (gadgets.length === 0) {
7947
+ throw new Error(
7948
+ "No gadgets exported from file.\nA valid gadget must have:\n - execute() method\n - description property\n - parameterSchema (optional)"
7949
+ );
7950
+ }
7951
+ const issues = [];
7952
+ for (const gadget of gadgets) {
7953
+ const name = gadget.name ?? gadget.constructor.name;
7954
+ if (!gadget.description) {
7955
+ issues.push(`${name}: Missing 'description' property.`);
7956
+ }
7957
+ if (gadget.parameterSchema) {
7958
+ try {
7959
+ validateGadgetSchema(gadget.parameterSchema, name);
7960
+ } catch (schemaError) {
7961
+ const message = schemaError instanceof Error ? schemaError.message : String(schemaError);
7962
+ issues.push(`${name}: ${message}`);
7963
+ }
7964
+ }
7965
+ if (typeof gadget.execute !== "function") {
7966
+ issues.push(`${name}: Missing 'execute()' method.`);
7967
+ }
7968
+ }
7969
+ if (issues.length > 0) {
7970
+ throw new Error(`Validation issues:
7971
+ ${issues.map((i) => ` - ${i}`).join("\n")}`);
7972
+ }
7973
+ env.stdout.write(import_chalk5.default.green.bold("\n\u2713 Valid\n\n"));
7974
+ env.stdout.write(import_chalk5.default.bold("Gadgets found:\n"));
7975
+ for (const gadget of gadgets) {
7976
+ const name = gadget.name ?? gadget.constructor.name;
7977
+ const schemaInfo = gadget.parameterSchema ? import_chalk5.default.cyan("(with schema)") : import_chalk5.default.dim("(no schema)");
7978
+ env.stdout.write(` ${import_chalk5.default.bold(name)} ${schemaInfo}
7979
+ `);
7980
+ env.stdout.write(import_chalk5.default.dim(` ${gadget.description}
7981
+ `));
7982
+ }
7983
+ env.stdout.write("\n");
7984
+ } catch (error) {
7985
+ const message = error instanceof Error ? error.message : String(error);
7986
+ env.stdout.write(import_chalk5.default.red.bold(`
7987
+ \u2717 Invalid
7988
+
7989
+ `));
7990
+ env.stdout.write(`${message}
7991
+
7992
+ `);
7993
+ env.setExitCode(1);
7994
+ }
7995
+ }
7996
+ function registerGadgetCommand(program, env) {
7997
+ const gadgetCmd = program.command("gadget").description("Test and inspect gadgets outside the agent loop.");
7998
+ gadgetCmd.command("run <file>").description("Execute a gadget with interactive prompts or stdin JSON.").option("--name <gadget>", "Select gadget by name (required if file exports multiple)").option("--json", "Format output as pretty-printed JSON").option("--raw", "Output result as raw string without formatting").action(
7999
+ (file, options) => executeAction(() => executeGadgetRun(file, options, env), env)
8000
+ );
8001
+ gadgetCmd.command("info <file>").description("Display gadget description, schema, and examples.").option("--name <gadget>", "Select gadget by name (required if file exports multiple)").option("--json", "Output as JSON instead of formatted text").action(
8002
+ (file, options) => executeAction(() => executeGadgetInfo(file, options, env), env)
8003
+ );
8004
+ gadgetCmd.command("validate <file>").description("Check if file exports valid gadget(s).").action(
8005
+ (file) => executeAction(() => executeGadgetValidate(file, env), env)
8006
+ );
8007
+ }
8008
+
8009
+ // src/cli/models-command.ts
8010
+ var import_chalk6 = __toESM(require("chalk"), 1);
7601
8011
  init_model_shortcuts();
7602
8012
  async function handleModelsCommand(options, env) {
7603
8013
  const client = env.createClient();
@@ -7617,13 +8027,13 @@ function renderTable(models, verbose, stream2) {
7617
8027
  }
7618
8028
  grouped.get(provider).push(model);
7619
8029
  }
7620
- stream2.write(import_chalk4.default.bold.cyan("\nAvailable Models\n"));
7621
- stream2.write(import_chalk4.default.cyan("=".repeat(80)) + "\n\n");
8030
+ stream2.write(import_chalk6.default.bold.cyan("\nAvailable Models\n"));
8031
+ stream2.write(import_chalk6.default.cyan("=".repeat(80)) + "\n\n");
7622
8032
  const providers = Array.from(grouped.keys()).sort();
7623
8033
  for (const provider of providers) {
7624
8034
  const providerModels = grouped.get(provider);
7625
8035
  const providerName = provider.charAt(0).toUpperCase() + provider.slice(1);
7626
- stream2.write(import_chalk4.default.bold.yellow(`${providerName} Models
8036
+ stream2.write(import_chalk6.default.bold.yellow(`${providerName} Models
7627
8037
  `));
7628
8038
  if (verbose) {
7629
8039
  renderVerboseTable(providerModels, stream2);
@@ -7632,11 +8042,11 @@ function renderTable(models, verbose, stream2) {
7632
8042
  }
7633
8043
  stream2.write("\n");
7634
8044
  }
7635
- stream2.write(import_chalk4.default.bold.magenta("Model Shortcuts\n"));
7636
- stream2.write(import_chalk4.default.dim("\u2500".repeat(80)) + "\n");
8045
+ stream2.write(import_chalk6.default.bold.magenta("Model Shortcuts\n"));
8046
+ stream2.write(import_chalk6.default.dim("\u2500".repeat(80)) + "\n");
7637
8047
  const shortcuts = Object.entries(MODEL_ALIASES).sort((a, b) => a[0].localeCompare(b[0]));
7638
8048
  for (const [shortcut, fullName] of shortcuts) {
7639
- stream2.write(import_chalk4.default.cyan(` ${shortcut.padEnd(15)}`) + import_chalk4.default.dim(" \u2192 ") + import_chalk4.default.white(fullName) + "\n");
8049
+ stream2.write(import_chalk6.default.cyan(` ${shortcut.padEnd(15)}`) + import_chalk6.default.dim(" \u2192 ") + import_chalk6.default.white(fullName) + "\n");
7640
8050
  }
7641
8051
  stream2.write("\n");
7642
8052
  }
@@ -7646,45 +8056,45 @@ function renderCompactTable(models, stream2) {
7646
8056
  const contextWidth = 13;
7647
8057
  const inputWidth = 10;
7648
8058
  const outputWidth = 10;
7649
- stream2.write(import_chalk4.default.dim("\u2500".repeat(idWidth + nameWidth + contextWidth + inputWidth + outputWidth + 8)) + "\n");
8059
+ stream2.write(import_chalk6.default.dim("\u2500".repeat(idWidth + nameWidth + contextWidth + inputWidth + outputWidth + 8)) + "\n");
7650
8060
  stream2.write(
7651
- import_chalk4.default.bold(
8061
+ import_chalk6.default.bold(
7652
8062
  "Model ID".padEnd(idWidth) + " " + "Display Name".padEnd(nameWidth) + " " + "Context".padEnd(contextWidth) + " " + "Input".padEnd(inputWidth) + " " + "Output".padEnd(outputWidth)
7653
8063
  ) + "\n"
7654
8064
  );
7655
- stream2.write(import_chalk4.default.dim("\u2500".repeat(idWidth + nameWidth + contextWidth + inputWidth + outputWidth + 8)) + "\n");
8065
+ stream2.write(import_chalk6.default.dim("\u2500".repeat(idWidth + nameWidth + contextWidth + inputWidth + outputWidth + 8)) + "\n");
7656
8066
  for (const model of models) {
7657
8067
  const contextFormatted = formatTokens2(model.contextWindow);
7658
8068
  const inputPrice = `$${model.pricing.input.toFixed(2)}`;
7659
8069
  const outputPrice = `$${model.pricing.output.toFixed(2)}`;
7660
8070
  stream2.write(
7661
- import_chalk4.default.green(model.modelId.padEnd(idWidth)) + " " + import_chalk4.default.white(model.displayName.padEnd(nameWidth)) + " " + import_chalk4.default.yellow(contextFormatted.padEnd(contextWidth)) + " " + import_chalk4.default.cyan(inputPrice.padEnd(inputWidth)) + " " + import_chalk4.default.cyan(outputPrice.padEnd(outputWidth)) + "\n"
8071
+ import_chalk6.default.green(model.modelId.padEnd(idWidth)) + " " + import_chalk6.default.white(model.displayName.padEnd(nameWidth)) + " " + import_chalk6.default.yellow(contextFormatted.padEnd(contextWidth)) + " " + import_chalk6.default.cyan(inputPrice.padEnd(inputWidth)) + " " + import_chalk6.default.cyan(outputPrice.padEnd(outputWidth)) + "\n"
7662
8072
  );
7663
8073
  }
7664
- stream2.write(import_chalk4.default.dim("\u2500".repeat(idWidth + nameWidth + contextWidth + inputWidth + outputWidth + 8)) + "\n");
7665
- stream2.write(import_chalk4.default.dim(` * Prices are per 1M tokens
8074
+ stream2.write(import_chalk6.default.dim("\u2500".repeat(idWidth + nameWidth + contextWidth + inputWidth + outputWidth + 8)) + "\n");
8075
+ stream2.write(import_chalk6.default.dim(` * Prices are per 1M tokens
7666
8076
  `));
7667
8077
  }
7668
8078
  function renderVerboseTable(models, stream2) {
7669
8079
  for (const model of models) {
7670
- stream2.write(import_chalk4.default.bold.green(`
8080
+ stream2.write(import_chalk6.default.bold.green(`
7671
8081
  ${model.modelId}
7672
8082
  `));
7673
- stream2.write(import_chalk4.default.dim(" " + "\u2500".repeat(60)) + "\n");
7674
- stream2.write(` ${import_chalk4.default.dim("Name:")} ${import_chalk4.default.white(model.displayName)}
8083
+ stream2.write(import_chalk6.default.dim(" " + "\u2500".repeat(60)) + "\n");
8084
+ stream2.write(` ${import_chalk6.default.dim("Name:")} ${import_chalk6.default.white(model.displayName)}
7675
8085
  `);
7676
- stream2.write(` ${import_chalk4.default.dim("Context:")} ${import_chalk4.default.yellow(formatTokens2(model.contextWindow))}
8086
+ stream2.write(` ${import_chalk6.default.dim("Context:")} ${import_chalk6.default.yellow(formatTokens2(model.contextWindow))}
7677
8087
  `);
7678
- stream2.write(` ${import_chalk4.default.dim("Max Output:")} ${import_chalk4.default.yellow(formatTokens2(model.maxOutputTokens))}
8088
+ stream2.write(` ${import_chalk6.default.dim("Max Output:")} ${import_chalk6.default.yellow(formatTokens2(model.maxOutputTokens))}
7679
8089
  `);
7680
- stream2.write(` ${import_chalk4.default.dim("Pricing:")} ${import_chalk4.default.cyan(`$${model.pricing.input.toFixed(2)} input`)} ${import_chalk4.default.dim("/")} ${import_chalk4.default.cyan(`$${model.pricing.output.toFixed(2)} output`)} ${import_chalk4.default.dim("(per 1M tokens)")}
8090
+ stream2.write(` ${import_chalk6.default.dim("Pricing:")} ${import_chalk6.default.cyan(`$${model.pricing.input.toFixed(2)} input`)} ${import_chalk6.default.dim("/")} ${import_chalk6.default.cyan(`$${model.pricing.output.toFixed(2)} output`)} ${import_chalk6.default.dim("(per 1M tokens)")}
7681
8091
  `);
7682
8092
  if (model.pricing.cachedInput !== void 0) {
7683
- stream2.write(` ${import_chalk4.default.dim("Cached Input:")} ${import_chalk4.default.cyan(`$${model.pricing.cachedInput.toFixed(2)} per 1M tokens`)}
8093
+ stream2.write(` ${import_chalk6.default.dim("Cached Input:")} ${import_chalk6.default.cyan(`$${model.pricing.cachedInput.toFixed(2)} per 1M tokens`)}
7684
8094
  `);
7685
8095
  }
7686
8096
  if (model.knowledgeCutoff) {
7687
- stream2.write(` ${import_chalk4.default.dim("Knowledge:")} ${model.knowledgeCutoff}
8097
+ stream2.write(` ${import_chalk6.default.dim("Knowledge:")} ${model.knowledgeCutoff}
7688
8098
  `);
7689
8099
  }
7690
8100
  const features = [];
@@ -7695,20 +8105,20 @@ function renderVerboseTable(models, stream2) {
7695
8105
  if (model.features.structuredOutputs) features.push("structured-outputs");
7696
8106
  if (model.features.fineTuning) features.push("fine-tuning");
7697
8107
  if (features.length > 0) {
7698
- stream2.write(` ${import_chalk4.default.dim("Features:")} ${import_chalk4.default.blue(features.join(", "))}
8108
+ stream2.write(` ${import_chalk6.default.dim("Features:")} ${import_chalk6.default.blue(features.join(", "))}
7699
8109
  `);
7700
8110
  }
7701
8111
  if (model.metadata) {
7702
8112
  if (model.metadata.family) {
7703
- stream2.write(` ${import_chalk4.default.dim("Family:")} ${model.metadata.family}
8113
+ stream2.write(` ${import_chalk6.default.dim("Family:")} ${model.metadata.family}
7704
8114
  `);
7705
8115
  }
7706
8116
  if (model.metadata.releaseDate) {
7707
- stream2.write(` ${import_chalk4.default.dim("Released:")} ${model.metadata.releaseDate}
8117
+ stream2.write(` ${import_chalk6.default.dim("Released:")} ${model.metadata.releaseDate}
7708
8118
  `);
7709
8119
  }
7710
8120
  if (model.metadata.notes) {
7711
- stream2.write(` ${import_chalk4.default.dim("Notes:")} ${import_chalk4.default.italic(model.metadata.notes)}
8121
+ stream2.write(` ${import_chalk6.default.dim("Notes:")} ${import_chalk6.default.italic(model.metadata.notes)}
7712
8122
  `);
7713
8123
  }
7714
8124
  }
@@ -7758,7 +8168,7 @@ function registerModelsCommand(program, env) {
7758
8168
 
7759
8169
  // src/cli/environment.ts
7760
8170
  var import_node_readline = __toESM(require("readline"), 1);
7761
- var import_chalk5 = __toESM(require("chalk"), 1);
8171
+ var import_chalk7 = __toESM(require("chalk"), 1);
7762
8172
  init_client();
7763
8173
  init_logger();
7764
8174
  var LOG_LEVEL_MAP = {
@@ -7807,14 +8217,14 @@ function createPromptFunction(stdin, stdout) {
7807
8217
  output: stdout
7808
8218
  });
7809
8219
  stdout.write("\n");
7810
- stdout.write(`${import_chalk5.default.cyan("\u2500".repeat(60))}
8220
+ stdout.write(`${import_chalk7.default.cyan("\u2500".repeat(60))}
7811
8221
  `);
7812
- stdout.write(import_chalk5.default.cyan.bold("\u{1F916} Agent asks:\n"));
8222
+ stdout.write(import_chalk7.default.cyan.bold("\u{1F916} Agent asks:\n"));
7813
8223
  stdout.write(`${question}
7814
8224
  `);
7815
- stdout.write(`${import_chalk5.default.cyan("\u2500".repeat(60))}
8225
+ stdout.write(`${import_chalk7.default.cyan("\u2500".repeat(60))}
7816
8226
  `);
7817
- rl.question(import_chalk5.default.green.bold("You: "), (answer) => {
8227
+ rl.question(import_chalk7.default.green.bold("You: "), (answer) => {
7818
8228
  rl.close();
7819
8229
  resolve(answer);
7820
8230
  });
@@ -7891,12 +8301,12 @@ function registerCustomCommand(program, name, config, env) {
7891
8301
  function parseLogLevel2(value) {
7892
8302
  const normalized = value.toLowerCase();
7893
8303
  if (!LOG_LEVELS.includes(normalized)) {
7894
- throw new import_commander3.InvalidArgumentError(`Log level must be one of: ${LOG_LEVELS.join(", ")}`);
8304
+ throw new import_commander2.InvalidArgumentError(`Log level must be one of: ${LOG_LEVELS.join(", ")}`);
7895
8305
  }
7896
8306
  return normalized;
7897
8307
  }
7898
8308
  function createProgram(env, config) {
7899
- const program = new import_commander3.Command();
8309
+ const program = new import_commander2.Command();
7900
8310
  program.name(CLI_NAME).description(CLI_DESCRIPTION).version(package_default.version).option(OPTION_FLAGS.logLevel, OPTION_DESCRIPTIONS.logLevel, parseLogLevel2).option(OPTION_FLAGS.logFile, OPTION_DESCRIPTIONS.logFile).option(OPTION_FLAGS.logReset, OPTION_DESCRIPTIONS.logReset).configureOutput({
7901
8311
  writeOut: (str) => env.stdout.write(str),
7902
8312
  writeErr: (str) => env.stderr.write(str)
@@ -7904,6 +8314,7 @@ function createProgram(env, config) {
7904
8314
  registerCompleteCommand(program, env, config?.complete);
7905
8315
  registerAgentCommand(program, env, config?.agent);
7906
8316
  registerModelsCommand(program, env);
8317
+ registerGadgetCommand(program, env);
7907
8318
  if (config) {
7908
8319
  const customNames = getCustomCommandNames(config);
7909
8320
  for (const name of customNames) {
@@ -7917,7 +8328,7 @@ async function runCLI(overrides = {}) {
7917
8328
  const opts = "env" in overrides || "config" in overrides ? overrides : { env: overrides };
7918
8329
  const config = opts.config !== void 0 ? opts.config : loadConfig();
7919
8330
  const envOverrides = opts.env ?? {};
7920
- const preParser = new import_commander3.Command();
8331
+ const preParser = new import_commander2.Command();
7921
8332
  preParser.option(OPTION_FLAGS.logLevel, OPTION_DESCRIPTIONS.logLevel, parseLogLevel2).option(OPTION_FLAGS.logFile, OPTION_DESCRIPTIONS.logFile).option(OPTION_FLAGS.logReset, OPTION_DESCRIPTIONS.logReset).allowUnknownOption().allowExcessArguments().helpOption(false);
7922
8333
  preParser.parse(process.argv);
7923
8334
  const globalOpts = preParser.opts();