llmist 17.2.1 → 17.5.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/README.md +21 -0
- package/dist/chunk-HM7PUGPA.js +2252 -0
- package/dist/chunk-HM7PUGPA.js.map +1 -0
- package/dist/index.cjs +1547 -341
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +452 -23
- package/dist/index.d.ts +452 -23
- package/dist/index.js +635 -1706
- package/dist/index.js.map +1 -1
- package/dist/runtime-GKQ6QIQP.js +187 -0
- package/dist/runtime-GKQ6QIQP.js.map +1 -0
- package/package.json +3 -2
package/dist/index.cjs
CHANGED
|
@@ -358,15 +358,15 @@ var init_execution_tree = __esm({
|
|
|
358
358
|
const parentId = params.parentId ?? this.parentNodeId;
|
|
359
359
|
const parent = parentId ? this.nodes.get(parentId) : null;
|
|
360
360
|
const depth = parent ? parent.depth + 1 : this.baseDepth;
|
|
361
|
-
const
|
|
361
|
+
const path4 = parent ? [...parent.path] : [];
|
|
362
362
|
const id = this.generateLLMCallId(params.iteration, parentId);
|
|
363
|
-
|
|
363
|
+
path4.push(id);
|
|
364
364
|
const node = {
|
|
365
365
|
id,
|
|
366
366
|
type: "llm_call",
|
|
367
367
|
parentId,
|
|
368
368
|
depth,
|
|
369
|
-
path:
|
|
369
|
+
path: path4,
|
|
370
370
|
createdAt: Date.now(),
|
|
371
371
|
completedAt: null,
|
|
372
372
|
iteration: params.iteration,
|
|
@@ -477,15 +477,15 @@ var init_execution_tree = __esm({
|
|
|
477
477
|
const parentId = params.parentId ?? this.getCurrentLLMCallId() ?? this.parentNodeId;
|
|
478
478
|
const parent = parentId ? this.nodes.get(parentId) : null;
|
|
479
479
|
const depth = parent ? parent.depth + 1 : this.baseDepth;
|
|
480
|
-
const
|
|
480
|
+
const path4 = parent ? [...parent.path] : [];
|
|
481
481
|
const id = this.generateGadgetId(params.invocationId);
|
|
482
|
-
|
|
482
|
+
path4.push(id);
|
|
483
483
|
const node = {
|
|
484
484
|
id,
|
|
485
485
|
type: "gadget",
|
|
486
486
|
parentId,
|
|
487
487
|
depth,
|
|
488
|
-
path:
|
|
488
|
+
path: path4,
|
|
489
489
|
createdAt: Date.now(),
|
|
490
490
|
completedAt: null,
|
|
491
491
|
invocationId: params.invocationId,
|
|
@@ -1424,8 +1424,8 @@ ${this.endPrefix}`
|
|
|
1424
1424
|
});
|
|
1425
1425
|
if (media && media.length > 0 && mediaIds && mediaIds.length > 0) {
|
|
1426
1426
|
const idRefs = media.map((m, i) => {
|
|
1427
|
-
const
|
|
1428
|
-
const pathInfo =
|
|
1427
|
+
const path4 = storedMedia?.[i]?.path;
|
|
1428
|
+
const pathInfo = path4 ? ` \u2192 saved to: ${path4}` : "";
|
|
1429
1429
|
return `[Media: ${mediaIds[i]} (${m.kind})${pathInfo}]`;
|
|
1430
1430
|
}).join("\n");
|
|
1431
1431
|
const textWithIds = `Result (${invocationId}): ${result}
|
|
@@ -3071,6 +3071,16 @@ var init_conversation_manager = __esm({
|
|
|
3071
3071
|
getBaseMessages() {
|
|
3072
3072
|
return [...this.baseMessages, ...this.initialMessages];
|
|
3073
3073
|
}
|
|
3074
|
+
/**
|
|
3075
|
+
* Replace the base (system + gadget catalog) messages.
|
|
3076
|
+
*
|
|
3077
|
+
* Used when async setup (e.g. MCP server connect-and-list) discovers
|
|
3078
|
+
* additional gadgets after the agent was constructed. Conversation history
|
|
3079
|
+
* is preserved; only the leading system block is swapped.
|
|
3080
|
+
*/
|
|
3081
|
+
replaceBaseMessages(newBase) {
|
|
3082
|
+
this.baseMessages = newBase;
|
|
3083
|
+
}
|
|
3074
3084
|
replaceHistory(newHistory) {
|
|
3075
3085
|
this.historyBuilder = new LLMMessageBuilder();
|
|
3076
3086
|
if (this.startPrefix && this.endPrefix) {
|
|
@@ -4088,29 +4098,29 @@ function schemaToJSONSchema(schema, options) {
|
|
|
4088
4098
|
}
|
|
4089
4099
|
function detectDescriptionMismatch(schema, jsonSchema) {
|
|
4090
4100
|
const mismatches = [];
|
|
4091
|
-
function checkSchema(zodSchema, json,
|
|
4101
|
+
function checkSchema(zodSchema, json, path4) {
|
|
4092
4102
|
if (!zodSchema || typeof zodSchema !== "object") return;
|
|
4093
4103
|
const def = zodSchema._def;
|
|
4094
4104
|
const jsonObj = json;
|
|
4095
4105
|
if (def?.description && !jsonObj?.description) {
|
|
4096
|
-
mismatches.push(
|
|
4106
|
+
mismatches.push(path4 || "root");
|
|
4097
4107
|
}
|
|
4098
4108
|
if (def?.typeName === "ZodObject" && def?.shape) {
|
|
4099
4109
|
const shape = typeof def.shape === "function" ? def.shape() : def.shape;
|
|
4100
4110
|
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
4101
4111
|
const properties = jsonObj?.properties;
|
|
4102
4112
|
const jsonProp = properties?.[key];
|
|
4103
|
-
checkSchema(fieldSchema, jsonProp,
|
|
4113
|
+
checkSchema(fieldSchema, jsonProp, path4 ? `${path4}.${key}` : key);
|
|
4104
4114
|
}
|
|
4105
4115
|
}
|
|
4106
4116
|
if (def?.typeName === "ZodArray" && def?.type) {
|
|
4107
|
-
checkSchema(def.type, jsonObj?.items,
|
|
4117
|
+
checkSchema(def.type, jsonObj?.items, path4 ? `${path4}[]` : "[]");
|
|
4108
4118
|
}
|
|
4109
4119
|
if ((def?.typeName === "ZodOptional" || def?.typeName === "ZodNullable") && def?.innerType) {
|
|
4110
|
-
checkSchema(def.innerType, json,
|
|
4120
|
+
checkSchema(def.innerType, json, path4);
|
|
4111
4121
|
}
|
|
4112
4122
|
if (def?.typeName === "ZodDefault" && def?.innerType) {
|
|
4113
|
-
checkSchema(def.innerType, json,
|
|
4123
|
+
checkSchema(def.innerType, json, path4);
|
|
4114
4124
|
}
|
|
4115
4125
|
}
|
|
4116
4126
|
checkSchema(schema, jsonSchema, "");
|
|
@@ -4203,7 +4213,7 @@ Example fixes:
|
|
|
4203
4213
|
);
|
|
4204
4214
|
}
|
|
4205
4215
|
}
|
|
4206
|
-
function findUnknownTypes(schema,
|
|
4216
|
+
function findUnknownTypes(schema, path4 = []) {
|
|
4207
4217
|
const issues = [];
|
|
4208
4218
|
if (!schema || typeof schema !== "object") {
|
|
4209
4219
|
return issues;
|
|
@@ -4215,7 +4225,7 @@ function findUnknownTypes(schema, path3 = []) {
|
|
|
4215
4225
|
}
|
|
4216
4226
|
if (schema.properties) {
|
|
4217
4227
|
for (const [propName, propSchema] of Object.entries(schema.properties)) {
|
|
4218
|
-
const propPath = [...
|
|
4228
|
+
const propPath = [...path4, propName];
|
|
4219
4229
|
if (hasNoType(propSchema)) {
|
|
4220
4230
|
issues.push(propPath.join(".") || propName);
|
|
4221
4231
|
}
|
|
@@ -4223,7 +4233,7 @@ function findUnknownTypes(schema, path3 = []) {
|
|
|
4223
4233
|
}
|
|
4224
4234
|
}
|
|
4225
4235
|
if (schema.items) {
|
|
4226
|
-
const itemPath = [...
|
|
4236
|
+
const itemPath = [...path4, "[]"];
|
|
4227
4237
|
if (hasNoType(schema.items)) {
|
|
4228
4238
|
issues.push(itemPath.join("."));
|
|
4229
4239
|
}
|
|
@@ -4231,17 +4241,17 @@ function findUnknownTypes(schema, path3 = []) {
|
|
|
4231
4241
|
}
|
|
4232
4242
|
if (schema.anyOf) {
|
|
4233
4243
|
schema.anyOf.forEach((subSchema, index) => {
|
|
4234
|
-
issues.push(...findUnknownTypes(subSchema, [...
|
|
4244
|
+
issues.push(...findUnknownTypes(subSchema, [...path4, `anyOf[${index}]`]));
|
|
4235
4245
|
});
|
|
4236
4246
|
}
|
|
4237
4247
|
if (schema.oneOf) {
|
|
4238
4248
|
schema.oneOf.forEach((subSchema, index) => {
|
|
4239
|
-
issues.push(...findUnknownTypes(subSchema, [...
|
|
4249
|
+
issues.push(...findUnknownTypes(subSchema, [...path4, `oneOf[${index}]`]));
|
|
4240
4250
|
});
|
|
4241
4251
|
}
|
|
4242
4252
|
if (schema.allOf) {
|
|
4243
4253
|
schema.allOf.forEach((subSchema, index) => {
|
|
4244
|
-
issues.push(...findUnknownTypes(subSchema, [...
|
|
4254
|
+
issues.push(...findUnknownTypes(subSchema, [...path4, `allOf[${index}]`]));
|
|
4245
4255
|
});
|
|
4246
4256
|
}
|
|
4247
4257
|
return issues;
|
|
@@ -4660,6 +4670,9 @@ var init_create_gadget = __esm({
|
|
|
4660
4670
|
});
|
|
4661
4671
|
|
|
4662
4672
|
// src/gadgets/output-viewer.ts
|
|
4673
|
+
function pluralize(count, singular, plural = `${singular}s`) {
|
|
4674
|
+
return count === 1 ? singular : plural;
|
|
4675
|
+
}
|
|
4663
4676
|
function applyPattern(lines, pattern) {
|
|
4664
4677
|
const regex = new RegExp(pattern.regex);
|
|
4665
4678
|
if (!pattern.include) {
|
|
@@ -4684,80 +4697,169 @@ function applyPatterns(lines, patterns) {
|
|
|
4684
4697
|
}
|
|
4685
4698
|
return result;
|
|
4686
4699
|
}
|
|
4687
|
-
function
|
|
4700
|
+
function parseLimitWindow(limit) {
|
|
4688
4701
|
const trimmed = limit.trim();
|
|
4689
4702
|
if (trimmed.endsWith("-") && !trimmed.startsWith("-")) {
|
|
4690
4703
|
const n = parseInt(trimmed.slice(0, -1), 10);
|
|
4691
|
-
if (!isNaN(n) && n > 0) {
|
|
4692
|
-
return
|
|
4704
|
+
if (!Number.isNaN(n) && n > 0) {
|
|
4705
|
+
return { kind: "first", count: n };
|
|
4693
4706
|
}
|
|
4694
4707
|
}
|
|
4695
4708
|
if (trimmed.startsWith("-") && !trimmed.includes("-", 1)) {
|
|
4696
4709
|
const n = parseInt(trimmed, 10);
|
|
4697
|
-
if (!isNaN(n) && n < 0) {
|
|
4698
|
-
return
|
|
4710
|
+
if (!Number.isNaN(n) && n < 0) {
|
|
4711
|
+
return { kind: "last", count: Math.abs(n) };
|
|
4699
4712
|
}
|
|
4700
4713
|
}
|
|
4701
4714
|
const rangeMatch = trimmed.match(/^(\d+)-(\d+)$/);
|
|
4702
4715
|
if (rangeMatch) {
|
|
4703
4716
|
const start = parseInt(rangeMatch[1], 10);
|
|
4704
4717
|
const end = parseInt(rangeMatch[2], 10);
|
|
4705
|
-
if (!isNaN(start) && !isNaN(end) && start > 0 && end >= start) {
|
|
4706
|
-
return
|
|
4718
|
+
if (!Number.isNaN(start) && !Number.isNaN(end) && start > 0 && end >= start) {
|
|
4719
|
+
return { kind: "range", start, end };
|
|
4720
|
+
}
|
|
4721
|
+
}
|
|
4722
|
+
return null;
|
|
4723
|
+
}
|
|
4724
|
+
function applyLineLimit(lines, limit) {
|
|
4725
|
+
const window = parseLimitWindow(limit);
|
|
4726
|
+
if (!window) return lines;
|
|
4727
|
+
switch (window.kind) {
|
|
4728
|
+
case "first":
|
|
4729
|
+
return lines.slice(0, window.count);
|
|
4730
|
+
case "last":
|
|
4731
|
+
return lines.slice(-window.count);
|
|
4732
|
+
case "range":
|
|
4733
|
+
return lines.slice(window.start - 1, window.end);
|
|
4734
|
+
}
|
|
4735
|
+
}
|
|
4736
|
+
function applyCharacterLimit(content, limit, maxOutputChars) {
|
|
4737
|
+
const total = content.length;
|
|
4738
|
+
if (total === 0) {
|
|
4739
|
+
return { text: "", start: 0, end: 0, total: 0, truncatedBySize: false, hasMoreAfter: false };
|
|
4740
|
+
}
|
|
4741
|
+
let startIndex = 0;
|
|
4742
|
+
let endExclusive = total;
|
|
4743
|
+
const window = limit ? parseLimitWindow(limit) : null;
|
|
4744
|
+
if (window) {
|
|
4745
|
+
switch (window.kind) {
|
|
4746
|
+
case "first":
|
|
4747
|
+
endExclusive = Math.min(window.count, total);
|
|
4748
|
+
break;
|
|
4749
|
+
case "last":
|
|
4750
|
+
startIndex = Math.max(0, total - window.count);
|
|
4751
|
+
break;
|
|
4752
|
+
case "range":
|
|
4753
|
+
startIndex = Math.min(window.start - 1, total);
|
|
4754
|
+
endExclusive = Math.min(window.end, total);
|
|
4755
|
+
break;
|
|
4707
4756
|
}
|
|
4708
4757
|
}
|
|
4709
|
-
|
|
4758
|
+
let text3 = content.slice(startIndex, endExclusive);
|
|
4759
|
+
let truncatedBySize = false;
|
|
4760
|
+
if (text3.length > maxOutputChars) {
|
|
4761
|
+
text3 = window?.kind === "last" ? text3.slice(-maxOutputChars) : text3.slice(0, maxOutputChars);
|
|
4762
|
+
if (window?.kind === "last") {
|
|
4763
|
+
startIndex = endExclusive - text3.length;
|
|
4764
|
+
}
|
|
4765
|
+
truncatedBySize = true;
|
|
4766
|
+
}
|
|
4767
|
+
return {
|
|
4768
|
+
text: text3,
|
|
4769
|
+
start: text3.length === 0 ? 0 : startIndex + 1,
|
|
4770
|
+
end: text3.length === 0 ? 0 : startIndex + text3.length,
|
|
4771
|
+
total,
|
|
4772
|
+
truncatedBySize,
|
|
4773
|
+
hasMoreAfter: startIndex + text3.length < total
|
|
4774
|
+
};
|
|
4775
|
+
}
|
|
4776
|
+
function buildCharacterRangeHint(start, total) {
|
|
4777
|
+
if (total <= 0 || start > total) return null;
|
|
4778
|
+
const end = Math.min(total, start + CHARACTER_HINT_WINDOW - 1);
|
|
4779
|
+
return `${start}-${end}`;
|
|
4780
|
+
}
|
|
4781
|
+
function buildCharacterModeSuggestion(stored, opts = {}) {
|
|
4782
|
+
const hint = buildCharacterRangeHint(opts.start ?? 1, stored.charCount);
|
|
4783
|
+
const action = opts.removePatterns ? "Remove patterns and then try" : "Try";
|
|
4784
|
+
const lineLabel = pluralize(stored.lineCount, "line");
|
|
4785
|
+
return `This output is dense (${stored.lineCount.toLocaleString()} ${lineLabel}; longest line ${stored.maxLineLength.toLocaleString()} chars). ${action} mode: "character"` + (hint ? `, limit: "${hint}"` : "") + ".";
|
|
4786
|
+
}
|
|
4787
|
+
function shouldSuggestCharacterMode(stored, maxOutputChars = DEFAULT_MAX_OUTPUT_CHARS) {
|
|
4788
|
+
return stored.lineCount <= 3 && (stored.maxLineLength > maxOutputChars || stored.maxLineLength >= DENSE_LINE_THRESHOLD);
|
|
4710
4789
|
}
|
|
4711
4790
|
function createGadgetOutputViewer(store, maxOutputChars = DEFAULT_MAX_OUTPUT_CHARS) {
|
|
4712
4791
|
return createGadget({
|
|
4713
4792
|
name: "GadgetOutputViewer",
|
|
4714
|
-
description:
|
|
4793
|
+
description: 'View stored output from gadgets that returned too much data. Use mode "line" for grep-like filtering and mode "character" for raw chunked browsing when the output is dense or effectively single-line. Patterns work only in line mode.',
|
|
4715
4794
|
schema: import_zod.z.object({
|
|
4716
4795
|
id: import_zod.z.string().describe("ID of the stored output (from the truncation message)"),
|
|
4796
|
+
mode: import_zod.z.enum(["line", "character"]).default("line").describe(
|
|
4797
|
+
'Browse by "line" (supports patterns) or by "character" (raw windows for dense output).'
|
|
4798
|
+
),
|
|
4717
4799
|
patterns: import_zod.z.array(patternSchema).optional().describe(
|
|
4718
|
-
|
|
4800
|
+
'Line-mode filter patterns applied in order (like piping through grep). Not supported in mode "character".'
|
|
4719
4801
|
),
|
|
4720
4802
|
limit: import_zod.z.string().optional().describe(
|
|
4721
|
-
"
|
|
4803
|
+
`Pagination window. In mode "line" it is a line range; in mode "character" it is a character range. Formats: "100-" (first 100), "-25" (last 25), "50-100" (inclusive range).`
|
|
4722
4804
|
)
|
|
4723
4805
|
}),
|
|
4724
4806
|
examples: [
|
|
4725
4807
|
{
|
|
4726
4808
|
comment: "View first 50 lines of stored output",
|
|
4727
|
-
params: { id: "Search_abc12345", limit: "50-" }
|
|
4809
|
+
params: { id: "Search_abc12345", mode: "line", limit: "50-" }
|
|
4728
4810
|
},
|
|
4729
4811
|
{
|
|
4730
4812
|
comment: "Filter for error lines with context",
|
|
4731
4813
|
params: {
|
|
4732
4814
|
id: "Search_abc12345",
|
|
4815
|
+
mode: "line",
|
|
4733
4816
|
patterns: [{ regex: "error|Error|ERROR", include: true, before: 2, after: 5 }]
|
|
4734
4817
|
}
|
|
4735
4818
|
},
|
|
4736
4819
|
{
|
|
4737
|
-
comment: "Exclude blank lines, then show first 100",
|
|
4820
|
+
comment: "Exclude blank lines, then show first 100 lines",
|
|
4738
4821
|
params: {
|
|
4739
4822
|
id: "Search_abc12345",
|
|
4823
|
+
mode: "line",
|
|
4740
4824
|
patterns: [{ regex: "^\\s*$", include: false, before: 0, after: 0 }],
|
|
4741
4825
|
limit: "100-"
|
|
4742
4826
|
}
|
|
4743
4827
|
},
|
|
4744
4828
|
{
|
|
4745
|
-
comment: "
|
|
4829
|
+
comment: "Browse the raw output by character window when line mode is too dense",
|
|
4746
4830
|
params: {
|
|
4747
4831
|
id: "Search_abc12345",
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
{ regex: "test|spec", include: false, before: 0, after: 0 }
|
|
4751
|
-
],
|
|
4752
|
-
limit: "50-"
|
|
4832
|
+
mode: "character",
|
|
4833
|
+
limit: "1-2000"
|
|
4753
4834
|
}
|
|
4754
4835
|
}
|
|
4755
4836
|
],
|
|
4756
|
-
execute: ({ id, patterns, limit }) => {
|
|
4837
|
+
execute: ({ id, mode, patterns, limit }) => {
|
|
4757
4838
|
const stored = store.get(id);
|
|
4758
4839
|
if (!stored) {
|
|
4759
4840
|
return `Error: No stored output with id "${id}". Available IDs: ${store.getIds().join(", ") || "(none)"}`;
|
|
4760
4841
|
}
|
|
4842
|
+
const suggestCharacterMode = shouldSuggestCharacterMode(stored, maxOutputChars);
|
|
4843
|
+
if (mode === "character") {
|
|
4844
|
+
if (patterns && patterns.length > 0) {
|
|
4845
|
+
return 'Error: patterns are only supported in mode "line". Remove patterns or switch back to mode: "line".';
|
|
4846
|
+
}
|
|
4847
|
+
const window = applyCharacterLimit(stored.content, limit, maxOutputChars);
|
|
4848
|
+
if (window.total === 0) {
|
|
4849
|
+
return "[Mode: character | Output is empty]";
|
|
4850
|
+
}
|
|
4851
|
+
const header2 = [
|
|
4852
|
+
`[Mode: character | Showing chars ${window.start.toLocaleString()}-${window.end.toLocaleString()} of ${window.total.toLocaleString()}${window.truncatedBySize ? " (truncated due to viewer size limit)" : ""}]`
|
|
4853
|
+
];
|
|
4854
|
+
if (window.hasMoreAfter) {
|
|
4855
|
+
const nextRange = buildCharacterRangeHint(window.end + 1, window.total);
|
|
4856
|
+
if (nextRange) {
|
|
4857
|
+
header2.push(`[Next chunk: mode: "character", limit: "${nextRange}"]`);
|
|
4858
|
+
}
|
|
4859
|
+
}
|
|
4860
|
+
return `${header2.join("\n")}
|
|
4861
|
+
${window.text}`;
|
|
4862
|
+
}
|
|
4761
4863
|
let lines = stored.content.split("\n");
|
|
4762
4864
|
if (patterns && patterns.length > 0) {
|
|
4763
4865
|
lines = applyPatterns(
|
|
@@ -4773,55 +4875,77 @@ function createGadgetOutputViewer(store, maxOutputChars = DEFAULT_MAX_OUTPUT_CHA
|
|
|
4773
4875
|
if (limit) {
|
|
4774
4876
|
lines = applyLineLimit(lines, limit);
|
|
4775
4877
|
}
|
|
4776
|
-
let output = lines.join("\n");
|
|
4777
4878
|
const totalLines = stored.lineCount;
|
|
4879
|
+
const totalLineLabel = pluralize(totalLines, "line");
|
|
4778
4880
|
const returnedLines = lines.length;
|
|
4779
4881
|
if (returnedLines === 0) {
|
|
4780
|
-
|
|
4882
|
+
const base = `No lines matched the filters. Original output had ${totalLines.toLocaleString()} lines.`;
|
|
4883
|
+
if (!suggestCharacterMode) return base;
|
|
4884
|
+
return `${base} ${buildCharacterModeSuggestion(stored, {
|
|
4885
|
+
removePatterns: Boolean(patterns && patterns.length > 0)
|
|
4886
|
+
})}`;
|
|
4781
4887
|
}
|
|
4888
|
+
let output = lines.join("\n");
|
|
4782
4889
|
let truncatedBySize = false;
|
|
4783
4890
|
let linesIncluded = returnedLines;
|
|
4891
|
+
let clippedFirstLine = false;
|
|
4784
4892
|
if (output.length > maxOutputChars) {
|
|
4785
4893
|
truncatedBySize = true;
|
|
4786
4894
|
let truncatedOutput = "";
|
|
4787
4895
|
linesIncluded = 0;
|
|
4788
4896
|
for (const line of lines) {
|
|
4789
|
-
|
|
4790
|
-
|
|
4897
|
+
const addition = linesIncluded === 0 ? line : `
|
|
4898
|
+
${line}`;
|
|
4899
|
+
if (truncatedOutput.length + addition.length > maxOutputChars) break;
|
|
4900
|
+
truncatedOutput += addition;
|
|
4791
4901
|
linesIncluded++;
|
|
4792
4902
|
}
|
|
4903
|
+
if (linesIncluded === 0) {
|
|
4904
|
+
clippedFirstLine = true;
|
|
4905
|
+
linesIncluded = 1;
|
|
4906
|
+
truncatedOutput = lines[0].slice(0, maxOutputChars);
|
|
4907
|
+
}
|
|
4793
4908
|
output = truncatedOutput;
|
|
4794
4909
|
}
|
|
4795
4910
|
let header;
|
|
4796
|
-
if (
|
|
4911
|
+
if (clippedFirstLine) {
|
|
4912
|
+
header = `[Mode: line | Showing 1 partial line of ${totalLines.toLocaleString()} ${totalLineLabel} (the selected line exceeds the viewer size limit)]
|
|
4913
|
+
`;
|
|
4914
|
+
} else if (truncatedBySize) {
|
|
4797
4915
|
const remainingLines = returnedLines - linesIncluded;
|
|
4798
|
-
header = `[Showing ${linesIncluded} of ${totalLines}
|
|
4799
|
-
[... ${remainingLines.toLocaleString()} more
|
|
4916
|
+
header = `[Mode: line | Showing ${linesIncluded.toLocaleString()} of ${totalLines.toLocaleString()} ${totalLineLabel} (truncated due to size limit)]
|
|
4917
|
+
[... ${remainingLines.toLocaleString()} more ${pluralize(remainingLines, "line")}. Use limit parameter to paginate, e.g., limit: "${linesIncluded + 1}-${linesIncluded + 200}"]
|
|
4800
4918
|
`;
|
|
4801
4919
|
} else if (returnedLines < totalLines) {
|
|
4802
|
-
header = `[Showing ${returnedLines} of ${totalLines}
|
|
4920
|
+
header = `[Mode: line | Showing ${returnedLines.toLocaleString()} of ${totalLines.toLocaleString()} ${totalLineLabel}]
|
|
4803
4921
|
`;
|
|
4804
4922
|
} else {
|
|
4805
|
-
header = `[Showing all ${totalLines}
|
|
4923
|
+
header = `[Mode: line | Showing all ${totalLines.toLocaleString()} ${totalLineLabel}]
|
|
4806
4924
|
`;
|
|
4807
4925
|
}
|
|
4808
|
-
|
|
4926
|
+
const footer = suggestCharacterMode || clippedFirstLine ? `
|
|
4927
|
+
[Tip: ${buildCharacterModeSuggestion(stored, {
|
|
4928
|
+
removePatterns: Boolean(patterns && patterns.length > 0)
|
|
4929
|
+
})}]` : "";
|
|
4930
|
+
return header + output + footer;
|
|
4809
4931
|
}
|
|
4810
4932
|
});
|
|
4811
4933
|
}
|
|
4812
|
-
var import_zod,
|
|
4934
|
+
var import_zod, DEFAULT_MAX_OUTPUT_CHARS, CHARACTER_HINT_WINDOW, DENSE_LINE_THRESHOLD, patternSchema;
|
|
4813
4935
|
var init_output_viewer = __esm({
|
|
4814
4936
|
"src/gadgets/output-viewer.ts"() {
|
|
4815
4937
|
"use strict";
|
|
4816
4938
|
import_zod = require("zod");
|
|
4817
4939
|
init_create_gadget();
|
|
4940
|
+
DEFAULT_MAX_OUTPUT_CHARS = 76800;
|
|
4941
|
+
CHARACTER_HINT_WINDOW = 2e3;
|
|
4942
|
+
DENSE_LINE_THRESHOLD = 4e3;
|
|
4818
4943
|
patternSchema = import_zod.z.object({
|
|
4819
4944
|
regex: import_zod.z.string().describe("Regular expression to match"),
|
|
4820
4945
|
include: import_zod.z.boolean().default(true).describe("true = keep matching lines, false = exclude matching lines"),
|
|
4821
4946
|
before: import_zod.z.number().int().min(0).default(0).describe("Context lines before each match (like grep -B)"),
|
|
4822
4947
|
after: import_zod.z.number().int().min(0).default(0).describe("Context lines after each match (like grep -A)")
|
|
4823
4948
|
});
|
|
4824
|
-
DEFAULT_MAX_OUTPUT_CHARS = 76800;
|
|
4825
4949
|
}
|
|
4826
4950
|
});
|
|
4827
4951
|
|
|
@@ -4843,12 +4967,15 @@ var init_gadget_output_store = __esm({
|
|
|
4843
4967
|
store(gadgetName, content) {
|
|
4844
4968
|
const id = this.generateId(gadgetName);
|
|
4845
4969
|
const encoder = new TextEncoder();
|
|
4970
|
+
const lines = content.split("\n");
|
|
4846
4971
|
const stored = {
|
|
4847
4972
|
id,
|
|
4848
4973
|
gadgetName,
|
|
4849
4974
|
content,
|
|
4975
|
+
charCount: content.length,
|
|
4850
4976
|
byteSize: encoder.encode(content).length,
|
|
4851
|
-
lineCount:
|
|
4977
|
+
lineCount: lines.length,
|
|
4978
|
+
maxLineLength: lines.reduce((max, line) => Math.max(max, line.length), 0),
|
|
4852
4979
|
timestamp: /* @__PURE__ */ new Date()
|
|
4853
4980
|
};
|
|
4854
4981
|
this.outputs.set(id, stored);
|
|
@@ -4952,16 +5079,20 @@ var init_output_limit_manager = __esm({
|
|
|
4952
5079
|
}
|
|
4953
5080
|
if (result.length > this.charLimit) {
|
|
4954
5081
|
const id = this.outputStore.store(ctx.gadgetName, result);
|
|
4955
|
-
const
|
|
4956
|
-
const
|
|
5082
|
+
const stored = this.outputStore.get(id);
|
|
5083
|
+
const lines = stored?.lineCount ?? result.split("\n").length;
|
|
5084
|
+
const bytes = stored?.byteSize ?? new TextEncoder().encode(result).length;
|
|
5085
|
+
const denseSuggestion = stored && shouldSuggestCharacterMode(stored, this.charLimit) ? ` ${buildCharacterModeSuggestion(stored)}` : "";
|
|
4957
5086
|
this.logger.info("Gadget output exceeded limit, stored for browsing", {
|
|
4958
5087
|
gadgetName: ctx.gadgetName,
|
|
4959
5088
|
outputId: id,
|
|
4960
5089
|
bytes,
|
|
4961
5090
|
lines,
|
|
5091
|
+
charCount: stored?.charCount,
|
|
5092
|
+
maxLineLength: stored?.maxLineLength,
|
|
4962
5093
|
charLimit: this.charLimit
|
|
4963
5094
|
});
|
|
4964
|
-
return `[Gadget "${ctx.gadgetName}" returned too much data: ${bytes.toLocaleString()} bytes, ${lines.toLocaleString()} lines. Use GadgetOutputViewer with id "${id}" to read it]
|
|
5095
|
+
return `[Gadget "${ctx.gadgetName}" returned too much data: ${bytes.toLocaleString()} bytes, ${lines.toLocaleString()} lines. Use GadgetOutputViewer with id "${id}" to read it.]` + denseSuggestion;
|
|
4965
5096
|
}
|
|
4966
5097
|
return result;
|
|
4967
5098
|
};
|
|
@@ -13111,6 +13242,7 @@ var init_builder = __esm({
|
|
|
13111
13242
|
subagents;
|
|
13112
13243
|
policies;
|
|
13113
13244
|
skills;
|
|
13245
|
+
mcp;
|
|
13114
13246
|
constructor(client) {
|
|
13115
13247
|
this.core = { client, initialMessages: [] };
|
|
13116
13248
|
this.gadgets = { gadgets: [] };
|
|
@@ -13118,6 +13250,7 @@ var init_builder = __esm({
|
|
|
13118
13250
|
this.subagents = {};
|
|
13119
13251
|
this.policies = {};
|
|
13120
13252
|
this.skills = { preActivated: [], skillDirs: [] };
|
|
13253
|
+
this.mcp = { servers: [] };
|
|
13121
13254
|
}
|
|
13122
13255
|
/** Set the model to use. Supports aliases like "sonnet", "flash". */
|
|
13123
13256
|
withModel(model) {
|
|
@@ -13164,6 +13297,45 @@ var init_builder = __esm({
|
|
|
13164
13297
|
this.gadgets.gadgets.push(...gadgets);
|
|
13165
13298
|
return this;
|
|
13166
13299
|
}
|
|
13300
|
+
/**
|
|
13301
|
+
* Attach a Model Context Protocol (MCP) server.
|
|
13302
|
+
*
|
|
13303
|
+
* The agent connects to the server lazily at the start of `run()`,
|
|
13304
|
+
* discovers its tools, and registers them as native gadgets so the LLM
|
|
13305
|
+
* can call them through the standard streaming block format.
|
|
13306
|
+
*
|
|
13307
|
+
* Calling this multiple times accumulates servers. Tools across servers
|
|
13308
|
+
* are merged into a single registry; in plan 1, conflicting tool names
|
|
13309
|
+
* raise a registration warning. Plan 2 introduces deterministic
|
|
13310
|
+
* `<server>__<tool>` prefixing for collisions.
|
|
13311
|
+
*
|
|
13312
|
+
* STDIO commands are gated by an allowlist (see allowlist.ts) — pass
|
|
13313
|
+
* `trust: true` on the spec to opt in for non-allowlisted binaries.
|
|
13314
|
+
*
|
|
13315
|
+
* Zero-overhead invariant: if you never call this method, the MCP
|
|
13316
|
+
* runtime module is never loaded. Agents without MCP pay nothing.
|
|
13317
|
+
*
|
|
13318
|
+
* @example
|
|
13319
|
+
* ```typescript
|
|
13320
|
+
* const agent = LLMist.createAgent()
|
|
13321
|
+
* .withModel("sonnet")
|
|
13322
|
+
* .withMcpServer({
|
|
13323
|
+
* name: "filesystem",
|
|
13324
|
+
* transport: "stdio",
|
|
13325
|
+
* command: "npx",
|
|
13326
|
+
* args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
|
|
13327
|
+
* })
|
|
13328
|
+
* .ask("list files in /tmp");
|
|
13329
|
+
* ```
|
|
13330
|
+
*/
|
|
13331
|
+
withMcpServer(spec) {
|
|
13332
|
+
this.mcp.servers.push(spec);
|
|
13333
|
+
return this;
|
|
13334
|
+
}
|
|
13335
|
+
/** Inspect the configured MCP server specs. Useful for tests. */
|
|
13336
|
+
getMcpServerSpecs() {
|
|
13337
|
+
return this.mcp.servers;
|
|
13338
|
+
}
|
|
13167
13339
|
/** Add conversation history messages. */
|
|
13168
13340
|
withHistory(messages) {
|
|
13169
13341
|
this.core.initialMessages.push(...normalizeHistory(messages));
|
|
@@ -13484,7 +13656,8 @@ ${preActivatedBlock}` : preActivatedBlock;
|
|
|
13484
13656
|
parentObservers: this.subagents.parentObservers
|
|
13485
13657
|
},
|
|
13486
13658
|
sharedRateLimitTracker: this.subagents.sharedRateLimitTracker,
|
|
13487
|
-
sharedRetryConfig: this.retry.sharedRetryConfig
|
|
13659
|
+
sharedRetryConfig: this.retry.sharedRetryConfig,
|
|
13660
|
+
mcpSpecs: this.mcp.servers.length > 0 ? [...this.mcp.servers] : void 0
|
|
13488
13661
|
};
|
|
13489
13662
|
}
|
|
13490
13663
|
/** Create agent and start with a user prompt. */
|
|
@@ -14130,8 +14303,8 @@ var init_error_formatter = __esm({
|
|
|
14130
14303
|
const parts = [];
|
|
14131
14304
|
parts.push(`Error: Invalid parameters for '${gadgetName}':`);
|
|
14132
14305
|
for (const issue of zodError.issues) {
|
|
14133
|
-
const
|
|
14134
|
-
parts.push(` - ${
|
|
14306
|
+
const path4 = issue.path.join(".") || "root";
|
|
14307
|
+
parts.push(` - ${path4}: ${issue.message}`);
|
|
14135
14308
|
}
|
|
14136
14309
|
parts.push("");
|
|
14137
14310
|
parts.push("Gadget Usage:");
|
|
@@ -16491,157 +16664,1054 @@ var init_stream_processor_factory = __esm({
|
|
|
16491
16664
|
}
|
|
16492
16665
|
});
|
|
16493
16666
|
|
|
16494
|
-
// src/
|
|
16495
|
-
var
|
|
16496
|
-
var
|
|
16497
|
-
"src/
|
|
16667
|
+
// src/mcp/errors.ts
|
|
16668
|
+
var McpError, McpUntrustedCommandError, McpConnectError, McpToolCallError, McpTimeoutError, JsonSchemaConversionError;
|
|
16669
|
+
var init_errors = __esm({
|
|
16670
|
+
"src/mcp/errors.ts"() {
|
|
16498
16671
|
"use strict";
|
|
16499
|
-
|
|
16500
|
-
|
|
16501
|
-
|
|
16502
|
-
|
|
16503
|
-
|
|
16504
|
-
|
|
16505
|
-
|
|
16506
|
-
|
|
16507
|
-
|
|
16508
|
-
|
|
16509
|
-
|
|
16510
|
-
|
|
16511
|
-
|
|
16512
|
-
|
|
16513
|
-
|
|
16514
|
-
|
|
16515
|
-
|
|
16516
|
-
|
|
16517
|
-
|
|
16518
|
-
|
|
16519
|
-
|
|
16520
|
-
|
|
16521
|
-
|
|
16522
|
-
|
|
16523
|
-
|
|
16524
|
-
|
|
16525
|
-
|
|
16526
|
-
|
|
16527
|
-
|
|
16528
|
-
|
|
16529
|
-
|
|
16530
|
-
|
|
16531
|
-
|
|
16532
|
-
|
|
16533
|
-
|
|
16534
|
-
|
|
16535
|
-
|
|
16536
|
-
|
|
16537
|
-
|
|
16538
|
-
|
|
16539
|
-
|
|
16540
|
-
|
|
16541
|
-
|
|
16542
|
-
|
|
16543
|
-
|
|
16544
|
-
|
|
16545
|
-
|
|
16546
|
-
|
|
16547
|
-
|
|
16548
|
-
|
|
16549
|
-
|
|
16550
|
-
|
|
16551
|
-
|
|
16552
|
-
|
|
16553
|
-
|
|
16554
|
-
|
|
16555
|
-
|
|
16556
|
-
|
|
16557
|
-
|
|
16558
|
-
|
|
16559
|
-
|
|
16560
|
-
|
|
16561
|
-
|
|
16562
|
-
|
|
16563
|
-
|
|
16564
|
-
|
|
16565
|
-
|
|
16566
|
-
|
|
16672
|
+
McpError = class extends Error {
|
|
16673
|
+
serverName;
|
|
16674
|
+
constructor(message, serverName) {
|
|
16675
|
+
super(message);
|
|
16676
|
+
this.name = "McpError";
|
|
16677
|
+
this.serverName = serverName;
|
|
16678
|
+
}
|
|
16679
|
+
};
|
|
16680
|
+
McpUntrustedCommandError = class extends McpError {
|
|
16681
|
+
command;
|
|
16682
|
+
constructor(command, serverName) {
|
|
16683
|
+
super(
|
|
16684
|
+
`Refusing to spawn MCP stdio command "${command}" because its basename is not in the default allowlist. To opt in, set { trust: true } on the server spec (library), or trust = true in your TOML mcp.servers block, or pass --mcp-trust ${serverName ?? "<name>"} on the CLI. See https://llmist.dev/library/advanced/mcp-security/ for context (CVE-2026-30623).`,
|
|
16685
|
+
serverName
|
|
16686
|
+
);
|
|
16687
|
+
this.name = "McpUntrustedCommandError";
|
|
16688
|
+
this.command = command;
|
|
16689
|
+
}
|
|
16690
|
+
};
|
|
16691
|
+
McpConnectError = class extends McpError {
|
|
16692
|
+
cause;
|
|
16693
|
+
constructor(message, opts) {
|
|
16694
|
+
super(message, opts?.serverName);
|
|
16695
|
+
this.name = "McpConnectError";
|
|
16696
|
+
this.cause = opts?.cause;
|
|
16697
|
+
}
|
|
16698
|
+
};
|
|
16699
|
+
McpToolCallError = class extends McpError {
|
|
16700
|
+
toolName;
|
|
16701
|
+
cause;
|
|
16702
|
+
constructor(toolName, message, opts) {
|
|
16703
|
+
super(message, opts?.serverName);
|
|
16704
|
+
this.name = "McpToolCallError";
|
|
16705
|
+
this.toolName = toolName;
|
|
16706
|
+
this.cause = opts?.cause;
|
|
16707
|
+
}
|
|
16708
|
+
};
|
|
16709
|
+
McpTimeoutError = class extends McpError {
|
|
16710
|
+
operation;
|
|
16711
|
+
timeoutMs;
|
|
16712
|
+
constructor(operation, timeoutMs, serverName) {
|
|
16713
|
+
super(
|
|
16714
|
+
`MCP operation "${operation}" on server "${serverName ?? "<unknown>"}" timed out after ${timeoutMs}ms`,
|
|
16715
|
+
serverName
|
|
16716
|
+
);
|
|
16717
|
+
this.name = "McpTimeoutError";
|
|
16718
|
+
this.operation = operation;
|
|
16719
|
+
this.timeoutMs = timeoutMs;
|
|
16720
|
+
}
|
|
16721
|
+
};
|
|
16722
|
+
JsonSchemaConversionError = class extends Error {
|
|
16723
|
+
schemaFragment;
|
|
16724
|
+
reason;
|
|
16725
|
+
constructor(reason, schemaFragment) {
|
|
16726
|
+
super(`JSON Schema \u2192 Zod conversion failed: ${reason}`);
|
|
16727
|
+
this.name = "JsonSchemaConversionError";
|
|
16728
|
+
this.reason = reason;
|
|
16729
|
+
this.schemaFragment = schemaFragment;
|
|
16730
|
+
}
|
|
16731
|
+
};
|
|
16732
|
+
}
|
|
16733
|
+
});
|
|
16734
|
+
|
|
16735
|
+
// src/mcp/allowlist.ts
|
|
16736
|
+
function assertCommandAllowed(command, trusted, customAllowlist) {
|
|
16737
|
+
if (!command || typeof command !== "string") {
|
|
16738
|
+
throw new McpUntrustedCommandError(String(command));
|
|
16739
|
+
}
|
|
16740
|
+
if (WHITESPACE_OR_META_RE.test(command)) {
|
|
16741
|
+
throw new McpUntrustedCommandError(command);
|
|
16742
|
+
}
|
|
16743
|
+
if (trusted) return;
|
|
16744
|
+
const allowlist = customAllowlist ?? DEFAULT_MCP_COMMAND_ALLOWLIST;
|
|
16745
|
+
const base = import_node_path6.default.basename(command);
|
|
16746
|
+
if (!allowlist.has(base)) {
|
|
16747
|
+
throw new McpUntrustedCommandError(command);
|
|
16748
|
+
}
|
|
16749
|
+
}
|
|
16750
|
+
var import_node_path6, DEFAULT_MCP_COMMAND_ALLOWLIST, WHITESPACE_OR_META_RE;
|
|
16751
|
+
var init_allowlist = __esm({
|
|
16752
|
+
"src/mcp/allowlist.ts"() {
|
|
16753
|
+
"use strict";
|
|
16754
|
+
import_node_path6 = __toESM(require("path"), 1);
|
|
16755
|
+
init_errors();
|
|
16756
|
+
DEFAULT_MCP_COMMAND_ALLOWLIST = /* @__PURE__ */ new Set([
|
|
16757
|
+
"npx",
|
|
16758
|
+
"node",
|
|
16759
|
+
"uvx",
|
|
16760
|
+
"uv",
|
|
16761
|
+
"python",
|
|
16762
|
+
"python3",
|
|
16763
|
+
"deno",
|
|
16764
|
+
"bun"
|
|
16765
|
+
]);
|
|
16766
|
+
WHITESPACE_OR_META_RE = /[\s;|&`$<>()'"\\]/;
|
|
16767
|
+
}
|
|
16768
|
+
});
|
|
16769
|
+
|
|
16770
|
+
// src/mcp/client.ts
|
|
16771
|
+
async function loadSdk() {
|
|
16772
|
+
if (!cachedSdk) {
|
|
16773
|
+
cachedSdk = (async () => {
|
|
16774
|
+
const [client, stdio, http] = await Promise.all([
|
|
16775
|
+
import("@modelcontextprotocol/sdk/client/index.js"),
|
|
16776
|
+
import("@modelcontextprotocol/sdk/client/stdio.js"),
|
|
16777
|
+
import("@modelcontextprotocol/sdk/client/streamableHttp.js")
|
|
16778
|
+
]);
|
|
16779
|
+
return {
|
|
16780
|
+
Client: client.Client,
|
|
16781
|
+
StdioClientTransport: stdio.StdioClientTransport,
|
|
16782
|
+
StreamableHTTPClientTransport: http.StreamableHTTPClientTransport
|
|
16783
|
+
};
|
|
16784
|
+
})();
|
|
16785
|
+
}
|
|
16786
|
+
return cachedSdk;
|
|
16787
|
+
}
|
|
16788
|
+
var cachedSdk, DEFAULT_CLIENT_INFO, McpClient;
|
|
16789
|
+
var init_client2 = __esm({
|
|
16790
|
+
"src/mcp/client.ts"() {
|
|
16791
|
+
"use strict";
|
|
16792
|
+
init_allowlist();
|
|
16793
|
+
init_errors();
|
|
16794
|
+
cachedSdk = null;
|
|
16795
|
+
DEFAULT_CLIENT_INFO = { name: "llmist", version: "0.0.0" };
|
|
16796
|
+
McpClient = class {
|
|
16797
|
+
constructor(spec, opts) {
|
|
16798
|
+
this.spec = spec;
|
|
16799
|
+
this.injectedTransport = opts?.transport;
|
|
16800
|
+
this.clientInfo = opts?.clientInfo ?? DEFAULT_CLIENT_INFO;
|
|
16801
|
+
}
|
|
16802
|
+
sdkClient = null;
|
|
16803
|
+
spawnedPid = null;
|
|
16804
|
+
closed = false;
|
|
16805
|
+
injectedTransport;
|
|
16806
|
+
clientInfo;
|
|
16807
|
+
get serverName() {
|
|
16808
|
+
return this.spec.name;
|
|
16809
|
+
}
|
|
16810
|
+
get pid() {
|
|
16811
|
+
return this.spawnedPid;
|
|
16812
|
+
}
|
|
16813
|
+
get serverCapabilities() {
|
|
16814
|
+
if (!this.sdkClient) return null;
|
|
16815
|
+
return this.sdkClient.getServerCapabilities() ?? null;
|
|
16816
|
+
}
|
|
16817
|
+
async connect() {
|
|
16818
|
+
if (this.sdkClient) return;
|
|
16819
|
+
let transport;
|
|
16820
|
+
if (this.injectedTransport) {
|
|
16821
|
+
transport = this.injectedTransport;
|
|
16822
|
+
} else if (this.spec.transport === "stdio") {
|
|
16823
|
+
assertCommandAllowed(this.spec.command, this.spec.trust === true);
|
|
16824
|
+
const { StdioClientTransport } = await loadSdk();
|
|
16825
|
+
const stdioTransport = new StdioClientTransport({
|
|
16826
|
+
command: this.spec.command,
|
|
16827
|
+
args: this.spec.args,
|
|
16828
|
+
env: this.spec.env
|
|
16829
|
+
});
|
|
16830
|
+
transport = stdioTransport;
|
|
16831
|
+
this.spawnedPid = null;
|
|
16832
|
+
} else {
|
|
16833
|
+
const { StreamableHTTPClientTransport } = await loadSdk();
|
|
16834
|
+
let url;
|
|
16835
|
+
try {
|
|
16836
|
+
url = new URL(this.spec.url);
|
|
16837
|
+
} catch (err) {
|
|
16838
|
+
throw new McpConnectError(
|
|
16839
|
+
`MCP server "${this.spec.name}" has an invalid URL: ${err.message}`,
|
|
16840
|
+
{ serverName: this.spec.name, cause: err }
|
|
16841
|
+
);
|
|
16842
|
+
}
|
|
16843
|
+
transport = new StreamableHTTPClientTransport(url, {
|
|
16844
|
+
requestInit: this.spec.headers ? { headers: this.spec.headers } : void 0
|
|
16845
|
+
});
|
|
16846
|
+
}
|
|
16847
|
+
const { Client } = await loadSdk();
|
|
16848
|
+
const client = new Client(this.clientInfo, { capabilities: {} });
|
|
16849
|
+
try {
|
|
16850
|
+
await this.withTimeout(() => client.connect(transport), "connect");
|
|
16851
|
+
} catch (err) {
|
|
16852
|
+
throw new McpConnectError(
|
|
16853
|
+
`Failed to connect to MCP server "${this.spec.name}": ${err.message}`,
|
|
16854
|
+
{ serverName: this.spec.name, cause: err }
|
|
16567
16855
|
);
|
|
16568
16856
|
}
|
|
16569
|
-
this.
|
|
16570
|
-
|
|
16571
|
-
|
|
16572
|
-
|
|
16573
|
-
this.temperature = options.temperature;
|
|
16574
|
-
this.logger = options.logger ?? createLogger({ name: "llmist:agent" });
|
|
16575
|
-
this.registry = options.registry;
|
|
16576
|
-
this.prefixConfig = options.prefixConfig;
|
|
16577
|
-
this.defaultMaxTokens = this.resolveMaxTokensFromCatalog(options.model);
|
|
16578
|
-
const outputLimitConfig = {
|
|
16579
|
-
enabled: options.outputLimitConfig?.enabled,
|
|
16580
|
-
limitPercent: options.outputLimitConfig?.limitPercent
|
|
16581
|
-
};
|
|
16582
|
-
this.outputLimitManager = new OutputLimitManager(
|
|
16583
|
-
this.client,
|
|
16584
|
-
this.model,
|
|
16585
|
-
outputLimitConfig,
|
|
16586
|
-
this.registry,
|
|
16587
|
-
this.logger
|
|
16588
|
-
);
|
|
16589
|
-
this.mediaStore = new MediaStore();
|
|
16590
|
-
this.hooks = this.outputLimitManager.getHooks(options.hooks);
|
|
16591
|
-
const baseBuilder = new LLMMessageBuilder(options.promptConfig);
|
|
16592
|
-
if (options.systemPrompt) {
|
|
16593
|
-
baseBuilder.addSystem(options.systemPrompt);
|
|
16857
|
+
this.sdkClient = client;
|
|
16858
|
+
const maybePid = transport.pid;
|
|
16859
|
+
if (typeof maybePid === "number") {
|
|
16860
|
+
this.spawnedPid = maybePid;
|
|
16594
16861
|
}
|
|
16595
|
-
|
|
16596
|
-
|
|
16597
|
-
|
|
16598
|
-
|
|
16599
|
-
|
|
16600
|
-
|
|
16601
|
-
|
|
16602
|
-
|
|
16603
|
-
content: message.content
|
|
16862
|
+
}
|
|
16863
|
+
async listTools() {
|
|
16864
|
+
const client = this.requireClient();
|
|
16865
|
+
const res = await this.withTimeout(() => client.listTools(), "tools/list");
|
|
16866
|
+
return res.tools.map((t) => ({
|
|
16867
|
+
name: t.name,
|
|
16868
|
+
description: t.description,
|
|
16869
|
+
inputSchema: t.inputSchema
|
|
16604
16870
|
}));
|
|
16605
|
-
|
|
16606
|
-
|
|
16607
|
-
|
|
16608
|
-
|
|
16609
|
-
|
|
16610
|
-
|
|
16611
|
-
|
|
16612
|
-
|
|
16871
|
+
}
|
|
16872
|
+
async callTool(name, args) {
|
|
16873
|
+
const client = this.requireClient();
|
|
16874
|
+
try {
|
|
16875
|
+
const res = await this.withTimeout(
|
|
16876
|
+
() => client.callTool({
|
|
16877
|
+
name,
|
|
16878
|
+
arguments: args ?? {}
|
|
16879
|
+
}),
|
|
16880
|
+
`tools/call ${name}`
|
|
16881
|
+
);
|
|
16882
|
+
return {
|
|
16883
|
+
content: res.content ?? [],
|
|
16884
|
+
isError: res.isError
|
|
16885
|
+
};
|
|
16886
|
+
} catch (err) {
|
|
16887
|
+
throw new McpToolCallError(
|
|
16888
|
+
name,
|
|
16889
|
+
`MCP tool call "${name}" on server "${this.spec.name}" failed: ${err.message}`,
|
|
16890
|
+
{ serverName: this.spec.name, cause: err }
|
|
16891
|
+
);
|
|
16613
16892
|
}
|
|
16614
|
-
|
|
16615
|
-
|
|
16616
|
-
|
|
16617
|
-
|
|
16618
|
-
|
|
16619
|
-
|
|
16620
|
-
const
|
|
16621
|
-
|
|
16622
|
-
|
|
16623
|
-
|
|
16624
|
-
|
|
16625
|
-
|
|
16626
|
-
|
|
16893
|
+
}
|
|
16894
|
+
async listPrompts() {
|
|
16895
|
+
const client = this.requireClient();
|
|
16896
|
+
if (!client.listPrompts) {
|
|
16897
|
+
return [];
|
|
16898
|
+
}
|
|
16899
|
+
const listPrompts = client.listPrompts.bind(client);
|
|
16900
|
+
const res = await this.withTimeout(() => listPrompts(), "prompts/list");
|
|
16901
|
+
return res.prompts.map((p) => ({
|
|
16902
|
+
name: p.name,
|
|
16903
|
+
description: p.description,
|
|
16904
|
+
arguments: p.arguments
|
|
16905
|
+
}));
|
|
16906
|
+
}
|
|
16907
|
+
async getPrompt(name, args) {
|
|
16908
|
+
const client = this.requireClient();
|
|
16909
|
+
if (!client.getPrompt) {
|
|
16910
|
+
throw new McpToolCallError(name, "Server has no getPrompt method", {
|
|
16911
|
+
serverName: this.spec.name
|
|
16912
|
+
});
|
|
16913
|
+
}
|
|
16914
|
+
const getPrompt = client.getPrompt.bind(client);
|
|
16915
|
+
try {
|
|
16916
|
+
const res = await this.withTimeout(
|
|
16917
|
+
() => getPrompt({ name, arguments: args ?? {} }),
|
|
16918
|
+
`prompts/get ${name}`
|
|
16919
|
+
);
|
|
16920
|
+
return {
|
|
16921
|
+
description: res.description,
|
|
16922
|
+
messages: res.messages.map((m) => ({
|
|
16923
|
+
role: m.role,
|
|
16924
|
+
content: m.content
|
|
16925
|
+
}))
|
|
16926
|
+
};
|
|
16927
|
+
} catch (err) {
|
|
16928
|
+
throw new McpToolCallError(
|
|
16929
|
+
name,
|
|
16930
|
+
`MCP prompts/get "${name}" on server "${this.spec.name}" failed: ${err.message}`,
|
|
16931
|
+
{ serverName: this.spec.name, cause: err }
|
|
16627
16932
|
);
|
|
16628
16933
|
}
|
|
16629
|
-
|
|
16630
|
-
|
|
16631
|
-
this.
|
|
16632
|
-
this.
|
|
16633
|
-
if (
|
|
16634
|
-
|
|
16635
|
-
|
|
16636
|
-
|
|
16637
|
-
if (rateLimitConfig.enabled) {
|
|
16638
|
-
this.rateLimitTracker = new RateLimitTracker(options.rateLimitConfig);
|
|
16934
|
+
}
|
|
16935
|
+
async close() {
|
|
16936
|
+
if (this.closed) return;
|
|
16937
|
+
this.closed = true;
|
|
16938
|
+
if (this.sdkClient) {
|
|
16939
|
+
try {
|
|
16940
|
+
await this.sdkClient.close();
|
|
16941
|
+
} catch {
|
|
16639
16942
|
}
|
|
16943
|
+
this.sdkClient = null;
|
|
16640
16944
|
}
|
|
16641
|
-
|
|
16642
|
-
|
|
16643
|
-
this.
|
|
16644
|
-
|
|
16945
|
+
}
|
|
16946
|
+
requireClient() {
|
|
16947
|
+
if (!this.sdkClient) {
|
|
16948
|
+
throw new McpConnectError(
|
|
16949
|
+
`MCP client for server "${this.spec.name}" is not connected. Call connect() first.`,
|
|
16950
|
+
{ serverName: this.spec.name }
|
|
16951
|
+
);
|
|
16952
|
+
}
|
|
16953
|
+
return this.sdkClient;
|
|
16954
|
+
}
|
|
16955
|
+
async withTimeout(fn, operation) {
|
|
16956
|
+
const timeoutMs = this.spec.timeoutMs;
|
|
16957
|
+
if (timeoutMs === void 0 || timeoutMs <= 0) {
|
|
16958
|
+
return fn();
|
|
16959
|
+
}
|
|
16960
|
+
return new Promise((resolve2, reject) => {
|
|
16961
|
+
let settled = false;
|
|
16962
|
+
const timeoutId = setTimeout(() => {
|
|
16963
|
+
if (settled) return;
|
|
16964
|
+
settled = true;
|
|
16965
|
+
reject(new McpTimeoutError(operation, timeoutMs, this.spec.name));
|
|
16966
|
+
}, timeoutMs);
|
|
16967
|
+
fn().then((result) => {
|
|
16968
|
+
if (settled) return;
|
|
16969
|
+
settled = true;
|
|
16970
|
+
clearTimeout(timeoutId);
|
|
16971
|
+
resolve2(result);
|
|
16972
|
+
}).catch((err) => {
|
|
16973
|
+
if (settled) return;
|
|
16974
|
+
settled = true;
|
|
16975
|
+
clearTimeout(timeoutId);
|
|
16976
|
+
reject(err);
|
|
16977
|
+
});
|
|
16978
|
+
});
|
|
16979
|
+
}
|
|
16980
|
+
};
|
|
16981
|
+
}
|
|
16982
|
+
});
|
|
16983
|
+
|
|
16984
|
+
// src/mcp/lifecycle.ts
|
|
16985
|
+
var McpLifecycle;
|
|
16986
|
+
var init_lifecycle = __esm({
|
|
16987
|
+
"src/mcp/lifecycle.ts"() {
|
|
16988
|
+
"use strict";
|
|
16989
|
+
init_logger();
|
|
16990
|
+
McpLifecycle = class {
|
|
16991
|
+
clients = [];
|
|
16992
|
+
closing = null;
|
|
16993
|
+
signalHandlersInstalled = false;
|
|
16994
|
+
sigtermHandler = null;
|
|
16995
|
+
sigintHandler = null;
|
|
16996
|
+
get size() {
|
|
16997
|
+
return this.clients.length;
|
|
16998
|
+
}
|
|
16999
|
+
register(client) {
|
|
17000
|
+
this.clients.push(client);
|
|
17001
|
+
}
|
|
17002
|
+
/**
|
|
17003
|
+
* Attach SIGTERM/SIGINT handlers that close every registered client when
|
|
17004
|
+
* the parent process is asked to exit. Idempotent (double install is a
|
|
17005
|
+
* no-op) and removable via `removeSignalHandlers()`.
|
|
17006
|
+
*/
|
|
17007
|
+
installSignalHandlers() {
|
|
17008
|
+
if (this.signalHandlersInstalled) return;
|
|
17009
|
+
this.signalHandlersInstalled = true;
|
|
17010
|
+
this.sigtermHandler = () => {
|
|
17011
|
+
void this.closeAll();
|
|
17012
|
+
};
|
|
17013
|
+
this.sigintHandler = () => {
|
|
17014
|
+
void this.closeAll();
|
|
17015
|
+
};
|
|
17016
|
+
process.on("SIGTERM", this.sigtermHandler);
|
|
17017
|
+
process.on("SIGINT", this.sigintHandler);
|
|
17018
|
+
}
|
|
17019
|
+
removeSignalHandlers() {
|
|
17020
|
+
if (!this.signalHandlersInstalled) return;
|
|
17021
|
+
if (this.sigtermHandler) process.off("SIGTERM", this.sigtermHandler);
|
|
17022
|
+
if (this.sigintHandler) process.off("SIGINT", this.sigintHandler);
|
|
17023
|
+
this.sigtermHandler = null;
|
|
17024
|
+
this.sigintHandler = null;
|
|
17025
|
+
this.signalHandlersInstalled = false;
|
|
17026
|
+
}
|
|
17027
|
+
/**
|
|
17028
|
+
* Close every registered client in parallel. Errors from individual close()
|
|
17029
|
+
* calls are swallowed (logged via console.warn) — a teardown path must not
|
|
17030
|
+
* throw because that would mask the original reason the agent is shutting
|
|
17031
|
+
* down. Idempotent: concurrent calls all return the same in-flight promise.
|
|
17032
|
+
*/
|
|
17033
|
+
async closeAll() {
|
|
17034
|
+
if (this.closing) return this.closing;
|
|
17035
|
+
const toClose = this.clients;
|
|
17036
|
+
this.clients = [];
|
|
17037
|
+
this.closing = (async () => {
|
|
17038
|
+
const results = await Promise.allSettled(toClose.map((c) => c.close()));
|
|
17039
|
+
for (const r of results) {
|
|
17040
|
+
if (r.status === "rejected") {
|
|
17041
|
+
defaultLogger.debug("MCP client close failed during teardown:", r.reason);
|
|
17042
|
+
}
|
|
17043
|
+
}
|
|
17044
|
+
})();
|
|
17045
|
+
try {
|
|
17046
|
+
await this.closing;
|
|
17047
|
+
} finally {
|
|
17048
|
+
this.closing = null;
|
|
17049
|
+
this.removeSignalHandlers();
|
|
17050
|
+
}
|
|
17051
|
+
}
|
|
17052
|
+
};
|
|
17053
|
+
}
|
|
17054
|
+
});
|
|
17055
|
+
|
|
17056
|
+
// src/mcp/multi-server.ts
|
|
17057
|
+
function resolveToolNames(input) {
|
|
17058
|
+
const counts = /* @__PURE__ */ new Map();
|
|
17059
|
+
for (const s of input) {
|
|
17060
|
+
for (const t of s.tools) {
|
|
17061
|
+
counts.set(t.name, (counts.get(t.name) ?? 0) + 1);
|
|
17062
|
+
}
|
|
17063
|
+
}
|
|
17064
|
+
const collidingServers = /* @__PURE__ */ new Set();
|
|
17065
|
+
for (const s of input) {
|
|
17066
|
+
if (s.tools.some((t) => (counts.get(t.name) ?? 0) > 1)) {
|
|
17067
|
+
collidingServers.add(s.server.name);
|
|
17068
|
+
}
|
|
17069
|
+
}
|
|
17070
|
+
return input.map((s) => ({
|
|
17071
|
+
...s,
|
|
17072
|
+
prefix: collidingServers.has(s.server.name) ? `${s.server.name}__` : void 0
|
|
17073
|
+
}));
|
|
17074
|
+
}
|
|
17075
|
+
var init_multi_server = __esm({
|
|
17076
|
+
"src/mcp/multi-server.ts"() {
|
|
17077
|
+
"use strict";
|
|
17078
|
+
}
|
|
17079
|
+
});
|
|
17080
|
+
|
|
17081
|
+
// src/mcp/prompt-adapter.ts
|
|
17082
|
+
function mcpPromptToSkill(descriptor, client, opts) {
|
|
17083
|
+
return new McpPromptSkill(descriptor, client, opts);
|
|
17084
|
+
}
|
|
17085
|
+
var McpPromptSkill;
|
|
17086
|
+
var init_prompt_adapter = __esm({
|
|
17087
|
+
"src/mcp/prompt-adapter.ts"() {
|
|
17088
|
+
"use strict";
|
|
17089
|
+
McpPromptSkill = class {
|
|
17090
|
+
name;
|
|
17091
|
+
description;
|
|
17092
|
+
metadata;
|
|
17093
|
+
isUserInvocable = true;
|
|
17094
|
+
isModelInvocable = true;
|
|
17095
|
+
client;
|
|
17096
|
+
mcpToolName;
|
|
17097
|
+
constructor(descriptor, client, opts) {
|
|
17098
|
+
const prefix = opts?.prefix ?? "";
|
|
17099
|
+
this.name = prefix + descriptor.name;
|
|
17100
|
+
this.description = descriptor.description ?? `MCP prompt "${descriptor.name}" from server "${client.serverName}"`;
|
|
17101
|
+
this.metadata = {
|
|
17102
|
+
name: this.name,
|
|
17103
|
+
description: this.description,
|
|
17104
|
+
...descriptor.arguments ? { arguments: descriptor.arguments } : {}
|
|
17105
|
+
};
|
|
17106
|
+
this.client = client;
|
|
17107
|
+
this.mcpToolName = descriptor.name;
|
|
17108
|
+
}
|
|
17109
|
+
/**
|
|
17110
|
+
* Render the prompt by calling the MCP server's prompts/get with the
|
|
17111
|
+
* supplied arguments and joining the resulting message text.
|
|
17112
|
+
*/
|
|
17113
|
+
async getInstructions(args) {
|
|
17114
|
+
const result = await this.client.getPrompt(this.mcpToolName, args ?? {});
|
|
17115
|
+
const parts = [];
|
|
17116
|
+
for (const m of result.messages) {
|
|
17117
|
+
const c = m.content;
|
|
17118
|
+
if (c.type === "text" && typeof c.text === "string") {
|
|
17119
|
+
parts.push(c.text);
|
|
17120
|
+
} else {
|
|
17121
|
+
try {
|
|
17122
|
+
parts.push(JSON.stringify(c));
|
|
17123
|
+
} catch {
|
|
17124
|
+
parts.push(String(c));
|
|
17125
|
+
}
|
|
17126
|
+
}
|
|
17127
|
+
}
|
|
17128
|
+
return parts.join("\n");
|
|
17129
|
+
}
|
|
17130
|
+
};
|
|
17131
|
+
}
|
|
17132
|
+
});
|
|
17133
|
+
|
|
17134
|
+
// src/gadgets/helpers.ts
|
|
17135
|
+
function gadgetSuccess(data = {}) {
|
|
17136
|
+
return JSON.stringify({ success: true, ...data });
|
|
17137
|
+
}
|
|
17138
|
+
function gadgetError(message, details) {
|
|
17139
|
+
return JSON.stringify({ error: message, ...details });
|
|
17140
|
+
}
|
|
17141
|
+
function getErrorMessage(error) {
|
|
17142
|
+
return error instanceof Error ? error.message : String(error);
|
|
17143
|
+
}
|
|
17144
|
+
function withErrorHandling(execute) {
|
|
17145
|
+
return async (params, ctx) => {
|
|
17146
|
+
try {
|
|
17147
|
+
return await execute(params, ctx);
|
|
17148
|
+
} catch (error) {
|
|
17149
|
+
return gadgetError(getErrorMessage(error));
|
|
17150
|
+
}
|
|
17151
|
+
};
|
|
17152
|
+
}
|
|
17153
|
+
function createMediaOutput(kind, data, mimeType, options) {
|
|
17154
|
+
const buffer = data instanceof Buffer ? data : Buffer.from(data);
|
|
17155
|
+
return {
|
|
17156
|
+
kind,
|
|
17157
|
+
data: buffer.toString("base64"),
|
|
17158
|
+
mimeType,
|
|
17159
|
+
description: options?.description,
|
|
17160
|
+
metadata: options?.metadata,
|
|
17161
|
+
fileName: options?.fileName
|
|
17162
|
+
};
|
|
17163
|
+
}
|
|
17164
|
+
function resultWithMedia(result, media, cost) {
|
|
17165
|
+
if (media.length === 0) {
|
|
17166
|
+
throw new Error("resultWithMedia: media array cannot be empty");
|
|
17167
|
+
}
|
|
17168
|
+
return {
|
|
17169
|
+
result,
|
|
17170
|
+
media,
|
|
17171
|
+
cost
|
|
17172
|
+
};
|
|
17173
|
+
}
|
|
17174
|
+
function resultWithImage(result, imageData, options) {
|
|
17175
|
+
const buffer = imageData instanceof Buffer ? imageData : Buffer.from(imageData);
|
|
17176
|
+
const mimeType = options?.mimeType ?? detectImageMimeType(buffer);
|
|
17177
|
+
if (!mimeType) {
|
|
17178
|
+
throw new Error(
|
|
17179
|
+
"Could not detect image MIME type. Please provide mimeType explicitly in options."
|
|
17180
|
+
);
|
|
17181
|
+
}
|
|
17182
|
+
return {
|
|
17183
|
+
result,
|
|
17184
|
+
media: [
|
|
17185
|
+
{
|
|
17186
|
+
kind: "image",
|
|
17187
|
+
data: buffer.toString("base64"),
|
|
17188
|
+
mimeType,
|
|
17189
|
+
description: options?.description,
|
|
17190
|
+
metadata: options?.metadata,
|
|
17191
|
+
fileName: options?.fileName
|
|
17192
|
+
}
|
|
17193
|
+
],
|
|
17194
|
+
cost: options?.cost
|
|
17195
|
+
};
|
|
17196
|
+
}
|
|
17197
|
+
function resultWithImages(result, images, cost) {
|
|
17198
|
+
if (images.length === 0) {
|
|
17199
|
+
throw new Error("resultWithImages: images array cannot be empty");
|
|
17200
|
+
}
|
|
17201
|
+
const media = images.map((img, index) => {
|
|
17202
|
+
const buffer = img.data instanceof Buffer ? img.data : Buffer.from(img.data);
|
|
17203
|
+
const mimeType = img.mimeType ?? detectImageMimeType(buffer);
|
|
17204
|
+
if (!mimeType) {
|
|
17205
|
+
throw new Error(
|
|
17206
|
+
`Could not detect MIME type for image at index ${index}. Please provide mimeType explicitly.`
|
|
17207
|
+
);
|
|
17208
|
+
}
|
|
17209
|
+
return {
|
|
17210
|
+
kind: "image",
|
|
17211
|
+
data: buffer.toString("base64"),
|
|
17212
|
+
mimeType,
|
|
17213
|
+
description: img.description,
|
|
17214
|
+
metadata: img.metadata,
|
|
17215
|
+
fileName: img.fileName
|
|
17216
|
+
};
|
|
17217
|
+
});
|
|
17218
|
+
return { result, media, cost };
|
|
17219
|
+
}
|
|
17220
|
+
function resultWithAudio(result, audioData, options) {
|
|
17221
|
+
const buffer = audioData instanceof Buffer ? audioData : Buffer.from(audioData);
|
|
17222
|
+
const mimeType = options?.mimeType ?? detectAudioMimeType(buffer);
|
|
17223
|
+
if (!mimeType) {
|
|
17224
|
+
throw new Error(
|
|
17225
|
+
"Could not detect audio MIME type. Please provide mimeType explicitly in options."
|
|
17226
|
+
);
|
|
17227
|
+
}
|
|
17228
|
+
const metadata = options?.durationMs ? { durationMs: options.durationMs } : void 0;
|
|
17229
|
+
return {
|
|
17230
|
+
result,
|
|
17231
|
+
media: [
|
|
17232
|
+
{
|
|
17233
|
+
kind: "audio",
|
|
17234
|
+
data: buffer.toString("base64"),
|
|
17235
|
+
mimeType,
|
|
17236
|
+
description: options?.description,
|
|
17237
|
+
metadata,
|
|
17238
|
+
fileName: options?.fileName
|
|
17239
|
+
}
|
|
17240
|
+
],
|
|
17241
|
+
cost: options?.cost
|
|
17242
|
+
};
|
|
17243
|
+
}
|
|
17244
|
+
function resultWithFile(result, fileData, mimeType, options) {
|
|
17245
|
+
const buffer = fileData instanceof Buffer ? fileData : Buffer.from(fileData);
|
|
17246
|
+
return {
|
|
17247
|
+
result,
|
|
17248
|
+
media: [
|
|
17249
|
+
{
|
|
17250
|
+
kind: "file",
|
|
17251
|
+
data: buffer.toString("base64"),
|
|
17252
|
+
mimeType,
|
|
17253
|
+
description: options?.description,
|
|
17254
|
+
fileName: options?.fileName
|
|
17255
|
+
}
|
|
17256
|
+
],
|
|
17257
|
+
cost: options?.cost
|
|
17258
|
+
};
|
|
17259
|
+
}
|
|
17260
|
+
var init_helpers = __esm({
|
|
17261
|
+
"src/gadgets/helpers.ts"() {
|
|
17262
|
+
"use strict";
|
|
17263
|
+
init_input_content();
|
|
17264
|
+
}
|
|
17265
|
+
});
|
|
17266
|
+
|
|
17267
|
+
// src/mcp/json-schema-to-zod.ts
|
|
17268
|
+
function jsonSchemaToZod(schema) {
|
|
17269
|
+
if (!schema || typeof schema !== "object") {
|
|
17270
|
+
return import_zod4.z.unknown();
|
|
17271
|
+
}
|
|
17272
|
+
if (schema.$ref) {
|
|
17273
|
+
throw new JsonSchemaConversionError("$ref is not supported in MCP tool schemas", schema);
|
|
17274
|
+
}
|
|
17275
|
+
if (schema.allOf) {
|
|
17276
|
+
throw new JsonSchemaConversionError(
|
|
17277
|
+
"allOf is not supported (MCP tools should use a single composed schema)",
|
|
17278
|
+
schema
|
|
17279
|
+
);
|
|
17280
|
+
}
|
|
17281
|
+
const union = schema.oneOf ?? schema.anyOf;
|
|
17282
|
+
if (union) {
|
|
17283
|
+
if (!Array.isArray(union) || union.length < 2) {
|
|
17284
|
+
throw new JsonSchemaConversionError("oneOf/anyOf must have at least two members", schema);
|
|
17285
|
+
}
|
|
17286
|
+
const branches = union.map((m) => jsonSchemaToZod(m));
|
|
17287
|
+
return applyDecorators(import_zod4.z.union(branches), schema);
|
|
17288
|
+
}
|
|
17289
|
+
const type = Array.isArray(schema.type) ? schema.type[0] : schema.type;
|
|
17290
|
+
if (type === void 0 && schema.enum && Array.isArray(schema.enum)) {
|
|
17291
|
+
return applyDecorators(buildEnum(schema.enum), schema);
|
|
17292
|
+
}
|
|
17293
|
+
if (type === void 0) {
|
|
17294
|
+
return applyDecorators(import_zod4.z.unknown(), schema);
|
|
17295
|
+
}
|
|
17296
|
+
switch (type) {
|
|
17297
|
+
case "string": {
|
|
17298
|
+
let s;
|
|
17299
|
+
if (schema.enum && Array.isArray(schema.enum)) {
|
|
17300
|
+
s = buildEnum(schema.enum);
|
|
17301
|
+
} else {
|
|
17302
|
+
s = import_zod4.z.string();
|
|
17303
|
+
}
|
|
17304
|
+
return applyDecorators(s, schema);
|
|
17305
|
+
}
|
|
17306
|
+
case "number":
|
|
17307
|
+
return applyDecorators(import_zod4.z.number(), schema);
|
|
17308
|
+
case "integer":
|
|
17309
|
+
return applyDecorators(import_zod4.z.number().int(), schema);
|
|
17310
|
+
case "boolean":
|
|
17311
|
+
return applyDecorators(import_zod4.z.boolean(), schema);
|
|
17312
|
+
case "null":
|
|
17313
|
+
return applyDecorators(import_zod4.z.null(), schema);
|
|
17314
|
+
case "array": {
|
|
17315
|
+
const items = schema.items;
|
|
17316
|
+
if (Array.isArray(items)) {
|
|
17317
|
+
throw new JsonSchemaConversionError("tuple-style items arrays are not supported", schema);
|
|
17318
|
+
}
|
|
17319
|
+
const inner = items ? jsonSchemaToZod(items) : import_zod4.z.unknown();
|
|
17320
|
+
return applyDecorators(import_zod4.z.array(inner), schema);
|
|
17321
|
+
}
|
|
17322
|
+
case "object": {
|
|
17323
|
+
const props = schema.properties ?? {};
|
|
17324
|
+
const required = new Set(schema.required ?? []);
|
|
17325
|
+
const keys = Object.keys(props);
|
|
17326
|
+
if (keys.length === 0) {
|
|
17327
|
+
return applyDecorators(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown()), schema);
|
|
17328
|
+
}
|
|
17329
|
+
const shape = {};
|
|
17330
|
+
for (const key of keys) {
|
|
17331
|
+
const inner = jsonSchemaToZod(props[key]);
|
|
17332
|
+
shape[key] = required.has(key) ? inner : inner.optional();
|
|
17333
|
+
}
|
|
17334
|
+
return applyDecorators(import_zod4.z.object(shape), schema);
|
|
17335
|
+
}
|
|
17336
|
+
default:
|
|
17337
|
+
throw new JsonSchemaConversionError(`unknown JSON Schema type "${type}"`, schema);
|
|
17338
|
+
}
|
|
17339
|
+
}
|
|
17340
|
+
function buildEnum(values) {
|
|
17341
|
+
if (values.every((v) => typeof v === "string")) {
|
|
17342
|
+
const literals2 = values;
|
|
17343
|
+
if (literals2.length === 0) {
|
|
17344
|
+
throw new JsonSchemaConversionError("enum cannot be empty", values);
|
|
17345
|
+
}
|
|
17346
|
+
return import_zod4.z.enum(literals2);
|
|
17347
|
+
}
|
|
17348
|
+
const literals = values.map((v) => import_zod4.z.literal(v));
|
|
17349
|
+
if (literals.length === 0) {
|
|
17350
|
+
throw new JsonSchemaConversionError("enum cannot be empty", values);
|
|
17351
|
+
}
|
|
17352
|
+
if (literals.length === 1) {
|
|
17353
|
+
return literals[0];
|
|
17354
|
+
}
|
|
17355
|
+
return import_zod4.z.union(literals);
|
|
17356
|
+
}
|
|
17357
|
+
function applyDecorators(base, schema) {
|
|
17358
|
+
let s = base;
|
|
17359
|
+
if (schema.nullable === true) {
|
|
17360
|
+
s = s.nullable();
|
|
17361
|
+
}
|
|
17362
|
+
if (schema.description) {
|
|
17363
|
+
s = s.describe(schema.description);
|
|
17364
|
+
}
|
|
17365
|
+
if (schema.default !== void 0) {
|
|
17366
|
+
s = s.default(schema.default);
|
|
17367
|
+
}
|
|
17368
|
+
return s;
|
|
17369
|
+
}
|
|
17370
|
+
var import_zod4;
|
|
17371
|
+
var init_json_schema_to_zod = __esm({
|
|
17372
|
+
"src/mcp/json-schema-to-zod.ts"() {
|
|
17373
|
+
"use strict";
|
|
17374
|
+
import_zod4 = require("zod");
|
|
17375
|
+
init_errors();
|
|
17376
|
+
}
|
|
17377
|
+
});
|
|
17378
|
+
|
|
17379
|
+
// src/mcp/tool-adapter.ts
|
|
17380
|
+
function mcpToolToGadget(tool, client, opts) {
|
|
17381
|
+
const gadgetName = (opts?.prefix ?? "") + tool.name;
|
|
17382
|
+
const schema = buildSchema(tool.inputSchema);
|
|
17383
|
+
const description = tool.description ?? `MCP tool "${tool.name}" from server "${client.serverName}"`;
|
|
17384
|
+
return createGadget({
|
|
17385
|
+
name: gadgetName,
|
|
17386
|
+
description,
|
|
17387
|
+
schema,
|
|
17388
|
+
execute: async (params) => {
|
|
17389
|
+
const result = await client.callTool(tool.name, params);
|
|
17390
|
+
return mcpResultToGadgetReturn(result, tool.name);
|
|
17391
|
+
}
|
|
17392
|
+
});
|
|
17393
|
+
}
|
|
17394
|
+
function buildSchema(inputSchema) {
|
|
17395
|
+
if (!inputSchema) {
|
|
17396
|
+
return import_zod5.z.object({});
|
|
17397
|
+
}
|
|
17398
|
+
const converted = jsonSchemaToZod(inputSchema);
|
|
17399
|
+
if (!(converted instanceof import_zod5.z.ZodObject) && !(converted instanceof import_zod5.z.ZodRecord)) {
|
|
17400
|
+
return import_zod5.z.object({}).passthrough();
|
|
17401
|
+
}
|
|
17402
|
+
return converted;
|
|
17403
|
+
}
|
|
17404
|
+
function mcpResultToGadgetReturn(result, toolName) {
|
|
17405
|
+
const blocks = result.content ?? [];
|
|
17406
|
+
const textParts = [];
|
|
17407
|
+
const media = [];
|
|
17408
|
+
for (const block of blocks) {
|
|
17409
|
+
const kind = block.type;
|
|
17410
|
+
if (kind === "text" && typeof block.text === "string") {
|
|
17411
|
+
textParts.push(block.text);
|
|
17412
|
+
} else if (kind === "image") {
|
|
17413
|
+
const b = block;
|
|
17414
|
+
media.push({ kind: "image", data: b.data, mimeType: b.mimeType });
|
|
17415
|
+
} else if (kind === "audio") {
|
|
17416
|
+
const b = block;
|
|
17417
|
+
media.push({ kind: "audio", data: b.data, mimeType: b.mimeType });
|
|
17418
|
+
} else {
|
|
17419
|
+
try {
|
|
17420
|
+
textParts.push(JSON.stringify(block));
|
|
17421
|
+
} catch {
|
|
17422
|
+
textParts.push(String(block));
|
|
17423
|
+
}
|
|
17424
|
+
}
|
|
17425
|
+
}
|
|
17426
|
+
const text3 = textParts.join("\n");
|
|
17427
|
+
if (result.isError) {
|
|
17428
|
+
throw new Error(
|
|
17429
|
+
text3 ? text3 : `MCP tool "${toolName}" returned an error result with no text content`
|
|
17430
|
+
);
|
|
17431
|
+
}
|
|
17432
|
+
if (media.length === 0) {
|
|
17433
|
+
return text3;
|
|
17434
|
+
}
|
|
17435
|
+
if (media.length === 1 && media[0].kind === "image") {
|
|
17436
|
+
const img = media[0];
|
|
17437
|
+
return resultWithImage(text3, Buffer.from(img.data, "base64"), {
|
|
17438
|
+
mimeType: img.mimeType
|
|
17439
|
+
});
|
|
17440
|
+
}
|
|
17441
|
+
return {
|
|
17442
|
+
result: text3,
|
|
17443
|
+
media: media.map((m) => ({
|
|
17444
|
+
kind: m.kind,
|
|
17445
|
+
data: m.data,
|
|
17446
|
+
mimeType: m.mimeType
|
|
17447
|
+
}))
|
|
17448
|
+
};
|
|
17449
|
+
}
|
|
17450
|
+
var import_zod5;
|
|
17451
|
+
var init_tool_adapter = __esm({
|
|
17452
|
+
"src/mcp/tool-adapter.ts"() {
|
|
17453
|
+
"use strict";
|
|
17454
|
+
import_zod5 = require("zod");
|
|
17455
|
+
init_create_gadget();
|
|
17456
|
+
init_helpers();
|
|
17457
|
+
init_json_schema_to_zod();
|
|
17458
|
+
}
|
|
17459
|
+
});
|
|
17460
|
+
|
|
17461
|
+
// src/mcp/runtime.ts
|
|
17462
|
+
var runtime_exports = {};
|
|
17463
|
+
__export(runtime_exports, {
|
|
17464
|
+
setupMcpServers: () => setupMcpServers
|
|
17465
|
+
});
|
|
17466
|
+
async function setupMcpServers(opts) {
|
|
17467
|
+
const { specs, registry, conversation, prefixConfig, systemPrompt, logger: logger2, onPromptDiscovered } = opts;
|
|
17468
|
+
const lifecycle = new McpLifecycle();
|
|
17469
|
+
lifecycle.installSignalHandlers();
|
|
17470
|
+
const connected = [];
|
|
17471
|
+
await Promise.all(
|
|
17472
|
+
specs.map(async (spec) => {
|
|
17473
|
+
const client = new McpClient(spec);
|
|
17474
|
+
try {
|
|
17475
|
+
await client.connect();
|
|
17476
|
+
} catch (err) {
|
|
17477
|
+
logger2.warn(
|
|
17478
|
+
`MCP server "${spec.name}" failed to connect \u2014 skipping. Reason: ${err.message}`
|
|
17479
|
+
);
|
|
17480
|
+
return;
|
|
17481
|
+
}
|
|
17482
|
+
lifecycle.register(client);
|
|
17483
|
+
const caps = client.serverCapabilities;
|
|
17484
|
+
const hasTools = caps?.tools !== void 0;
|
|
17485
|
+
let tools = [];
|
|
17486
|
+
if (hasTools) {
|
|
17487
|
+
try {
|
|
17488
|
+
tools = await client.listTools();
|
|
17489
|
+
} catch (err) {
|
|
17490
|
+
logger2.warn(
|
|
17491
|
+
`MCP server "${spec.name}" listTools failed \u2014 skipping. Reason: ${err.message}`
|
|
17492
|
+
);
|
|
17493
|
+
return;
|
|
17494
|
+
}
|
|
17495
|
+
} else {
|
|
17496
|
+
logger2.debug(
|
|
17497
|
+
`MCP server "${spec.name}" did not advertise tools capability \u2014 skipping listTools.`
|
|
17498
|
+
);
|
|
17499
|
+
}
|
|
17500
|
+
if (caps?.resources !== void 0) {
|
|
17501
|
+
logger2.debug(
|
|
17502
|
+
`MCP server "${spec.name}" advertises 'resources' capability \u2014 not yet implemented in llmist (deferred to v1.5).`
|
|
17503
|
+
);
|
|
17504
|
+
}
|
|
17505
|
+
if (caps?.prompts !== void 0 && onPromptDiscovered) {
|
|
17506
|
+
try {
|
|
17507
|
+
const prompts = await client.listPrompts();
|
|
17508
|
+
for (const p of prompts) {
|
|
17509
|
+
onPromptDiscovered(mcpPromptToSkill(p, client));
|
|
17510
|
+
}
|
|
17511
|
+
} catch (err) {
|
|
17512
|
+
logger2.debug(
|
|
17513
|
+
`MCP server "${spec.name}" listPrompts failed \u2014 skipping prompts. Reason: ${err.message}`
|
|
17514
|
+
);
|
|
17515
|
+
}
|
|
17516
|
+
}
|
|
17517
|
+
connected.push({ client, serverToolList: { server: spec, tools } });
|
|
17518
|
+
})
|
|
17519
|
+
);
|
|
17520
|
+
const resolved = resolveToolNames(connected.map((c) => c.serverToolList));
|
|
17521
|
+
for (const r of resolved) {
|
|
17522
|
+
const cs = connected.find((c) => c.serverToolList.server.name === r.server.name);
|
|
17523
|
+
if (!cs) continue;
|
|
17524
|
+
for (const tool of r.tools) {
|
|
17525
|
+
const gadget = mcpToolToGadget(tool, cs.client, { prefix: r.prefix });
|
|
17526
|
+
try {
|
|
17527
|
+
registry.register(gadget.name ?? tool.name, gadget);
|
|
17528
|
+
} catch (err) {
|
|
17529
|
+
logger2.warn(
|
|
17530
|
+
`MCP server "${r.server.name}" tool "${tool.name}" was not registered: ${err.message}`
|
|
17531
|
+
);
|
|
17532
|
+
}
|
|
17533
|
+
}
|
|
17534
|
+
}
|
|
17535
|
+
const builder = new LLMMessageBuilder();
|
|
17536
|
+
if (typeof systemPrompt === "string" && systemPrompt.length > 0) {
|
|
17537
|
+
builder.addSystem(systemPrompt);
|
|
17538
|
+
}
|
|
17539
|
+
builder.addGadgets(registry.getAll(), {
|
|
17540
|
+
startPrefix: prefixConfig?.gadgetStartPrefix,
|
|
17541
|
+
endPrefix: prefixConfig?.gadgetEndPrefix,
|
|
17542
|
+
argPrefix: prefixConfig?.gadgetArgPrefix
|
|
17543
|
+
});
|
|
17544
|
+
conversation.replaceBaseMessages(builder.build());
|
|
17545
|
+
return lifecycle;
|
|
17546
|
+
}
|
|
17547
|
+
var init_runtime = __esm({
|
|
17548
|
+
"src/mcp/runtime.ts"() {
|
|
17549
|
+
"use strict";
|
|
17550
|
+
init_messages();
|
|
17551
|
+
init_client2();
|
|
17552
|
+
init_lifecycle();
|
|
17553
|
+
init_multi_server();
|
|
17554
|
+
init_prompt_adapter();
|
|
17555
|
+
init_tool_adapter();
|
|
17556
|
+
}
|
|
17557
|
+
});
|
|
17558
|
+
|
|
17559
|
+
// src/agent/agent.ts
|
|
17560
|
+
var OVERFLOW_RECOVERY_MIN_HISTORY, Agent;
|
|
17561
|
+
var init_agent = __esm({
|
|
17562
|
+
"src/agent/agent.ts"() {
|
|
17563
|
+
"use strict";
|
|
17564
|
+
init_execution_tree();
|
|
17565
|
+
init_messages();
|
|
17566
|
+
init_model_shortcuts();
|
|
17567
|
+
init_rate_limit();
|
|
17568
|
+
init_retry();
|
|
17569
|
+
init_exceptions();
|
|
17570
|
+
init_media_store();
|
|
17571
|
+
init_logger();
|
|
17572
|
+
init_agent_internal_key();
|
|
17573
|
+
init_manager();
|
|
17574
|
+
init_conversation_manager();
|
|
17575
|
+
init_conversation_updater();
|
|
17576
|
+
init_event_handlers();
|
|
17577
|
+
init_llm_call_lifecycle();
|
|
17578
|
+
init_output_limit_manager();
|
|
17579
|
+
init_retry_orchestrator();
|
|
17580
|
+
init_safe_observe();
|
|
17581
|
+
init_stream_processor_factory();
|
|
17582
|
+
init_tree_hook_bridge();
|
|
17583
|
+
OVERFLOW_RECOVERY_MIN_HISTORY = 4;
|
|
17584
|
+
Agent = class {
|
|
17585
|
+
client;
|
|
17586
|
+
model;
|
|
17587
|
+
maxIterations;
|
|
17588
|
+
budget;
|
|
17589
|
+
temperature;
|
|
17590
|
+
logger;
|
|
17591
|
+
hooks;
|
|
17592
|
+
conversation;
|
|
17593
|
+
registry;
|
|
17594
|
+
prefixConfig;
|
|
17595
|
+
conversationUpdater;
|
|
17596
|
+
defaultMaxTokens;
|
|
17597
|
+
hasUserPrompt;
|
|
17598
|
+
// Gadget output limiting
|
|
17599
|
+
outputLimitManager;
|
|
17600
|
+
// Context compaction
|
|
17601
|
+
compactionManager;
|
|
17602
|
+
// Media storage (for gadgets returning images, audio, etc.)
|
|
17603
|
+
mediaStore;
|
|
17604
|
+
// Cancellation
|
|
17605
|
+
signal;
|
|
17606
|
+
reasoning;
|
|
17607
|
+
caching;
|
|
17608
|
+
// Retry configuration (shared reference also passed to StreamProcessorFactory)
|
|
17609
|
+
retryConfig;
|
|
17610
|
+
// Rate limit tracker for proactive throttling
|
|
17611
|
+
rateLimitTracker;
|
|
17612
|
+
// Cross-iteration dependency tracking - allows gadgets to depend on results from prior iterations
|
|
17613
|
+
completedInvocationIds = /* @__PURE__ */ new Set();
|
|
17614
|
+
failedInvocationIds = /* @__PURE__ */ new Set();
|
|
17615
|
+
// Queue for user messages injected during agent execution (REPL mid-session input)
|
|
17616
|
+
pendingUserMessages = [];
|
|
17617
|
+
// Execution Tree - first-class model for nested subagent support
|
|
17618
|
+
tree;
|
|
17619
|
+
parentNodeId;
|
|
17620
|
+
// StreamProcessor factory - encapsulates all pass-through StreamProcessor config
|
|
17621
|
+
streamProcessorFactory;
|
|
17622
|
+
// LLM call lifecycle helper (encapsulates prepareLLMCall, completeLLMCall, notifyLLMError)
|
|
17623
|
+
llmCallLifecycle;
|
|
17624
|
+
// MCP integration — populated only when mcpSpecs were provided.
|
|
17625
|
+
mcpSpecs;
|
|
17626
|
+
mcpLifecycle = null;
|
|
17627
|
+
mcpDiscoveredPrompts = [];
|
|
17628
|
+
/**
|
|
17629
|
+
* Creates a new Agent instance.
|
|
17630
|
+
* @internal This constructor is private. Use LLMist.createAgent() or AgentBuilder instead.
|
|
17631
|
+
*/
|
|
17632
|
+
constructor(key, options) {
|
|
17633
|
+
if (!isValidAgentKey(key)) {
|
|
17634
|
+
throw new Error(
|
|
17635
|
+
"Agent cannot be instantiated directly. Use LLMist.createAgent() or new AgentBuilder() instead."
|
|
17636
|
+
);
|
|
17637
|
+
}
|
|
17638
|
+
this.client = options.client;
|
|
17639
|
+
this.model = resolveModel(options.model);
|
|
17640
|
+
this.maxIterations = options.maxIterations ?? 10;
|
|
17641
|
+
this.budget = options.budget;
|
|
17642
|
+
this.temperature = options.temperature;
|
|
17643
|
+
this.logger = options.logger ?? createLogger({ name: "llmist:agent" });
|
|
17644
|
+
this.registry = options.registry;
|
|
17645
|
+
this.prefixConfig = options.prefixConfig;
|
|
17646
|
+
this.defaultMaxTokens = this.resolveMaxTokensFromCatalog(options.model);
|
|
17647
|
+
const outputLimitConfig = {
|
|
17648
|
+
enabled: options.outputLimitConfig?.enabled,
|
|
17649
|
+
limitPercent: options.outputLimitConfig?.limitPercent
|
|
17650
|
+
};
|
|
17651
|
+
this.outputLimitManager = new OutputLimitManager(
|
|
17652
|
+
this.client,
|
|
17653
|
+
this.model,
|
|
17654
|
+
outputLimitConfig,
|
|
17655
|
+
this.registry,
|
|
17656
|
+
this.logger
|
|
17657
|
+
);
|
|
17658
|
+
this.mediaStore = new MediaStore();
|
|
17659
|
+
this.hooks = this.outputLimitManager.getHooks(options.hooks);
|
|
17660
|
+
const baseBuilder = new LLMMessageBuilder(options.promptConfig);
|
|
17661
|
+
if (options.systemPrompt) {
|
|
17662
|
+
baseBuilder.addSystem(options.systemPrompt);
|
|
17663
|
+
}
|
|
17664
|
+
baseBuilder.addGadgets(this.registry.getAll(), {
|
|
17665
|
+
startPrefix: this.prefixConfig?.gadgetStartPrefix,
|
|
17666
|
+
endPrefix: this.prefixConfig?.gadgetEndPrefix,
|
|
17667
|
+
argPrefix: this.prefixConfig?.gadgetArgPrefix
|
|
17668
|
+
});
|
|
17669
|
+
const baseMessages = baseBuilder.build();
|
|
17670
|
+
const initialMessages = (options.initialMessages ?? []).map((message) => ({
|
|
17671
|
+
role: message.role,
|
|
17672
|
+
content: message.content
|
|
17673
|
+
}));
|
|
17674
|
+
this.conversation = new ConversationManager(baseMessages, initialMessages, {
|
|
17675
|
+
startPrefix: this.prefixConfig?.gadgetStartPrefix,
|
|
17676
|
+
endPrefix: this.prefixConfig?.gadgetEndPrefix,
|
|
17677
|
+
argPrefix: this.prefixConfig?.gadgetArgPrefix
|
|
17678
|
+
});
|
|
17679
|
+
this.hasUserPrompt = !!options.userPrompt;
|
|
17680
|
+
if (options.userPrompt) {
|
|
17681
|
+
this.conversation.addUserMessage(options.userPrompt);
|
|
17682
|
+
}
|
|
17683
|
+
this.conversationUpdater = new ConversationUpdater(
|
|
17684
|
+
this.conversation,
|
|
17685
|
+
options.textOnlyHandler ?? "terminate",
|
|
17686
|
+
options.textWithGadgetsHandler,
|
|
17687
|
+
this.logger
|
|
17688
|
+
);
|
|
17689
|
+
const compactionEnabled = options.compactionConfig?.enabled ?? true;
|
|
17690
|
+
if (compactionEnabled) {
|
|
17691
|
+
this.compactionManager = new CompactionManager(
|
|
17692
|
+
this.client,
|
|
17693
|
+
this.model,
|
|
17694
|
+
options.compactionConfig,
|
|
17695
|
+
this.logger
|
|
17696
|
+
);
|
|
17697
|
+
}
|
|
17698
|
+
this.signal = options.signal;
|
|
17699
|
+
this.mcpSpecs = options.mcpSpecs ?? [];
|
|
17700
|
+
this.reasoning = options.reasoning;
|
|
17701
|
+
this.caching = options.caching;
|
|
17702
|
+
this.retryConfig = options.sharedRetryConfig ?? resolveRetryConfig(options.retryConfig);
|
|
17703
|
+
if (options.sharedRateLimitTracker) {
|
|
17704
|
+
this.rateLimitTracker = options.sharedRateLimitTracker;
|
|
17705
|
+
} else {
|
|
17706
|
+
const rateLimitConfig = resolveRateLimitConfig(options.rateLimitConfig);
|
|
17707
|
+
if (rateLimitConfig.enabled) {
|
|
17708
|
+
this.rateLimitTracker = new RateLimitTracker(options.rateLimitConfig);
|
|
17709
|
+
}
|
|
17710
|
+
}
|
|
17711
|
+
const treeConfig = options.treeConfig;
|
|
17712
|
+
this.tree = treeConfig?.tree ?? new ExecutionTree();
|
|
17713
|
+
this.parentNodeId = treeConfig?.parentNodeId ?? null;
|
|
17714
|
+
this.streamProcessorFactory = new StreamProcessorFactory({
|
|
16645
17715
|
registry: this.registry,
|
|
16646
17716
|
prefixConfig: this.prefixConfig,
|
|
16647
17717
|
hooks: this.hooks,
|
|
@@ -16886,6 +17956,18 @@ var init_agent = __esm({
|
|
|
16886
17956
|
);
|
|
16887
17957
|
}
|
|
16888
17958
|
const unsubscribeBridge = bridgeTreeToHooks(this.tree, this.hooks, this.logger);
|
|
17959
|
+
if (this.mcpSpecs.length > 0) {
|
|
17960
|
+
const { setupMcpServers: setupMcpServers2 } = await Promise.resolve().then(() => (init_runtime(), runtime_exports));
|
|
17961
|
+
this.mcpLifecycle = await setupMcpServers2({
|
|
17962
|
+
specs: this.mcpSpecs,
|
|
17963
|
+
registry: this.registry,
|
|
17964
|
+
conversation: this.conversation,
|
|
17965
|
+
prefixConfig: this.prefixConfig,
|
|
17966
|
+
systemPrompt: this.conversation.getBaseMessages()[0]?.role === "system" ? this.conversation.getBaseMessages()[0].content : void 0,
|
|
17967
|
+
logger: this.logger,
|
|
17968
|
+
onPromptDiscovered: (skill) => this.mcpDiscoveredPrompts.push(skill)
|
|
17969
|
+
});
|
|
17970
|
+
}
|
|
16889
17971
|
let currentIteration = 0;
|
|
16890
17972
|
this.logger.info("Starting agent loop", {
|
|
16891
17973
|
model: this.model,
|
|
@@ -17085,6 +18167,14 @@ var init_agent = __esm({
|
|
|
17085
18167
|
}
|
|
17086
18168
|
}
|
|
17087
18169
|
unsubscribeBridge();
|
|
18170
|
+
if (this.mcpLifecycle) {
|
|
18171
|
+
try {
|
|
18172
|
+
await this.mcpLifecycle.closeAll();
|
|
18173
|
+
} catch (err) {
|
|
18174
|
+
this.logger.debug("MCP lifecycle teardown error (suppressed):", err);
|
|
18175
|
+
}
|
|
18176
|
+
this.mcpLifecycle = null;
|
|
18177
|
+
}
|
|
17088
18178
|
}
|
|
17089
18179
|
}
|
|
17090
18180
|
/**
|
|
@@ -17284,6 +18374,7 @@ __export(index_exports, {
|
|
|
17284
18374
|
ConversationManager: () => ConversationManager,
|
|
17285
18375
|
DEFAULT_COMPACTION_CONFIG: () => DEFAULT_COMPACTION_CONFIG,
|
|
17286
18376
|
DEFAULT_HINTS: () => DEFAULT_HINTS,
|
|
18377
|
+
DEFAULT_MCP_COMMAND_ALLOWLIST: () => DEFAULT_MCP_COMMAND_ALLOWLIST,
|
|
17287
18378
|
DEFAULT_PROMPTS: () => DEFAULT_PROMPTS,
|
|
17288
18379
|
DEFAULT_RATE_LIMIT_CONFIG: () => DEFAULT_RATE_LIMIT_CONFIG,
|
|
17289
18380
|
DEFAULT_RETRY_CONFIG: () => DEFAULT_RETRY_CONFIG,
|
|
@@ -17303,10 +18394,17 @@ __export(index_exports, {
|
|
|
17303
18394
|
HuggingFaceProvider: () => HuggingFaceProvider,
|
|
17304
18395
|
HumanInputRequiredException: () => HumanInputRequiredException,
|
|
17305
18396
|
HybridStrategy: () => HybridStrategy,
|
|
18397
|
+
JsonSchemaConversionError: () => JsonSchemaConversionError,
|
|
17306
18398
|
LLMMessageBuilder: () => LLMMessageBuilder,
|
|
17307
18399
|
LLMist: () => LLMist,
|
|
17308
18400
|
LOAD_SKILL_GADGET_NAME: () => LOAD_SKILL_GADGET_NAME,
|
|
17309
18401
|
MODEL_ALIASES: () => MODEL_ALIASES,
|
|
18402
|
+
McpClient: () => McpClient,
|
|
18403
|
+
McpConnectError: () => McpConnectError,
|
|
18404
|
+
McpError: () => McpError,
|
|
18405
|
+
McpLifecycle: () => McpLifecycle,
|
|
18406
|
+
McpToolCallError: () => McpToolCallError,
|
|
18407
|
+
McpUntrustedCommandError: () => McpUntrustedCommandError,
|
|
17310
18408
|
MediaStore: () => MediaStore,
|
|
17311
18409
|
ModelIdentifierParser: () => ModelIdentifierParser,
|
|
17312
18410
|
ModelRegistry: () => ModelRegistry,
|
|
@@ -17322,6 +18420,7 @@ __export(index_exports, {
|
|
|
17322
18420
|
SummarizationStrategy: () => SummarizationStrategy,
|
|
17323
18421
|
TaskCompletionSignal: () => TaskCompletionSignal,
|
|
17324
18422
|
TimeoutException: () => TimeoutException,
|
|
18423
|
+
assertCommandAllowed: () => assertCommandAllowed,
|
|
17325
18424
|
audioFromBase64: () => audioFromBase64,
|
|
17326
18425
|
audioFromBuffer: () => audioFromBuffer,
|
|
17327
18426
|
collectEvents: () => collectEvents,
|
|
@@ -17336,6 +18435,7 @@ __export(index_exports, {
|
|
|
17336
18435
|
createHuggingFaceProviderFromEnv: () => createHuggingFaceProviderFromEnv,
|
|
17337
18436
|
createLoadSkillGadget: () => createLoadSkillGadget,
|
|
17338
18437
|
createLogger: () => createLogger,
|
|
18438
|
+
createMcpServer: () => createMcpServer,
|
|
17339
18439
|
createMediaOutput: () => createMediaOutput,
|
|
17340
18440
|
createOpenAIProviderFromEnv: () => createOpenAIProviderFromEnv,
|
|
17341
18441
|
createOpenRouterProviderFromEnv: () => createOpenRouterProviderFromEnv,
|
|
@@ -17358,7 +18458,9 @@ __export(index_exports, {
|
|
|
17358
18458
|
formatLLMError: () => formatLLMError,
|
|
17359
18459
|
formatLlmRequest: () => formatLlmRequest,
|
|
17360
18460
|
gadgetError: () => gadgetError,
|
|
18461
|
+
gadgetResultToMcpContent: () => gadgetResultToMcpContent,
|
|
17361
18462
|
gadgetSuccess: () => gadgetSuccess,
|
|
18463
|
+
gadgetToMcpTool: () => gadgetToMcpTool,
|
|
17362
18464
|
getErrorMessage: () => getErrorMessage,
|
|
17363
18465
|
getHostExports: () => getHostExports2,
|
|
17364
18466
|
getModelId: () => getModelId,
|
|
@@ -17386,9 +18488,11 @@ __export(index_exports, {
|
|
|
17386
18488
|
isSubagentEvent: () => isSubagentEvent,
|
|
17387
18489
|
isTextPart: () => isTextPart,
|
|
17388
18490
|
iterationProgressHint: () => iterationProgressHint,
|
|
18491
|
+
jsonSchemaToZod: () => jsonSchemaToZod,
|
|
17389
18492
|
listPresets: () => listPresets,
|
|
17390
18493
|
listSubagents: () => listSubagents,
|
|
17391
18494
|
loadSkillsFromDirectory: () => loadSkillsFromDirectory,
|
|
18495
|
+
mcpToolToGadget: () => mcpToolToGadget,
|
|
17392
18496
|
normalizeMessageContent: () => normalizeMessageContent,
|
|
17393
18497
|
parallelGadgetHint: () => parallelGadgetHint,
|
|
17394
18498
|
parseDataUrl: () => parseDataUrl,
|
|
@@ -17399,6 +18503,7 @@ __export(index_exports, {
|
|
|
17399
18503
|
parseSkillContent: () => parseSkillContent,
|
|
17400
18504
|
parseSkillFile: () => parseSkillFile,
|
|
17401
18505
|
randomDelay: () => randomDelay,
|
|
18506
|
+
renderSkillForMcpPrompt: () => renderSkillForMcpPrompt,
|
|
17402
18507
|
resetFileLoggingState: () => resetFileLoggingState,
|
|
17403
18508
|
resolveConfig: () => resolveConfig,
|
|
17404
18509
|
resolveHintTemplate: () => resolveHintTemplate,
|
|
@@ -17416,9 +18521,11 @@ __export(index_exports, {
|
|
|
17416
18521
|
resultWithImage: () => resultWithImage,
|
|
17417
18522
|
resultWithImages: () => resultWithImages,
|
|
17418
18523
|
resultWithMedia: () => resultWithMedia,
|
|
18524
|
+
runGadgetForMcp: () => runGadgetForMcp,
|
|
17419
18525
|
runWithHandlers: () => runWithHandlers,
|
|
17420
18526
|
scanResources: () => scanResources,
|
|
17421
18527
|
schemaToJSONSchema: () => schemaToJSONSchema,
|
|
18528
|
+
skillToMcpPrompt: () => skillToMcpPrompt,
|
|
17422
18529
|
stream: () => stream,
|
|
17423
18530
|
stripProviderPrefix: () => stripProviderPrefix,
|
|
17424
18531
|
substituteArguments: () => substituteArguments,
|
|
@@ -17434,10 +18541,10 @@ __export(index_exports, {
|
|
|
17434
18541
|
withErrorHandling: () => withErrorHandling,
|
|
17435
18542
|
withRetry: () => withRetry,
|
|
17436
18543
|
withTimeout: () => withTimeout,
|
|
17437
|
-
z: () =>
|
|
18544
|
+
z: () => import_zod6.z
|
|
17438
18545
|
});
|
|
17439
18546
|
module.exports = __toCommonJS(index_exports);
|
|
17440
|
-
var
|
|
18547
|
+
var import_zod6 = require("zod");
|
|
17441
18548
|
init_agent();
|
|
17442
18549
|
init_builder();
|
|
17443
18550
|
init_event_handlers();
|
|
@@ -17620,140 +18727,254 @@ init_create_gadget();
|
|
|
17620
18727
|
init_exceptions();
|
|
17621
18728
|
init_executor();
|
|
17622
18729
|
init_gadget();
|
|
18730
|
+
init_helpers();
|
|
18731
|
+
init_output_viewer();
|
|
18732
|
+
init_parser2();
|
|
18733
|
+
init_registry();
|
|
18734
|
+
init_typed_gadget();
|
|
17623
18735
|
|
|
17624
|
-
// src/
|
|
17625
|
-
|
|
17626
|
-
|
|
17627
|
-
|
|
17628
|
-
|
|
17629
|
-
|
|
17630
|
-
|
|
17631
|
-
|
|
17632
|
-
|
|
17633
|
-
|
|
17634
|
-
|
|
17635
|
-
|
|
17636
|
-
|
|
17637
|
-
|
|
17638
|
-
|
|
17639
|
-
}
|
|
17640
|
-
|
|
17641
|
-
|
|
17642
|
-
|
|
17643
|
-
|
|
17644
|
-
|
|
17645
|
-
const
|
|
18736
|
+
// src/mcp/index.ts
|
|
18737
|
+
init_allowlist();
|
|
18738
|
+
init_client2();
|
|
18739
|
+
init_errors();
|
|
18740
|
+
|
|
18741
|
+
// src/mcp/gadget-exporter.ts
|
|
18742
|
+
init_schema_to_json();
|
|
18743
|
+
|
|
18744
|
+
// src/gadgets/validation.ts
|
|
18745
|
+
function validateAndApplyDefaults(schema, params) {
|
|
18746
|
+
const result = schema.safeParse(params);
|
|
18747
|
+
if (result.success) {
|
|
18748
|
+
return {
|
|
18749
|
+
success: true,
|
|
18750
|
+
data: result.data
|
|
18751
|
+
};
|
|
18752
|
+
}
|
|
18753
|
+
const issues = result.error.issues.map((issue) => ({
|
|
18754
|
+
path: issue.path.join(".") || "root",
|
|
18755
|
+
message: issue.message
|
|
18756
|
+
}));
|
|
18757
|
+
const formattedError = `Invalid parameters: ${issues.map((i) => `${i.path}: ${i.message}`).join("; ")}`;
|
|
17646
18758
|
return {
|
|
17647
|
-
|
|
17648
|
-
|
|
17649
|
-
|
|
17650
|
-
description: options?.description,
|
|
17651
|
-
metadata: options?.metadata,
|
|
17652
|
-
fileName: options?.fileName
|
|
18759
|
+
success: false,
|
|
18760
|
+
error: formattedError,
|
|
18761
|
+
issues
|
|
17653
18762
|
};
|
|
17654
18763
|
}
|
|
17655
|
-
function
|
|
17656
|
-
if (
|
|
17657
|
-
|
|
18764
|
+
function validateGadgetParams(gadget, params) {
|
|
18765
|
+
if (!gadget.parameterSchema) {
|
|
18766
|
+
return {
|
|
18767
|
+
success: true,
|
|
18768
|
+
data: params
|
|
18769
|
+
};
|
|
17658
18770
|
}
|
|
17659
|
-
return
|
|
17660
|
-
result,
|
|
17661
|
-
media,
|
|
17662
|
-
cost
|
|
17663
|
-
};
|
|
18771
|
+
return validateAndApplyDefaults(gadget.parameterSchema, params);
|
|
17664
18772
|
}
|
|
17665
|
-
|
|
17666
|
-
|
|
17667
|
-
|
|
17668
|
-
|
|
17669
|
-
|
|
17670
|
-
|
|
17671
|
-
);
|
|
18773
|
+
|
|
18774
|
+
// src/mcp/gadget-exporter.ts
|
|
18775
|
+
function gadgetToMcpTool(gadget) {
|
|
18776
|
+
const description = gadget.description && gadget.description.length > 0 ? gadget.description : `Native llmist gadget "${gadget.name ?? "unnamed"}"`;
|
|
18777
|
+
let inputSchema;
|
|
18778
|
+
if (gadget.parameterSchema) {
|
|
18779
|
+
inputSchema = schemaToJSONSchema(gadget.parameterSchema);
|
|
18780
|
+
} else {
|
|
18781
|
+
inputSchema = { type: "object", properties: {} };
|
|
17672
18782
|
}
|
|
17673
18783
|
return {
|
|
17674
|
-
|
|
17675
|
-
|
|
17676
|
-
|
|
17677
|
-
kind: "image",
|
|
17678
|
-
data: buffer.toString("base64"),
|
|
17679
|
-
mimeType,
|
|
17680
|
-
description: options?.description,
|
|
17681
|
-
metadata: options?.metadata,
|
|
17682
|
-
fileName: options?.fileName
|
|
17683
|
-
}
|
|
17684
|
-
],
|
|
17685
|
-
cost: options?.cost
|
|
18784
|
+
name: gadget.name ?? "unnamed-gadget",
|
|
18785
|
+
description,
|
|
18786
|
+
inputSchema
|
|
17686
18787
|
};
|
|
17687
18788
|
}
|
|
17688
|
-
function
|
|
17689
|
-
if (
|
|
17690
|
-
|
|
18789
|
+
function gadgetResultToMcpContent(ret) {
|
|
18790
|
+
if (typeof ret === "string") {
|
|
18791
|
+
return [{ type: "text", text: ret }];
|
|
18792
|
+
}
|
|
18793
|
+
if (ret && typeof ret === "object" && "result" in ret) {
|
|
18794
|
+
const r = ret;
|
|
18795
|
+
const blocks = [];
|
|
18796
|
+
if (typeof r.result === "string") {
|
|
18797
|
+
blocks.push({ type: "text", text: r.result });
|
|
18798
|
+
} else {
|
|
18799
|
+
blocks.push({ type: "text", text: JSON.stringify(r.result) });
|
|
18800
|
+
}
|
|
18801
|
+
if (r.media) {
|
|
18802
|
+
for (const m of r.media) {
|
|
18803
|
+
if (m.kind === "image" || m.kind === "audio") {
|
|
18804
|
+
blocks.push({
|
|
18805
|
+
type: m.kind,
|
|
18806
|
+
data: m.data,
|
|
18807
|
+
mimeType: m.mimeType
|
|
18808
|
+
});
|
|
18809
|
+
}
|
|
18810
|
+
}
|
|
18811
|
+
}
|
|
18812
|
+
return blocks;
|
|
17691
18813
|
}
|
|
17692
|
-
|
|
17693
|
-
|
|
17694
|
-
|
|
17695
|
-
|
|
17696
|
-
|
|
17697
|
-
|
|
17698
|
-
|
|
18814
|
+
return [{ type: "text", text: JSON.stringify(ret) }];
|
|
18815
|
+
}
|
|
18816
|
+
async function runGadgetForMcp(gadget, rawParams) {
|
|
18817
|
+
if (gadget.parameterSchema) {
|
|
18818
|
+
const validation = validateAndApplyDefaults(
|
|
18819
|
+
gadget.parameterSchema,
|
|
18820
|
+
rawParams ?? {}
|
|
18821
|
+
);
|
|
18822
|
+
if (!validation.success) {
|
|
18823
|
+
return {
|
|
18824
|
+
isError: true,
|
|
18825
|
+
content: [
|
|
18826
|
+
{
|
|
18827
|
+
type: "text",
|
|
18828
|
+
text: `Invalid arguments for gadget "${gadget.name}": ${validation.error}`
|
|
18829
|
+
}
|
|
18830
|
+
]
|
|
18831
|
+
};
|
|
17699
18832
|
}
|
|
18833
|
+
rawParams = validation.data;
|
|
18834
|
+
}
|
|
18835
|
+
try {
|
|
18836
|
+
const result = await gadget.execute(rawParams);
|
|
17700
18837
|
return {
|
|
17701
|
-
|
|
17702
|
-
data: buffer.toString("base64"),
|
|
17703
|
-
mimeType,
|
|
17704
|
-
description: img.description,
|
|
17705
|
-
metadata: img.metadata,
|
|
17706
|
-
fileName: img.fileName
|
|
18838
|
+
content: gadgetResultToMcpContent(result)
|
|
17707
18839
|
};
|
|
17708
|
-
})
|
|
17709
|
-
|
|
18840
|
+
} catch (err) {
|
|
18841
|
+
return {
|
|
18842
|
+
isError: true,
|
|
18843
|
+
content: [
|
|
18844
|
+
{
|
|
18845
|
+
type: "text",
|
|
18846
|
+
text: `Gadget "${gadget.name}" failed: ${err.message}`
|
|
18847
|
+
}
|
|
18848
|
+
]
|
|
18849
|
+
};
|
|
18850
|
+
}
|
|
17710
18851
|
}
|
|
17711
|
-
|
|
17712
|
-
|
|
17713
|
-
|
|
17714
|
-
|
|
17715
|
-
|
|
17716
|
-
|
|
17717
|
-
|
|
18852
|
+
|
|
18853
|
+
// src/mcp/index.ts
|
|
18854
|
+
init_json_schema_to_zod();
|
|
18855
|
+
init_lifecycle();
|
|
18856
|
+
|
|
18857
|
+
// src/mcp/skill-exporter.ts
|
|
18858
|
+
function skillToMcpPrompt(skill) {
|
|
18859
|
+
const description = skill.description && skill.description.length > 0 ? skill.description : `Native llmist skill "${skill.name}"`;
|
|
18860
|
+
const args = [];
|
|
18861
|
+
if (skill.metadata.argumentHint) {
|
|
18862
|
+
args.push({
|
|
18863
|
+
name: "arguments",
|
|
18864
|
+
description: skill.metadata.argumentHint,
|
|
18865
|
+
required: false
|
|
18866
|
+
});
|
|
17718
18867
|
}
|
|
17719
|
-
const metadata = options?.durationMs ? { durationMs: options.durationMs } : void 0;
|
|
17720
18868
|
return {
|
|
17721
|
-
|
|
17722
|
-
|
|
18869
|
+
name: skill.name,
|
|
18870
|
+
description,
|
|
18871
|
+
...args.length > 0 ? { arguments: args } : {}
|
|
18872
|
+
};
|
|
18873
|
+
}
|
|
18874
|
+
async function renderSkillForMcpPrompt(skill, args) {
|
|
18875
|
+
const argString = typeof args.arguments === "string" ? args.arguments : Object.values(args).filter((v) => typeof v === "string").join(" ");
|
|
18876
|
+
const activation = await skill.activate({
|
|
18877
|
+
arguments: argString || void 0
|
|
18878
|
+
});
|
|
18879
|
+
return {
|
|
18880
|
+
description: skill.description,
|
|
18881
|
+
messages: [
|
|
17723
18882
|
{
|
|
17724
|
-
|
|
17725
|
-
|
|
17726
|
-
mimeType,
|
|
17727
|
-
description: options?.description,
|
|
17728
|
-
metadata,
|
|
17729
|
-
fileName: options?.fileName
|
|
18883
|
+
role: "user",
|
|
18884
|
+
content: { type: "text", text: activation.resolvedInstructions }
|
|
17730
18885
|
}
|
|
17731
|
-
]
|
|
17732
|
-
cost: options?.cost
|
|
18886
|
+
]
|
|
17733
18887
|
};
|
|
17734
18888
|
}
|
|
17735
|
-
|
|
17736
|
-
|
|
18889
|
+
|
|
18890
|
+
// src/mcp/server.ts
|
|
18891
|
+
var DEFAULT_SERVER_INFO = { name: "llmist", version: "0.0.0" };
|
|
18892
|
+
function createMcpServer(opts) {
|
|
18893
|
+
const { gadgets, skills } = opts;
|
|
18894
|
+
const hasTools = gadgets.getAll().length > 0;
|
|
18895
|
+
const hasPrompts = !!skills && skills.size > 0;
|
|
18896
|
+
const capabilities = {};
|
|
18897
|
+
if (hasTools) capabilities.tools = {};
|
|
18898
|
+
if (hasPrompts) capabilities.prompts = {};
|
|
18899
|
+
let sdkServer = null;
|
|
18900
|
+
let running = false;
|
|
18901
|
+
async function ensureServer() {
|
|
18902
|
+
if (sdkServer) return sdkServer;
|
|
18903
|
+
const [serverMod, typesMod] = await Promise.all([
|
|
18904
|
+
import("@modelcontextprotocol/sdk/server/index.js"),
|
|
18905
|
+
import("@modelcontextprotocol/sdk/types.js")
|
|
18906
|
+
]);
|
|
18907
|
+
const ServerClass = serverMod.Server;
|
|
18908
|
+
const server = new ServerClass(opts.serverInfo ?? DEFAULT_SERVER_INFO, {
|
|
18909
|
+
capabilities
|
|
18910
|
+
});
|
|
18911
|
+
if (hasTools) {
|
|
18912
|
+
server.setRequestHandler(typesMod.ListToolsRequestSchema, async () => ({
|
|
18913
|
+
tools: gadgets.getAll().map(gadgetToMcpTool)
|
|
18914
|
+
}));
|
|
18915
|
+
server.setRequestHandler(
|
|
18916
|
+
typesMod.CallToolRequestSchema,
|
|
18917
|
+
async (req) => {
|
|
18918
|
+
const gadget = gadgets.get(req.params.name);
|
|
18919
|
+
if (!gadget) {
|
|
18920
|
+
return {
|
|
18921
|
+
isError: true,
|
|
18922
|
+
content: [
|
|
18923
|
+
{
|
|
18924
|
+
type: "text",
|
|
18925
|
+
text: `Unknown tool "${req.params.name}". Call tools/list first.`
|
|
18926
|
+
}
|
|
18927
|
+
]
|
|
18928
|
+
};
|
|
18929
|
+
}
|
|
18930
|
+
return runGadgetForMcp(gadget, req.params.arguments ?? {});
|
|
18931
|
+
}
|
|
18932
|
+
);
|
|
18933
|
+
}
|
|
18934
|
+
if (hasPrompts && skills) {
|
|
18935
|
+
server.setRequestHandler(typesMod.ListPromptsRequestSchema, async () => ({
|
|
18936
|
+
prompts: Array.from(skills.getAll()).map(skillToMcpPrompt)
|
|
18937
|
+
}));
|
|
18938
|
+
server.setRequestHandler(
|
|
18939
|
+
typesMod.GetPromptRequestSchema,
|
|
18940
|
+
async (req) => {
|
|
18941
|
+
const skill = skills.get(req.params.name);
|
|
18942
|
+
if (!skill) {
|
|
18943
|
+
throw new Error(`Unknown prompt "${req.params.name}"`);
|
|
18944
|
+
}
|
|
18945
|
+
const result = await renderSkillForMcpPrompt(skill, req.params.arguments ?? {});
|
|
18946
|
+
return result;
|
|
18947
|
+
}
|
|
18948
|
+
);
|
|
18949
|
+
}
|
|
18950
|
+
sdkServer = server;
|
|
18951
|
+
return server;
|
|
18952
|
+
}
|
|
17737
18953
|
return {
|
|
17738
|
-
|
|
17739
|
-
|
|
17740
|
-
|
|
17741
|
-
|
|
17742
|
-
|
|
17743
|
-
|
|
17744
|
-
|
|
17745
|
-
|
|
18954
|
+
get running() {
|
|
18955
|
+
return running;
|
|
18956
|
+
},
|
|
18957
|
+
async connect(transport) {
|
|
18958
|
+
const server = await ensureServer();
|
|
18959
|
+
await server.connect(transport);
|
|
18960
|
+
running = true;
|
|
18961
|
+
},
|
|
18962
|
+
async stop() {
|
|
18963
|
+
if (!sdkServer) return;
|
|
18964
|
+
try {
|
|
18965
|
+
await sdkServer.close();
|
|
18966
|
+
} catch {
|
|
17746
18967
|
}
|
|
17747
|
-
|
|
17748
|
-
|
|
18968
|
+
sdkServer = null;
|
|
18969
|
+
running = false;
|
|
18970
|
+
}
|
|
17749
18971
|
};
|
|
17750
18972
|
}
|
|
17751
18973
|
|
|
18974
|
+
// src/mcp/index.ts
|
|
18975
|
+
init_tool_adapter();
|
|
18976
|
+
|
|
17752
18977
|
// src/index.ts
|
|
17753
|
-
init_output_viewer();
|
|
17754
|
-
init_parser2();
|
|
17755
|
-
init_registry();
|
|
17756
|
-
init_typed_gadget();
|
|
17757
18978
|
init_constants2();
|
|
17758
18979
|
|
|
17759
18980
|
// src/utils/config-resolver.ts
|
|
@@ -17862,38 +19083,6 @@ function hasHostExports(ctx) {
|
|
|
17862
19083
|
init_media_store();
|
|
17863
19084
|
init_schema_to_json();
|
|
17864
19085
|
init_schema_validator();
|
|
17865
|
-
|
|
17866
|
-
// src/gadgets/validation.ts
|
|
17867
|
-
function validateAndApplyDefaults(schema, params) {
|
|
17868
|
-
const result = schema.safeParse(params);
|
|
17869
|
-
if (result.success) {
|
|
17870
|
-
return {
|
|
17871
|
-
success: true,
|
|
17872
|
-
data: result.data
|
|
17873
|
-
};
|
|
17874
|
-
}
|
|
17875
|
-
const issues = result.error.issues.map((issue) => ({
|
|
17876
|
-
path: issue.path.join(".") || "root",
|
|
17877
|
-
message: issue.message
|
|
17878
|
-
}));
|
|
17879
|
-
const formattedError = `Invalid parameters: ${issues.map((i) => `${i.path}: ${i.message}`).join("; ")}`;
|
|
17880
|
-
return {
|
|
17881
|
-
success: false,
|
|
17882
|
-
error: formattedError,
|
|
17883
|
-
issues
|
|
17884
|
-
};
|
|
17885
|
-
}
|
|
17886
|
-
function validateGadgetParams(gadget, params) {
|
|
17887
|
-
if (!gadget.parameterSchema) {
|
|
17888
|
-
return {
|
|
17889
|
-
success: true,
|
|
17890
|
-
data: params
|
|
17891
|
-
};
|
|
17892
|
-
}
|
|
17893
|
-
return validateAndApplyDefaults(gadget.parameterSchema, params);
|
|
17894
|
-
}
|
|
17895
|
-
|
|
17896
|
-
// src/index.ts
|
|
17897
19086
|
init_logger();
|
|
17898
19087
|
|
|
17899
19088
|
// src/package/manifest.ts
|
|
@@ -18192,6 +19381,7 @@ function getHostExports2(ctx) {
|
|
|
18192
19381
|
ConversationManager,
|
|
18193
19382
|
DEFAULT_COMPACTION_CONFIG,
|
|
18194
19383
|
DEFAULT_HINTS,
|
|
19384
|
+
DEFAULT_MCP_COMMAND_ALLOWLIST,
|
|
18195
19385
|
DEFAULT_PROMPTS,
|
|
18196
19386
|
DEFAULT_RATE_LIMIT_CONFIG,
|
|
18197
19387
|
DEFAULT_RETRY_CONFIG,
|
|
@@ -18211,10 +19401,17 @@ function getHostExports2(ctx) {
|
|
|
18211
19401
|
HuggingFaceProvider,
|
|
18212
19402
|
HumanInputRequiredException,
|
|
18213
19403
|
HybridStrategy,
|
|
19404
|
+
JsonSchemaConversionError,
|
|
18214
19405
|
LLMMessageBuilder,
|
|
18215
19406
|
LLMist,
|
|
18216
19407
|
LOAD_SKILL_GADGET_NAME,
|
|
18217
19408
|
MODEL_ALIASES,
|
|
19409
|
+
McpClient,
|
|
19410
|
+
McpConnectError,
|
|
19411
|
+
McpError,
|
|
19412
|
+
McpLifecycle,
|
|
19413
|
+
McpToolCallError,
|
|
19414
|
+
McpUntrustedCommandError,
|
|
18218
19415
|
MediaStore,
|
|
18219
19416
|
ModelIdentifierParser,
|
|
18220
19417
|
ModelRegistry,
|
|
@@ -18230,6 +19427,7 @@ function getHostExports2(ctx) {
|
|
|
18230
19427
|
SummarizationStrategy,
|
|
18231
19428
|
TaskCompletionSignal,
|
|
18232
19429
|
TimeoutException,
|
|
19430
|
+
assertCommandAllowed,
|
|
18233
19431
|
audioFromBase64,
|
|
18234
19432
|
audioFromBuffer,
|
|
18235
19433
|
collectEvents,
|
|
@@ -18244,6 +19442,7 @@ function getHostExports2(ctx) {
|
|
|
18244
19442
|
createHuggingFaceProviderFromEnv,
|
|
18245
19443
|
createLoadSkillGadget,
|
|
18246
19444
|
createLogger,
|
|
19445
|
+
createMcpServer,
|
|
18247
19446
|
createMediaOutput,
|
|
18248
19447
|
createOpenAIProviderFromEnv,
|
|
18249
19448
|
createOpenRouterProviderFromEnv,
|
|
@@ -18266,7 +19465,9 @@ function getHostExports2(ctx) {
|
|
|
18266
19465
|
formatLLMError,
|
|
18267
19466
|
formatLlmRequest,
|
|
18268
19467
|
gadgetError,
|
|
19468
|
+
gadgetResultToMcpContent,
|
|
18269
19469
|
gadgetSuccess,
|
|
19470
|
+
gadgetToMcpTool,
|
|
18270
19471
|
getErrorMessage,
|
|
18271
19472
|
getHostExports,
|
|
18272
19473
|
getModelId,
|
|
@@ -18294,9 +19495,11 @@ function getHostExports2(ctx) {
|
|
|
18294
19495
|
isSubagentEvent,
|
|
18295
19496
|
isTextPart,
|
|
18296
19497
|
iterationProgressHint,
|
|
19498
|
+
jsonSchemaToZod,
|
|
18297
19499
|
listPresets,
|
|
18298
19500
|
listSubagents,
|
|
18299
19501
|
loadSkillsFromDirectory,
|
|
19502
|
+
mcpToolToGadget,
|
|
18300
19503
|
normalizeMessageContent,
|
|
18301
19504
|
parallelGadgetHint,
|
|
18302
19505
|
parseDataUrl,
|
|
@@ -18307,6 +19510,7 @@ function getHostExports2(ctx) {
|
|
|
18307
19510
|
parseSkillContent,
|
|
18308
19511
|
parseSkillFile,
|
|
18309
19512
|
randomDelay,
|
|
19513
|
+
renderSkillForMcpPrompt,
|
|
18310
19514
|
resetFileLoggingState,
|
|
18311
19515
|
resolveConfig,
|
|
18312
19516
|
resolveHintTemplate,
|
|
@@ -18324,9 +19528,11 @@ function getHostExports2(ctx) {
|
|
|
18324
19528
|
resultWithImage,
|
|
18325
19529
|
resultWithImages,
|
|
18326
19530
|
resultWithMedia,
|
|
19531
|
+
runGadgetForMcp,
|
|
18327
19532
|
runWithHandlers,
|
|
18328
19533
|
scanResources,
|
|
18329
19534
|
schemaToJSONSchema,
|
|
19535
|
+
skillToMcpPrompt,
|
|
18330
19536
|
stream,
|
|
18331
19537
|
stripProviderPrefix,
|
|
18332
19538
|
substituteArguments,
|