llmist 1.0.0 → 1.2.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-T24KLXY4.js → chunk-KORMY3CD.js} +621 -216
- package/dist/chunk-KORMY3CD.js.map +1 -0
- package/dist/{chunk-53MM55JS.js → chunk-LELPPETT.js} +2 -2
- package/dist/cli.cjs +1187 -353
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +471 -34
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +649 -248
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -4
- package/dist/index.d.ts +21 -4
- package/dist/index.js +2 -2
- package/dist/testing/index.cjs +649 -248
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-T24KLXY4.js.map +0 -1
- /package/dist/{chunk-53MM55JS.js.map → chunk-LELPPETT.js.map} +0 -0
package/dist/cli.cjs
CHANGED
|
@@ -1447,6 +1447,447 @@ var init_hook_validators = __esm({
|
|
|
1447
1447
|
}
|
|
1448
1448
|
});
|
|
1449
1449
|
|
|
1450
|
+
// src/gadgets/schema-introspector.ts
|
|
1451
|
+
function getDef(schema) {
|
|
1452
|
+
return schema._def;
|
|
1453
|
+
}
|
|
1454
|
+
function getTypeName(schema) {
|
|
1455
|
+
const def = getDef(schema);
|
|
1456
|
+
return def?.type ?? def?.typeName;
|
|
1457
|
+
}
|
|
1458
|
+
function getShape(schema) {
|
|
1459
|
+
const def = getDef(schema);
|
|
1460
|
+
if (typeof def?.shape === "function") {
|
|
1461
|
+
return def.shape();
|
|
1462
|
+
}
|
|
1463
|
+
return def?.shape;
|
|
1464
|
+
}
|
|
1465
|
+
var SchemaIntrospector;
|
|
1466
|
+
var init_schema_introspector = __esm({
|
|
1467
|
+
"src/gadgets/schema-introspector.ts"() {
|
|
1468
|
+
"use strict";
|
|
1469
|
+
SchemaIntrospector = class {
|
|
1470
|
+
schema;
|
|
1471
|
+
cache = /* @__PURE__ */ new Map();
|
|
1472
|
+
constructor(schema) {
|
|
1473
|
+
this.schema = schema;
|
|
1474
|
+
}
|
|
1475
|
+
/**
|
|
1476
|
+
* Get the expected type at a JSON pointer path.
|
|
1477
|
+
*
|
|
1478
|
+
* @param pointer - JSON pointer path without leading / (e.g., "config/timeout", "items/0")
|
|
1479
|
+
* @returns Type hint for coercion decision
|
|
1480
|
+
*/
|
|
1481
|
+
getTypeAtPath(pointer) {
|
|
1482
|
+
const cached = this.cache.get(pointer);
|
|
1483
|
+
if (cached !== void 0) {
|
|
1484
|
+
return cached;
|
|
1485
|
+
}
|
|
1486
|
+
const result = this.resolveTypeAtPath(pointer);
|
|
1487
|
+
this.cache.set(pointer, result);
|
|
1488
|
+
return result;
|
|
1489
|
+
}
|
|
1490
|
+
/**
|
|
1491
|
+
* Internal method to resolve type at path without caching.
|
|
1492
|
+
*/
|
|
1493
|
+
resolveTypeAtPath(pointer) {
|
|
1494
|
+
if (!pointer) {
|
|
1495
|
+
return this.getBaseType(this.schema);
|
|
1496
|
+
}
|
|
1497
|
+
const segments = pointer.split("/");
|
|
1498
|
+
let current = this.schema;
|
|
1499
|
+
for (const segment of segments) {
|
|
1500
|
+
current = this.unwrapSchema(current);
|
|
1501
|
+
const typeName = getTypeName(current);
|
|
1502
|
+
if (typeName === "object" || typeName === "ZodObject") {
|
|
1503
|
+
const shape = getShape(current);
|
|
1504
|
+
if (!shape || !(segment in shape)) {
|
|
1505
|
+
return "unknown";
|
|
1506
|
+
}
|
|
1507
|
+
current = shape[segment];
|
|
1508
|
+
} else if (typeName === "array" || typeName === "ZodArray") {
|
|
1509
|
+
if (!/^\d+$/.test(segment)) {
|
|
1510
|
+
return "unknown";
|
|
1511
|
+
}
|
|
1512
|
+
const def = getDef(current);
|
|
1513
|
+
const elementType = def?.element ?? def?.type;
|
|
1514
|
+
if (!elementType) {
|
|
1515
|
+
return "unknown";
|
|
1516
|
+
}
|
|
1517
|
+
current = elementType;
|
|
1518
|
+
} else if (typeName === "tuple" || typeName === "ZodTuple") {
|
|
1519
|
+
if (!/^\d+$/.test(segment)) {
|
|
1520
|
+
return "unknown";
|
|
1521
|
+
}
|
|
1522
|
+
const index = parseInt(segment, 10);
|
|
1523
|
+
const def = getDef(current);
|
|
1524
|
+
const items = def?.items;
|
|
1525
|
+
if (!items || index >= items.length) {
|
|
1526
|
+
return "unknown";
|
|
1527
|
+
}
|
|
1528
|
+
current = items[index];
|
|
1529
|
+
} else if (typeName === "record" || typeName === "ZodRecord") {
|
|
1530
|
+
const def = getDef(current);
|
|
1531
|
+
const valueType = def?.valueType;
|
|
1532
|
+
if (!valueType) {
|
|
1533
|
+
return "unknown";
|
|
1534
|
+
}
|
|
1535
|
+
current = valueType;
|
|
1536
|
+
} else {
|
|
1537
|
+
return "unknown";
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
return this.getBaseType(current);
|
|
1541
|
+
}
|
|
1542
|
+
/**
|
|
1543
|
+
* Unwrap schema modifiers (optional, default, nullable, branded, etc.)
|
|
1544
|
+
* to get to the underlying type.
|
|
1545
|
+
*/
|
|
1546
|
+
unwrapSchema(schema) {
|
|
1547
|
+
let current = schema;
|
|
1548
|
+
let iterations = 0;
|
|
1549
|
+
const maxIterations = 20;
|
|
1550
|
+
while (iterations < maxIterations) {
|
|
1551
|
+
const typeName = getTypeName(current);
|
|
1552
|
+
const wrapperTypes = [
|
|
1553
|
+
"optional",
|
|
1554
|
+
"nullable",
|
|
1555
|
+
"default",
|
|
1556
|
+
"catch",
|
|
1557
|
+
"branded",
|
|
1558
|
+
"readonly",
|
|
1559
|
+
"pipeline",
|
|
1560
|
+
"ZodOptional",
|
|
1561
|
+
"ZodNullable",
|
|
1562
|
+
"ZodDefault",
|
|
1563
|
+
"ZodCatch",
|
|
1564
|
+
"ZodBranded",
|
|
1565
|
+
"ZodReadonly",
|
|
1566
|
+
"ZodPipeline"
|
|
1567
|
+
];
|
|
1568
|
+
if (typeName && wrapperTypes.includes(typeName)) {
|
|
1569
|
+
const def = getDef(current);
|
|
1570
|
+
const inner = def?.innerType ?? def?.in ?? def?.type;
|
|
1571
|
+
if (!inner || inner === current) break;
|
|
1572
|
+
current = inner;
|
|
1573
|
+
iterations++;
|
|
1574
|
+
continue;
|
|
1575
|
+
}
|
|
1576
|
+
break;
|
|
1577
|
+
}
|
|
1578
|
+
return current;
|
|
1579
|
+
}
|
|
1580
|
+
/**
|
|
1581
|
+
* Get the primitive type hint from an unwrapped schema.
|
|
1582
|
+
*/
|
|
1583
|
+
getBaseType(schema) {
|
|
1584
|
+
const unwrapped = this.unwrapSchema(schema);
|
|
1585
|
+
const typeName = getTypeName(unwrapped);
|
|
1586
|
+
switch (typeName) {
|
|
1587
|
+
// Primitive types
|
|
1588
|
+
case "string":
|
|
1589
|
+
case "ZodString":
|
|
1590
|
+
return "string";
|
|
1591
|
+
case "number":
|
|
1592
|
+
case "ZodNumber":
|
|
1593
|
+
case "bigint":
|
|
1594
|
+
case "ZodBigInt":
|
|
1595
|
+
return "number";
|
|
1596
|
+
case "boolean":
|
|
1597
|
+
case "ZodBoolean":
|
|
1598
|
+
return "boolean";
|
|
1599
|
+
// Literal types - check the literal value type
|
|
1600
|
+
case "literal":
|
|
1601
|
+
case "ZodLiteral": {
|
|
1602
|
+
const def = getDef(unwrapped);
|
|
1603
|
+
const values = def?.values;
|
|
1604
|
+
const value = values?.[0] ?? def?.value;
|
|
1605
|
+
if (typeof value === "string") return "string";
|
|
1606
|
+
if (typeof value === "number" || typeof value === "bigint")
|
|
1607
|
+
return "number";
|
|
1608
|
+
if (typeof value === "boolean") return "boolean";
|
|
1609
|
+
return "unknown";
|
|
1610
|
+
}
|
|
1611
|
+
// Enum - always string keys
|
|
1612
|
+
case "enum":
|
|
1613
|
+
case "ZodEnum":
|
|
1614
|
+
case "nativeEnum":
|
|
1615
|
+
case "ZodNativeEnum":
|
|
1616
|
+
return "string";
|
|
1617
|
+
// Union - return 'unknown' to let auto-coercion decide
|
|
1618
|
+
// Since multiple types are valid, we can't definitively say what the LLM intended
|
|
1619
|
+
// Auto-coercion will handle common cases (numbers, booleans) appropriately
|
|
1620
|
+
case "union":
|
|
1621
|
+
case "ZodUnion":
|
|
1622
|
+
return "unknown";
|
|
1623
|
+
// Discriminated union - complex, return unknown
|
|
1624
|
+
case "discriminatedUnion":
|
|
1625
|
+
case "ZodDiscriminatedUnion":
|
|
1626
|
+
return "unknown";
|
|
1627
|
+
// Intersection - check both sides
|
|
1628
|
+
case "intersection":
|
|
1629
|
+
case "ZodIntersection": {
|
|
1630
|
+
const def = getDef(unwrapped);
|
|
1631
|
+
const left = def?.left;
|
|
1632
|
+
const right = def?.right;
|
|
1633
|
+
if (!left || !right) return "unknown";
|
|
1634
|
+
const leftType = this.getBaseType(left);
|
|
1635
|
+
const rightType = this.getBaseType(right);
|
|
1636
|
+
if (leftType === rightType) return leftType;
|
|
1637
|
+
if (leftType === "string" || rightType === "string") return "string";
|
|
1638
|
+
return "unknown";
|
|
1639
|
+
}
|
|
1640
|
+
// Effects/transforms - return unknown to let Zod handle it
|
|
1641
|
+
case "effects":
|
|
1642
|
+
case "ZodEffects":
|
|
1643
|
+
return "unknown";
|
|
1644
|
+
// Lazy - can't resolve without evaluating
|
|
1645
|
+
case "lazy":
|
|
1646
|
+
case "ZodLazy":
|
|
1647
|
+
return "unknown";
|
|
1648
|
+
// Complex types - return unknown
|
|
1649
|
+
case "object":
|
|
1650
|
+
case "ZodObject":
|
|
1651
|
+
case "array":
|
|
1652
|
+
case "ZodArray":
|
|
1653
|
+
case "tuple":
|
|
1654
|
+
case "ZodTuple":
|
|
1655
|
+
case "record":
|
|
1656
|
+
case "ZodRecord":
|
|
1657
|
+
case "map":
|
|
1658
|
+
case "ZodMap":
|
|
1659
|
+
case "set":
|
|
1660
|
+
case "ZodSet":
|
|
1661
|
+
case "function":
|
|
1662
|
+
case "ZodFunction":
|
|
1663
|
+
case "promise":
|
|
1664
|
+
case "ZodPromise":
|
|
1665
|
+
case "date":
|
|
1666
|
+
case "ZodDate":
|
|
1667
|
+
return "unknown";
|
|
1668
|
+
// Unknown/any/never/void/undefined/null
|
|
1669
|
+
case "unknown":
|
|
1670
|
+
case "ZodUnknown":
|
|
1671
|
+
case "any":
|
|
1672
|
+
case "ZodAny":
|
|
1673
|
+
case "never":
|
|
1674
|
+
case "ZodNever":
|
|
1675
|
+
case "void":
|
|
1676
|
+
case "ZodVoid":
|
|
1677
|
+
case "undefined":
|
|
1678
|
+
case "ZodUndefined":
|
|
1679
|
+
case "null":
|
|
1680
|
+
case "ZodNull":
|
|
1681
|
+
return "unknown";
|
|
1682
|
+
default:
|
|
1683
|
+
return "unknown";
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
};
|
|
1687
|
+
}
|
|
1688
|
+
});
|
|
1689
|
+
|
|
1690
|
+
// src/gadgets/block-params.ts
|
|
1691
|
+
function parseBlockParams(content, options) {
|
|
1692
|
+
const argPrefix = options?.argPrefix ?? GADGET_ARG_PREFIX;
|
|
1693
|
+
const result = {};
|
|
1694
|
+
const seenPointers = /* @__PURE__ */ new Set();
|
|
1695
|
+
const introspector = options?.schema ? new SchemaIntrospector(options.schema) : void 0;
|
|
1696
|
+
const parts = content.split(argPrefix);
|
|
1697
|
+
for (let i = 1; i < parts.length; i++) {
|
|
1698
|
+
const part = parts[i];
|
|
1699
|
+
const newlineIndex = part.indexOf("\n");
|
|
1700
|
+
if (newlineIndex === -1) {
|
|
1701
|
+
const pointer2 = part.trim();
|
|
1702
|
+
if (pointer2) {
|
|
1703
|
+
if (seenPointers.has(pointer2)) {
|
|
1704
|
+
throw new Error(`Duplicate pointer: ${pointer2}`);
|
|
1705
|
+
}
|
|
1706
|
+
seenPointers.add(pointer2);
|
|
1707
|
+
setByPointer(result, pointer2, "", introspector);
|
|
1708
|
+
}
|
|
1709
|
+
continue;
|
|
1710
|
+
}
|
|
1711
|
+
const pointer = part.substring(0, newlineIndex).trim();
|
|
1712
|
+
let value = part.substring(newlineIndex + 1);
|
|
1713
|
+
if (value.endsWith("\n")) {
|
|
1714
|
+
value = value.slice(0, -1);
|
|
1715
|
+
}
|
|
1716
|
+
if (!pointer) {
|
|
1717
|
+
continue;
|
|
1718
|
+
}
|
|
1719
|
+
if (seenPointers.has(pointer)) {
|
|
1720
|
+
throw new Error(`Duplicate pointer: ${pointer}`);
|
|
1721
|
+
}
|
|
1722
|
+
seenPointers.add(pointer);
|
|
1723
|
+
setByPointer(result, pointer, value, introspector);
|
|
1724
|
+
}
|
|
1725
|
+
return result;
|
|
1726
|
+
}
|
|
1727
|
+
function coerceValue(value, expectedType) {
|
|
1728
|
+
if (value.includes("\n")) {
|
|
1729
|
+
return value;
|
|
1730
|
+
}
|
|
1731
|
+
const trimmed = value.trim();
|
|
1732
|
+
if (expectedType === "string") {
|
|
1733
|
+
return value;
|
|
1734
|
+
}
|
|
1735
|
+
if (expectedType === "boolean") {
|
|
1736
|
+
if (trimmed === "true") return true;
|
|
1737
|
+
if (trimmed === "false") return false;
|
|
1738
|
+
return value;
|
|
1739
|
+
}
|
|
1740
|
+
if (expectedType === "number") {
|
|
1741
|
+
const num = Number(trimmed);
|
|
1742
|
+
if (!isNaN(num) && isFinite(num) && trimmed !== "") {
|
|
1743
|
+
return num;
|
|
1744
|
+
}
|
|
1745
|
+
return value;
|
|
1746
|
+
}
|
|
1747
|
+
if (trimmed === "true") return true;
|
|
1748
|
+
if (trimmed === "false") return false;
|
|
1749
|
+
if (trimmed !== "" && /^-?\d+(\.\d+)?$/.test(trimmed)) {
|
|
1750
|
+
const num = Number(trimmed);
|
|
1751
|
+
if (!isNaN(num) && isFinite(num)) {
|
|
1752
|
+
return num;
|
|
1753
|
+
}
|
|
1754
|
+
}
|
|
1755
|
+
return value;
|
|
1756
|
+
}
|
|
1757
|
+
function setByPointer(obj, pointer, value, introspector) {
|
|
1758
|
+
const segments = pointer.split("/");
|
|
1759
|
+
let current = obj;
|
|
1760
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
1761
|
+
const segment = segments[i];
|
|
1762
|
+
const nextSegment = segments[i + 1];
|
|
1763
|
+
const nextIsArrayIndex = /^\d+$/.test(nextSegment);
|
|
1764
|
+
if (Array.isArray(current)) {
|
|
1765
|
+
const index = parseInt(segment, 10);
|
|
1766
|
+
if (isNaN(index) || index < 0) {
|
|
1767
|
+
throw new Error(`Invalid array index: ${segment}`);
|
|
1768
|
+
}
|
|
1769
|
+
if (index > current.length) {
|
|
1770
|
+
throw new Error(`Array index gap: expected ${current.length}, got ${index}`);
|
|
1771
|
+
}
|
|
1772
|
+
if (current[index] === void 0) {
|
|
1773
|
+
current[index] = nextIsArrayIndex ? [] : {};
|
|
1774
|
+
}
|
|
1775
|
+
current = current[index];
|
|
1776
|
+
} else {
|
|
1777
|
+
const rec = current;
|
|
1778
|
+
if (rec[segment] === void 0) {
|
|
1779
|
+
rec[segment] = nextIsArrayIndex ? [] : {};
|
|
1780
|
+
}
|
|
1781
|
+
current = rec[segment];
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1784
|
+
const lastSegment = segments[segments.length - 1];
|
|
1785
|
+
const expectedType = introspector?.getTypeAtPath(pointer);
|
|
1786
|
+
const coercedValue = coerceValue(value, expectedType);
|
|
1787
|
+
if (Array.isArray(current)) {
|
|
1788
|
+
const index = parseInt(lastSegment, 10);
|
|
1789
|
+
if (isNaN(index) || index < 0) {
|
|
1790
|
+
throw new Error(`Invalid array index: ${lastSegment}`);
|
|
1791
|
+
}
|
|
1792
|
+
if (index > current.length) {
|
|
1793
|
+
throw new Error(`Array index gap: expected ${current.length}, got ${index}`);
|
|
1794
|
+
}
|
|
1795
|
+
current[index] = coercedValue;
|
|
1796
|
+
} else {
|
|
1797
|
+
current[lastSegment] = coercedValue;
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
var init_block_params = __esm({
|
|
1801
|
+
"src/gadgets/block-params.ts"() {
|
|
1802
|
+
"use strict";
|
|
1803
|
+
init_constants();
|
|
1804
|
+
init_schema_introspector();
|
|
1805
|
+
}
|
|
1806
|
+
});
|
|
1807
|
+
|
|
1808
|
+
// src/gadgets/error-formatter.ts
|
|
1809
|
+
var GadgetErrorFormatter;
|
|
1810
|
+
var init_error_formatter = __esm({
|
|
1811
|
+
"src/gadgets/error-formatter.ts"() {
|
|
1812
|
+
"use strict";
|
|
1813
|
+
init_constants();
|
|
1814
|
+
GadgetErrorFormatter = class {
|
|
1815
|
+
argPrefix;
|
|
1816
|
+
startPrefix;
|
|
1817
|
+
endPrefix;
|
|
1818
|
+
constructor(options = {}) {
|
|
1819
|
+
this.argPrefix = options.argPrefix ?? GADGET_ARG_PREFIX;
|
|
1820
|
+
this.startPrefix = options.startPrefix ?? GADGET_START_PREFIX;
|
|
1821
|
+
this.endPrefix = options.endPrefix ?? GADGET_END_PREFIX;
|
|
1822
|
+
}
|
|
1823
|
+
/**
|
|
1824
|
+
* Format a Zod validation error with full gadget instructions.
|
|
1825
|
+
*
|
|
1826
|
+
* @param gadgetName - Name of the gadget that was called
|
|
1827
|
+
* @param zodError - The Zod validation error
|
|
1828
|
+
* @param gadget - The gadget instance (for generating instructions)
|
|
1829
|
+
* @returns Formatted error message with usage instructions
|
|
1830
|
+
*/
|
|
1831
|
+
formatValidationError(gadgetName, zodError, gadget) {
|
|
1832
|
+
const parts = [];
|
|
1833
|
+
parts.push(`Error: Invalid parameters for '${gadgetName}':`);
|
|
1834
|
+
for (const issue of zodError.issues) {
|
|
1835
|
+
const path2 = issue.path.join(".") || "root";
|
|
1836
|
+
parts.push(` - ${path2}: ${issue.message}`);
|
|
1837
|
+
}
|
|
1838
|
+
parts.push("");
|
|
1839
|
+
parts.push("Gadget Usage:");
|
|
1840
|
+
parts.push(gadget.getInstruction(this.argPrefix));
|
|
1841
|
+
return parts.join("\n");
|
|
1842
|
+
}
|
|
1843
|
+
/**
|
|
1844
|
+
* Format a parse error with block format reference.
|
|
1845
|
+
*
|
|
1846
|
+
* @param gadgetName - Name of the gadget that was called
|
|
1847
|
+
* @param parseError - The parse error message
|
|
1848
|
+
* @param gadget - The gadget instance if found (for generating instructions)
|
|
1849
|
+
* @returns Formatted error message with format reference
|
|
1850
|
+
*/
|
|
1851
|
+
formatParseError(gadgetName, parseError, gadget) {
|
|
1852
|
+
const parts = [];
|
|
1853
|
+
parts.push(`Error: Failed to parse parameters for '${gadgetName}':`);
|
|
1854
|
+
parts.push(` ${parseError}`);
|
|
1855
|
+
if (gadget) {
|
|
1856
|
+
parts.push("");
|
|
1857
|
+
parts.push("Gadget Usage:");
|
|
1858
|
+
parts.push(gadget.getInstruction(this.argPrefix));
|
|
1859
|
+
}
|
|
1860
|
+
parts.push("");
|
|
1861
|
+
parts.push("Block Format Reference:");
|
|
1862
|
+
parts.push(` ${this.startPrefix}${gadgetName}`);
|
|
1863
|
+
parts.push(` ${this.argPrefix}parameterName`);
|
|
1864
|
+
parts.push(" parameter value here");
|
|
1865
|
+
parts.push(` ${this.endPrefix}`);
|
|
1866
|
+
return parts.join("\n");
|
|
1867
|
+
}
|
|
1868
|
+
/**
|
|
1869
|
+
* Format a registry error (gadget not found) with available gadgets list.
|
|
1870
|
+
*
|
|
1871
|
+
* @param gadgetName - Name of the gadget that was not found
|
|
1872
|
+
* @param availableGadgets - List of available gadget names
|
|
1873
|
+
* @returns Formatted error message with available gadgets
|
|
1874
|
+
*/
|
|
1875
|
+
formatRegistryError(gadgetName, availableGadgets) {
|
|
1876
|
+
const parts = [];
|
|
1877
|
+
parts.push(`Error: Gadget '${gadgetName}' not found.`);
|
|
1878
|
+
if (availableGadgets.length > 0) {
|
|
1879
|
+
parts.push("");
|
|
1880
|
+
parts.push(`Available gadgets: ${availableGadgets.join(", ")}`);
|
|
1881
|
+
} else {
|
|
1882
|
+
parts.push("");
|
|
1883
|
+
parts.push("No gadgets are currently registered.");
|
|
1884
|
+
}
|
|
1885
|
+
return parts.join("\n");
|
|
1886
|
+
}
|
|
1887
|
+
};
|
|
1888
|
+
}
|
|
1889
|
+
});
|
|
1890
|
+
|
|
1450
1891
|
// src/gadgets/exceptions.ts
|
|
1451
1892
|
var BreakLoopException, HumanInputException, TimeoutException;
|
|
1452
1893
|
var init_exceptions = __esm({
|
|
@@ -1479,21 +1920,206 @@ var init_exceptions = __esm({
|
|
|
1479
1920
|
}
|
|
1480
1921
|
});
|
|
1481
1922
|
|
|
1923
|
+
// src/gadgets/parser.ts
|
|
1924
|
+
function stripMarkdownFences(content) {
|
|
1925
|
+
let cleaned = content.trim();
|
|
1926
|
+
const openingFence = /^```(?:toml|yaml|json)?\s*\n/i;
|
|
1927
|
+
const closingFence = /\n?```\s*$/;
|
|
1928
|
+
cleaned = cleaned.replace(openingFence, "");
|
|
1929
|
+
cleaned = cleaned.replace(closingFence, "");
|
|
1930
|
+
return cleaned.trim();
|
|
1931
|
+
}
|
|
1932
|
+
var globalInvocationCounter, StreamParser;
|
|
1933
|
+
var init_parser = __esm({
|
|
1934
|
+
"src/gadgets/parser.ts"() {
|
|
1935
|
+
"use strict";
|
|
1936
|
+
init_constants();
|
|
1937
|
+
init_block_params();
|
|
1938
|
+
globalInvocationCounter = 0;
|
|
1939
|
+
StreamParser = class {
|
|
1940
|
+
buffer = "";
|
|
1941
|
+
lastReportedTextLength = 0;
|
|
1942
|
+
startPrefix;
|
|
1943
|
+
endPrefix;
|
|
1944
|
+
argPrefix;
|
|
1945
|
+
constructor(options = {}) {
|
|
1946
|
+
this.startPrefix = options.startPrefix ?? GADGET_START_PREFIX;
|
|
1947
|
+
this.endPrefix = options.endPrefix ?? GADGET_END_PREFIX;
|
|
1948
|
+
this.argPrefix = options.argPrefix ?? GADGET_ARG_PREFIX;
|
|
1949
|
+
}
|
|
1950
|
+
takeTextUntil(index) {
|
|
1951
|
+
if (index <= this.lastReportedTextLength) {
|
|
1952
|
+
return void 0;
|
|
1953
|
+
}
|
|
1954
|
+
const segment = this.buffer.slice(this.lastReportedTextLength, index);
|
|
1955
|
+
this.lastReportedTextLength = index;
|
|
1956
|
+
return segment.trim().length > 0 ? segment : void 0;
|
|
1957
|
+
}
|
|
1958
|
+
/**
|
|
1959
|
+
* Parse gadget name, handling both old format (name:invocationId) and new format (just name).
|
|
1960
|
+
* For new format, generates a unique invocation ID.
|
|
1961
|
+
*/
|
|
1962
|
+
parseGadgetName(gadgetName) {
|
|
1963
|
+
if (gadgetName.includes(":")) {
|
|
1964
|
+
const parts = gadgetName.split(":");
|
|
1965
|
+
return { actualName: parts[0], invocationId: parts[1] };
|
|
1966
|
+
}
|
|
1967
|
+
return { actualName: gadgetName, invocationId: `gadget_${++globalInvocationCounter}` };
|
|
1968
|
+
}
|
|
1969
|
+
/**
|
|
1970
|
+
* Extract the error message from a parse error.
|
|
1971
|
+
* Preserves full message since the error formatter adds contextual help
|
|
1972
|
+
* that benefits from precise, detailed error information.
|
|
1973
|
+
*/
|
|
1974
|
+
extractParseError(error) {
|
|
1975
|
+
return error instanceof Error ? error.message : String(error);
|
|
1976
|
+
}
|
|
1977
|
+
/**
|
|
1978
|
+
* Parse parameter string using block format
|
|
1979
|
+
*/
|
|
1980
|
+
parseParameters(raw) {
|
|
1981
|
+
const cleaned = stripMarkdownFences(raw);
|
|
1982
|
+
try {
|
|
1983
|
+
return { parameters: parseBlockParams(cleaned, { argPrefix: this.argPrefix }) };
|
|
1984
|
+
} catch (error) {
|
|
1985
|
+
return { parseError: this.extractParseError(error) };
|
|
1986
|
+
}
|
|
1987
|
+
}
|
|
1988
|
+
// Feed a chunk of text and get parsed events
|
|
1989
|
+
*feed(chunk) {
|
|
1990
|
+
this.buffer += chunk;
|
|
1991
|
+
let startIndex = 0;
|
|
1992
|
+
while (true) {
|
|
1993
|
+
const partStartIndex = this.buffer.indexOf(this.startPrefix, startIndex);
|
|
1994
|
+
if (partStartIndex === -1) break;
|
|
1995
|
+
const textBefore = this.takeTextUntil(partStartIndex);
|
|
1996
|
+
if (textBefore !== void 0) {
|
|
1997
|
+
yield { type: "text", content: textBefore };
|
|
1998
|
+
}
|
|
1999
|
+
const metadataStartIndex = partStartIndex + this.startPrefix.length;
|
|
2000
|
+
const metadataEndIndex = this.buffer.indexOf("\n", metadataStartIndex);
|
|
2001
|
+
if (metadataEndIndex === -1) break;
|
|
2002
|
+
const gadgetName = this.buffer.substring(metadataStartIndex, metadataEndIndex).trim();
|
|
2003
|
+
const { actualName: actualGadgetName, invocationId } = this.parseGadgetName(gadgetName);
|
|
2004
|
+
const contentStartIndex = metadataEndIndex + 1;
|
|
2005
|
+
let partEndIndex;
|
|
2006
|
+
let endMarkerLength = 0;
|
|
2007
|
+
if (gadgetName.includes(":")) {
|
|
2008
|
+
const oldEndMarker = `${this.endPrefix + actualGadgetName}:${invocationId}`;
|
|
2009
|
+
partEndIndex = this.buffer.indexOf(oldEndMarker, contentStartIndex);
|
|
2010
|
+
if (partEndIndex === -1) break;
|
|
2011
|
+
endMarkerLength = oldEndMarker.length;
|
|
2012
|
+
} else {
|
|
2013
|
+
const nextStartPos = this.buffer.indexOf(this.startPrefix, contentStartIndex);
|
|
2014
|
+
let validEndPos = -1;
|
|
2015
|
+
let searchPos = contentStartIndex;
|
|
2016
|
+
while (true) {
|
|
2017
|
+
const endPos = this.buffer.indexOf(this.endPrefix, searchPos);
|
|
2018
|
+
if (endPos === -1) break;
|
|
2019
|
+
const afterEnd = this.buffer.substring(endPos + this.endPrefix.length);
|
|
2020
|
+
if (afterEnd.startsWith("\n") || afterEnd.startsWith("\r") || afterEnd.startsWith(this.startPrefix) || afterEnd.length === 0) {
|
|
2021
|
+
validEndPos = endPos;
|
|
2022
|
+
break;
|
|
2023
|
+
} else {
|
|
2024
|
+
searchPos = endPos + this.endPrefix.length;
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
if (nextStartPos !== -1 && (validEndPos === -1 || nextStartPos < validEndPos)) {
|
|
2028
|
+
partEndIndex = nextStartPos;
|
|
2029
|
+
endMarkerLength = 0;
|
|
2030
|
+
} else if (validEndPos !== -1) {
|
|
2031
|
+
partEndIndex = validEndPos;
|
|
2032
|
+
endMarkerLength = this.endPrefix.length;
|
|
2033
|
+
} else {
|
|
2034
|
+
break;
|
|
2035
|
+
}
|
|
2036
|
+
}
|
|
2037
|
+
const parametersRaw = this.buffer.substring(contentStartIndex, partEndIndex).trim();
|
|
2038
|
+
const { parameters, parseError } = this.parseParameters(parametersRaw);
|
|
2039
|
+
yield {
|
|
2040
|
+
type: "gadget_call",
|
|
2041
|
+
call: {
|
|
2042
|
+
gadgetName: actualGadgetName,
|
|
2043
|
+
invocationId,
|
|
2044
|
+
parametersRaw,
|
|
2045
|
+
parameters,
|
|
2046
|
+
parseError
|
|
2047
|
+
}
|
|
2048
|
+
};
|
|
2049
|
+
startIndex = partEndIndex + endMarkerLength;
|
|
2050
|
+
this.lastReportedTextLength = startIndex;
|
|
2051
|
+
}
|
|
2052
|
+
if (startIndex > 0) {
|
|
2053
|
+
this.buffer = this.buffer.substring(startIndex);
|
|
2054
|
+
this.lastReportedTextLength = 0;
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
// Finalize parsing and return remaining text or incomplete gadgets
|
|
2058
|
+
*finalize() {
|
|
2059
|
+
const startIndex = this.buffer.indexOf(this.startPrefix, this.lastReportedTextLength);
|
|
2060
|
+
if (startIndex !== -1) {
|
|
2061
|
+
const textBefore = this.takeTextUntil(startIndex);
|
|
2062
|
+
if (textBefore !== void 0) {
|
|
2063
|
+
yield { type: "text", content: textBefore };
|
|
2064
|
+
}
|
|
2065
|
+
const metadataStartIndex = startIndex + this.startPrefix.length;
|
|
2066
|
+
const metadataEndIndex = this.buffer.indexOf("\n", metadataStartIndex);
|
|
2067
|
+
if (metadataEndIndex !== -1) {
|
|
2068
|
+
const gadgetName = this.buffer.substring(metadataStartIndex, metadataEndIndex).trim();
|
|
2069
|
+
const { actualName: actualGadgetName, invocationId } = this.parseGadgetName(gadgetName);
|
|
2070
|
+
const contentStartIndex = metadataEndIndex + 1;
|
|
2071
|
+
const parametersRaw = this.buffer.substring(contentStartIndex).trim();
|
|
2072
|
+
const { parameters, parseError } = this.parseParameters(parametersRaw);
|
|
2073
|
+
yield {
|
|
2074
|
+
type: "gadget_call",
|
|
2075
|
+
call: {
|
|
2076
|
+
gadgetName: actualGadgetName,
|
|
2077
|
+
invocationId,
|
|
2078
|
+
parametersRaw,
|
|
2079
|
+
parameters,
|
|
2080
|
+
parseError
|
|
2081
|
+
}
|
|
2082
|
+
};
|
|
2083
|
+
return;
|
|
2084
|
+
}
|
|
2085
|
+
}
|
|
2086
|
+
const remainingText = this.takeTextUntil(this.buffer.length);
|
|
2087
|
+
if (remainingText !== void 0) {
|
|
2088
|
+
yield { type: "text", content: remainingText };
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
// Reset parser state (note: global invocation counter is NOT reset to ensure unique IDs)
|
|
2092
|
+
reset() {
|
|
2093
|
+
this.buffer = "";
|
|
2094
|
+
this.lastReportedTextLength = 0;
|
|
2095
|
+
}
|
|
2096
|
+
};
|
|
2097
|
+
}
|
|
2098
|
+
});
|
|
2099
|
+
|
|
1482
2100
|
// src/gadgets/executor.ts
|
|
1483
2101
|
var GadgetExecutor;
|
|
1484
2102
|
var init_executor = __esm({
|
|
1485
2103
|
"src/gadgets/executor.ts"() {
|
|
1486
2104
|
"use strict";
|
|
2105
|
+
init_constants();
|
|
1487
2106
|
init_logger();
|
|
2107
|
+
init_block_params();
|
|
2108
|
+
init_error_formatter();
|
|
1488
2109
|
init_exceptions();
|
|
2110
|
+
init_parser();
|
|
1489
2111
|
GadgetExecutor = class {
|
|
1490
|
-
constructor(registry, onHumanInputRequired, logger, defaultGadgetTimeoutMs) {
|
|
2112
|
+
constructor(registry, onHumanInputRequired, logger, defaultGadgetTimeoutMs, errorFormatterOptions) {
|
|
1491
2113
|
this.registry = registry;
|
|
1492
2114
|
this.onHumanInputRequired = onHumanInputRequired;
|
|
1493
2115
|
this.defaultGadgetTimeoutMs = defaultGadgetTimeoutMs;
|
|
1494
2116
|
this.logger = logger ?? createLogger({ name: "llmist:executor" });
|
|
2117
|
+
this.errorFormatter = new GadgetErrorFormatter(errorFormatterOptions);
|
|
2118
|
+
this.argPrefix = errorFormatterOptions?.argPrefix ?? GADGET_ARG_PREFIX;
|
|
1495
2119
|
}
|
|
1496
2120
|
logger;
|
|
2121
|
+
errorFormatter;
|
|
2122
|
+
argPrefix;
|
|
1497
2123
|
/**
|
|
1498
2124
|
* Creates a promise that rejects with a TimeoutException after the specified timeout.
|
|
1499
2125
|
*/
|
|
@@ -1518,11 +2144,12 @@ var init_executor = __esm({
|
|
|
1518
2144
|
const gadget = this.registry.get(call.gadgetName);
|
|
1519
2145
|
if (!gadget) {
|
|
1520
2146
|
this.logger.error("Gadget not found", { gadgetName: call.gadgetName });
|
|
2147
|
+
const availableGadgets = this.registry.getNames();
|
|
1521
2148
|
return {
|
|
1522
2149
|
gadgetName: call.gadgetName,
|
|
1523
2150
|
invocationId: call.invocationId,
|
|
1524
2151
|
parameters: call.parameters ?? {},
|
|
1525
|
-
error:
|
|
2152
|
+
error: this.errorFormatter.formatRegistryError(call.gadgetName, availableGadgets),
|
|
1526
2153
|
executionTimeMs: Date.now() - startTime
|
|
1527
2154
|
};
|
|
1528
2155
|
}
|
|
@@ -1532,35 +2159,69 @@ var init_executor = __esm({
|
|
|
1532
2159
|
parseError: call.parseError,
|
|
1533
2160
|
rawParameters: call.parametersRaw
|
|
1534
2161
|
});
|
|
2162
|
+
const parseErrorMessage = call.parseError ?? "Failed to parse parameters";
|
|
1535
2163
|
return {
|
|
1536
2164
|
gadgetName: call.gadgetName,
|
|
1537
2165
|
invocationId: call.invocationId,
|
|
1538
2166
|
parameters: {},
|
|
1539
|
-
error: call.
|
|
2167
|
+
error: this.errorFormatter.formatParseError(call.gadgetName, parseErrorMessage, gadget),
|
|
1540
2168
|
executionTimeMs: Date.now() - startTime
|
|
1541
2169
|
};
|
|
1542
2170
|
}
|
|
2171
|
+
let schemaAwareParameters = rawParameters;
|
|
2172
|
+
const hasBlockFormat = call.parametersRaw?.includes(this.argPrefix);
|
|
2173
|
+
if (gadget.parameterSchema && hasBlockFormat) {
|
|
2174
|
+
try {
|
|
2175
|
+
const cleanedRaw = stripMarkdownFences(call.parametersRaw);
|
|
2176
|
+
const initialParse = parseBlockParams(cleanedRaw, { argPrefix: this.argPrefix });
|
|
2177
|
+
const parametersWereModified = !this.deepEquals(rawParameters, initialParse);
|
|
2178
|
+
if (parametersWereModified) {
|
|
2179
|
+
this.logger.debug("Parameters modified by interceptor, skipping re-parse", {
|
|
2180
|
+
gadgetName: call.gadgetName
|
|
2181
|
+
});
|
|
2182
|
+
schemaAwareParameters = rawParameters;
|
|
2183
|
+
} else {
|
|
2184
|
+
schemaAwareParameters = parseBlockParams(cleanedRaw, {
|
|
2185
|
+
argPrefix: this.argPrefix,
|
|
2186
|
+
schema: gadget.parameterSchema
|
|
2187
|
+
});
|
|
2188
|
+
this.logger.debug("Re-parsed parameters with schema", {
|
|
2189
|
+
gadgetName: call.gadgetName,
|
|
2190
|
+
original: rawParameters,
|
|
2191
|
+
schemaAware: schemaAwareParameters
|
|
2192
|
+
});
|
|
2193
|
+
}
|
|
2194
|
+
} catch (error) {
|
|
2195
|
+
this.logger.warn("Schema-aware re-parsing failed, using original parameters", {
|
|
2196
|
+
gadgetName: call.gadgetName,
|
|
2197
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2198
|
+
});
|
|
2199
|
+
schemaAwareParameters = rawParameters;
|
|
2200
|
+
}
|
|
2201
|
+
}
|
|
1543
2202
|
if (gadget.parameterSchema) {
|
|
1544
|
-
const validationResult = gadget.parameterSchema.safeParse(
|
|
2203
|
+
const validationResult = gadget.parameterSchema.safeParse(schemaAwareParameters);
|
|
1545
2204
|
if (!validationResult.success) {
|
|
1546
|
-
const
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
2205
|
+
const validationError = this.errorFormatter.formatValidationError(
|
|
2206
|
+
call.gadgetName,
|
|
2207
|
+
validationResult.error,
|
|
2208
|
+
gadget
|
|
2209
|
+
);
|
|
1551
2210
|
this.logger.error("Gadget parameter validation failed", {
|
|
1552
2211
|
gadgetName: call.gadgetName,
|
|
1553
|
-
|
|
2212
|
+
issueCount: validationResult.error.issues.length
|
|
1554
2213
|
});
|
|
1555
2214
|
return {
|
|
1556
2215
|
gadgetName: call.gadgetName,
|
|
1557
2216
|
invocationId: call.invocationId,
|
|
1558
|
-
parameters:
|
|
2217
|
+
parameters: schemaAwareParameters,
|
|
1559
2218
|
error: validationError,
|
|
1560
2219
|
executionTimeMs: Date.now() - startTime
|
|
1561
2220
|
};
|
|
1562
2221
|
}
|
|
1563
2222
|
validatedParameters = validationResult.data;
|
|
2223
|
+
} else {
|
|
2224
|
+
validatedParameters = schemaAwareParameters;
|
|
1564
2225
|
}
|
|
1565
2226
|
const timeoutMs = gadget.timeoutMs ?? this.defaultGadgetTimeoutMs;
|
|
1566
2227
|
let result;
|
|
@@ -1653,322 +2314,61 @@ var init_executor = __esm({
|
|
|
1653
2314
|
gadgetName: call.gadgetName,
|
|
1654
2315
|
invocationId: call.invocationId,
|
|
1655
2316
|
parameters: validatedParameters,
|
|
1656
|
-
error: inputError instanceof Error ? inputError.message : String(inputError),
|
|
1657
|
-
executionTimeMs: Date.now() - startTime
|
|
1658
|
-
};
|
|
1659
|
-
}
|
|
1660
|
-
}
|
|
1661
|
-
this.logger.warn("Human input required but no callback provided", {
|
|
1662
|
-
gadgetName: call.gadgetName
|
|
1663
|
-
});
|
|
1664
|
-
return {
|
|
1665
|
-
gadgetName: call.gadgetName,
|
|
1666
|
-
invocationId: call.invocationId,
|
|
1667
|
-
parameters: validatedParameters,
|
|
1668
|
-
error: "Human input required but not available (stdin is not interactive)",
|
|
1669
|
-
executionTimeMs: Date.now() - startTime
|
|
1670
|
-
};
|
|
1671
|
-
}
|
|
1672
|
-
const executionTimeMs = Date.now() - startTime;
|
|
1673
|
-
this.logger.error("Gadget execution failed", {
|
|
1674
|
-
gadgetName: call.gadgetName,
|
|
1675
|
-
error: error instanceof Error ? error.message : String(error),
|
|
1676
|
-
executionTimeMs
|
|
1677
|
-
});
|
|
1678
|
-
return {
|
|
1679
|
-
gadgetName: call.gadgetName,
|
|
1680
|
-
invocationId: call.invocationId,
|
|
1681
|
-
parameters: validatedParameters,
|
|
1682
|
-
error: error instanceof Error ? error.message : String(error),
|
|
1683
|
-
executionTimeMs
|
|
1684
|
-
};
|
|
1685
|
-
}
|
|
1686
|
-
}
|
|
1687
|
-
// Execute multiple gadget calls in parallel
|
|
1688
|
-
async executeAll(calls) {
|
|
1689
|
-
return Promise.all(calls.map((call) => this.execute(call)));
|
|
1690
|
-
}
|
|
1691
|
-
};
|
|
1692
|
-
}
|
|
1693
|
-
});
|
|
1694
|
-
|
|
1695
|
-
// src/gadgets/block-params.ts
|
|
1696
|
-
function parseBlockParams(content, options) {
|
|
1697
|
-
const argPrefix = options?.argPrefix ?? GADGET_ARG_PREFIX;
|
|
1698
|
-
const result = {};
|
|
1699
|
-
const seenPointers = /* @__PURE__ */ new Set();
|
|
1700
|
-
const parts = content.split(argPrefix);
|
|
1701
|
-
for (let i = 1; i < parts.length; i++) {
|
|
1702
|
-
const part = parts[i];
|
|
1703
|
-
const newlineIndex = part.indexOf("\n");
|
|
1704
|
-
if (newlineIndex === -1) {
|
|
1705
|
-
const pointer2 = part.trim();
|
|
1706
|
-
if (pointer2) {
|
|
1707
|
-
if (seenPointers.has(pointer2)) {
|
|
1708
|
-
throw new Error(`Duplicate pointer: ${pointer2}`);
|
|
1709
|
-
}
|
|
1710
|
-
seenPointers.add(pointer2);
|
|
1711
|
-
setByPointer(result, pointer2, "");
|
|
1712
|
-
}
|
|
1713
|
-
continue;
|
|
1714
|
-
}
|
|
1715
|
-
const pointer = part.substring(0, newlineIndex).trim();
|
|
1716
|
-
let value = part.substring(newlineIndex + 1);
|
|
1717
|
-
if (value.endsWith("\n")) {
|
|
1718
|
-
value = value.slice(0, -1);
|
|
1719
|
-
}
|
|
1720
|
-
if (!pointer) {
|
|
1721
|
-
continue;
|
|
1722
|
-
}
|
|
1723
|
-
if (seenPointers.has(pointer)) {
|
|
1724
|
-
throw new Error(`Duplicate pointer: ${pointer}`);
|
|
1725
|
-
}
|
|
1726
|
-
seenPointers.add(pointer);
|
|
1727
|
-
setByPointer(result, pointer, value);
|
|
1728
|
-
}
|
|
1729
|
-
return result;
|
|
1730
|
-
}
|
|
1731
|
-
function coerceValue(value) {
|
|
1732
|
-
if (value.includes("\n")) {
|
|
1733
|
-
return value;
|
|
1734
|
-
}
|
|
1735
|
-
const trimmed = value.trim();
|
|
1736
|
-
if (trimmed === "true") return true;
|
|
1737
|
-
if (trimmed === "false") return false;
|
|
1738
|
-
if (trimmed !== "" && /^-?\d+(\.\d+)?$/.test(trimmed)) {
|
|
1739
|
-
const num = Number(trimmed);
|
|
1740
|
-
if (!isNaN(num) && isFinite(num)) {
|
|
1741
|
-
return num;
|
|
1742
|
-
}
|
|
1743
|
-
}
|
|
1744
|
-
return value;
|
|
1745
|
-
}
|
|
1746
|
-
function setByPointer(obj, pointer, value) {
|
|
1747
|
-
const segments = pointer.split("/");
|
|
1748
|
-
let current = obj;
|
|
1749
|
-
for (let i = 0; i < segments.length - 1; i++) {
|
|
1750
|
-
const segment = segments[i];
|
|
1751
|
-
const nextSegment = segments[i + 1];
|
|
1752
|
-
const nextIsArrayIndex = /^\d+$/.test(nextSegment);
|
|
1753
|
-
if (Array.isArray(current)) {
|
|
1754
|
-
const index = parseInt(segment, 10);
|
|
1755
|
-
if (isNaN(index) || index < 0) {
|
|
1756
|
-
throw new Error(`Invalid array index: ${segment}`);
|
|
1757
|
-
}
|
|
1758
|
-
if (index > current.length) {
|
|
1759
|
-
throw new Error(`Array index gap: expected ${current.length}, got ${index}`);
|
|
1760
|
-
}
|
|
1761
|
-
if (current[index] === void 0) {
|
|
1762
|
-
current[index] = nextIsArrayIndex ? [] : {};
|
|
1763
|
-
}
|
|
1764
|
-
current = current[index];
|
|
1765
|
-
} else {
|
|
1766
|
-
const rec = current;
|
|
1767
|
-
if (rec[segment] === void 0) {
|
|
1768
|
-
rec[segment] = nextIsArrayIndex ? [] : {};
|
|
1769
|
-
}
|
|
1770
|
-
current = rec[segment];
|
|
1771
|
-
}
|
|
1772
|
-
}
|
|
1773
|
-
const lastSegment = segments[segments.length - 1];
|
|
1774
|
-
const coercedValue = coerceValue(value);
|
|
1775
|
-
if (Array.isArray(current)) {
|
|
1776
|
-
const index = parseInt(lastSegment, 10);
|
|
1777
|
-
if (isNaN(index) || index < 0) {
|
|
1778
|
-
throw new Error(`Invalid array index: ${lastSegment}`);
|
|
1779
|
-
}
|
|
1780
|
-
if (index > current.length) {
|
|
1781
|
-
throw new Error(`Array index gap: expected ${current.length}, got ${index}`);
|
|
1782
|
-
}
|
|
1783
|
-
current[index] = coercedValue;
|
|
1784
|
-
} else {
|
|
1785
|
-
current[lastSegment] = coercedValue;
|
|
1786
|
-
}
|
|
1787
|
-
}
|
|
1788
|
-
var init_block_params = __esm({
|
|
1789
|
-
"src/gadgets/block-params.ts"() {
|
|
1790
|
-
"use strict";
|
|
1791
|
-
init_constants();
|
|
1792
|
-
}
|
|
1793
|
-
});
|
|
1794
|
-
|
|
1795
|
-
// src/gadgets/parser.ts
|
|
1796
|
-
function stripMarkdownFences(content) {
|
|
1797
|
-
let cleaned = content.trim();
|
|
1798
|
-
const openingFence = /^```(?:toml|yaml|json)?\s*\n/i;
|
|
1799
|
-
const closingFence = /\n?```\s*$/;
|
|
1800
|
-
cleaned = cleaned.replace(openingFence, "");
|
|
1801
|
-
cleaned = cleaned.replace(closingFence, "");
|
|
1802
|
-
return cleaned.trim();
|
|
1803
|
-
}
|
|
1804
|
-
var globalInvocationCounter, StreamParser;
|
|
1805
|
-
var init_parser = __esm({
|
|
1806
|
-
"src/gadgets/parser.ts"() {
|
|
1807
|
-
"use strict";
|
|
1808
|
-
init_constants();
|
|
1809
|
-
init_block_params();
|
|
1810
|
-
globalInvocationCounter = 0;
|
|
1811
|
-
StreamParser = class {
|
|
1812
|
-
buffer = "";
|
|
1813
|
-
lastReportedTextLength = 0;
|
|
1814
|
-
startPrefix;
|
|
1815
|
-
endPrefix;
|
|
1816
|
-
argPrefix;
|
|
1817
|
-
constructor(options = {}) {
|
|
1818
|
-
this.startPrefix = options.startPrefix ?? GADGET_START_PREFIX;
|
|
1819
|
-
this.endPrefix = options.endPrefix ?? GADGET_END_PREFIX;
|
|
1820
|
-
this.argPrefix = options.argPrefix ?? GADGET_ARG_PREFIX;
|
|
1821
|
-
}
|
|
1822
|
-
takeTextUntil(index) {
|
|
1823
|
-
if (index <= this.lastReportedTextLength) {
|
|
1824
|
-
return void 0;
|
|
1825
|
-
}
|
|
1826
|
-
const segment = this.buffer.slice(this.lastReportedTextLength, index);
|
|
1827
|
-
this.lastReportedTextLength = index;
|
|
1828
|
-
return segment.trim().length > 0 ? segment : void 0;
|
|
1829
|
-
}
|
|
1830
|
-
/**
|
|
1831
|
-
* Parse gadget name, handling both old format (name:invocationId) and new format (just name).
|
|
1832
|
-
* For new format, generates a unique invocation ID.
|
|
1833
|
-
*/
|
|
1834
|
-
parseGadgetName(gadgetName) {
|
|
1835
|
-
if (gadgetName.includes(":")) {
|
|
1836
|
-
const parts = gadgetName.split(":");
|
|
1837
|
-
return { actualName: parts[0], invocationId: parts[1] };
|
|
1838
|
-
}
|
|
1839
|
-
return { actualName: gadgetName, invocationId: `gadget_${++globalInvocationCounter}` };
|
|
1840
|
-
}
|
|
1841
|
-
/**
|
|
1842
|
-
* Truncate verbose parse errors to avoid context overflow.
|
|
1843
|
-
* Keeps first meaningful line and limits total length.
|
|
1844
|
-
*/
|
|
1845
|
-
truncateParseError(error, format) {
|
|
1846
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1847
|
-
const firstLine = message.split("\n")[0];
|
|
1848
|
-
const maxLen = 200;
|
|
1849
|
-
if (firstLine.length <= maxLen) {
|
|
1850
|
-
return firstLine;
|
|
1851
|
-
}
|
|
1852
|
-
return `${firstLine.slice(0, maxLen)}... (${message.length} chars total)`;
|
|
1853
|
-
}
|
|
1854
|
-
/**
|
|
1855
|
-
* Parse parameter string using block format
|
|
1856
|
-
*/
|
|
1857
|
-
parseParameters(raw) {
|
|
1858
|
-
const cleaned = stripMarkdownFences(raw);
|
|
1859
|
-
try {
|
|
1860
|
-
return { parameters: parseBlockParams(cleaned, { argPrefix: this.argPrefix }) };
|
|
1861
|
-
} catch (error) {
|
|
1862
|
-
return { parseError: this.truncateParseError(error, "block") };
|
|
1863
|
-
}
|
|
1864
|
-
}
|
|
1865
|
-
// Feed a chunk of text and get parsed events
|
|
1866
|
-
*feed(chunk) {
|
|
1867
|
-
this.buffer += chunk;
|
|
1868
|
-
let startIndex = 0;
|
|
1869
|
-
while (true) {
|
|
1870
|
-
const partStartIndex = this.buffer.indexOf(this.startPrefix, startIndex);
|
|
1871
|
-
if (partStartIndex === -1) break;
|
|
1872
|
-
const textBefore = this.takeTextUntil(partStartIndex);
|
|
1873
|
-
if (textBefore !== void 0) {
|
|
1874
|
-
yield { type: "text", content: textBefore };
|
|
1875
|
-
}
|
|
1876
|
-
const metadataStartIndex = partStartIndex + this.startPrefix.length;
|
|
1877
|
-
const metadataEndIndex = this.buffer.indexOf("\n", metadataStartIndex);
|
|
1878
|
-
if (metadataEndIndex === -1) break;
|
|
1879
|
-
const gadgetName = this.buffer.substring(metadataStartIndex, metadataEndIndex).trim();
|
|
1880
|
-
const { actualName: actualGadgetName, invocationId } = this.parseGadgetName(gadgetName);
|
|
1881
|
-
const contentStartIndex = metadataEndIndex + 1;
|
|
1882
|
-
let partEndIndex;
|
|
1883
|
-
let endMarkerLength = 0;
|
|
1884
|
-
if (gadgetName.includes(":")) {
|
|
1885
|
-
const oldEndMarker = `${this.endPrefix + actualGadgetName}:${invocationId}`;
|
|
1886
|
-
partEndIndex = this.buffer.indexOf(oldEndMarker, contentStartIndex);
|
|
1887
|
-
if (partEndIndex === -1) break;
|
|
1888
|
-
endMarkerLength = oldEndMarker.length;
|
|
1889
|
-
} else {
|
|
1890
|
-
const nextStartPos = this.buffer.indexOf(this.startPrefix, contentStartIndex);
|
|
1891
|
-
let validEndPos = -1;
|
|
1892
|
-
let searchPos = contentStartIndex;
|
|
1893
|
-
while (true) {
|
|
1894
|
-
const endPos = this.buffer.indexOf(this.endPrefix, searchPos);
|
|
1895
|
-
if (endPos === -1) break;
|
|
1896
|
-
const afterEnd = this.buffer.substring(endPos + this.endPrefix.length);
|
|
1897
|
-
if (afterEnd.startsWith("\n") || afterEnd.startsWith("\r") || afterEnd.startsWith(this.startPrefix) || afterEnd.length === 0) {
|
|
1898
|
-
validEndPos = endPos;
|
|
1899
|
-
break;
|
|
1900
|
-
} else {
|
|
1901
|
-
searchPos = endPos + this.endPrefix.length;
|
|
2317
|
+
error: inputError instanceof Error ? inputError.message : String(inputError),
|
|
2318
|
+
executionTimeMs: Date.now() - startTime
|
|
2319
|
+
};
|
|
1902
2320
|
}
|
|
1903
2321
|
}
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
2322
|
+
this.logger.warn("Human input required but no callback provided", {
|
|
2323
|
+
gadgetName: call.gadgetName
|
|
2324
|
+
});
|
|
2325
|
+
return {
|
|
2326
|
+
gadgetName: call.gadgetName,
|
|
2327
|
+
invocationId: call.invocationId,
|
|
2328
|
+
parameters: validatedParameters,
|
|
2329
|
+
error: "Human input required but not available (stdin is not interactive)",
|
|
2330
|
+
executionTimeMs: Date.now() - startTime
|
|
2331
|
+
};
|
|
1913
2332
|
}
|
|
1914
|
-
const
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
2333
|
+
const executionTimeMs = Date.now() - startTime;
|
|
2334
|
+
this.logger.error("Gadget execution failed", {
|
|
2335
|
+
gadgetName: call.gadgetName,
|
|
2336
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2337
|
+
executionTimeMs
|
|
2338
|
+
});
|
|
2339
|
+
return {
|
|
2340
|
+
gadgetName: call.gadgetName,
|
|
2341
|
+
invocationId: call.invocationId,
|
|
2342
|
+
parameters: validatedParameters,
|
|
2343
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2344
|
+
executionTimeMs
|
|
1925
2345
|
};
|
|
1926
|
-
startIndex = partEndIndex + endMarkerLength;
|
|
1927
|
-
this.lastReportedTextLength = startIndex;
|
|
1928
|
-
}
|
|
1929
|
-
if (startIndex > 0) {
|
|
1930
|
-
this.buffer = this.buffer.substring(startIndex);
|
|
1931
|
-
this.lastReportedTextLength = 0;
|
|
1932
2346
|
}
|
|
1933
2347
|
}
|
|
1934
|
-
//
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
if (startIndex !== -1) {
|
|
1938
|
-
const textBefore = this.takeTextUntil(startIndex);
|
|
1939
|
-
if (textBefore !== void 0) {
|
|
1940
|
-
yield { type: "text", content: textBefore };
|
|
1941
|
-
}
|
|
1942
|
-
const metadataStartIndex = startIndex + this.startPrefix.length;
|
|
1943
|
-
const metadataEndIndex = this.buffer.indexOf("\n", metadataStartIndex);
|
|
1944
|
-
if (metadataEndIndex !== -1) {
|
|
1945
|
-
const gadgetName = this.buffer.substring(metadataStartIndex, metadataEndIndex).trim();
|
|
1946
|
-
const { actualName: actualGadgetName, invocationId } = this.parseGadgetName(gadgetName);
|
|
1947
|
-
const contentStartIndex = metadataEndIndex + 1;
|
|
1948
|
-
const parametersRaw = this.buffer.substring(contentStartIndex).trim();
|
|
1949
|
-
const { parameters, parseError } = this.parseParameters(parametersRaw);
|
|
1950
|
-
yield {
|
|
1951
|
-
type: "gadget_call",
|
|
1952
|
-
call: {
|
|
1953
|
-
gadgetName: actualGadgetName,
|
|
1954
|
-
invocationId,
|
|
1955
|
-
parametersRaw,
|
|
1956
|
-
parameters,
|
|
1957
|
-
parseError
|
|
1958
|
-
}
|
|
1959
|
-
};
|
|
1960
|
-
return;
|
|
1961
|
-
}
|
|
1962
|
-
}
|
|
1963
|
-
const remainingText = this.takeTextUntil(this.buffer.length);
|
|
1964
|
-
if (remainingText !== void 0) {
|
|
1965
|
-
yield { type: "text", content: remainingText };
|
|
1966
|
-
}
|
|
2348
|
+
// Execute multiple gadget calls in parallel
|
|
2349
|
+
async executeAll(calls) {
|
|
2350
|
+
return Promise.all(calls.map((call) => this.execute(call)));
|
|
1967
2351
|
}
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
2352
|
+
/**
|
|
2353
|
+
* Deep equality check for objects/arrays.
|
|
2354
|
+
* Used to detect if parameters were modified by an interceptor.
|
|
2355
|
+
*/
|
|
2356
|
+
deepEquals(a, b) {
|
|
2357
|
+
if (a === b) return true;
|
|
2358
|
+
if (a === null || b === null) return a === b;
|
|
2359
|
+
if (typeof a !== typeof b) return false;
|
|
2360
|
+
if (typeof a !== "object") return a === b;
|
|
2361
|
+
if (Array.isArray(a) !== Array.isArray(b)) return false;
|
|
2362
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
2363
|
+
if (a.length !== b.length) return false;
|
|
2364
|
+
return a.every((val, i) => this.deepEquals(val, b[i]));
|
|
2365
|
+
}
|
|
2366
|
+
const aObj = a;
|
|
2367
|
+
const bObj = b;
|
|
2368
|
+
const aKeys = Object.keys(aObj);
|
|
2369
|
+
const bKeys = Object.keys(bObj);
|
|
2370
|
+
if (aKeys.length !== bKeys.length) return false;
|
|
2371
|
+
return aKeys.every((key) => this.deepEquals(aObj[key], bObj[key]));
|
|
1972
2372
|
}
|
|
1973
2373
|
};
|
|
1974
2374
|
}
|
|
@@ -2011,7 +2411,8 @@ var init_stream_processor = __esm({
|
|
|
2011
2411
|
options.registry,
|
|
2012
2412
|
options.onHumanInputRequired,
|
|
2013
2413
|
this.logger.getSubLogger({ name: "executor" }),
|
|
2014
|
-
options.defaultGadgetTimeoutMs
|
|
2414
|
+
options.defaultGadgetTimeoutMs,
|
|
2415
|
+
{ argPrefix: options.gadgetArgPrefix }
|
|
2015
2416
|
);
|
|
2016
2417
|
}
|
|
2017
2418
|
/**
|
|
@@ -5460,7 +5861,8 @@ var CLI_DESCRIPTION = "Command line utilities for llmist agents and direct LLM a
|
|
|
5460
5861
|
var COMMANDS = {
|
|
5461
5862
|
complete: "complete",
|
|
5462
5863
|
agent: "agent",
|
|
5463
|
-
models: "models"
|
|
5864
|
+
models: "models",
|
|
5865
|
+
gadget: "gadget"
|
|
5464
5866
|
};
|
|
5465
5867
|
var LOG_LEVELS = ["silly", "trace", "debug", "info", "warn", "error", "fatal"];
|
|
5466
5868
|
var DEFAULT_MODEL = "openai:gpt-5-nano";
|
|
@@ -5504,7 +5906,7 @@ var import_commander2 = require("commander");
|
|
|
5504
5906
|
// package.json
|
|
5505
5907
|
var package_default = {
|
|
5506
5908
|
name: "llmist",
|
|
5507
|
-
version: "
|
|
5909
|
+
version: "1.1.0",
|
|
5508
5910
|
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.",
|
|
5509
5911
|
type: "module",
|
|
5510
5912
|
main: "dist/index.cjs",
|
|
@@ -7491,8 +7893,439 @@ function resolveInheritance(config, configPath) {
|
|
|
7491
7893
|
return resolved;
|
|
7492
7894
|
}
|
|
7493
7895
|
|
|
7494
|
-
// src/cli/
|
|
7896
|
+
// src/cli/gadget-command.ts
|
|
7897
|
+
var import_chalk5 = __toESM(require("chalk"), 1);
|
|
7898
|
+
init_schema_to_json();
|
|
7899
|
+
init_schema_validator();
|
|
7900
|
+
|
|
7901
|
+
// src/cli/gadget-prompts.ts
|
|
7902
|
+
var import_promises3 = require("readline/promises");
|
|
7495
7903
|
var import_chalk4 = __toESM(require("chalk"), 1);
|
|
7904
|
+
init_schema_to_json();
|
|
7905
|
+
async function promptForParameters(schema, ctx) {
|
|
7906
|
+
if (!schema) {
|
|
7907
|
+
return {};
|
|
7908
|
+
}
|
|
7909
|
+
const jsonSchema = schemaToJSONSchema(schema, { target: "draft-7" });
|
|
7910
|
+
if (!jsonSchema.properties || Object.keys(jsonSchema.properties).length === 0) {
|
|
7911
|
+
return {};
|
|
7912
|
+
}
|
|
7913
|
+
const rl = (0, import_promises3.createInterface)({ input: ctx.stdin, output: ctx.stdout });
|
|
7914
|
+
const params = {};
|
|
7915
|
+
try {
|
|
7916
|
+
for (const [key, prop] of Object.entries(jsonSchema.properties)) {
|
|
7917
|
+
const value = await promptForField(rl, key, prop, jsonSchema.required ?? []);
|
|
7918
|
+
if (value !== void 0) {
|
|
7919
|
+
params[key] = value;
|
|
7920
|
+
}
|
|
7921
|
+
}
|
|
7922
|
+
} finally {
|
|
7923
|
+
rl.close();
|
|
7924
|
+
}
|
|
7925
|
+
const result = schema.safeParse(params);
|
|
7926
|
+
if (!result.success) {
|
|
7927
|
+
const issues = result.error.issues.map((i) => ` ${i.path.join(".")}: ${i.message}`).join("\n");
|
|
7928
|
+
throw new Error(`Invalid parameters:
|
|
7929
|
+
${issues}`);
|
|
7930
|
+
}
|
|
7931
|
+
return result.data;
|
|
7932
|
+
}
|
|
7933
|
+
async function promptForField(rl, key, prop, required) {
|
|
7934
|
+
const isRequired = required.includes(key);
|
|
7935
|
+
const typeHint = formatTypeHint(prop);
|
|
7936
|
+
const defaultHint = prop.default !== void 0 ? import_chalk4.default.dim(` [default: ${JSON.stringify(prop.default)}]`) : "";
|
|
7937
|
+
const requiredMarker = isRequired ? import_chalk4.default.red("*") : "";
|
|
7938
|
+
let prompt = `
|
|
7939
|
+
${import_chalk4.default.cyan.bold(key)}${requiredMarker}`;
|
|
7940
|
+
if (prop.description) {
|
|
7941
|
+
prompt += import_chalk4.default.dim(` - ${prop.description}`);
|
|
7942
|
+
}
|
|
7943
|
+
prompt += `
|
|
7944
|
+
${typeHint}${defaultHint}
|
|
7945
|
+
${import_chalk4.default.green(">")} `;
|
|
7946
|
+
const answer = await rl.question(prompt);
|
|
7947
|
+
const trimmed = answer.trim();
|
|
7948
|
+
if (!trimmed) {
|
|
7949
|
+
if (prop.default !== void 0) {
|
|
7950
|
+
return void 0;
|
|
7951
|
+
}
|
|
7952
|
+
if (!isRequired) {
|
|
7953
|
+
return void 0;
|
|
7954
|
+
}
|
|
7955
|
+
throw new Error(`Parameter '${key}' is required.`);
|
|
7956
|
+
}
|
|
7957
|
+
return parseValue(trimmed, prop, key);
|
|
7958
|
+
}
|
|
7959
|
+
function formatTypeHint(prop) {
|
|
7960
|
+
if (prop.enum) {
|
|
7961
|
+
return import_chalk4.default.yellow(`(${prop.enum.join(" | ")})`);
|
|
7962
|
+
}
|
|
7963
|
+
if (prop.type === "array") {
|
|
7964
|
+
const items = prop.items;
|
|
7965
|
+
if (items?.enum) {
|
|
7966
|
+
return import_chalk4.default.yellow(`(${items.enum.join(" | ")})[] comma-separated`);
|
|
7967
|
+
}
|
|
7968
|
+
const itemType = items?.type ?? "any";
|
|
7969
|
+
return import_chalk4.default.yellow(`(${itemType}[]) comma-separated`);
|
|
7970
|
+
}
|
|
7971
|
+
if (prop.type === "object" && prop.properties) {
|
|
7972
|
+
return import_chalk4.default.yellow("(object) enter as JSON");
|
|
7973
|
+
}
|
|
7974
|
+
return import_chalk4.default.yellow(`(${prop.type ?? "any"})`);
|
|
7975
|
+
}
|
|
7976
|
+
function parseValue(input, prop, key) {
|
|
7977
|
+
const type = prop.type;
|
|
7978
|
+
if (type === "number" || type === "integer") {
|
|
7979
|
+
const num = Number(input);
|
|
7980
|
+
if (Number.isNaN(num)) {
|
|
7981
|
+
throw new Error(`Invalid number for '${key}': ${input}`);
|
|
7982
|
+
}
|
|
7983
|
+
if (type === "integer" && !Number.isInteger(num)) {
|
|
7984
|
+
throw new Error(`Expected integer for '${key}', got: ${input}`);
|
|
7985
|
+
}
|
|
7986
|
+
return num;
|
|
7987
|
+
}
|
|
7988
|
+
if (type === "boolean") {
|
|
7989
|
+
const lower = input.toLowerCase();
|
|
7990
|
+
if (["true", "yes", "1", "y"].includes(lower)) return true;
|
|
7991
|
+
if (["false", "no", "0", "n"].includes(lower)) return false;
|
|
7992
|
+
throw new Error(`Invalid boolean for '${key}': ${input} (use true/false, yes/no, 1/0)`);
|
|
7993
|
+
}
|
|
7994
|
+
if (type === "array") {
|
|
7995
|
+
const items = input.split(",").map((s) => s.trim()).filter(Boolean);
|
|
7996
|
+
const itemType = prop.items?.type;
|
|
7997
|
+
if (itemType === "number" || itemType === "integer") {
|
|
7998
|
+
return items.map((item) => {
|
|
7999
|
+
const num = Number(item);
|
|
8000
|
+
if (Number.isNaN(num)) throw new Error(`Invalid number in '${key}' array: ${item}`);
|
|
8001
|
+
return num;
|
|
8002
|
+
});
|
|
8003
|
+
}
|
|
8004
|
+
if (itemType === "boolean") {
|
|
8005
|
+
return items.map((item) => {
|
|
8006
|
+
const lower = item.toLowerCase();
|
|
8007
|
+
if (["true", "yes", "1", "y"].includes(lower)) return true;
|
|
8008
|
+
if (["false", "no", "0", "n"].includes(lower)) return false;
|
|
8009
|
+
throw new Error(`Invalid boolean in '${key}' array: ${item}`);
|
|
8010
|
+
});
|
|
8011
|
+
}
|
|
8012
|
+
return items;
|
|
8013
|
+
}
|
|
8014
|
+
if (type === "object") {
|
|
8015
|
+
try {
|
|
8016
|
+
return JSON.parse(input);
|
|
8017
|
+
} catch {
|
|
8018
|
+
throw new Error(`Invalid JSON for '${key}': ${input}`);
|
|
8019
|
+
}
|
|
8020
|
+
}
|
|
8021
|
+
return input;
|
|
8022
|
+
}
|
|
8023
|
+
async function readStdinJson(stdin) {
|
|
8024
|
+
const chunks = [];
|
|
8025
|
+
for await (const chunk of stdin) {
|
|
8026
|
+
if (typeof chunk === "string") {
|
|
8027
|
+
chunks.push(chunk);
|
|
8028
|
+
} else {
|
|
8029
|
+
chunks.push(chunk.toString("utf8"));
|
|
8030
|
+
}
|
|
8031
|
+
}
|
|
8032
|
+
const content = chunks.join("").trim();
|
|
8033
|
+
if (!content) {
|
|
8034
|
+
return {};
|
|
8035
|
+
}
|
|
8036
|
+
try {
|
|
8037
|
+
const parsed = JSON.parse(content);
|
|
8038
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
8039
|
+
throw new Error("Stdin must contain a JSON object, not an array or primitive.");
|
|
8040
|
+
}
|
|
8041
|
+
return parsed;
|
|
8042
|
+
} catch (error) {
|
|
8043
|
+
if (error instanceof SyntaxError) {
|
|
8044
|
+
throw new Error(`Invalid JSON from stdin: ${error.message}`);
|
|
8045
|
+
}
|
|
8046
|
+
throw error;
|
|
8047
|
+
}
|
|
8048
|
+
}
|
|
8049
|
+
|
|
8050
|
+
// src/cli/gadget-command.ts
|
|
8051
|
+
async function selectGadget(file, nameOption, cwd) {
|
|
8052
|
+
const gadgets = await loadGadgets([file], cwd);
|
|
8053
|
+
if (gadgets.length === 0) {
|
|
8054
|
+
throw new Error(
|
|
8055
|
+
`No gadgets found in '${file}'.
|
|
8056
|
+
Ensure the file exports a Gadget class or instance.`
|
|
8057
|
+
);
|
|
8058
|
+
}
|
|
8059
|
+
if (gadgets.length === 1) {
|
|
8060
|
+
const gadget = gadgets[0];
|
|
8061
|
+
const name = gadget.name ?? gadget.constructor.name;
|
|
8062
|
+
return { gadget, name };
|
|
8063
|
+
}
|
|
8064
|
+
const names = gadgets.map((g) => g.name ?? g.constructor.name);
|
|
8065
|
+
if (!nameOption) {
|
|
8066
|
+
throw new Error(
|
|
8067
|
+
`File '${file}' exports ${gadgets.length} gadgets.
|
|
8068
|
+
Use --name to select one:
|
|
8069
|
+
` + names.map((n) => ` - ${n}`).join("\n")
|
|
8070
|
+
);
|
|
8071
|
+
}
|
|
8072
|
+
const found = gadgets.find((g) => (g.name ?? g.constructor.name) === nameOption);
|
|
8073
|
+
if (!found) {
|
|
8074
|
+
throw new Error(
|
|
8075
|
+
`Gadget '${nameOption}' not found in '${file}'.
|
|
8076
|
+
Available gadgets:
|
|
8077
|
+
` + names.map((n) => ` - ${n}`).join("\n")
|
|
8078
|
+
);
|
|
8079
|
+
}
|
|
8080
|
+
return { gadget: found, name: nameOption };
|
|
8081
|
+
}
|
|
8082
|
+
async function executeGadgetRun(file, options, env) {
|
|
8083
|
+
const cwd = process.cwd();
|
|
8084
|
+
const { gadget, name } = await selectGadget(file, options.name, cwd);
|
|
8085
|
+
env.stderr.write(import_chalk5.default.cyan.bold(`
|
|
8086
|
+
\u{1F527} Running gadget: ${name}
|
|
8087
|
+
`));
|
|
8088
|
+
let params;
|
|
8089
|
+
if (env.isTTY) {
|
|
8090
|
+
params = await promptForParameters(gadget.parameterSchema, {
|
|
8091
|
+
stdin: env.stdin,
|
|
8092
|
+
stdout: env.stderr
|
|
8093
|
+
// Prompts go to stderr to keep stdout clean
|
|
8094
|
+
});
|
|
8095
|
+
} else {
|
|
8096
|
+
env.stderr.write(import_chalk5.default.dim("Reading parameters from stdin...\n"));
|
|
8097
|
+
const stdinParams = await readStdinJson(env.stdin);
|
|
8098
|
+
if (gadget.parameterSchema) {
|
|
8099
|
+
const result2 = gadget.parameterSchema.safeParse(stdinParams);
|
|
8100
|
+
if (!result2.success) {
|
|
8101
|
+
const issues = result2.error.issues.map((i) => ` ${i.path.join(".")}: ${i.message}`).join("\n");
|
|
8102
|
+
throw new Error(`Invalid parameters:
|
|
8103
|
+
${issues}`);
|
|
8104
|
+
}
|
|
8105
|
+
params = result2.data;
|
|
8106
|
+
} else {
|
|
8107
|
+
params = stdinParams;
|
|
8108
|
+
}
|
|
8109
|
+
}
|
|
8110
|
+
env.stderr.write(import_chalk5.default.dim("\nExecuting...\n"));
|
|
8111
|
+
const startTime = Date.now();
|
|
8112
|
+
let result;
|
|
8113
|
+
try {
|
|
8114
|
+
if (gadget.timeoutMs && gadget.timeoutMs > 0) {
|
|
8115
|
+
result = await Promise.race([
|
|
8116
|
+
Promise.resolve(gadget.execute(params)),
|
|
8117
|
+
new Promise(
|
|
8118
|
+
(_, reject) => setTimeout(
|
|
8119
|
+
() => reject(new Error(`Gadget timed out after ${gadget.timeoutMs}ms`)),
|
|
8120
|
+
gadget.timeoutMs
|
|
8121
|
+
)
|
|
8122
|
+
)
|
|
8123
|
+
]);
|
|
8124
|
+
} else {
|
|
8125
|
+
result = await Promise.resolve(gadget.execute(params));
|
|
8126
|
+
}
|
|
8127
|
+
} catch (error) {
|
|
8128
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
8129
|
+
throw new Error(`Execution failed: ${message}`);
|
|
8130
|
+
}
|
|
8131
|
+
const elapsed = Date.now() - startTime;
|
|
8132
|
+
env.stderr.write(import_chalk5.default.green(`
|
|
8133
|
+
\u2713 Completed in ${elapsed}ms
|
|
8134
|
+
|
|
8135
|
+
`));
|
|
8136
|
+
formatOutput(result, options, env.stdout);
|
|
8137
|
+
}
|
|
8138
|
+
function formatOutput(result, options, stdout) {
|
|
8139
|
+
if (options.raw) {
|
|
8140
|
+
stdout.write(result);
|
|
8141
|
+
if (!result.endsWith("\n")) stdout.write("\n");
|
|
8142
|
+
return;
|
|
8143
|
+
}
|
|
8144
|
+
if (options.json || looksLikeJson(result)) {
|
|
8145
|
+
try {
|
|
8146
|
+
const parsed = JSON.parse(result);
|
|
8147
|
+
stdout.write(JSON.stringify(parsed, null, 2) + "\n");
|
|
8148
|
+
return;
|
|
8149
|
+
} catch {
|
|
8150
|
+
}
|
|
8151
|
+
}
|
|
8152
|
+
stdout.write(result);
|
|
8153
|
+
if (!result.endsWith("\n")) stdout.write("\n");
|
|
8154
|
+
}
|
|
8155
|
+
function looksLikeJson(str) {
|
|
8156
|
+
const trimmed = str.trim();
|
|
8157
|
+
return trimmed.startsWith("{") && trimmed.endsWith("}") || trimmed.startsWith("[") && trimmed.endsWith("]");
|
|
8158
|
+
}
|
|
8159
|
+
async function executeGadgetInfo(file, options, env) {
|
|
8160
|
+
const cwd = process.cwd();
|
|
8161
|
+
const { gadget, name } = await selectGadget(file, options.name, cwd);
|
|
8162
|
+
if (options.json) {
|
|
8163
|
+
const info = buildGadgetInfo(gadget, name);
|
|
8164
|
+
env.stdout.write(JSON.stringify(info, null, 2) + "\n");
|
|
8165
|
+
return;
|
|
8166
|
+
}
|
|
8167
|
+
env.stdout.write("\n");
|
|
8168
|
+
env.stdout.write(import_chalk5.default.cyan.bold(`${name}
|
|
8169
|
+
`));
|
|
8170
|
+
env.stdout.write(import_chalk5.default.cyan("\u2550".repeat(name.length)) + "\n\n");
|
|
8171
|
+
env.stdout.write(import_chalk5.default.bold("Description:\n"));
|
|
8172
|
+
env.stdout.write(` ${gadget.description}
|
|
8173
|
+
|
|
8174
|
+
`);
|
|
8175
|
+
if (gadget.parameterSchema) {
|
|
8176
|
+
env.stdout.write(import_chalk5.default.bold("Parameters:\n"));
|
|
8177
|
+
const jsonSchema = schemaToJSONSchema(gadget.parameterSchema, { target: "draft-7" });
|
|
8178
|
+
env.stdout.write(formatSchemaAsText(jsonSchema, " ") + "\n\n");
|
|
8179
|
+
} else {
|
|
8180
|
+
env.stdout.write(import_chalk5.default.dim("No parameters required.\n\n"));
|
|
8181
|
+
}
|
|
8182
|
+
if (gadget.timeoutMs) {
|
|
8183
|
+
env.stdout.write(import_chalk5.default.bold("Timeout:\n"));
|
|
8184
|
+
env.stdout.write(` ${gadget.timeoutMs}ms
|
|
8185
|
+
|
|
8186
|
+
`);
|
|
8187
|
+
}
|
|
8188
|
+
if (gadget.examples && gadget.examples.length > 0) {
|
|
8189
|
+
env.stdout.write(import_chalk5.default.bold("Examples:\n"));
|
|
8190
|
+
for (const example of gadget.examples) {
|
|
8191
|
+
if (example.comment) {
|
|
8192
|
+
env.stdout.write(import_chalk5.default.dim(` # ${example.comment}
|
|
8193
|
+
`));
|
|
8194
|
+
}
|
|
8195
|
+
env.stdout.write(` Input: ${import_chalk5.default.cyan(JSON.stringify(example.params))}
|
|
8196
|
+
`);
|
|
8197
|
+
if (example.output !== void 0) {
|
|
8198
|
+
env.stdout.write(` Output: ${import_chalk5.default.green(example.output)}
|
|
8199
|
+
`);
|
|
8200
|
+
}
|
|
8201
|
+
env.stdout.write("\n");
|
|
8202
|
+
}
|
|
8203
|
+
}
|
|
8204
|
+
}
|
|
8205
|
+
function buildGadgetInfo(gadget, name) {
|
|
8206
|
+
const info = {
|
|
8207
|
+
name,
|
|
8208
|
+
description: gadget.description
|
|
8209
|
+
};
|
|
8210
|
+
if (gadget.parameterSchema) {
|
|
8211
|
+
info.schema = schemaToJSONSchema(gadget.parameterSchema, { target: "draft-7" });
|
|
8212
|
+
}
|
|
8213
|
+
if (gadget.timeoutMs) {
|
|
8214
|
+
info.timeoutMs = gadget.timeoutMs;
|
|
8215
|
+
}
|
|
8216
|
+
if (gadget.examples && gadget.examples.length > 0) {
|
|
8217
|
+
info.examples = gadget.examples;
|
|
8218
|
+
}
|
|
8219
|
+
return info;
|
|
8220
|
+
}
|
|
8221
|
+
function formatSchemaAsText(schema, indent = "") {
|
|
8222
|
+
const lines = [];
|
|
8223
|
+
const properties = schema.properties || {};
|
|
8224
|
+
const required = schema.required || [];
|
|
8225
|
+
for (const [key, prop] of Object.entries(properties)) {
|
|
8226
|
+
const type = prop.type;
|
|
8227
|
+
const description = prop.description;
|
|
8228
|
+
const isRequired = required.includes(key);
|
|
8229
|
+
const enumValues = prop.enum;
|
|
8230
|
+
const defaultValue = prop.default;
|
|
8231
|
+
let line = `${indent}${import_chalk5.default.cyan(key)}`;
|
|
8232
|
+
if (isRequired) {
|
|
8233
|
+
line += import_chalk5.default.red("*");
|
|
8234
|
+
}
|
|
8235
|
+
if (type === "array") {
|
|
8236
|
+
const items = prop.items;
|
|
8237
|
+
const itemType = items?.type || "any";
|
|
8238
|
+
line += import_chalk5.default.dim(` (${itemType}[])`);
|
|
8239
|
+
} else if (type === "object" && prop.properties) {
|
|
8240
|
+
line += import_chalk5.default.dim(" (object)");
|
|
8241
|
+
} else {
|
|
8242
|
+
line += import_chalk5.default.dim(` (${type})`);
|
|
8243
|
+
}
|
|
8244
|
+
if (defaultValue !== void 0) {
|
|
8245
|
+
line += import_chalk5.default.dim(` [default: ${JSON.stringify(defaultValue)}]`);
|
|
8246
|
+
}
|
|
8247
|
+
if (description) {
|
|
8248
|
+
line += `: ${description}`;
|
|
8249
|
+
}
|
|
8250
|
+
if (enumValues) {
|
|
8251
|
+
line += import_chalk5.default.yellow(` - one of: ${enumValues.join(", ")}`);
|
|
8252
|
+
}
|
|
8253
|
+
lines.push(line);
|
|
8254
|
+
if (type === "object" && prop.properties) {
|
|
8255
|
+
lines.push(formatSchemaAsText(prop, indent + " "));
|
|
8256
|
+
}
|
|
8257
|
+
}
|
|
8258
|
+
return lines.join("\n");
|
|
8259
|
+
}
|
|
8260
|
+
async function executeGadgetValidate(file, env) {
|
|
8261
|
+
const cwd = process.cwd();
|
|
8262
|
+
try {
|
|
8263
|
+
const gadgets = await loadGadgets([file], cwd);
|
|
8264
|
+
if (gadgets.length === 0) {
|
|
8265
|
+
throw new Error(
|
|
8266
|
+
"No gadgets exported from file.\nA valid gadget must have:\n - execute() method\n - description property\n - parameterSchema (optional)"
|
|
8267
|
+
);
|
|
8268
|
+
}
|
|
8269
|
+
const issues = [];
|
|
8270
|
+
for (const gadget of gadgets) {
|
|
8271
|
+
const name = gadget.name ?? gadget.constructor.name;
|
|
8272
|
+
if (!gadget.description) {
|
|
8273
|
+
issues.push(`${name}: Missing 'description' property.`);
|
|
8274
|
+
}
|
|
8275
|
+
if (gadget.parameterSchema) {
|
|
8276
|
+
try {
|
|
8277
|
+
validateGadgetSchema(gadget.parameterSchema, name);
|
|
8278
|
+
} catch (schemaError) {
|
|
8279
|
+
const message = schemaError instanceof Error ? schemaError.message : String(schemaError);
|
|
8280
|
+
issues.push(`${name}: ${message}`);
|
|
8281
|
+
}
|
|
8282
|
+
}
|
|
8283
|
+
if (typeof gadget.execute !== "function") {
|
|
8284
|
+
issues.push(`${name}: Missing 'execute()' method.`);
|
|
8285
|
+
}
|
|
8286
|
+
}
|
|
8287
|
+
if (issues.length > 0) {
|
|
8288
|
+
throw new Error(`Validation issues:
|
|
8289
|
+
${issues.map((i) => ` - ${i}`).join("\n")}`);
|
|
8290
|
+
}
|
|
8291
|
+
env.stdout.write(import_chalk5.default.green.bold("\n\u2713 Valid\n\n"));
|
|
8292
|
+
env.stdout.write(import_chalk5.default.bold("Gadgets found:\n"));
|
|
8293
|
+
for (const gadget of gadgets) {
|
|
8294
|
+
const name = gadget.name ?? gadget.constructor.name;
|
|
8295
|
+
const schemaInfo = gadget.parameterSchema ? import_chalk5.default.cyan("(with schema)") : import_chalk5.default.dim("(no schema)");
|
|
8296
|
+
env.stdout.write(` ${import_chalk5.default.bold(name)} ${schemaInfo}
|
|
8297
|
+
`);
|
|
8298
|
+
env.stdout.write(import_chalk5.default.dim(` ${gadget.description}
|
|
8299
|
+
`));
|
|
8300
|
+
}
|
|
8301
|
+
env.stdout.write("\n");
|
|
8302
|
+
} catch (error) {
|
|
8303
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
8304
|
+
env.stdout.write(import_chalk5.default.red.bold(`
|
|
8305
|
+
\u2717 Invalid
|
|
8306
|
+
|
|
8307
|
+
`));
|
|
8308
|
+
env.stdout.write(`${message}
|
|
8309
|
+
|
|
8310
|
+
`);
|
|
8311
|
+
env.setExitCode(1);
|
|
8312
|
+
}
|
|
8313
|
+
}
|
|
8314
|
+
function registerGadgetCommand(program, env) {
|
|
8315
|
+
const gadgetCmd = program.command("gadget").description("Test and inspect gadgets outside the agent loop.");
|
|
8316
|
+
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(
|
|
8317
|
+
(file, options) => executeAction(() => executeGadgetRun(file, options, env), env)
|
|
8318
|
+
);
|
|
8319
|
+
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(
|
|
8320
|
+
(file, options) => executeAction(() => executeGadgetInfo(file, options, env), env)
|
|
8321
|
+
);
|
|
8322
|
+
gadgetCmd.command("validate <file>").description("Check if file exports valid gadget(s).").action(
|
|
8323
|
+
(file) => executeAction(() => executeGadgetValidate(file, env), env)
|
|
8324
|
+
);
|
|
8325
|
+
}
|
|
8326
|
+
|
|
8327
|
+
// src/cli/models-command.ts
|
|
8328
|
+
var import_chalk6 = __toESM(require("chalk"), 1);
|
|
7496
8329
|
init_model_shortcuts();
|
|
7497
8330
|
async function handleModelsCommand(options, env) {
|
|
7498
8331
|
const client = env.createClient();
|
|
@@ -7512,13 +8345,13 @@ function renderTable(models, verbose, stream2) {
|
|
|
7512
8345
|
}
|
|
7513
8346
|
grouped.get(provider).push(model);
|
|
7514
8347
|
}
|
|
7515
|
-
stream2.write(
|
|
7516
|
-
stream2.write(
|
|
8348
|
+
stream2.write(import_chalk6.default.bold.cyan("\nAvailable Models\n"));
|
|
8349
|
+
stream2.write(import_chalk6.default.cyan("=".repeat(80)) + "\n\n");
|
|
7517
8350
|
const providers = Array.from(grouped.keys()).sort();
|
|
7518
8351
|
for (const provider of providers) {
|
|
7519
8352
|
const providerModels = grouped.get(provider);
|
|
7520
8353
|
const providerName = provider.charAt(0).toUpperCase() + provider.slice(1);
|
|
7521
|
-
stream2.write(
|
|
8354
|
+
stream2.write(import_chalk6.default.bold.yellow(`${providerName} Models
|
|
7522
8355
|
`));
|
|
7523
8356
|
if (verbose) {
|
|
7524
8357
|
renderVerboseTable(providerModels, stream2);
|
|
@@ -7527,11 +8360,11 @@ function renderTable(models, verbose, stream2) {
|
|
|
7527
8360
|
}
|
|
7528
8361
|
stream2.write("\n");
|
|
7529
8362
|
}
|
|
7530
|
-
stream2.write(
|
|
7531
|
-
stream2.write(
|
|
8363
|
+
stream2.write(import_chalk6.default.bold.magenta("Model Shortcuts\n"));
|
|
8364
|
+
stream2.write(import_chalk6.default.dim("\u2500".repeat(80)) + "\n");
|
|
7532
8365
|
const shortcuts = Object.entries(MODEL_ALIASES).sort((a, b) => a[0].localeCompare(b[0]));
|
|
7533
8366
|
for (const [shortcut, fullName] of shortcuts) {
|
|
7534
|
-
stream2.write(
|
|
8367
|
+
stream2.write(import_chalk6.default.cyan(` ${shortcut.padEnd(15)}`) + import_chalk6.default.dim(" \u2192 ") + import_chalk6.default.white(fullName) + "\n");
|
|
7535
8368
|
}
|
|
7536
8369
|
stream2.write("\n");
|
|
7537
8370
|
}
|
|
@@ -7541,45 +8374,45 @@ function renderCompactTable(models, stream2) {
|
|
|
7541
8374
|
const contextWidth = 13;
|
|
7542
8375
|
const inputWidth = 10;
|
|
7543
8376
|
const outputWidth = 10;
|
|
7544
|
-
stream2.write(
|
|
8377
|
+
stream2.write(import_chalk6.default.dim("\u2500".repeat(idWidth + nameWidth + contextWidth + inputWidth + outputWidth + 8)) + "\n");
|
|
7545
8378
|
stream2.write(
|
|
7546
|
-
|
|
8379
|
+
import_chalk6.default.bold(
|
|
7547
8380
|
"Model ID".padEnd(idWidth) + " " + "Display Name".padEnd(nameWidth) + " " + "Context".padEnd(contextWidth) + " " + "Input".padEnd(inputWidth) + " " + "Output".padEnd(outputWidth)
|
|
7548
8381
|
) + "\n"
|
|
7549
8382
|
);
|
|
7550
|
-
stream2.write(
|
|
8383
|
+
stream2.write(import_chalk6.default.dim("\u2500".repeat(idWidth + nameWidth + contextWidth + inputWidth + outputWidth + 8)) + "\n");
|
|
7551
8384
|
for (const model of models) {
|
|
7552
8385
|
const contextFormatted = formatTokens2(model.contextWindow);
|
|
7553
8386
|
const inputPrice = `$${model.pricing.input.toFixed(2)}`;
|
|
7554
8387
|
const outputPrice = `$${model.pricing.output.toFixed(2)}`;
|
|
7555
8388
|
stream2.write(
|
|
7556
|
-
|
|
8389
|
+
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"
|
|
7557
8390
|
);
|
|
7558
8391
|
}
|
|
7559
|
-
stream2.write(
|
|
7560
|
-
stream2.write(
|
|
8392
|
+
stream2.write(import_chalk6.default.dim("\u2500".repeat(idWidth + nameWidth + contextWidth + inputWidth + outputWidth + 8)) + "\n");
|
|
8393
|
+
stream2.write(import_chalk6.default.dim(` * Prices are per 1M tokens
|
|
7561
8394
|
`));
|
|
7562
8395
|
}
|
|
7563
8396
|
function renderVerboseTable(models, stream2) {
|
|
7564
8397
|
for (const model of models) {
|
|
7565
|
-
stream2.write(
|
|
8398
|
+
stream2.write(import_chalk6.default.bold.green(`
|
|
7566
8399
|
${model.modelId}
|
|
7567
8400
|
`));
|
|
7568
|
-
stream2.write(
|
|
7569
|
-
stream2.write(` ${
|
|
8401
|
+
stream2.write(import_chalk6.default.dim(" " + "\u2500".repeat(60)) + "\n");
|
|
8402
|
+
stream2.write(` ${import_chalk6.default.dim("Name:")} ${import_chalk6.default.white(model.displayName)}
|
|
7570
8403
|
`);
|
|
7571
|
-
stream2.write(` ${
|
|
8404
|
+
stream2.write(` ${import_chalk6.default.dim("Context:")} ${import_chalk6.default.yellow(formatTokens2(model.contextWindow))}
|
|
7572
8405
|
`);
|
|
7573
|
-
stream2.write(` ${
|
|
8406
|
+
stream2.write(` ${import_chalk6.default.dim("Max Output:")} ${import_chalk6.default.yellow(formatTokens2(model.maxOutputTokens))}
|
|
7574
8407
|
`);
|
|
7575
|
-
stream2.write(` ${
|
|
8408
|
+
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)")}
|
|
7576
8409
|
`);
|
|
7577
8410
|
if (model.pricing.cachedInput !== void 0) {
|
|
7578
|
-
stream2.write(` ${
|
|
8411
|
+
stream2.write(` ${import_chalk6.default.dim("Cached Input:")} ${import_chalk6.default.cyan(`$${model.pricing.cachedInput.toFixed(2)} per 1M tokens`)}
|
|
7579
8412
|
`);
|
|
7580
8413
|
}
|
|
7581
8414
|
if (model.knowledgeCutoff) {
|
|
7582
|
-
stream2.write(` ${
|
|
8415
|
+
stream2.write(` ${import_chalk6.default.dim("Knowledge:")} ${model.knowledgeCutoff}
|
|
7583
8416
|
`);
|
|
7584
8417
|
}
|
|
7585
8418
|
const features = [];
|
|
@@ -7590,20 +8423,20 @@ function renderVerboseTable(models, stream2) {
|
|
|
7590
8423
|
if (model.features.structuredOutputs) features.push("structured-outputs");
|
|
7591
8424
|
if (model.features.fineTuning) features.push("fine-tuning");
|
|
7592
8425
|
if (features.length > 0) {
|
|
7593
|
-
stream2.write(` ${
|
|
8426
|
+
stream2.write(` ${import_chalk6.default.dim("Features:")} ${import_chalk6.default.blue(features.join(", "))}
|
|
7594
8427
|
`);
|
|
7595
8428
|
}
|
|
7596
8429
|
if (model.metadata) {
|
|
7597
8430
|
if (model.metadata.family) {
|
|
7598
|
-
stream2.write(` ${
|
|
8431
|
+
stream2.write(` ${import_chalk6.default.dim("Family:")} ${model.metadata.family}
|
|
7599
8432
|
`);
|
|
7600
8433
|
}
|
|
7601
8434
|
if (model.metadata.releaseDate) {
|
|
7602
|
-
stream2.write(` ${
|
|
8435
|
+
stream2.write(` ${import_chalk6.default.dim("Released:")} ${model.metadata.releaseDate}
|
|
7603
8436
|
`);
|
|
7604
8437
|
}
|
|
7605
8438
|
if (model.metadata.notes) {
|
|
7606
|
-
stream2.write(` ${
|
|
8439
|
+
stream2.write(` ${import_chalk6.default.dim("Notes:")} ${import_chalk6.default.italic(model.metadata.notes)}
|
|
7607
8440
|
`);
|
|
7608
8441
|
}
|
|
7609
8442
|
}
|
|
@@ -7653,7 +8486,7 @@ function registerModelsCommand(program, env) {
|
|
|
7653
8486
|
|
|
7654
8487
|
// src/cli/environment.ts
|
|
7655
8488
|
var import_node_readline = __toESM(require("readline"), 1);
|
|
7656
|
-
var
|
|
8489
|
+
var import_chalk7 = __toESM(require("chalk"), 1);
|
|
7657
8490
|
init_client();
|
|
7658
8491
|
init_logger();
|
|
7659
8492
|
var LOG_LEVEL_MAP = {
|
|
@@ -7702,14 +8535,14 @@ function createPromptFunction(stdin, stdout) {
|
|
|
7702
8535
|
output: stdout
|
|
7703
8536
|
});
|
|
7704
8537
|
stdout.write("\n");
|
|
7705
|
-
stdout.write(`${
|
|
8538
|
+
stdout.write(`${import_chalk7.default.cyan("\u2500".repeat(60))}
|
|
7706
8539
|
`);
|
|
7707
|
-
stdout.write(
|
|
8540
|
+
stdout.write(import_chalk7.default.cyan.bold("\u{1F916} Agent asks:\n"));
|
|
7708
8541
|
stdout.write(`${question}
|
|
7709
8542
|
`);
|
|
7710
|
-
stdout.write(`${
|
|
8543
|
+
stdout.write(`${import_chalk7.default.cyan("\u2500".repeat(60))}
|
|
7711
8544
|
`);
|
|
7712
|
-
rl.question(
|
|
8545
|
+
rl.question(import_chalk7.default.green.bold("You: "), (answer) => {
|
|
7713
8546
|
rl.close();
|
|
7714
8547
|
resolve(answer);
|
|
7715
8548
|
});
|
|
@@ -7799,6 +8632,7 @@ function createProgram(env, config) {
|
|
|
7799
8632
|
registerCompleteCommand(program, env, config?.complete);
|
|
7800
8633
|
registerAgentCommand(program, env, config?.agent);
|
|
7801
8634
|
registerModelsCommand(program, env);
|
|
8635
|
+
registerGadgetCommand(program, env);
|
|
7802
8636
|
if (config) {
|
|
7803
8637
|
const customNames = getCustomCommandNames(config);
|
|
7804
8638
|
for (const name of customNames) {
|