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/{chunk-4IMGADVY.js → chunk-OIPLYP7M.js} +40 -5
- package/dist/chunk-OIPLYP7M.js.map +1 -0
- package/dist/{chunk-62M4TDAK.js → chunk-VXPZQZF5.js} +432 -555
- package/dist/chunk-VXPZQZF5.js.map +1 -0
- package/dist/cli.cjs +1069 -658
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +638 -95
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +464 -558
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +78 -9
- package/dist/index.d.ts +78 -9
- package/dist/index.js +2 -2
- package/dist/{mock-stream-CjmvWDc3.d.cts → mock-stream-DKF5yatf.d.cts} +41 -102
- package/dist/{mock-stream-CjmvWDc3.d.ts → mock-stream-DKF5yatf.d.ts} +41 -102
- package/dist/testing/index.cjs +464 -558
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.cts +2 -2
- package/dist/testing/index.d.ts +2 -2
- package/dist/testing/index.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-4IMGADVY.js.map +0 -1
- package/dist/chunk-62M4TDAK.js.map +0 -1
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
|
-
|
|
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,
|
|
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
|
|
439
|
-
parts.push(this.buildUsageSection(
|
|
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
|
|
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(
|
|
450
|
-
const
|
|
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 (
|
|
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(
|
|
471
|
+
buildUsageSection(context) {
|
|
476
472
|
const parts = [];
|
|
477
|
-
const
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
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(
|
|
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(
|
|
500
|
+
buildExamplesSection(context) {
|
|
520
501
|
if (this.promptConfig.customExamples) {
|
|
521
502
|
return this.promptConfig.customExamples(context);
|
|
522
503
|
}
|
|
523
504
|
const parts = [];
|
|
524
|
-
const
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
to
|
|
528
|
-
|
|
529
|
-
${this.
|
|
530
|
-
|
|
531
|
-
{
|
|
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
|
-
${
|
|
547
|
-
const
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
to
|
|
551
|
-
|
|
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
|
|
555
|
-
|
|
556
|
-
|
|
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
|
-
|
|
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
|
-
${
|
|
594
|
-
|
|
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
|
-
|
|
605
|
-
|
|
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
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
546
|
+
${this.argPrefix}filename
|
|
547
|
+
calculator.ts
|
|
548
|
+
${this.argPrefix}code
|
|
549
|
+
class Calculator {
|
|
550
|
+
private history: string[] = [];
|
|
614
551
|
|
|
615
|
-
|
|
616
|
-
|
|
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
|
-
|
|
619
|
-
|
|
620
|
-
|
|
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
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
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
|
-
|
|
629
|
-
|
|
630
|
-
|
|
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
|
|
653
|
-
const paramStr = this.
|
|
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
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
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
|
|
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
|
|
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
|
|
918
|
-
if (
|
|
919
|
-
|
|
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(`${
|
|
827
|
+
lines.push(`${argPrefix}${fullPath}`);
|
|
828
|
+
lines.push(String(value));
|
|
922
829
|
}
|
|
923
830
|
}
|
|
924
831
|
return lines.join("\n");
|
|
925
832
|
}
|
|
926
|
-
function
|
|
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
|
-
|
|
964
|
-
|
|
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
|
|
869
|
+
var BaseGadget;
|
|
969
870
|
var init_gadget = __esm({
|
|
970
871
|
"src/gadgets/gadget.ts"() {
|
|
971
872
|
"use strict";
|
|
972
|
-
|
|
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(
|
|
906
|
+
* @deprecated Use getInstruction() instead
|
|
1016
907
|
*/
|
|
1017
908
|
get instruction() {
|
|
1018
|
-
return this.getInstruction(
|
|
909
|
+
return this.getInstruction();
|
|
1019
910
|
}
|
|
1020
911
|
/**
|
|
1021
|
-
* Generate instruction text for the LLM
|
|
912
|
+
* Generate instruction text for the LLM.
|
|
1022
913
|
* Combines name, description, and parameter schema into a formatted instruction.
|
|
1023
914
|
*
|
|
1024
|
-
* @param
|
|
915
|
+
* @param argPrefix - Optional custom argument prefix for block format examples
|
|
1025
916
|
* @returns Formatted instruction string
|
|
1026
917
|
*/
|
|
1027
|
-
getInstruction(
|
|
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
|
-
|
|
1037
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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:
|
|
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.
|
|
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.
|
|
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
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
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
|
-
|
|
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/
|
|
1821
|
-
function
|
|
1822
|
-
const
|
|
1823
|
-
const result =
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
const
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
const
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
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
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1978
|
-
|
|
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
|
|
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
|
-
|
|
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.
|
|
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
|
-
*
|
|
2030
|
-
*
|
|
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
|
-
|
|
2033
|
-
|
|
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
|
|
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:
|
|
2069
|
-
} catch {
|
|
2070
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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(),
|
|
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
|
|
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
|
|
5492
|
-
* Uses heredoc for multiline string values.
|
|
5357
|
+
* Format parameters as block format with JSON Pointer paths.
|
|
5493
5358
|
*/
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
if (
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
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
|
-
|
|
5509
|
-
|
|
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
|
|
5586
|
+
var import_commander2 = require("commander");
|
|
5713
5587
|
|
|
5714
5588
|
// package.json
|
|
5715
5589
|
var package_default = {
|
|
5716
5590
|
name: "llmist",
|
|
5717
|
-
version: "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
|
|
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/
|
|
6020
|
-
var
|
|
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
|
-
|
|
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 =
|
|
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,
|
|
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,
|
|
6592
|
+
const rl = (0, import_promises2.createInterface)({ input: env.stdin, output: env.stdout });
|
|
6684
6593
|
try {
|
|
6685
6594
|
const questionLine = question.trim() ? `
|
|
6686
|
-
${
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
6991
|
-
progress.update(
|
|
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
|
|
7020
|
-
var
|
|
7021
|
-
var
|
|
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,
|
|
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,
|
|
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/
|
|
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(
|
|
7621
|
-
stream2.write(
|
|
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(
|
|
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(
|
|
7636
|
-
stream2.write(
|
|
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(
|
|
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(
|
|
8059
|
+
stream2.write(import_chalk6.default.dim("\u2500".repeat(idWidth + nameWidth + contextWidth + inputWidth + outputWidth + 8)) + "\n");
|
|
7650
8060
|
stream2.write(
|
|
7651
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
7665
|
-
stream2.write(
|
|
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(
|
|
8080
|
+
stream2.write(import_chalk6.default.bold.green(`
|
|
7671
8081
|
${model.modelId}
|
|
7672
8082
|
`));
|
|
7673
|
-
stream2.write(
|
|
7674
|
-
stream2.write(` ${
|
|
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(` ${
|
|
8086
|
+
stream2.write(` ${import_chalk6.default.dim("Context:")} ${import_chalk6.default.yellow(formatTokens2(model.contextWindow))}
|
|
7677
8087
|
`);
|
|
7678
|
-
stream2.write(` ${
|
|
8088
|
+
stream2.write(` ${import_chalk6.default.dim("Max Output:")} ${import_chalk6.default.yellow(formatTokens2(model.maxOutputTokens))}
|
|
7679
8089
|
`);
|
|
7680
|
-
stream2.write(` ${
|
|
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(` ${
|
|
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(` ${
|
|
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(` ${
|
|
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(` ${
|
|
8113
|
+
stream2.write(` ${import_chalk6.default.dim("Family:")} ${model.metadata.family}
|
|
7704
8114
|
`);
|
|
7705
8115
|
}
|
|
7706
8116
|
if (model.metadata.releaseDate) {
|
|
7707
|
-
stream2.write(` ${
|
|
8117
|
+
stream2.write(` ${import_chalk6.default.dim("Released:")} ${model.metadata.releaseDate}
|
|
7708
8118
|
`);
|
|
7709
8119
|
}
|
|
7710
8120
|
if (model.metadata.notes) {
|
|
7711
|
-
stream2.write(` ${
|
|
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
|
|
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(`${
|
|
8220
|
+
stdout.write(`${import_chalk7.default.cyan("\u2500".repeat(60))}
|
|
7811
8221
|
`);
|
|
7812
|
-
stdout.write(
|
|
8222
|
+
stdout.write(import_chalk7.default.cyan.bold("\u{1F916} Agent asks:\n"));
|
|
7813
8223
|
stdout.write(`${question}
|
|
7814
8224
|
`);
|
|
7815
|
-
stdout.write(`${
|
|
8225
|
+
stdout.write(`${import_chalk7.default.cyan("\u2500".repeat(60))}
|
|
7816
8226
|
`);
|
|
7817
|
-
rl.question(
|
|
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
|
|
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
|
|
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
|
|
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();
|