llmist 1.1.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-VXPZQZF5.js → chunk-KORMY3CD.js} +693 -375
- package/dist/chunk-KORMY3CD.js.map +1 -0
- package/dist/{chunk-OIPLYP7M.js → chunk-LELPPETT.js} +2 -2
- package/dist/cli.cjs +639 -321
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +638 -320
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +2 -2
- package/dist/testing/index.cjs +638 -320
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-VXPZQZF5.js.map +0 -1
- /package/dist/{chunk-OIPLYP7M.js.map → chunk-LELPPETT.js.map} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -1493,6 +1493,364 @@ var init_hook_validators = __esm({
|
|
|
1493
1493
|
}
|
|
1494
1494
|
});
|
|
1495
1495
|
|
|
1496
|
+
// src/gadgets/schema-introspector.ts
|
|
1497
|
+
function getDef(schema) {
|
|
1498
|
+
return schema._def;
|
|
1499
|
+
}
|
|
1500
|
+
function getTypeName(schema) {
|
|
1501
|
+
const def = getDef(schema);
|
|
1502
|
+
return def?.type ?? def?.typeName;
|
|
1503
|
+
}
|
|
1504
|
+
function getShape(schema) {
|
|
1505
|
+
const def = getDef(schema);
|
|
1506
|
+
if (typeof def?.shape === "function") {
|
|
1507
|
+
return def.shape();
|
|
1508
|
+
}
|
|
1509
|
+
return def?.shape;
|
|
1510
|
+
}
|
|
1511
|
+
var SchemaIntrospector;
|
|
1512
|
+
var init_schema_introspector = __esm({
|
|
1513
|
+
"src/gadgets/schema-introspector.ts"() {
|
|
1514
|
+
"use strict";
|
|
1515
|
+
SchemaIntrospector = class {
|
|
1516
|
+
schema;
|
|
1517
|
+
cache = /* @__PURE__ */ new Map();
|
|
1518
|
+
constructor(schema) {
|
|
1519
|
+
this.schema = schema;
|
|
1520
|
+
}
|
|
1521
|
+
/**
|
|
1522
|
+
* Get the expected type at a JSON pointer path.
|
|
1523
|
+
*
|
|
1524
|
+
* @param pointer - JSON pointer path without leading / (e.g., "config/timeout", "items/0")
|
|
1525
|
+
* @returns Type hint for coercion decision
|
|
1526
|
+
*/
|
|
1527
|
+
getTypeAtPath(pointer) {
|
|
1528
|
+
const cached = this.cache.get(pointer);
|
|
1529
|
+
if (cached !== void 0) {
|
|
1530
|
+
return cached;
|
|
1531
|
+
}
|
|
1532
|
+
const result = this.resolveTypeAtPath(pointer);
|
|
1533
|
+
this.cache.set(pointer, result);
|
|
1534
|
+
return result;
|
|
1535
|
+
}
|
|
1536
|
+
/**
|
|
1537
|
+
* Internal method to resolve type at path without caching.
|
|
1538
|
+
*/
|
|
1539
|
+
resolveTypeAtPath(pointer) {
|
|
1540
|
+
if (!pointer) {
|
|
1541
|
+
return this.getBaseType(this.schema);
|
|
1542
|
+
}
|
|
1543
|
+
const segments = pointer.split("/");
|
|
1544
|
+
let current = this.schema;
|
|
1545
|
+
for (const segment of segments) {
|
|
1546
|
+
current = this.unwrapSchema(current);
|
|
1547
|
+
const typeName = getTypeName(current);
|
|
1548
|
+
if (typeName === "object" || typeName === "ZodObject") {
|
|
1549
|
+
const shape = getShape(current);
|
|
1550
|
+
if (!shape || !(segment in shape)) {
|
|
1551
|
+
return "unknown";
|
|
1552
|
+
}
|
|
1553
|
+
current = shape[segment];
|
|
1554
|
+
} else if (typeName === "array" || typeName === "ZodArray") {
|
|
1555
|
+
if (!/^\d+$/.test(segment)) {
|
|
1556
|
+
return "unknown";
|
|
1557
|
+
}
|
|
1558
|
+
const def = getDef(current);
|
|
1559
|
+
const elementType = def?.element ?? def?.type;
|
|
1560
|
+
if (!elementType) {
|
|
1561
|
+
return "unknown";
|
|
1562
|
+
}
|
|
1563
|
+
current = elementType;
|
|
1564
|
+
} else if (typeName === "tuple" || typeName === "ZodTuple") {
|
|
1565
|
+
if (!/^\d+$/.test(segment)) {
|
|
1566
|
+
return "unknown";
|
|
1567
|
+
}
|
|
1568
|
+
const index = parseInt(segment, 10);
|
|
1569
|
+
const def = getDef(current);
|
|
1570
|
+
const items = def?.items;
|
|
1571
|
+
if (!items || index >= items.length) {
|
|
1572
|
+
return "unknown";
|
|
1573
|
+
}
|
|
1574
|
+
current = items[index];
|
|
1575
|
+
} else if (typeName === "record" || typeName === "ZodRecord") {
|
|
1576
|
+
const def = getDef(current);
|
|
1577
|
+
const valueType = def?.valueType;
|
|
1578
|
+
if (!valueType) {
|
|
1579
|
+
return "unknown";
|
|
1580
|
+
}
|
|
1581
|
+
current = valueType;
|
|
1582
|
+
} else {
|
|
1583
|
+
return "unknown";
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
return this.getBaseType(current);
|
|
1587
|
+
}
|
|
1588
|
+
/**
|
|
1589
|
+
* Unwrap schema modifiers (optional, default, nullable, branded, etc.)
|
|
1590
|
+
* to get to the underlying type.
|
|
1591
|
+
*/
|
|
1592
|
+
unwrapSchema(schema) {
|
|
1593
|
+
let current = schema;
|
|
1594
|
+
let iterations = 0;
|
|
1595
|
+
const maxIterations = 20;
|
|
1596
|
+
while (iterations < maxIterations) {
|
|
1597
|
+
const typeName = getTypeName(current);
|
|
1598
|
+
const wrapperTypes = [
|
|
1599
|
+
"optional",
|
|
1600
|
+
"nullable",
|
|
1601
|
+
"default",
|
|
1602
|
+
"catch",
|
|
1603
|
+
"branded",
|
|
1604
|
+
"readonly",
|
|
1605
|
+
"pipeline",
|
|
1606
|
+
"ZodOptional",
|
|
1607
|
+
"ZodNullable",
|
|
1608
|
+
"ZodDefault",
|
|
1609
|
+
"ZodCatch",
|
|
1610
|
+
"ZodBranded",
|
|
1611
|
+
"ZodReadonly",
|
|
1612
|
+
"ZodPipeline"
|
|
1613
|
+
];
|
|
1614
|
+
if (typeName && wrapperTypes.includes(typeName)) {
|
|
1615
|
+
const def = getDef(current);
|
|
1616
|
+
const inner = def?.innerType ?? def?.in ?? def?.type;
|
|
1617
|
+
if (!inner || inner === current) break;
|
|
1618
|
+
current = inner;
|
|
1619
|
+
iterations++;
|
|
1620
|
+
continue;
|
|
1621
|
+
}
|
|
1622
|
+
break;
|
|
1623
|
+
}
|
|
1624
|
+
return current;
|
|
1625
|
+
}
|
|
1626
|
+
/**
|
|
1627
|
+
* Get the primitive type hint from an unwrapped schema.
|
|
1628
|
+
*/
|
|
1629
|
+
getBaseType(schema) {
|
|
1630
|
+
const unwrapped = this.unwrapSchema(schema);
|
|
1631
|
+
const typeName = getTypeName(unwrapped);
|
|
1632
|
+
switch (typeName) {
|
|
1633
|
+
// Primitive types
|
|
1634
|
+
case "string":
|
|
1635
|
+
case "ZodString":
|
|
1636
|
+
return "string";
|
|
1637
|
+
case "number":
|
|
1638
|
+
case "ZodNumber":
|
|
1639
|
+
case "bigint":
|
|
1640
|
+
case "ZodBigInt":
|
|
1641
|
+
return "number";
|
|
1642
|
+
case "boolean":
|
|
1643
|
+
case "ZodBoolean":
|
|
1644
|
+
return "boolean";
|
|
1645
|
+
// Literal types - check the literal value type
|
|
1646
|
+
case "literal":
|
|
1647
|
+
case "ZodLiteral": {
|
|
1648
|
+
const def = getDef(unwrapped);
|
|
1649
|
+
const values = def?.values;
|
|
1650
|
+
const value = values?.[0] ?? def?.value;
|
|
1651
|
+
if (typeof value === "string") return "string";
|
|
1652
|
+
if (typeof value === "number" || typeof value === "bigint")
|
|
1653
|
+
return "number";
|
|
1654
|
+
if (typeof value === "boolean") return "boolean";
|
|
1655
|
+
return "unknown";
|
|
1656
|
+
}
|
|
1657
|
+
// Enum - always string keys
|
|
1658
|
+
case "enum":
|
|
1659
|
+
case "ZodEnum":
|
|
1660
|
+
case "nativeEnum":
|
|
1661
|
+
case "ZodNativeEnum":
|
|
1662
|
+
return "string";
|
|
1663
|
+
// Union - return 'unknown' to let auto-coercion decide
|
|
1664
|
+
// Since multiple types are valid, we can't definitively say what the LLM intended
|
|
1665
|
+
// Auto-coercion will handle common cases (numbers, booleans) appropriately
|
|
1666
|
+
case "union":
|
|
1667
|
+
case "ZodUnion":
|
|
1668
|
+
return "unknown";
|
|
1669
|
+
// Discriminated union - complex, return unknown
|
|
1670
|
+
case "discriminatedUnion":
|
|
1671
|
+
case "ZodDiscriminatedUnion":
|
|
1672
|
+
return "unknown";
|
|
1673
|
+
// Intersection - check both sides
|
|
1674
|
+
case "intersection":
|
|
1675
|
+
case "ZodIntersection": {
|
|
1676
|
+
const def = getDef(unwrapped);
|
|
1677
|
+
const left = def?.left;
|
|
1678
|
+
const right = def?.right;
|
|
1679
|
+
if (!left || !right) return "unknown";
|
|
1680
|
+
const leftType = this.getBaseType(left);
|
|
1681
|
+
const rightType = this.getBaseType(right);
|
|
1682
|
+
if (leftType === rightType) return leftType;
|
|
1683
|
+
if (leftType === "string" || rightType === "string") return "string";
|
|
1684
|
+
return "unknown";
|
|
1685
|
+
}
|
|
1686
|
+
// Effects/transforms - return unknown to let Zod handle it
|
|
1687
|
+
case "effects":
|
|
1688
|
+
case "ZodEffects":
|
|
1689
|
+
return "unknown";
|
|
1690
|
+
// Lazy - can't resolve without evaluating
|
|
1691
|
+
case "lazy":
|
|
1692
|
+
case "ZodLazy":
|
|
1693
|
+
return "unknown";
|
|
1694
|
+
// Complex types - return unknown
|
|
1695
|
+
case "object":
|
|
1696
|
+
case "ZodObject":
|
|
1697
|
+
case "array":
|
|
1698
|
+
case "ZodArray":
|
|
1699
|
+
case "tuple":
|
|
1700
|
+
case "ZodTuple":
|
|
1701
|
+
case "record":
|
|
1702
|
+
case "ZodRecord":
|
|
1703
|
+
case "map":
|
|
1704
|
+
case "ZodMap":
|
|
1705
|
+
case "set":
|
|
1706
|
+
case "ZodSet":
|
|
1707
|
+
case "function":
|
|
1708
|
+
case "ZodFunction":
|
|
1709
|
+
case "promise":
|
|
1710
|
+
case "ZodPromise":
|
|
1711
|
+
case "date":
|
|
1712
|
+
case "ZodDate":
|
|
1713
|
+
return "unknown";
|
|
1714
|
+
// Unknown/any/never/void/undefined/null
|
|
1715
|
+
case "unknown":
|
|
1716
|
+
case "ZodUnknown":
|
|
1717
|
+
case "any":
|
|
1718
|
+
case "ZodAny":
|
|
1719
|
+
case "never":
|
|
1720
|
+
case "ZodNever":
|
|
1721
|
+
case "void":
|
|
1722
|
+
case "ZodVoid":
|
|
1723
|
+
case "undefined":
|
|
1724
|
+
case "ZodUndefined":
|
|
1725
|
+
case "null":
|
|
1726
|
+
case "ZodNull":
|
|
1727
|
+
return "unknown";
|
|
1728
|
+
default:
|
|
1729
|
+
return "unknown";
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
};
|
|
1733
|
+
}
|
|
1734
|
+
});
|
|
1735
|
+
|
|
1736
|
+
// src/gadgets/block-params.ts
|
|
1737
|
+
function parseBlockParams(content, options) {
|
|
1738
|
+
const argPrefix = options?.argPrefix ?? GADGET_ARG_PREFIX;
|
|
1739
|
+
const result = {};
|
|
1740
|
+
const seenPointers = /* @__PURE__ */ new Set();
|
|
1741
|
+
const introspector = options?.schema ? new SchemaIntrospector(options.schema) : void 0;
|
|
1742
|
+
const parts = content.split(argPrefix);
|
|
1743
|
+
for (let i = 1; i < parts.length; i++) {
|
|
1744
|
+
const part = parts[i];
|
|
1745
|
+
const newlineIndex = part.indexOf("\n");
|
|
1746
|
+
if (newlineIndex === -1) {
|
|
1747
|
+
const pointer2 = part.trim();
|
|
1748
|
+
if (pointer2) {
|
|
1749
|
+
if (seenPointers.has(pointer2)) {
|
|
1750
|
+
throw new Error(`Duplicate pointer: ${pointer2}`);
|
|
1751
|
+
}
|
|
1752
|
+
seenPointers.add(pointer2);
|
|
1753
|
+
setByPointer(result, pointer2, "", introspector);
|
|
1754
|
+
}
|
|
1755
|
+
continue;
|
|
1756
|
+
}
|
|
1757
|
+
const pointer = part.substring(0, newlineIndex).trim();
|
|
1758
|
+
let value = part.substring(newlineIndex + 1);
|
|
1759
|
+
if (value.endsWith("\n")) {
|
|
1760
|
+
value = value.slice(0, -1);
|
|
1761
|
+
}
|
|
1762
|
+
if (!pointer) {
|
|
1763
|
+
continue;
|
|
1764
|
+
}
|
|
1765
|
+
if (seenPointers.has(pointer)) {
|
|
1766
|
+
throw new Error(`Duplicate pointer: ${pointer}`);
|
|
1767
|
+
}
|
|
1768
|
+
seenPointers.add(pointer);
|
|
1769
|
+
setByPointer(result, pointer, value, introspector);
|
|
1770
|
+
}
|
|
1771
|
+
return result;
|
|
1772
|
+
}
|
|
1773
|
+
function coerceValue(value, expectedType) {
|
|
1774
|
+
if (value.includes("\n")) {
|
|
1775
|
+
return value;
|
|
1776
|
+
}
|
|
1777
|
+
const trimmed = value.trim();
|
|
1778
|
+
if (expectedType === "string") {
|
|
1779
|
+
return value;
|
|
1780
|
+
}
|
|
1781
|
+
if (expectedType === "boolean") {
|
|
1782
|
+
if (trimmed === "true") return true;
|
|
1783
|
+
if (trimmed === "false") return false;
|
|
1784
|
+
return value;
|
|
1785
|
+
}
|
|
1786
|
+
if (expectedType === "number") {
|
|
1787
|
+
const num = Number(trimmed);
|
|
1788
|
+
if (!isNaN(num) && isFinite(num) && trimmed !== "") {
|
|
1789
|
+
return num;
|
|
1790
|
+
}
|
|
1791
|
+
return value;
|
|
1792
|
+
}
|
|
1793
|
+
if (trimmed === "true") return true;
|
|
1794
|
+
if (trimmed === "false") return false;
|
|
1795
|
+
if (trimmed !== "" && /^-?\d+(\.\d+)?$/.test(trimmed)) {
|
|
1796
|
+
const num = Number(trimmed);
|
|
1797
|
+
if (!isNaN(num) && isFinite(num)) {
|
|
1798
|
+
return num;
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
return value;
|
|
1802
|
+
}
|
|
1803
|
+
function setByPointer(obj, pointer, value, introspector) {
|
|
1804
|
+
const segments = pointer.split("/");
|
|
1805
|
+
let current = obj;
|
|
1806
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
1807
|
+
const segment = segments[i];
|
|
1808
|
+
const nextSegment = segments[i + 1];
|
|
1809
|
+
const nextIsArrayIndex = /^\d+$/.test(nextSegment);
|
|
1810
|
+
if (Array.isArray(current)) {
|
|
1811
|
+
const index = parseInt(segment, 10);
|
|
1812
|
+
if (isNaN(index) || index < 0) {
|
|
1813
|
+
throw new Error(`Invalid array index: ${segment}`);
|
|
1814
|
+
}
|
|
1815
|
+
if (index > current.length) {
|
|
1816
|
+
throw new Error(`Array index gap: expected ${current.length}, got ${index}`);
|
|
1817
|
+
}
|
|
1818
|
+
if (current[index] === void 0) {
|
|
1819
|
+
current[index] = nextIsArrayIndex ? [] : {};
|
|
1820
|
+
}
|
|
1821
|
+
current = current[index];
|
|
1822
|
+
} else {
|
|
1823
|
+
const rec = current;
|
|
1824
|
+
if (rec[segment] === void 0) {
|
|
1825
|
+
rec[segment] = nextIsArrayIndex ? [] : {};
|
|
1826
|
+
}
|
|
1827
|
+
current = rec[segment];
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1830
|
+
const lastSegment = segments[segments.length - 1];
|
|
1831
|
+
const expectedType = introspector?.getTypeAtPath(pointer);
|
|
1832
|
+
const coercedValue = coerceValue(value, expectedType);
|
|
1833
|
+
if (Array.isArray(current)) {
|
|
1834
|
+
const index = parseInt(lastSegment, 10);
|
|
1835
|
+
if (isNaN(index) || index < 0) {
|
|
1836
|
+
throw new Error(`Invalid array index: ${lastSegment}`);
|
|
1837
|
+
}
|
|
1838
|
+
if (index > current.length) {
|
|
1839
|
+
throw new Error(`Array index gap: expected ${current.length}, got ${index}`);
|
|
1840
|
+
}
|
|
1841
|
+
current[index] = coercedValue;
|
|
1842
|
+
} else {
|
|
1843
|
+
current[lastSegment] = coercedValue;
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
var init_block_params = __esm({
|
|
1847
|
+
"src/gadgets/block-params.ts"() {
|
|
1848
|
+
"use strict";
|
|
1849
|
+
init_constants();
|
|
1850
|
+
init_schema_introspector();
|
|
1851
|
+
}
|
|
1852
|
+
});
|
|
1853
|
+
|
|
1496
1854
|
// src/gadgets/error-formatter.ts
|
|
1497
1855
|
var GadgetErrorFormatter;
|
|
1498
1856
|
var init_error_formatter = __esm({
|
|
@@ -1604,325 +1962,7 @@ var init_exceptions = __esm({
|
|
|
1604
1962
|
this.gadgetName = gadgetName;
|
|
1605
1963
|
this.timeoutMs = timeoutMs;
|
|
1606
1964
|
}
|
|
1607
|
-
};
|
|
1608
|
-
}
|
|
1609
|
-
});
|
|
1610
|
-
|
|
1611
|
-
// src/gadgets/executor.ts
|
|
1612
|
-
var GadgetExecutor;
|
|
1613
|
-
var init_executor = __esm({
|
|
1614
|
-
"src/gadgets/executor.ts"() {
|
|
1615
|
-
"use strict";
|
|
1616
|
-
init_logger();
|
|
1617
|
-
init_error_formatter();
|
|
1618
|
-
init_exceptions();
|
|
1619
|
-
GadgetExecutor = class {
|
|
1620
|
-
constructor(registry, onHumanInputRequired, logger, defaultGadgetTimeoutMs, errorFormatterOptions) {
|
|
1621
|
-
this.registry = registry;
|
|
1622
|
-
this.onHumanInputRequired = onHumanInputRequired;
|
|
1623
|
-
this.defaultGadgetTimeoutMs = defaultGadgetTimeoutMs;
|
|
1624
|
-
this.logger = logger ?? createLogger({ name: "llmist:executor" });
|
|
1625
|
-
this.errorFormatter = new GadgetErrorFormatter(errorFormatterOptions);
|
|
1626
|
-
}
|
|
1627
|
-
logger;
|
|
1628
|
-
errorFormatter;
|
|
1629
|
-
/**
|
|
1630
|
-
* Creates a promise that rejects with a TimeoutException after the specified timeout.
|
|
1631
|
-
*/
|
|
1632
|
-
createTimeoutPromise(gadgetName, timeoutMs) {
|
|
1633
|
-
return new Promise((_, reject) => {
|
|
1634
|
-
setTimeout(() => {
|
|
1635
|
-
reject(new TimeoutException(gadgetName, timeoutMs));
|
|
1636
|
-
}, timeoutMs);
|
|
1637
|
-
});
|
|
1638
|
-
}
|
|
1639
|
-
// Execute a gadget call asynchronously
|
|
1640
|
-
async execute(call) {
|
|
1641
|
-
const startTime = Date.now();
|
|
1642
|
-
this.logger.debug("Executing gadget", {
|
|
1643
|
-
gadgetName: call.gadgetName,
|
|
1644
|
-
invocationId: call.invocationId,
|
|
1645
|
-
parameters: call.parameters
|
|
1646
|
-
});
|
|
1647
|
-
const rawParameters = call.parameters ?? {};
|
|
1648
|
-
let validatedParameters = rawParameters;
|
|
1649
|
-
try {
|
|
1650
|
-
const gadget = this.registry.get(call.gadgetName);
|
|
1651
|
-
if (!gadget) {
|
|
1652
|
-
this.logger.error("Gadget not found", { gadgetName: call.gadgetName });
|
|
1653
|
-
const availableGadgets = this.registry.getNames();
|
|
1654
|
-
return {
|
|
1655
|
-
gadgetName: call.gadgetName,
|
|
1656
|
-
invocationId: call.invocationId,
|
|
1657
|
-
parameters: call.parameters ?? {},
|
|
1658
|
-
error: this.errorFormatter.formatRegistryError(call.gadgetName, availableGadgets),
|
|
1659
|
-
executionTimeMs: Date.now() - startTime
|
|
1660
|
-
};
|
|
1661
|
-
}
|
|
1662
|
-
if (call.parseError || !call.parameters) {
|
|
1663
|
-
this.logger.error("Gadget parameter parse error", {
|
|
1664
|
-
gadgetName: call.gadgetName,
|
|
1665
|
-
parseError: call.parseError,
|
|
1666
|
-
rawParameters: call.parametersRaw
|
|
1667
|
-
});
|
|
1668
|
-
const parseErrorMessage = call.parseError ?? "Failed to parse parameters";
|
|
1669
|
-
return {
|
|
1670
|
-
gadgetName: call.gadgetName,
|
|
1671
|
-
invocationId: call.invocationId,
|
|
1672
|
-
parameters: {},
|
|
1673
|
-
error: this.errorFormatter.formatParseError(call.gadgetName, parseErrorMessage, gadget),
|
|
1674
|
-
executionTimeMs: Date.now() - startTime
|
|
1675
|
-
};
|
|
1676
|
-
}
|
|
1677
|
-
if (gadget.parameterSchema) {
|
|
1678
|
-
const validationResult = gadget.parameterSchema.safeParse(rawParameters);
|
|
1679
|
-
if (!validationResult.success) {
|
|
1680
|
-
const validationError = this.errorFormatter.formatValidationError(
|
|
1681
|
-
call.gadgetName,
|
|
1682
|
-
validationResult.error,
|
|
1683
|
-
gadget
|
|
1684
|
-
);
|
|
1685
|
-
this.logger.error("Gadget parameter validation failed", {
|
|
1686
|
-
gadgetName: call.gadgetName,
|
|
1687
|
-
issueCount: validationResult.error.issues.length
|
|
1688
|
-
});
|
|
1689
|
-
return {
|
|
1690
|
-
gadgetName: call.gadgetName,
|
|
1691
|
-
invocationId: call.invocationId,
|
|
1692
|
-
parameters: rawParameters,
|
|
1693
|
-
error: validationError,
|
|
1694
|
-
executionTimeMs: Date.now() - startTime
|
|
1695
|
-
};
|
|
1696
|
-
}
|
|
1697
|
-
validatedParameters = validationResult.data;
|
|
1698
|
-
}
|
|
1699
|
-
const timeoutMs = gadget.timeoutMs ?? this.defaultGadgetTimeoutMs;
|
|
1700
|
-
let result;
|
|
1701
|
-
if (timeoutMs && timeoutMs > 0) {
|
|
1702
|
-
this.logger.debug("Executing gadget with timeout", {
|
|
1703
|
-
gadgetName: call.gadgetName,
|
|
1704
|
-
timeoutMs
|
|
1705
|
-
});
|
|
1706
|
-
result = await Promise.race([
|
|
1707
|
-
Promise.resolve(gadget.execute(validatedParameters)),
|
|
1708
|
-
this.createTimeoutPromise(call.gadgetName, timeoutMs)
|
|
1709
|
-
]);
|
|
1710
|
-
} else {
|
|
1711
|
-
result = await Promise.resolve(gadget.execute(validatedParameters));
|
|
1712
|
-
}
|
|
1713
|
-
const executionTimeMs = Date.now() - startTime;
|
|
1714
|
-
this.logger.info("Gadget executed successfully", {
|
|
1715
|
-
gadgetName: call.gadgetName,
|
|
1716
|
-
invocationId: call.invocationId,
|
|
1717
|
-
executionTimeMs
|
|
1718
|
-
});
|
|
1719
|
-
this.logger.debug("Gadget result", {
|
|
1720
|
-
gadgetName: call.gadgetName,
|
|
1721
|
-
invocationId: call.invocationId,
|
|
1722
|
-
parameters: validatedParameters,
|
|
1723
|
-
result,
|
|
1724
|
-
executionTimeMs
|
|
1725
|
-
});
|
|
1726
|
-
return {
|
|
1727
|
-
gadgetName: call.gadgetName,
|
|
1728
|
-
invocationId: call.invocationId,
|
|
1729
|
-
parameters: validatedParameters,
|
|
1730
|
-
result,
|
|
1731
|
-
executionTimeMs
|
|
1732
|
-
};
|
|
1733
|
-
} catch (error) {
|
|
1734
|
-
if (error instanceof BreakLoopException) {
|
|
1735
|
-
this.logger.info("Gadget requested loop termination", {
|
|
1736
|
-
gadgetName: call.gadgetName,
|
|
1737
|
-
message: error.message
|
|
1738
|
-
});
|
|
1739
|
-
return {
|
|
1740
|
-
gadgetName: call.gadgetName,
|
|
1741
|
-
invocationId: call.invocationId,
|
|
1742
|
-
parameters: validatedParameters,
|
|
1743
|
-
result: error.message,
|
|
1744
|
-
breaksLoop: true,
|
|
1745
|
-
executionTimeMs: Date.now() - startTime
|
|
1746
|
-
};
|
|
1747
|
-
}
|
|
1748
|
-
if (error instanceof TimeoutException) {
|
|
1749
|
-
this.logger.error("Gadget execution timed out", {
|
|
1750
|
-
gadgetName: call.gadgetName,
|
|
1751
|
-
timeoutMs: error.timeoutMs,
|
|
1752
|
-
executionTimeMs: Date.now() - startTime
|
|
1753
|
-
});
|
|
1754
|
-
return {
|
|
1755
|
-
gadgetName: call.gadgetName,
|
|
1756
|
-
invocationId: call.invocationId,
|
|
1757
|
-
parameters: validatedParameters,
|
|
1758
|
-
error: error.message,
|
|
1759
|
-
executionTimeMs: Date.now() - startTime
|
|
1760
|
-
};
|
|
1761
|
-
}
|
|
1762
|
-
if (error instanceof HumanInputException) {
|
|
1763
|
-
this.logger.info("Gadget requested human input", {
|
|
1764
|
-
gadgetName: call.gadgetName,
|
|
1765
|
-
question: error.question
|
|
1766
|
-
});
|
|
1767
|
-
if (this.onHumanInputRequired) {
|
|
1768
|
-
try {
|
|
1769
|
-
const answer = await this.onHumanInputRequired(error.question);
|
|
1770
|
-
this.logger.debug("Human input received", {
|
|
1771
|
-
gadgetName: call.gadgetName,
|
|
1772
|
-
answerLength: answer.length
|
|
1773
|
-
});
|
|
1774
|
-
return {
|
|
1775
|
-
gadgetName: call.gadgetName,
|
|
1776
|
-
invocationId: call.invocationId,
|
|
1777
|
-
parameters: validatedParameters,
|
|
1778
|
-
result: answer,
|
|
1779
|
-
executionTimeMs: Date.now() - startTime
|
|
1780
|
-
};
|
|
1781
|
-
} catch (inputError) {
|
|
1782
|
-
this.logger.error("Human input callback error", {
|
|
1783
|
-
gadgetName: call.gadgetName,
|
|
1784
|
-
error: inputError instanceof Error ? inputError.message : String(inputError)
|
|
1785
|
-
});
|
|
1786
|
-
return {
|
|
1787
|
-
gadgetName: call.gadgetName,
|
|
1788
|
-
invocationId: call.invocationId,
|
|
1789
|
-
parameters: validatedParameters,
|
|
1790
|
-
error: inputError instanceof Error ? inputError.message : String(inputError),
|
|
1791
|
-
executionTimeMs: Date.now() - startTime
|
|
1792
|
-
};
|
|
1793
|
-
}
|
|
1794
|
-
}
|
|
1795
|
-
this.logger.warn("Human input required but no callback provided", {
|
|
1796
|
-
gadgetName: call.gadgetName
|
|
1797
|
-
});
|
|
1798
|
-
return {
|
|
1799
|
-
gadgetName: call.gadgetName,
|
|
1800
|
-
invocationId: call.invocationId,
|
|
1801
|
-
parameters: validatedParameters,
|
|
1802
|
-
error: "Human input required but not available (stdin is not interactive)",
|
|
1803
|
-
executionTimeMs: Date.now() - startTime
|
|
1804
|
-
};
|
|
1805
|
-
}
|
|
1806
|
-
const executionTimeMs = Date.now() - startTime;
|
|
1807
|
-
this.logger.error("Gadget execution failed", {
|
|
1808
|
-
gadgetName: call.gadgetName,
|
|
1809
|
-
error: error instanceof Error ? error.message : String(error),
|
|
1810
|
-
executionTimeMs
|
|
1811
|
-
});
|
|
1812
|
-
return {
|
|
1813
|
-
gadgetName: call.gadgetName,
|
|
1814
|
-
invocationId: call.invocationId,
|
|
1815
|
-
parameters: validatedParameters,
|
|
1816
|
-
error: error instanceof Error ? error.message : String(error),
|
|
1817
|
-
executionTimeMs
|
|
1818
|
-
};
|
|
1819
|
-
}
|
|
1820
|
-
}
|
|
1821
|
-
// Execute multiple gadget calls in parallel
|
|
1822
|
-
async executeAll(calls) {
|
|
1823
|
-
return Promise.all(calls.map((call) => this.execute(call)));
|
|
1824
|
-
}
|
|
1825
|
-
};
|
|
1826
|
-
}
|
|
1827
|
-
});
|
|
1828
|
-
|
|
1829
|
-
// src/gadgets/block-params.ts
|
|
1830
|
-
function parseBlockParams(content, options) {
|
|
1831
|
-
const argPrefix = options?.argPrefix ?? GADGET_ARG_PREFIX;
|
|
1832
|
-
const result = {};
|
|
1833
|
-
const seenPointers = /* @__PURE__ */ new Set();
|
|
1834
|
-
const parts = content.split(argPrefix);
|
|
1835
|
-
for (let i = 1; i < parts.length; i++) {
|
|
1836
|
-
const part = parts[i];
|
|
1837
|
-
const newlineIndex = part.indexOf("\n");
|
|
1838
|
-
if (newlineIndex === -1) {
|
|
1839
|
-
const pointer2 = part.trim();
|
|
1840
|
-
if (pointer2) {
|
|
1841
|
-
if (seenPointers.has(pointer2)) {
|
|
1842
|
-
throw new Error(`Duplicate pointer: ${pointer2}`);
|
|
1843
|
-
}
|
|
1844
|
-
seenPointers.add(pointer2);
|
|
1845
|
-
setByPointer(result, pointer2, "");
|
|
1846
|
-
}
|
|
1847
|
-
continue;
|
|
1848
|
-
}
|
|
1849
|
-
const pointer = part.substring(0, newlineIndex).trim();
|
|
1850
|
-
let value = part.substring(newlineIndex + 1);
|
|
1851
|
-
if (value.endsWith("\n")) {
|
|
1852
|
-
value = value.slice(0, -1);
|
|
1853
|
-
}
|
|
1854
|
-
if (!pointer) {
|
|
1855
|
-
continue;
|
|
1856
|
-
}
|
|
1857
|
-
if (seenPointers.has(pointer)) {
|
|
1858
|
-
throw new Error(`Duplicate pointer: ${pointer}`);
|
|
1859
|
-
}
|
|
1860
|
-
seenPointers.add(pointer);
|
|
1861
|
-
setByPointer(result, pointer, value);
|
|
1862
|
-
}
|
|
1863
|
-
return result;
|
|
1864
|
-
}
|
|
1865
|
-
function coerceValue(value) {
|
|
1866
|
-
if (value.includes("\n")) {
|
|
1867
|
-
return value;
|
|
1868
|
-
}
|
|
1869
|
-
const trimmed = value.trim();
|
|
1870
|
-
if (trimmed === "true") return true;
|
|
1871
|
-
if (trimmed === "false") return false;
|
|
1872
|
-
if (trimmed !== "" && /^-?\d+(\.\d+)?$/.test(trimmed)) {
|
|
1873
|
-
const num = Number(trimmed);
|
|
1874
|
-
if (!isNaN(num) && isFinite(num)) {
|
|
1875
|
-
return num;
|
|
1876
|
-
}
|
|
1877
|
-
}
|
|
1878
|
-
return value;
|
|
1879
|
-
}
|
|
1880
|
-
function setByPointer(obj, pointer, value) {
|
|
1881
|
-
const segments = pointer.split("/");
|
|
1882
|
-
let current = obj;
|
|
1883
|
-
for (let i = 0; i < segments.length - 1; i++) {
|
|
1884
|
-
const segment = segments[i];
|
|
1885
|
-
const nextSegment = segments[i + 1];
|
|
1886
|
-
const nextIsArrayIndex = /^\d+$/.test(nextSegment);
|
|
1887
|
-
if (Array.isArray(current)) {
|
|
1888
|
-
const index = parseInt(segment, 10);
|
|
1889
|
-
if (isNaN(index) || index < 0) {
|
|
1890
|
-
throw new Error(`Invalid array index: ${segment}`);
|
|
1891
|
-
}
|
|
1892
|
-
if (index > current.length) {
|
|
1893
|
-
throw new Error(`Array index gap: expected ${current.length}, got ${index}`);
|
|
1894
|
-
}
|
|
1895
|
-
if (current[index] === void 0) {
|
|
1896
|
-
current[index] = nextIsArrayIndex ? [] : {};
|
|
1897
|
-
}
|
|
1898
|
-
current = current[index];
|
|
1899
|
-
} else {
|
|
1900
|
-
const rec = current;
|
|
1901
|
-
if (rec[segment] === void 0) {
|
|
1902
|
-
rec[segment] = nextIsArrayIndex ? [] : {};
|
|
1903
|
-
}
|
|
1904
|
-
current = rec[segment];
|
|
1905
|
-
}
|
|
1906
|
-
}
|
|
1907
|
-
const lastSegment = segments[segments.length - 1];
|
|
1908
|
-
const coercedValue = coerceValue(value);
|
|
1909
|
-
if (Array.isArray(current)) {
|
|
1910
|
-
const index = parseInt(lastSegment, 10);
|
|
1911
|
-
if (isNaN(index) || index < 0) {
|
|
1912
|
-
throw new Error(`Invalid array index: ${lastSegment}`);
|
|
1913
|
-
}
|
|
1914
|
-
if (index > current.length) {
|
|
1915
|
-
throw new Error(`Array index gap: expected ${current.length}, got ${index}`);
|
|
1916
|
-
}
|
|
1917
|
-
current[index] = coercedValue;
|
|
1918
|
-
} else {
|
|
1919
|
-
current[lastSegment] = coercedValue;
|
|
1920
|
-
}
|
|
1921
|
-
}
|
|
1922
|
-
var init_block_params = __esm({
|
|
1923
|
-
"src/gadgets/block-params.ts"() {
|
|
1924
|
-
"use strict";
|
|
1925
|
-
init_constants();
|
|
1965
|
+
};
|
|
1926
1966
|
}
|
|
1927
1967
|
});
|
|
1928
1968
|
|
|
@@ -2103,6 +2143,283 @@ var init_parser = __esm({
|
|
|
2103
2143
|
}
|
|
2104
2144
|
});
|
|
2105
2145
|
|
|
2146
|
+
// src/gadgets/executor.ts
|
|
2147
|
+
var GadgetExecutor;
|
|
2148
|
+
var init_executor = __esm({
|
|
2149
|
+
"src/gadgets/executor.ts"() {
|
|
2150
|
+
"use strict";
|
|
2151
|
+
init_constants();
|
|
2152
|
+
init_logger();
|
|
2153
|
+
init_block_params();
|
|
2154
|
+
init_error_formatter();
|
|
2155
|
+
init_exceptions();
|
|
2156
|
+
init_parser();
|
|
2157
|
+
GadgetExecutor = class {
|
|
2158
|
+
constructor(registry, onHumanInputRequired, logger, defaultGadgetTimeoutMs, errorFormatterOptions) {
|
|
2159
|
+
this.registry = registry;
|
|
2160
|
+
this.onHumanInputRequired = onHumanInputRequired;
|
|
2161
|
+
this.defaultGadgetTimeoutMs = defaultGadgetTimeoutMs;
|
|
2162
|
+
this.logger = logger ?? createLogger({ name: "llmist:executor" });
|
|
2163
|
+
this.errorFormatter = new GadgetErrorFormatter(errorFormatterOptions);
|
|
2164
|
+
this.argPrefix = errorFormatterOptions?.argPrefix ?? GADGET_ARG_PREFIX;
|
|
2165
|
+
}
|
|
2166
|
+
logger;
|
|
2167
|
+
errorFormatter;
|
|
2168
|
+
argPrefix;
|
|
2169
|
+
/**
|
|
2170
|
+
* Creates a promise that rejects with a TimeoutException after the specified timeout.
|
|
2171
|
+
*/
|
|
2172
|
+
createTimeoutPromise(gadgetName, timeoutMs) {
|
|
2173
|
+
return new Promise((_, reject) => {
|
|
2174
|
+
setTimeout(() => {
|
|
2175
|
+
reject(new TimeoutException(gadgetName, timeoutMs));
|
|
2176
|
+
}, timeoutMs);
|
|
2177
|
+
});
|
|
2178
|
+
}
|
|
2179
|
+
// Execute a gadget call asynchronously
|
|
2180
|
+
async execute(call) {
|
|
2181
|
+
const startTime = Date.now();
|
|
2182
|
+
this.logger.debug("Executing gadget", {
|
|
2183
|
+
gadgetName: call.gadgetName,
|
|
2184
|
+
invocationId: call.invocationId,
|
|
2185
|
+
parameters: call.parameters
|
|
2186
|
+
});
|
|
2187
|
+
const rawParameters = call.parameters ?? {};
|
|
2188
|
+
let validatedParameters = rawParameters;
|
|
2189
|
+
try {
|
|
2190
|
+
const gadget = this.registry.get(call.gadgetName);
|
|
2191
|
+
if (!gadget) {
|
|
2192
|
+
this.logger.error("Gadget not found", { gadgetName: call.gadgetName });
|
|
2193
|
+
const availableGadgets = this.registry.getNames();
|
|
2194
|
+
return {
|
|
2195
|
+
gadgetName: call.gadgetName,
|
|
2196
|
+
invocationId: call.invocationId,
|
|
2197
|
+
parameters: call.parameters ?? {},
|
|
2198
|
+
error: this.errorFormatter.formatRegistryError(call.gadgetName, availableGadgets),
|
|
2199
|
+
executionTimeMs: Date.now() - startTime
|
|
2200
|
+
};
|
|
2201
|
+
}
|
|
2202
|
+
if (call.parseError || !call.parameters) {
|
|
2203
|
+
this.logger.error("Gadget parameter parse error", {
|
|
2204
|
+
gadgetName: call.gadgetName,
|
|
2205
|
+
parseError: call.parseError,
|
|
2206
|
+
rawParameters: call.parametersRaw
|
|
2207
|
+
});
|
|
2208
|
+
const parseErrorMessage = call.parseError ?? "Failed to parse parameters";
|
|
2209
|
+
return {
|
|
2210
|
+
gadgetName: call.gadgetName,
|
|
2211
|
+
invocationId: call.invocationId,
|
|
2212
|
+
parameters: {},
|
|
2213
|
+
error: this.errorFormatter.formatParseError(call.gadgetName, parseErrorMessage, gadget),
|
|
2214
|
+
executionTimeMs: Date.now() - startTime
|
|
2215
|
+
};
|
|
2216
|
+
}
|
|
2217
|
+
let schemaAwareParameters = rawParameters;
|
|
2218
|
+
const hasBlockFormat = call.parametersRaw?.includes(this.argPrefix);
|
|
2219
|
+
if (gadget.parameterSchema && hasBlockFormat) {
|
|
2220
|
+
try {
|
|
2221
|
+
const cleanedRaw = stripMarkdownFences(call.parametersRaw);
|
|
2222
|
+
const initialParse = parseBlockParams(cleanedRaw, { argPrefix: this.argPrefix });
|
|
2223
|
+
const parametersWereModified = !this.deepEquals(rawParameters, initialParse);
|
|
2224
|
+
if (parametersWereModified) {
|
|
2225
|
+
this.logger.debug("Parameters modified by interceptor, skipping re-parse", {
|
|
2226
|
+
gadgetName: call.gadgetName
|
|
2227
|
+
});
|
|
2228
|
+
schemaAwareParameters = rawParameters;
|
|
2229
|
+
} else {
|
|
2230
|
+
schemaAwareParameters = parseBlockParams(cleanedRaw, {
|
|
2231
|
+
argPrefix: this.argPrefix,
|
|
2232
|
+
schema: gadget.parameterSchema
|
|
2233
|
+
});
|
|
2234
|
+
this.logger.debug("Re-parsed parameters with schema", {
|
|
2235
|
+
gadgetName: call.gadgetName,
|
|
2236
|
+
original: rawParameters,
|
|
2237
|
+
schemaAware: schemaAwareParameters
|
|
2238
|
+
});
|
|
2239
|
+
}
|
|
2240
|
+
} catch (error) {
|
|
2241
|
+
this.logger.warn("Schema-aware re-parsing failed, using original parameters", {
|
|
2242
|
+
gadgetName: call.gadgetName,
|
|
2243
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2244
|
+
});
|
|
2245
|
+
schemaAwareParameters = rawParameters;
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2248
|
+
if (gadget.parameterSchema) {
|
|
2249
|
+
const validationResult = gadget.parameterSchema.safeParse(schemaAwareParameters);
|
|
2250
|
+
if (!validationResult.success) {
|
|
2251
|
+
const validationError = this.errorFormatter.formatValidationError(
|
|
2252
|
+
call.gadgetName,
|
|
2253
|
+
validationResult.error,
|
|
2254
|
+
gadget
|
|
2255
|
+
);
|
|
2256
|
+
this.logger.error("Gadget parameter validation failed", {
|
|
2257
|
+
gadgetName: call.gadgetName,
|
|
2258
|
+
issueCount: validationResult.error.issues.length
|
|
2259
|
+
});
|
|
2260
|
+
return {
|
|
2261
|
+
gadgetName: call.gadgetName,
|
|
2262
|
+
invocationId: call.invocationId,
|
|
2263
|
+
parameters: schemaAwareParameters,
|
|
2264
|
+
error: validationError,
|
|
2265
|
+
executionTimeMs: Date.now() - startTime
|
|
2266
|
+
};
|
|
2267
|
+
}
|
|
2268
|
+
validatedParameters = validationResult.data;
|
|
2269
|
+
} else {
|
|
2270
|
+
validatedParameters = schemaAwareParameters;
|
|
2271
|
+
}
|
|
2272
|
+
const timeoutMs = gadget.timeoutMs ?? this.defaultGadgetTimeoutMs;
|
|
2273
|
+
let result;
|
|
2274
|
+
if (timeoutMs && timeoutMs > 0) {
|
|
2275
|
+
this.logger.debug("Executing gadget with timeout", {
|
|
2276
|
+
gadgetName: call.gadgetName,
|
|
2277
|
+
timeoutMs
|
|
2278
|
+
});
|
|
2279
|
+
result = await Promise.race([
|
|
2280
|
+
Promise.resolve(gadget.execute(validatedParameters)),
|
|
2281
|
+
this.createTimeoutPromise(call.gadgetName, timeoutMs)
|
|
2282
|
+
]);
|
|
2283
|
+
} else {
|
|
2284
|
+
result = await Promise.resolve(gadget.execute(validatedParameters));
|
|
2285
|
+
}
|
|
2286
|
+
const executionTimeMs = Date.now() - startTime;
|
|
2287
|
+
this.logger.info("Gadget executed successfully", {
|
|
2288
|
+
gadgetName: call.gadgetName,
|
|
2289
|
+
invocationId: call.invocationId,
|
|
2290
|
+
executionTimeMs
|
|
2291
|
+
});
|
|
2292
|
+
this.logger.debug("Gadget result", {
|
|
2293
|
+
gadgetName: call.gadgetName,
|
|
2294
|
+
invocationId: call.invocationId,
|
|
2295
|
+
parameters: validatedParameters,
|
|
2296
|
+
result,
|
|
2297
|
+
executionTimeMs
|
|
2298
|
+
});
|
|
2299
|
+
return {
|
|
2300
|
+
gadgetName: call.gadgetName,
|
|
2301
|
+
invocationId: call.invocationId,
|
|
2302
|
+
parameters: validatedParameters,
|
|
2303
|
+
result,
|
|
2304
|
+
executionTimeMs
|
|
2305
|
+
};
|
|
2306
|
+
} catch (error) {
|
|
2307
|
+
if (error instanceof BreakLoopException) {
|
|
2308
|
+
this.logger.info("Gadget requested loop termination", {
|
|
2309
|
+
gadgetName: call.gadgetName,
|
|
2310
|
+
message: error.message
|
|
2311
|
+
});
|
|
2312
|
+
return {
|
|
2313
|
+
gadgetName: call.gadgetName,
|
|
2314
|
+
invocationId: call.invocationId,
|
|
2315
|
+
parameters: validatedParameters,
|
|
2316
|
+
result: error.message,
|
|
2317
|
+
breaksLoop: true,
|
|
2318
|
+
executionTimeMs: Date.now() - startTime
|
|
2319
|
+
};
|
|
2320
|
+
}
|
|
2321
|
+
if (error instanceof TimeoutException) {
|
|
2322
|
+
this.logger.error("Gadget execution timed out", {
|
|
2323
|
+
gadgetName: call.gadgetName,
|
|
2324
|
+
timeoutMs: error.timeoutMs,
|
|
2325
|
+
executionTimeMs: Date.now() - startTime
|
|
2326
|
+
});
|
|
2327
|
+
return {
|
|
2328
|
+
gadgetName: call.gadgetName,
|
|
2329
|
+
invocationId: call.invocationId,
|
|
2330
|
+
parameters: validatedParameters,
|
|
2331
|
+
error: error.message,
|
|
2332
|
+
executionTimeMs: Date.now() - startTime
|
|
2333
|
+
};
|
|
2334
|
+
}
|
|
2335
|
+
if (error instanceof HumanInputException) {
|
|
2336
|
+
this.logger.info("Gadget requested human input", {
|
|
2337
|
+
gadgetName: call.gadgetName,
|
|
2338
|
+
question: error.question
|
|
2339
|
+
});
|
|
2340
|
+
if (this.onHumanInputRequired) {
|
|
2341
|
+
try {
|
|
2342
|
+
const answer = await this.onHumanInputRequired(error.question);
|
|
2343
|
+
this.logger.debug("Human input received", {
|
|
2344
|
+
gadgetName: call.gadgetName,
|
|
2345
|
+
answerLength: answer.length
|
|
2346
|
+
});
|
|
2347
|
+
return {
|
|
2348
|
+
gadgetName: call.gadgetName,
|
|
2349
|
+
invocationId: call.invocationId,
|
|
2350
|
+
parameters: validatedParameters,
|
|
2351
|
+
result: answer,
|
|
2352
|
+
executionTimeMs: Date.now() - startTime
|
|
2353
|
+
};
|
|
2354
|
+
} catch (inputError) {
|
|
2355
|
+
this.logger.error("Human input callback error", {
|
|
2356
|
+
gadgetName: call.gadgetName,
|
|
2357
|
+
error: inputError instanceof Error ? inputError.message : String(inputError)
|
|
2358
|
+
});
|
|
2359
|
+
return {
|
|
2360
|
+
gadgetName: call.gadgetName,
|
|
2361
|
+
invocationId: call.invocationId,
|
|
2362
|
+
parameters: validatedParameters,
|
|
2363
|
+
error: inputError instanceof Error ? inputError.message : String(inputError),
|
|
2364
|
+
executionTimeMs: Date.now() - startTime
|
|
2365
|
+
};
|
|
2366
|
+
}
|
|
2367
|
+
}
|
|
2368
|
+
this.logger.warn("Human input required but no callback provided", {
|
|
2369
|
+
gadgetName: call.gadgetName
|
|
2370
|
+
});
|
|
2371
|
+
return {
|
|
2372
|
+
gadgetName: call.gadgetName,
|
|
2373
|
+
invocationId: call.invocationId,
|
|
2374
|
+
parameters: validatedParameters,
|
|
2375
|
+
error: "Human input required but not available (stdin is not interactive)",
|
|
2376
|
+
executionTimeMs: Date.now() - startTime
|
|
2377
|
+
};
|
|
2378
|
+
}
|
|
2379
|
+
const executionTimeMs = Date.now() - startTime;
|
|
2380
|
+
this.logger.error("Gadget execution failed", {
|
|
2381
|
+
gadgetName: call.gadgetName,
|
|
2382
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2383
|
+
executionTimeMs
|
|
2384
|
+
});
|
|
2385
|
+
return {
|
|
2386
|
+
gadgetName: call.gadgetName,
|
|
2387
|
+
invocationId: call.invocationId,
|
|
2388
|
+
parameters: validatedParameters,
|
|
2389
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2390
|
+
executionTimeMs
|
|
2391
|
+
};
|
|
2392
|
+
}
|
|
2393
|
+
}
|
|
2394
|
+
// Execute multiple gadget calls in parallel
|
|
2395
|
+
async executeAll(calls) {
|
|
2396
|
+
return Promise.all(calls.map((call) => this.execute(call)));
|
|
2397
|
+
}
|
|
2398
|
+
/**
|
|
2399
|
+
* Deep equality check for objects/arrays.
|
|
2400
|
+
* Used to detect if parameters were modified by an interceptor.
|
|
2401
|
+
*/
|
|
2402
|
+
deepEquals(a, b) {
|
|
2403
|
+
if (a === b) return true;
|
|
2404
|
+
if (a === null || b === null) return a === b;
|
|
2405
|
+
if (typeof a !== typeof b) return false;
|
|
2406
|
+
if (typeof a !== "object") return a === b;
|
|
2407
|
+
if (Array.isArray(a) !== Array.isArray(b)) return false;
|
|
2408
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
2409
|
+
if (a.length !== b.length) return false;
|
|
2410
|
+
return a.every((val, i) => this.deepEquals(val, b[i]));
|
|
2411
|
+
}
|
|
2412
|
+
const aObj = a;
|
|
2413
|
+
const bObj = b;
|
|
2414
|
+
const aKeys = Object.keys(aObj);
|
|
2415
|
+
const bKeys = Object.keys(bObj);
|
|
2416
|
+
if (aKeys.length !== bKeys.length) return false;
|
|
2417
|
+
return aKeys.every((key) => this.deepEquals(aObj[key], bObj[key]));
|
|
2418
|
+
}
|
|
2419
|
+
};
|
|
2420
|
+
}
|
|
2421
|
+
});
|
|
2422
|
+
|
|
2106
2423
|
// src/agent/stream-processor.ts
|
|
2107
2424
|
var StreamProcessor;
|
|
2108
2425
|
var init_stream_processor = __esm({
|
|
@@ -2140,7 +2457,8 @@ var init_stream_processor = __esm({
|
|
|
2140
2457
|
options.registry,
|
|
2141
2458
|
options.onHumanInputRequired,
|
|
2142
2459
|
this.logger.getSubLogger({ name: "executor" }),
|
|
2143
|
-
options.defaultGadgetTimeoutMs
|
|
2460
|
+
options.defaultGadgetTimeoutMs,
|
|
2461
|
+
{ argPrefix: options.gadgetArgPrefix }
|
|
2144
2462
|
);
|
|
2145
2463
|
}
|
|
2146
2464
|
/**
|