@frontmcp/plugin-codecall 1.10.8 → 1.10.9-rc.2
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/esm/index.mjs +24 -4216
- package/esm/package.json +8 -8
- package/index.js +24 -4244
- package/package.json +8 -8
package/index.js
CHANGED
|
@@ -1,2542 +1,9 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __export = (target, all) => {
|
|
9
|
-
for (var name in all)
|
|
10
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
-
};
|
|
12
|
-
var __copyProps = (to, from, except, desc) => {
|
|
13
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
-
for (let key of __getOwnPropNames(from))
|
|
15
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
-
}
|
|
18
|
-
return to;
|
|
19
|
-
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
-
var __decorateClass = (decorators, target, key, kind) => {
|
|
30
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
31
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
32
|
-
if (decorator = decorators[i])
|
|
33
|
-
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
34
|
-
if (kind && result) __defProp(target, key, result);
|
|
35
|
-
return result;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
// plugins/plugin-codecall/src/index.ts
|
|
39
|
-
var index_exports = {};
|
|
40
|
-
__export(index_exports, {
|
|
41
|
-
AUDIT_EVENT_TYPES: () => AUDIT_EVENT_TYPES,
|
|
42
|
-
AuditLoggerService: () => AuditLoggerService,
|
|
43
|
-
CodeCallPlugin: () => CodeCallPlugin,
|
|
44
|
-
codeCallDirectCallsOptionsSchema: () => codeCallDirectCallsOptionsSchema,
|
|
45
|
-
codeCallEmbeddingOptionsSchema: () => codeCallEmbeddingOptionsSchema,
|
|
46
|
-
codeCallModeSchema: () => codeCallModeSchema,
|
|
47
|
-
codeCallPluginOptionsSchema: () => codeCallPluginOptionsSchema,
|
|
48
|
-
codeCallSidecarOptionsSchema: () => codeCallSidecarOptionsSchema,
|
|
49
|
-
codeCallVmOptionsSchema: () => codeCallVmOptionsSchema,
|
|
50
|
-
codeCallVmPresetSchema: () => codeCallVmPresetSchema,
|
|
51
|
-
default: () => CodeCallPlugin,
|
|
52
|
-
embeddingStrategySchema: () => embeddingStrategySchema,
|
|
53
|
-
synonymExpansionConfigSchema: () => synonymExpansionConfigSchema
|
|
54
|
-
});
|
|
55
|
-
module.exports = __toCommonJS(index_exports);
|
|
56
|
-
|
|
57
|
-
// plugins/plugin-codecall/src/codecall.plugin.ts
|
|
58
|
-
var import_plugin_cache = __toESM(require("@frontmcp/plugin-cache"));
|
|
59
|
-
var import_sdk11 = require("@frontmcp/sdk");
|
|
60
|
-
|
|
61
|
-
// plugins/plugin-codecall/src/codecall.types.ts
|
|
62
|
-
var import_lazy_zod = require("@frontmcp/lazy-zod");
|
|
63
|
-
var directCallsFilterSchema = import_lazy_zod.z.custom((val) => typeof val === "function", {
|
|
64
|
-
message: "filter must be a function with signature (tool: DirectCallsFilterToolInfo) => boolean"
|
|
65
|
-
});
|
|
66
|
-
var includeToolsFilterSchema = import_lazy_zod.z.custom((val) => typeof val === "function", {
|
|
67
|
-
message: "includeTools must be a function with signature (tool: IncludeToolsFilterToolInfo) => boolean"
|
|
68
|
-
});
|
|
69
|
-
var codeCallModeSchema = import_lazy_zod.z.enum(["codecall_only", "codecall_opt_in", "metadata_driven"]).default("codecall_only");
|
|
70
|
-
var codeCallVmPresetSchema = import_lazy_zod.z.enum(["locked_down", "secure", "balanced", "experimental"]).default("secure");
|
|
71
|
-
var DEFAULT_VM_OPTIONS = {
|
|
72
|
-
preset: "secure"
|
|
73
|
-
};
|
|
74
|
-
var codeCallVmOptionsSchema = import_lazy_zod.z.object({
|
|
75
|
-
/**
|
|
76
|
-
* CSP-like preset; see README.
|
|
77
|
-
* @default 'secure'
|
|
78
|
-
*/
|
|
79
|
-
preset: codeCallVmPresetSchema,
|
|
80
|
-
/**
|
|
81
|
-
* Timeout for script execution in milliseconds
|
|
82
|
-
* Defaults vary by preset
|
|
83
|
-
*/
|
|
84
|
-
timeoutMs: import_lazy_zod.z.number().positive().optional(),
|
|
85
|
-
/**
|
|
86
|
-
* Allow `for` loops besides `for-of`; false refuses every loop but `for-of` before the script runs.
|
|
87
|
-
* The sandbox always refuses `while`, `do-while` and `for-in`.
|
|
88
|
-
* Defaults vary by preset
|
|
89
|
-
*/
|
|
90
|
-
allowLoops: import_lazy_zod.z.boolean().optional(),
|
|
91
|
-
/**
|
|
92
|
-
* Maximum number of steps (if applicable)
|
|
93
|
-
* Defaults vary by preset
|
|
94
|
-
*/
|
|
95
|
-
maxSteps: import_lazy_zod.z.number().positive().optional(),
|
|
96
|
-
/**
|
|
97
|
-
* List of disabled builtin functions
|
|
98
|
-
* Defaults vary by preset
|
|
99
|
-
*/
|
|
100
|
-
disabledBuiltins: import_lazy_zod.z.array(import_lazy_zod.z.string()).optional(),
|
|
101
|
-
/**
|
|
102
|
-
* List of disabled global variables
|
|
103
|
-
* Defaults vary by preset
|
|
104
|
-
*/
|
|
105
|
-
disabledGlobals: import_lazy_zod.z.array(import_lazy_zod.z.string()).optional(),
|
|
106
|
-
/**
|
|
107
|
-
* @deprecated Has no effect: scripts never get `console`, and one that uses it is refused before it runs.
|
|
108
|
-
* Scripts log with `mcpLog(level, message)`.
|
|
109
|
-
*/
|
|
110
|
-
allowConsole: import_lazy_zod.z.boolean().optional(),
|
|
111
|
-
/**
|
|
112
|
-
* Maximum nesting depth for sanitized output values
|
|
113
|
-
* Prevents deeply nested objects from causing stack overflow
|
|
114
|
-
* @default varies by preset (secure: 50)
|
|
115
|
-
*/
|
|
116
|
-
maxSanitizeDepth: import_lazy_zod.z.number().positive().optional(),
|
|
117
|
-
/**
|
|
118
|
-
* Maximum properties per object in sanitized output values
|
|
119
|
-
* Limits array sizes and object keys in return values
|
|
120
|
-
* @default varies by preset (secure: 2000)
|
|
121
|
-
*/
|
|
122
|
-
maxSanitizeProperties: import_lazy_zod.z.number().positive().optional(),
|
|
123
|
-
/**
|
|
124
|
-
* Calls a script may make to one tool within about 2 seconds; one more stops the script with
|
|
125
|
-
* `[RAPID_ENUMERATION]`. Calls made through `parallel()` count. The sandbox's message says "in 5s",
|
|
126
|
-
* but it keeps only the last 2 seconds of calls.
|
|
127
|
-
* @default 30
|
|
128
|
-
*/
|
|
129
|
-
rapidEnumerationThreshold: import_lazy_zod.z.number().int().positive().optional(),
|
|
130
|
-
/**
|
|
131
|
-
* Per-tool values of `rapidEnumerationThreshold`, by tool name, e.g. `{ 'users:get': 100 }`.
|
|
132
|
-
*/
|
|
133
|
-
rapidEnumerationOverrides: import_lazy_zod.z.record(import_lazy_zod.z.string(), import_lazy_zod.z.number().int().positive()).optional()
|
|
134
|
-
}).default(() => DEFAULT_VM_OPTIONS);
|
|
135
|
-
var codeCallDirectCallsOptionsSchema = import_lazy_zod.z.object({
|
|
136
|
-
/**
|
|
137
|
-
* Enable/disable the `codecall.invoke` meta-tool.
|
|
138
|
-
*/
|
|
139
|
-
enabled: import_lazy_zod.z.boolean(),
|
|
140
|
-
/**
|
|
141
|
-
* Optional allowlist of tool names.
|
|
142
|
-
*/
|
|
143
|
-
allowedTools: import_lazy_zod.z.array(import_lazy_zod.z.string()).optional(),
|
|
144
|
-
/**
|
|
145
|
-
* Optional advanced filter function.
|
|
146
|
-
* Signature: (tool: DirectCallsFilterToolInfo) => boolean
|
|
147
|
-
*/
|
|
148
|
-
filter: directCallsFilterSchema.optional()
|
|
149
|
-
});
|
|
150
|
-
var embeddingStrategySchema = import_lazy_zod.z.enum(["tfidf", "ml"]).default("tfidf");
|
|
151
|
-
var synonymExpansionConfigSchema = import_lazy_zod.z.object({
|
|
152
|
-
/**
|
|
153
|
-
* Enable/disable synonym expansion for TF-IDF search.
|
|
154
|
-
* When enabled, queries are expanded with synonyms to improve relevance.
|
|
155
|
-
* For example, "add user" will also match tools containing "create user".
|
|
156
|
-
* @default true
|
|
157
|
-
*/
|
|
158
|
-
enabled: import_lazy_zod.z.boolean().default(true),
|
|
159
|
-
/**
|
|
160
|
-
* Additional synonym groups beyond the defaults.
|
|
161
|
-
* Each group is an array of related terms that should be treated as equivalent.
|
|
162
|
-
* @example [['customer', 'client', 'buyer'], ['order', 'purchase', 'transaction']]
|
|
163
|
-
*/
|
|
164
|
-
additionalSynonyms: import_lazy_zod.z.array(import_lazy_zod.z.array(import_lazy_zod.z.string())).optional(),
|
|
165
|
-
/**
|
|
166
|
-
* Replace default synonyms entirely with additionalSynonyms.
|
|
167
|
-
* @default false
|
|
168
|
-
*/
|
|
169
|
-
replaceDefaults: import_lazy_zod.z.boolean().default(false),
|
|
170
|
-
/**
|
|
171
|
-
* Maximum number of synonym expansions per term.
|
|
172
|
-
* Prevents query explosion for terms with many synonyms.
|
|
173
|
-
* @default 5
|
|
174
|
-
*/
|
|
175
|
-
maxExpansionsPerTerm: import_lazy_zod.z.number().positive().default(5)
|
|
176
|
-
}).default({ enabled: true, replaceDefaults: false, maxExpansionsPerTerm: 5 });
|
|
177
|
-
var DEFAULT_EMBEDDING_OPTIONS = {
|
|
178
|
-
strategy: "tfidf",
|
|
179
|
-
modelName: "Xenova/all-MiniLM-L6-v2",
|
|
180
|
-
cacheDir: "./.cache/transformers",
|
|
181
|
-
useHNSW: false,
|
|
182
|
-
synonymExpansion: { enabled: true, replaceDefaults: false, maxExpansionsPerTerm: 5 }
|
|
183
|
-
};
|
|
184
|
-
var codeCallEmbeddingOptionsSchema = import_lazy_zod.z.object({
|
|
185
|
-
/**
|
|
186
|
-
* Embedding strategy to use for tool search
|
|
187
|
-
* - 'tfidf': Lightweight, synchronous TF-IDF based search (no ML models required)
|
|
188
|
-
* - 'ml': ML-based semantic search using transformers.js (better quality, requires model download)
|
|
189
|
-
* @default 'tfidf'
|
|
190
|
-
*/
|
|
191
|
-
strategy: embeddingStrategySchema.optional(),
|
|
192
|
-
/**
|
|
193
|
-
* Model name for ML-based embeddings (only used when strategy='ml')
|
|
194
|
-
* @default 'Xenova/all-MiniLM-L6-v2'
|
|
195
|
-
*/
|
|
196
|
-
modelName: import_lazy_zod.z.string().optional(),
|
|
197
|
-
/**
|
|
198
|
-
* Cache directory for ML models (only used when strategy='ml')
|
|
199
|
-
* @default './.cache/transformers'
|
|
200
|
-
*/
|
|
201
|
-
cacheDir: import_lazy_zod.z.string().optional(),
|
|
202
|
-
/**
|
|
203
|
-
* Enable HNSW index for faster search (only used when strategy='ml')
|
|
204
|
-
* When enabled, provides O(log n) search instead of O(n) brute-force
|
|
205
|
-
* @default false
|
|
206
|
-
*/
|
|
207
|
-
useHNSW: import_lazy_zod.z.boolean().optional(),
|
|
208
|
-
/**
|
|
209
|
-
* Synonym expansion configuration for TF-IDF search.
|
|
210
|
-
* When enabled, queries like "add user" will match tools for "create user".
|
|
211
|
-
* Only applies when strategy is 'tfidf' (ML already handles semantic similarity).
|
|
212
|
-
* Set to false to disable, or provide a config object to customize.
|
|
213
|
-
* @default { enabled: true }
|
|
214
|
-
*/
|
|
215
|
-
synonymExpansion: import_lazy_zod.z.union([import_lazy_zod.z.literal(false), synonymExpansionConfigSchema]).optional()
|
|
216
|
-
}).optional().transform((opts) => ({
|
|
217
|
-
strategy: opts?.strategy ?? DEFAULT_EMBEDDING_OPTIONS.strategy,
|
|
218
|
-
modelName: opts?.modelName ?? DEFAULT_EMBEDDING_OPTIONS.modelName,
|
|
219
|
-
cacheDir: opts?.cacheDir ?? DEFAULT_EMBEDDING_OPTIONS.cacheDir,
|
|
220
|
-
useHNSW: opts?.useHNSW ?? DEFAULT_EMBEDDING_OPTIONS.useHNSW,
|
|
221
|
-
synonymExpansion: opts?.synonymExpansion ?? DEFAULT_EMBEDDING_OPTIONS.synonymExpansion
|
|
222
|
-
}));
|
|
223
|
-
var codeCallSidecarOptionsSchema = import_lazy_zod.z.object({
|
|
224
|
-
/**
|
|
225
|
-
* Enable pass-by-reference support via sidecar
|
|
226
|
-
* When enabled, large strings are automatically lifted to a sidecar
|
|
227
|
-
* and resolved at the callTool boundary
|
|
228
|
-
* @default false
|
|
229
|
-
*/
|
|
230
|
-
enabled: import_lazy_zod.z.boolean().default(false),
|
|
231
|
-
/**
|
|
232
|
-
* Maximum total size of all stored references in bytes
|
|
233
|
-
* @default 16MB (from security level)
|
|
234
|
-
*/
|
|
235
|
-
maxTotalSize: import_lazy_zod.z.number().positive().optional(),
|
|
236
|
-
/**
|
|
237
|
-
* Maximum size of a single reference in bytes
|
|
238
|
-
* @default 4MB (from security level)
|
|
239
|
-
*/
|
|
240
|
-
maxReferenceSize: import_lazy_zod.z.number().positive().optional(),
|
|
241
|
-
/**
|
|
242
|
-
* Threshold in bytes to trigger extraction from source code
|
|
243
|
-
* Strings larger than this are lifted to the sidecar
|
|
244
|
-
* @default 64KB (from security level)
|
|
245
|
-
*/
|
|
246
|
-
extractionThreshold: import_lazy_zod.z.number().positive().optional(),
|
|
247
|
-
/**
|
|
248
|
-
* Maximum expanded size when resolving references for tool calls
|
|
249
|
-
* @default 8MB (from security level)
|
|
250
|
-
*/
|
|
251
|
-
maxResolvedSize: import_lazy_zod.z.number().positive().optional(),
|
|
252
|
-
/**
|
|
253
|
-
* Whether to allow composite handles from string concatenation
|
|
254
|
-
* If false, concatenating references throws an error
|
|
255
|
-
* @default false (strict mode)
|
|
256
|
-
*/
|
|
257
|
-
allowComposites: import_lazy_zod.z.boolean().optional(),
|
|
258
|
-
/**
|
|
259
|
-
* Maximum script length (in characters) when sidecar is disabled
|
|
260
|
-
* Prevents large inline data from being embedded in script
|
|
261
|
-
* If null, no limit is enforced
|
|
262
|
-
* @default 64KB
|
|
263
|
-
*/
|
|
264
|
-
maxScriptLengthWhenDisabled: import_lazy_zod.z.number().positive().nullable().default(64 * 1024)
|
|
265
|
-
}).default(() => ({
|
|
266
|
-
enabled: false,
|
|
267
|
-
maxScriptLengthWhenDisabled: 64 * 1024
|
|
268
|
-
}));
|
|
269
|
-
var codeCallPluginOptionsObjectSchema = import_lazy_zod.z.object({
|
|
270
|
-
/**
|
|
271
|
-
* CodeCall mode
|
|
272
|
-
* @default 'codecall_only'
|
|
273
|
-
*/
|
|
274
|
-
mode: codeCallModeSchema,
|
|
275
|
-
/**
|
|
276
|
-
* App IDs that CodeCall manages. When set, `codecall_only` mode only hides tools
|
|
277
|
-
* from these apps — tools from other apps remain visible in list_tools.
|
|
278
|
-
* When unset (default), all tools in the server are affected.
|
|
279
|
-
* @example ['ecommerce'] — only hide ecommerce app tools, keep calc tools visible
|
|
280
|
-
*/
|
|
281
|
-
appIds: import_lazy_zod.z.array(import_lazy_zod.z.string()).optional(),
|
|
282
|
-
/**
|
|
283
|
-
* Search results per query when a `codecall:search` call names no `topK`
|
|
284
|
-
* @default 8
|
|
285
|
-
*/
|
|
286
|
-
topK: import_lazy_zod.z.number().positive().default(8),
|
|
287
|
-
/**
|
|
288
|
-
* Most tool definitions one `codecall:describe` call returns; a call that would describe more is refused
|
|
289
|
-
* @default 8
|
|
290
|
-
*/
|
|
291
|
-
maxDefinitions: import_lazy_zod.z.number().int().positive().default(8),
|
|
292
|
-
/**
|
|
293
|
-
* Optional filter function for including tools.
|
|
294
|
-
* Signature: (tool: IncludeToolsFilterToolInfo) => boolean
|
|
295
|
-
*/
|
|
296
|
-
includeTools: includeToolsFilterSchema.optional(),
|
|
297
|
-
/**
|
|
298
|
-
* Direct calls configuration
|
|
299
|
-
*/
|
|
300
|
-
directCalls: codeCallDirectCallsOptionsSchema.optional(),
|
|
301
|
-
/**
|
|
302
|
-
* VM execution options
|
|
303
|
-
*/
|
|
304
|
-
vm: codeCallVmOptionsSchema,
|
|
305
|
-
/**
|
|
306
|
-
* Embedding configuration for tool search
|
|
307
|
-
*/
|
|
308
|
-
embedding: codeCallEmbeddingOptionsSchema,
|
|
309
|
-
/**
|
|
310
|
-
* Sidecar (pass-by-reference) configuration
|
|
311
|
-
* When enabled, large data is stored outside the sandbox and resolved at callTool boundary
|
|
312
|
-
*/
|
|
313
|
-
sidecar: codeCallSidecarOptionsSchema
|
|
314
|
-
});
|
|
315
|
-
var DEFAULT_PLUGIN_OPTIONS = {
|
|
316
|
-
mode: "codecall_only",
|
|
317
|
-
topK: 8,
|
|
318
|
-
maxDefinitions: 8,
|
|
319
|
-
vm: DEFAULT_VM_OPTIONS,
|
|
320
|
-
embedding: DEFAULT_EMBEDDING_OPTIONS,
|
|
321
|
-
sidecar: {
|
|
322
|
-
enabled: false,
|
|
323
|
-
maxScriptLengthWhenDisabled: 64 * 1024
|
|
324
|
-
}
|
|
325
|
-
};
|
|
326
|
-
var codeCallPluginOptionsSchema = codeCallPluginOptionsObjectSchema.prefault(DEFAULT_PLUGIN_OPTIONS);
|
|
327
|
-
|
|
328
|
-
// plugins/plugin-codecall/src/providers/code-call.config.ts
|
|
329
|
-
var import_sdk = require("@frontmcp/sdk");
|
|
330
|
-
var CodeCallConfig = class extends import_sdk.BaseConfig {
|
|
331
|
-
constructor(options = {}) {
|
|
332
|
-
const parsedConfig = codeCallPluginOptionsSchema.parse(options);
|
|
333
|
-
const resolvedVm = resolveVmOptions(parsedConfig.vm);
|
|
334
|
-
super({ ...parsedConfig, resolvedVm });
|
|
335
|
-
}
|
|
336
|
-
};
|
|
337
|
-
CodeCallConfig = __decorateClass([
|
|
338
|
-
(0, import_sdk.Provider)({
|
|
339
|
-
name: "codecall:config",
|
|
340
|
-
description: "CodeCall plugin configuration with validated defaults",
|
|
341
|
-
scope: import_sdk.ProviderScope.GLOBAL
|
|
342
|
-
})
|
|
343
|
-
], CodeCallConfig);
|
|
344
|
-
var MAX_ITERATIONS_PER_LOOP = 1e4;
|
|
345
|
-
function maxToolCallsOf(vmOptions) {
|
|
346
|
-
return vmOptions.maxSteps || 100;
|
|
347
|
-
}
|
|
348
|
-
var SANDBOX_RAPID_ENUMERATION_THRESHOLD = 30;
|
|
349
|
-
function rapidEnumerationThresholdOf(vmOptions) {
|
|
350
|
-
return vmOptions.rapidEnumerationThreshold ?? SANDBOX_RAPID_ENUMERATION_THRESHOLD;
|
|
351
|
-
}
|
|
352
|
-
function resolveVmOptions(vmOptions) {
|
|
353
|
-
const preset = vmOptions?.preset ?? "secure";
|
|
354
|
-
const base = presetDefaults(preset);
|
|
355
|
-
return {
|
|
356
|
-
...base,
|
|
357
|
-
...vmOptions,
|
|
358
|
-
disabledBuiltins: vmOptions?.disabledBuiltins ?? base.disabledBuiltins,
|
|
359
|
-
disabledGlobals: vmOptions?.disabledGlobals ?? base.disabledGlobals
|
|
360
|
-
};
|
|
361
|
-
}
|
|
362
|
-
function presetDefaults(preset) {
|
|
363
|
-
switch (preset) {
|
|
364
|
-
case "locked_down":
|
|
365
|
-
return {
|
|
366
|
-
preset,
|
|
367
|
-
timeoutMs: 2e3,
|
|
368
|
-
allowLoops: false,
|
|
369
|
-
allowConsole: false,
|
|
370
|
-
maxSteps: 2e3,
|
|
371
|
-
disabledBuiltins: ["eval", "Function", "AsyncFunction"],
|
|
372
|
-
disabledGlobals: [
|
|
373
|
-
"require",
|
|
374
|
-
"process",
|
|
375
|
-
"fetch",
|
|
376
|
-
"setTimeout",
|
|
377
|
-
"setInterval",
|
|
378
|
-
"setImmediate",
|
|
379
|
-
"global",
|
|
380
|
-
"globalThis"
|
|
381
|
-
],
|
|
382
|
-
maxSanitizeDepth: 10,
|
|
383
|
-
maxSanitizeProperties: 1e3
|
|
384
|
-
};
|
|
385
|
-
case "balanced":
|
|
386
|
-
return {
|
|
387
|
-
preset,
|
|
388
|
-
timeoutMs: 5e3,
|
|
389
|
-
allowLoops: true,
|
|
390
|
-
allowConsole: true,
|
|
391
|
-
maxSteps: 1e4,
|
|
392
|
-
disabledBuiltins: ["eval", "Function", "AsyncFunction"],
|
|
393
|
-
disabledGlobals: ["require", "process", "fetch"],
|
|
394
|
-
maxSanitizeDepth: 50,
|
|
395
|
-
maxSanitizeProperties: 5e3
|
|
396
|
-
};
|
|
397
|
-
case "experimental":
|
|
398
|
-
return {
|
|
399
|
-
preset,
|
|
400
|
-
timeoutMs: 1e4,
|
|
401
|
-
allowLoops: true,
|
|
402
|
-
allowConsole: true,
|
|
403
|
-
maxSteps: 2e4,
|
|
404
|
-
disabledBuiltins: ["eval", "Function", "AsyncFunction"],
|
|
405
|
-
disabledGlobals: ["require", "process"],
|
|
406
|
-
maxSanitizeDepth: 100,
|
|
407
|
-
maxSanitizeProperties: 2e4
|
|
408
|
-
};
|
|
409
|
-
case "secure":
|
|
410
|
-
default:
|
|
411
|
-
return {
|
|
412
|
-
preset: "secure",
|
|
413
|
-
timeoutMs: 3500,
|
|
414
|
-
allowLoops: false,
|
|
415
|
-
allowConsole: true,
|
|
416
|
-
maxSteps: 5e3,
|
|
417
|
-
disabledBuiltins: ["eval", "Function", "AsyncFunction"],
|
|
418
|
-
disabledGlobals: [
|
|
419
|
-
"require",
|
|
420
|
-
"process",
|
|
421
|
-
"fetch",
|
|
422
|
-
"setTimeout",
|
|
423
|
-
"setInterval",
|
|
424
|
-
"setImmediate",
|
|
425
|
-
"global",
|
|
426
|
-
"globalThis"
|
|
427
|
-
],
|
|
428
|
-
maxSanitizeDepth: 50,
|
|
429
|
-
maxSanitizeProperties: 2e3
|
|
430
|
-
};
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
// plugins/plugin-codecall/src/security/codecall-dispatch.ts
|
|
435
|
-
var import_sdk2 = require("@frontmcp/sdk");
|
|
436
|
-
var CODECALL_DISPATCH = /* @__PURE__ */ Symbol("frontmcp.codecall.dispatch");
|
|
437
|
-
function asCodeCallDispatch(ctx) {
|
|
438
|
-
return Object.defineProperty(ctx, CODECALL_DISPATCH, { value: true, enumerable: false });
|
|
439
|
-
}
|
|
440
|
-
function isInProcessDispatch(ctx) {
|
|
441
|
-
if ((0, import_sdk2.getRunningTool)()) return true;
|
|
442
|
-
if (typeof ctx !== "object" || ctx === null) return false;
|
|
443
|
-
const marks = ctx;
|
|
444
|
-
return marks[CODECALL_DISPATCH] === true || marks.internalCall === true;
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
// plugins/plugin-codecall/src/security/codecall-tool-policy.ts
|
|
448
|
-
var BLOCKED_NAMESPACE_PATTERNS = Object.freeze([/^system:/, /^internal:/, /^__/]);
|
|
449
|
-
function isOfferedToCaller(availableWhen, surface) {
|
|
450
|
-
const offered = availableWhen?.surface;
|
|
451
|
-
return offered === void 0 || surface === void 0 || offered.includes(surface);
|
|
452
|
-
}
|
|
453
|
-
var ALLOWED = { allowed: true };
|
|
454
|
-
function deny(reason) {
|
|
455
|
-
return { allowed: false, reason };
|
|
456
|
-
}
|
|
457
|
-
function codeCallAppIdOf(scope, entry) {
|
|
458
|
-
const lineage = scope?.tools?.lineageOf?.(entry) ?? [];
|
|
459
|
-
const owners = entry.owner ? [...lineage, entry.owner] : lineage;
|
|
460
|
-
return owners.find((owner) => owner.kind === "app")?.id;
|
|
461
|
-
}
|
|
462
|
-
function toCodeCallPolicyTool(entry, requestedName, scope) {
|
|
463
|
-
const { metadata } = entry;
|
|
464
|
-
return {
|
|
465
|
-
name: entry.name || entry.fullName,
|
|
466
|
-
fullName: entry.fullName,
|
|
467
|
-
aliases: requestedName ? [requestedName] : void 0,
|
|
468
|
-
appId: codeCallAppIdOf(scope, entry),
|
|
469
|
-
description: metadata?.description,
|
|
470
|
-
tags: metadata?.tags,
|
|
471
|
-
// `internal` tools refuse every external tools/call, CodeCall's included, so no surface may offer them.
|
|
472
|
-
hidden: metadata?.hideFromDiscovery === true || metadata?.visibility === "hidden" || metadata?.visibility === "internal",
|
|
473
|
-
codecall: metadata?.codecall,
|
|
474
|
-
annotations: metadata?.annotations,
|
|
475
|
-
metadata
|
|
476
|
-
};
|
|
477
|
-
}
|
|
478
|
-
function isPlainData(value) {
|
|
479
|
-
if (Array.isArray(value)) return true;
|
|
480
|
-
const proto = Object.getPrototypeOf(value);
|
|
481
|
-
return proto === Object.prototype || proto === null;
|
|
482
|
-
}
|
|
483
|
-
function readOnlyCopy(value, copies) {
|
|
484
|
-
if (typeof value !== "object" || value === null || !isPlainData(value)) return value;
|
|
485
|
-
const existing = copies.get(value);
|
|
486
|
-
if (existing !== void 0) return existing;
|
|
487
|
-
const copy = Array.isArray(value) ? [] : Object.create(Object.getPrototypeOf(value));
|
|
488
|
-
copies.set(value, copy);
|
|
489
|
-
for (const key of Reflect.ownKeys(value)) {
|
|
490
|
-
if (!Object.prototype.propertyIsEnumerable.call(value, key)) continue;
|
|
491
|
-
Object.defineProperty(copy, key, {
|
|
492
|
-
value: readOnlyCopy(Reflect.get(value, key), copies),
|
|
493
|
-
enumerable: true,
|
|
494
|
-
writable: true,
|
|
495
|
-
configurable: true
|
|
496
|
-
});
|
|
497
|
-
}
|
|
498
|
-
return Object.freeze(copy);
|
|
499
|
-
}
|
|
500
|
-
function toToolFilterInfo(tool) {
|
|
501
|
-
const copies = /* @__PURE__ */ new WeakMap();
|
|
502
|
-
const annotations = readOnlyCopy(tool.annotations, copies);
|
|
503
|
-
const metadata = tool.metadata ? readOnlyCopy({ ...tool.metadata, ...annotations ? { annotations: tool.annotations } : {} }, copies) : void 0;
|
|
504
|
-
return {
|
|
505
|
-
name: tool.name,
|
|
506
|
-
fullName: tool.fullName,
|
|
507
|
-
appId: tool.appId,
|
|
508
|
-
source: tool.codecall?.source,
|
|
509
|
-
description: tool.description,
|
|
510
|
-
tags: readOnlyCopy(tool.codecall?.tags ?? tool.tags, copies),
|
|
511
|
-
annotations,
|
|
512
|
-
metadata
|
|
513
|
-
};
|
|
514
|
-
}
|
|
515
|
-
function ownNamesOf(tool) {
|
|
516
|
-
return [tool.name, tool.fullName].filter((candidate) => !!candidate);
|
|
517
|
-
}
|
|
518
|
-
function checkCodeCallToolPolicy(tool, config) {
|
|
519
|
-
const { name } = tool;
|
|
520
|
-
const spellings = [...ownNamesOf(tool), ...tool.aliases ?? []];
|
|
521
|
-
if (spellings.some((candidate) => candidate.startsWith("codecall:"))) {
|
|
522
|
-
return deny("CodeCall meta-tools are not callable from CodeCall");
|
|
523
|
-
}
|
|
524
|
-
for (const candidate of spellings) {
|
|
525
|
-
if (BLOCKED_NAMESPACE_PATTERNS.some((pattern) => pattern.test(candidate))) {
|
|
526
|
-
return deny(`Tool "${candidate}" is in a namespace CodeCall never calls`);
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
if (tool.hidden === true) {
|
|
530
|
-
return deny(`Tool "${name}" is hidden from discovery`);
|
|
531
|
-
}
|
|
532
|
-
const enabled = tool.codecall?.enabledInCodeCall;
|
|
533
|
-
switch (config.mode) {
|
|
534
|
-
case "codecall_only":
|
|
535
|
-
case "metadata_driven":
|
|
536
|
-
if (enabled === false) {
|
|
537
|
-
return deny(`Tool "${name}" sets enabledInCodeCall: false`);
|
|
538
|
-
}
|
|
539
|
-
break;
|
|
540
|
-
case "codecall_opt_in":
|
|
541
|
-
if (enabled !== true) {
|
|
542
|
-
return deny(`Tool "${name}" has not opted in to CodeCall`);
|
|
543
|
-
}
|
|
544
|
-
break;
|
|
545
|
-
default:
|
|
546
|
-
return deny(`Unknown CodeCall mode: ${String(config.mode)}`);
|
|
547
|
-
}
|
|
548
|
-
if (config.includeTools && !config.includeTools(toToolFilterInfo(tool))) {
|
|
549
|
-
return deny(`Tool "${name}" is excluded by the includeTools filter`);
|
|
550
|
-
}
|
|
551
|
-
return ALLOWED;
|
|
552
|
-
}
|
|
553
|
-
function denyUnknownTool(name) {
|
|
554
|
-
return deny(`Tool "${name}" is not available through CodeCall`);
|
|
555
|
-
}
|
|
556
|
-
function resolveCodeCallTool(scope, name) {
|
|
557
|
-
const typedScope = scope;
|
|
558
|
-
const alias = /[-_]/.test(name) ? name.includes("_") ? name.replace(/_/g, "-") : name.replace(/-/g, "_") : void 0;
|
|
559
|
-
const candidates = alias ? [name, alias] : [name];
|
|
560
|
-
const matches = (entry) => candidates.includes(entry.fullName) || candidates.includes(entry.name);
|
|
561
|
-
const local = typedScope.tools?.getTools(true)?.find(matches);
|
|
562
|
-
if (local) return local;
|
|
563
|
-
const registries = typedScope.providers?.getRegistries?.("AppRegistry") ?? [];
|
|
564
|
-
for (const registry of registries) {
|
|
565
|
-
for (const app of registry.getApps()) {
|
|
566
|
-
if (!app.isRemote) continue;
|
|
567
|
-
const remote = app.tools.getTools(true).find(matches);
|
|
568
|
-
if (remote) return remote;
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
return void 0;
|
|
572
|
-
}
|
|
573
|
-
function checkDirectCallPolicy(tool, directCalls) {
|
|
574
|
-
if (!directCalls) return ALLOWED;
|
|
575
|
-
if (directCalls.enabled === false) {
|
|
576
|
-
return deny("Direct tool invocation is disabled");
|
|
577
|
-
}
|
|
578
|
-
const { allowedTools } = directCalls;
|
|
579
|
-
if (allowedTools && !ownNamesOf(tool).some((ownName) => allowedTools.includes(ownName))) {
|
|
580
|
-
return deny(`Tool "${tool.name}" is not in the direct-call allowlist`);
|
|
581
|
-
}
|
|
582
|
-
if (directCalls.filter && !directCalls.filter(toToolFilterInfo(tool))) {
|
|
583
|
-
return deny(`Tool "${tool.name}" is excluded by the directCalls filter`);
|
|
584
|
-
}
|
|
585
|
-
return ALLOWED;
|
|
586
|
-
}
|
|
587
|
-
function readCodeCallPolicyConfig(config) {
|
|
588
|
-
return {
|
|
589
|
-
// An absent mode means an unparsed/partial config, not a hostile one: fall back to the
|
|
590
|
-
// schema's own documented default rather than denying every call. An unrecognised mode
|
|
591
|
-
// still fails closed inside the policy's switch.
|
|
592
|
-
mode: config.get("mode") ?? "codecall_only",
|
|
593
|
-
includeTools: config.get("includeTools")
|
|
594
|
-
};
|
|
595
|
-
}
|
|
596
|
-
function checkCodeCallToolAccess(scope, config, name, options = {}) {
|
|
597
|
-
const entry = resolveCodeCallTool(scope, name);
|
|
598
|
-
if (!entry) return denyUnknownTool(name);
|
|
599
|
-
if (!isOfferedToCaller(entry.metadata?.availableWhen, options.surface)) {
|
|
600
|
-
return deny(`Tool "${name}" is not offered on the caller's surface "${options.surface}"`);
|
|
601
|
-
}
|
|
602
|
-
const policyTool = toCodeCallPolicyTool(entry, name, scope);
|
|
603
|
-
const baseDecision = checkCodeCallToolPolicy(policyTool, readCodeCallPolicyConfig(config));
|
|
604
|
-
if (!baseDecision.allowed) return baseDecision;
|
|
605
|
-
if (options.directCall) {
|
|
606
|
-
const directDecision = checkDirectCallPolicy(
|
|
607
|
-
policyTool,
|
|
608
|
-
config.get("directCalls")
|
|
609
|
-
);
|
|
610
|
-
if (!directDecision.allowed) return directDecision;
|
|
611
|
-
}
|
|
612
|
-
return { allowed: true, entry };
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
// plugins/plugin-codecall/src/utils/client-error-message.ts
|
|
616
|
-
var EMBEDDED_STACK_FRAME_RE = /\n[ \t]*at\s[^\n]*/g;
|
|
617
|
-
var QUOTED_PATH_RE = /(['"`])((?:~?\/|[A-Za-z]:[\\/]|\\\\)[^\s'"`\\/][^'"`\n]*)\1/g;
|
|
618
|
-
var URL_RE = /\b[A-Za-z][A-Za-z0-9+.-]{1,31}:\/\/(?:[^\s'"`<>,;]|[,;](?!~?\/|[A-Za-z]:[\\/]|\\\\))*/g;
|
|
619
|
-
var QUERY_PATH_VALUE_RE = /([?&][^=&#]*=)(?:~?\/|[A-Za-z]:[\\/]|\\\\)[^&#]*/g;
|
|
620
|
-
var POSIX_SEGMENT = String.raw`[^\s/\\'"\x60<>|,;:()\[\]{}]+`;
|
|
621
|
-
var WINDOWS_SEGMENT = String.raw`[^\s/\\'"\x60<>|,;:*?]+`;
|
|
622
|
-
function segments(segment, separator) {
|
|
623
|
-
const spaced = `${segment}(?: ${segment}){0,2}`;
|
|
624
|
-
return `(?:(?:${spaced}${separator})+(?:${segment})?|${segment})`;
|
|
625
|
-
}
|
|
626
|
-
var UNQUOTED_PATH_RE = new RegExp(
|
|
627
|
-
[
|
|
628
|
-
String.raw`(?<![\w.~/\\)\]-])~?/+${segments(POSIX_SEGMENT, "/+")}`,
|
|
629
|
-
String.raw`(?<![\w\\/])[A-Za-z]:[\\/]+${segments(WINDOWS_SEGMENT, String.raw`[\\/]+`)}?`,
|
|
630
|
-
String.raw`(?<![\w\\])\\\\${segments(WINDOWS_SEGMENT, String.raw`[\\/]+`)}`
|
|
631
|
-
].join("|"),
|
|
632
|
-
"g"
|
|
633
|
-
);
|
|
634
|
-
function redactPaths(text) {
|
|
635
|
-
return text.replace(QUOTED_PATH_RE, "$1[path]$1").replace(UNQUOTED_PATH_RE, "[path]");
|
|
636
|
-
}
|
|
637
|
-
function toClientErrorMessage(message) {
|
|
638
|
-
if (!message) return "";
|
|
639
|
-
return redactAbsolutePaths(message.replace(EMBEDDED_STACK_FRAME_RE, ""));
|
|
640
|
-
}
|
|
641
|
-
function redactAbsolutePaths(text) {
|
|
642
|
-
let result = "";
|
|
643
|
-
let last = 0;
|
|
644
|
-
for (const match of text.matchAll(URL_RE)) {
|
|
645
|
-
const start = match.index ?? 0;
|
|
646
|
-
result += redactPaths(text.slice(last, start));
|
|
647
|
-
result += /^file:/i.test(match[0]) ? "[path]" : match[0].replace(QUERY_PATH_VALUE_RE, "$1[path]");
|
|
648
|
-
last = start + match[0].length;
|
|
649
|
-
}
|
|
650
|
-
return result + redactPaths(text.slice(last));
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
// plugins/plugin-codecall/src/errors/tool-call.errors.ts
|
|
654
|
-
var TOOL_CALL_ERROR_CODES = {
|
|
655
|
-
NOT_FOUND: "NOT_FOUND",
|
|
656
|
-
VALIDATION: "VALIDATION",
|
|
657
|
-
EXECUTION: "EXECUTION",
|
|
658
|
-
TIMEOUT: "TIMEOUT",
|
|
659
|
-
ACCESS_DENIED: "ACCESS_DENIED",
|
|
660
|
-
RATE_LIMITED: "RATE_LIMITED",
|
|
661
|
-
SELF_REFERENCE: "SELF_REFERENCE"
|
|
662
|
-
};
|
|
663
|
-
function createToolCallError(code, toolName, rawMessage) {
|
|
664
|
-
const sanitizedMessage = getSanitizedMessage(code, toolName, rawMessage);
|
|
665
|
-
return Object.freeze({
|
|
666
|
-
code,
|
|
667
|
-
message: sanitizedMessage,
|
|
668
|
-
toolName
|
|
669
|
-
});
|
|
670
|
-
}
|
|
671
|
-
function getSanitizedMessage(code, toolName, rawMessage) {
|
|
672
|
-
switch (code) {
|
|
673
|
-
case TOOL_CALL_ERROR_CODES.NOT_FOUND:
|
|
674
|
-
return `Tool "${toolName}" was not found`;
|
|
675
|
-
case TOOL_CALL_ERROR_CODES.VALIDATION:
|
|
676
|
-
return rawMessage ? sanitizeValidationMessage(rawMessage) : `Input validation failed for tool "${toolName}"`;
|
|
677
|
-
case TOOL_CALL_ERROR_CODES.EXECUTION:
|
|
678
|
-
return `Tool "${toolName}" execution failed`;
|
|
679
|
-
case TOOL_CALL_ERROR_CODES.TIMEOUT:
|
|
680
|
-
return `Tool "${toolName}" execution timed out`;
|
|
681
|
-
case TOOL_CALL_ERROR_CODES.ACCESS_DENIED:
|
|
682
|
-
return `Access denied for tool "${toolName}"`;
|
|
683
|
-
case TOOL_CALL_ERROR_CODES.RATE_LIMITED:
|
|
684
|
-
return `Tool "${toolName}" was rate limited`;
|
|
685
|
-
case TOOL_CALL_ERROR_CODES.SELF_REFERENCE:
|
|
686
|
-
return `Cannot call CodeCall tools from within AgentScript`;
|
|
687
|
-
default:
|
|
688
|
-
return `An error occurred while calling "${toolName}"`;
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
function sanitizeValidationMessage(message) {
|
|
692
|
-
let sanitized = toClientErrorMessage(message);
|
|
693
|
-
sanitized = sanitized.replace(/\bat line \d+/gi, "");
|
|
694
|
-
sanitized = sanitized.replace(/\bline \d+/gi, "");
|
|
695
|
-
sanitized = sanitized.replace(/:\d+:\d+/g, "");
|
|
696
|
-
if (sanitized.length > 200) {
|
|
697
|
-
sanitized = sanitized.substring(0, 200) + "...";
|
|
698
|
-
}
|
|
699
|
-
return sanitized.trim();
|
|
700
|
-
}
|
|
701
|
-
var SelfReferenceError = class extends Error {
|
|
702
|
-
code = TOOL_CALL_ERROR_CODES.SELF_REFERENCE;
|
|
703
|
-
toolName;
|
|
704
|
-
constructor(toolName) {
|
|
705
|
-
super(`Self-reference attack: Attempted to call CodeCall tool "${toolName}" from within AgentScript`);
|
|
706
|
-
this.name = "SelfReferenceError";
|
|
707
|
-
this.toolName = toolName;
|
|
708
|
-
Object.freeze(this);
|
|
709
|
-
}
|
|
710
|
-
};
|
|
711
|
-
|
|
712
|
-
// plugins/plugin-codecall/src/security/self-reference-guard.ts
|
|
713
|
-
var CODECALL_TOOL_PREFIX = "codecall:";
|
|
714
|
-
var BLOCKED_CODECALL_TOOLS = Object.freeze(
|
|
715
|
-
/* @__PURE__ */ new Set(["codecall:search", "codecall:describe", "codecall:execute", "codecall:invoke"])
|
|
716
|
-
);
|
|
717
|
-
function isBlockedSelfReference(toolName) {
|
|
718
|
-
const normalizedName = toolName.toLowerCase().trim();
|
|
719
|
-
if (normalizedName.startsWith(CODECALL_TOOL_PREFIX)) {
|
|
720
|
-
return true;
|
|
721
|
-
}
|
|
722
|
-
if (BLOCKED_CODECALL_TOOLS.has(toolName)) {
|
|
723
|
-
return true;
|
|
724
|
-
}
|
|
725
|
-
return false;
|
|
726
|
-
}
|
|
727
|
-
function assertNotSelfReference(toolName) {
|
|
728
|
-
if (isBlockedSelfReference(toolName)) {
|
|
729
|
-
throw new SelfReferenceError(toolName);
|
|
730
|
-
}
|
|
731
|
-
}
|
|
732
|
-
|
|
733
|
-
// plugins/plugin-codecall/src/services/audit-logger.service.ts
|
|
734
|
-
var import_sdk3 = require("@frontmcp/sdk");
|
|
735
|
-
var AUDIT_EVENT_TYPES = {
|
|
736
|
-
/** Script execution started */
|
|
737
|
-
EXECUTION_START: "codecall:execution:start",
|
|
738
|
-
/** Script execution completed successfully */
|
|
739
|
-
EXECUTION_SUCCESS: "codecall:execution:success",
|
|
740
|
-
/** Script execution failed */
|
|
741
|
-
EXECUTION_FAILURE: "codecall:execution:failure",
|
|
742
|
-
/** Script execution timed out */
|
|
743
|
-
EXECUTION_TIMEOUT: "codecall:execution:timeout",
|
|
744
|
-
/** Tool call initiated from script */
|
|
745
|
-
TOOL_CALL_START: "codecall:tool:call:start",
|
|
746
|
-
/** Tool call completed successfully */
|
|
747
|
-
TOOL_CALL_SUCCESS: "codecall:tool:call:success",
|
|
748
|
-
/** Tool call failed */
|
|
749
|
-
TOOL_CALL_FAILURE: "codecall:tool:call:failure",
|
|
750
|
-
/** Self-reference attack blocked */
|
|
751
|
-
SECURITY_SELF_REFERENCE: "codecall:security:self-reference",
|
|
752
|
-
/** Tool access denied */
|
|
753
|
-
SECURITY_ACCESS_DENIED: "codecall:security:access-denied",
|
|
754
|
-
/** AST validation failed (blocked code pattern) */
|
|
755
|
-
SECURITY_AST_BLOCKED: "codecall:security:ast-blocked",
|
|
756
|
-
/** Search performed */
|
|
757
|
-
SEARCH_PERFORMED: "codecall:search:performed",
|
|
758
|
-
/** Tool described */
|
|
759
|
-
DESCRIBE_PERFORMED: "codecall:describe:performed",
|
|
760
|
-
/** Direct invoke performed */
|
|
761
|
-
INVOKE_PERFORMED: "codecall:invoke:performed"
|
|
762
|
-
};
|
|
763
|
-
var AuditLoggerService = class {
|
|
764
|
-
listeners = /* @__PURE__ */ new Set();
|
|
765
|
-
executionCounter = 0;
|
|
766
|
-
/**
|
|
767
|
-
* Subscribe to audit events.
|
|
768
|
-
*
|
|
769
|
-
* @param listener - Function to call when events occur
|
|
770
|
-
* @returns Unsubscribe function
|
|
771
|
-
*/
|
|
772
|
-
subscribe(listener) {
|
|
773
|
-
this.listeners.add(listener);
|
|
774
|
-
return () => {
|
|
775
|
-
this.listeners.delete(listener);
|
|
776
|
-
};
|
|
777
|
-
}
|
|
778
|
-
/**
|
|
779
|
-
* Generate a unique execution ID.
|
|
780
|
-
*/
|
|
781
|
-
generateExecutionId() {
|
|
782
|
-
const timestamp = Date.now().toString(36);
|
|
783
|
-
const counter = (++this.executionCounter).toString(36).padStart(4, "0");
|
|
784
|
-
const random = Math.random().toString(36).substring(2, 8);
|
|
785
|
-
return `exec_${timestamp}_${counter}_${random}`;
|
|
786
|
-
}
|
|
787
|
-
/**
|
|
788
|
-
* Log execution start.
|
|
789
|
-
*/
|
|
790
|
-
logExecutionStart(executionId, script) {
|
|
791
|
-
this.emit({
|
|
792
|
-
type: AUDIT_EVENT_TYPES.EXECUTION_START,
|
|
793
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
794
|
-
executionId,
|
|
795
|
-
data: {
|
|
796
|
-
scriptHash: this.hashScript(script),
|
|
797
|
-
scriptLength: script.length
|
|
798
|
-
}
|
|
799
|
-
});
|
|
800
|
-
}
|
|
801
|
-
/**
|
|
802
|
-
* Log execution success.
|
|
803
|
-
*/
|
|
804
|
-
logExecutionSuccess(executionId, script, durationMs, toolCallCount) {
|
|
805
|
-
this.emit({
|
|
806
|
-
type: AUDIT_EVENT_TYPES.EXECUTION_SUCCESS,
|
|
807
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
808
|
-
executionId,
|
|
809
|
-
durationMs,
|
|
810
|
-
data: {
|
|
811
|
-
scriptHash: this.hashScript(script),
|
|
812
|
-
scriptLength: script.length,
|
|
813
|
-
toolCallCount
|
|
814
|
-
}
|
|
815
|
-
});
|
|
816
|
-
}
|
|
817
|
-
/**
|
|
818
|
-
* Log execution failure.
|
|
819
|
-
*/
|
|
820
|
-
logExecutionFailure(executionId, script, durationMs, error) {
|
|
821
|
-
this.emit({
|
|
822
|
-
type: AUDIT_EVENT_TYPES.EXECUTION_FAILURE,
|
|
823
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
824
|
-
executionId,
|
|
825
|
-
durationMs,
|
|
826
|
-
data: {
|
|
827
|
-
scriptHash: this.hashScript(script),
|
|
828
|
-
scriptLength: script.length,
|
|
829
|
-
error: this.sanitizeError(error)
|
|
830
|
-
}
|
|
831
|
-
});
|
|
832
|
-
}
|
|
833
|
-
/**
|
|
834
|
-
* Log execution timeout.
|
|
835
|
-
*/
|
|
836
|
-
logExecutionTimeout(executionId, script, durationMs) {
|
|
837
|
-
this.emit({
|
|
838
|
-
type: AUDIT_EVENT_TYPES.EXECUTION_TIMEOUT,
|
|
839
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
840
|
-
executionId,
|
|
841
|
-
durationMs,
|
|
842
|
-
data: {
|
|
843
|
-
scriptHash: this.hashScript(script),
|
|
844
|
-
scriptLength: script.length
|
|
845
|
-
}
|
|
846
|
-
});
|
|
847
|
-
}
|
|
848
|
-
/**
|
|
849
|
-
* Log tool call start.
|
|
850
|
-
*/
|
|
851
|
-
logToolCallStart(executionId, toolName, callDepth) {
|
|
852
|
-
this.emit({
|
|
853
|
-
type: AUDIT_EVENT_TYPES.TOOL_CALL_START,
|
|
854
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
855
|
-
executionId,
|
|
856
|
-
data: {
|
|
857
|
-
toolName,
|
|
858
|
-
callDepth
|
|
859
|
-
}
|
|
860
|
-
});
|
|
861
|
-
}
|
|
862
|
-
/**
|
|
863
|
-
* Log tool call success.
|
|
864
|
-
*/
|
|
865
|
-
logToolCallSuccess(executionId, toolName, callDepth, durationMs) {
|
|
866
|
-
this.emit({
|
|
867
|
-
type: AUDIT_EVENT_TYPES.TOOL_CALL_SUCCESS,
|
|
868
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
869
|
-
executionId,
|
|
870
|
-
durationMs,
|
|
871
|
-
data: {
|
|
872
|
-
toolName,
|
|
873
|
-
callDepth
|
|
874
|
-
}
|
|
875
|
-
});
|
|
876
|
-
}
|
|
877
|
-
/**
|
|
878
|
-
* Log tool call failure.
|
|
879
|
-
*/
|
|
880
|
-
logToolCallFailure(executionId, toolName, callDepth, durationMs, errorCode) {
|
|
881
|
-
this.emit({
|
|
882
|
-
type: AUDIT_EVENT_TYPES.TOOL_CALL_FAILURE,
|
|
883
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
884
|
-
executionId,
|
|
885
|
-
durationMs,
|
|
886
|
-
data: {
|
|
887
|
-
toolName,
|
|
888
|
-
callDepth,
|
|
889
|
-
errorCode
|
|
890
|
-
}
|
|
891
|
-
});
|
|
892
|
-
}
|
|
893
|
-
/**
|
|
894
|
-
* Log security event: self-reference blocked.
|
|
895
|
-
*/
|
|
896
|
-
logSecuritySelfReference(executionId, toolName) {
|
|
897
|
-
this.emit({
|
|
898
|
-
type: AUDIT_EVENT_TYPES.SECURITY_SELF_REFERENCE,
|
|
899
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
900
|
-
executionId,
|
|
901
|
-
data: {
|
|
902
|
-
blocked: toolName,
|
|
903
|
-
reason: "Self-reference attack: attempted to call CodeCall tool from within AgentScript"
|
|
904
|
-
}
|
|
905
|
-
});
|
|
906
|
-
}
|
|
907
|
-
/**
|
|
908
|
-
* Log security event: access denied.
|
|
909
|
-
*/
|
|
910
|
-
logSecurityAccessDenied(executionId, toolName, reason) {
|
|
911
|
-
this.emit({
|
|
912
|
-
type: AUDIT_EVENT_TYPES.SECURITY_ACCESS_DENIED,
|
|
913
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
914
|
-
executionId,
|
|
915
|
-
data: {
|
|
916
|
-
blocked: toolName,
|
|
917
|
-
reason: this.sanitizeError(reason)
|
|
918
|
-
}
|
|
919
|
-
});
|
|
920
|
-
}
|
|
921
|
-
/**
|
|
922
|
-
* Log security event: AST validation blocked.
|
|
923
|
-
*/
|
|
924
|
-
logSecurityAstBlocked(executionId, pattern, reason) {
|
|
925
|
-
this.emit({
|
|
926
|
-
type: AUDIT_EVENT_TYPES.SECURITY_AST_BLOCKED,
|
|
927
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
928
|
-
executionId,
|
|
929
|
-
data: {
|
|
930
|
-
blocked: pattern,
|
|
931
|
-
reason: this.sanitizeError(reason)
|
|
932
|
-
}
|
|
933
|
-
});
|
|
934
|
-
}
|
|
935
|
-
/**
|
|
936
|
-
* Log search operation.
|
|
937
|
-
*/
|
|
938
|
-
logSearch(executionId, query, resultCount, durationMs) {
|
|
939
|
-
this.emit({
|
|
940
|
-
type: AUDIT_EVENT_TYPES.SEARCH_PERFORMED,
|
|
941
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
942
|
-
executionId,
|
|
943
|
-
durationMs,
|
|
944
|
-
data: {
|
|
945
|
-
queryLength: query.length,
|
|
946
|
-
resultCount
|
|
947
|
-
}
|
|
948
|
-
});
|
|
949
|
-
}
|
|
950
|
-
/**
|
|
951
|
-
* Log describe operation.
|
|
952
|
-
*/
|
|
953
|
-
logDescribe(executionId, toolNames, durationMs) {
|
|
954
|
-
this.emit({
|
|
955
|
-
type: AUDIT_EVENT_TYPES.DESCRIBE_PERFORMED,
|
|
956
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
957
|
-
executionId,
|
|
958
|
-
durationMs,
|
|
959
|
-
data: {
|
|
960
|
-
toolCount: toolNames.length,
|
|
961
|
-
toolNames: toolNames.slice(0, 10)
|
|
962
|
-
// Limit to first 10 for audit
|
|
963
|
-
}
|
|
964
|
-
});
|
|
965
|
-
}
|
|
966
|
-
/**
|
|
967
|
-
* Log invoke operation.
|
|
968
|
-
*/
|
|
969
|
-
logInvoke(executionId, toolName, success, durationMs) {
|
|
970
|
-
this.emit({
|
|
971
|
-
type: AUDIT_EVENT_TYPES.INVOKE_PERFORMED,
|
|
972
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
973
|
-
executionId,
|
|
974
|
-
durationMs,
|
|
975
|
-
data: {
|
|
976
|
-
toolName,
|
|
977
|
-
success
|
|
978
|
-
}
|
|
979
|
-
});
|
|
980
|
-
}
|
|
981
|
-
/**
|
|
982
|
-
* Emit an audit event to all listeners.
|
|
983
|
-
*/
|
|
984
|
-
emit(event) {
|
|
985
|
-
const frozenEvent = Object.freeze({ ...event, data: Object.freeze({ ...event.data }) });
|
|
986
|
-
for (const listener of this.listeners) {
|
|
987
|
-
try {
|
|
988
|
-
listener(frozenEvent);
|
|
989
|
-
} catch {
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
}
|
|
993
|
-
/**
|
|
994
|
-
* Create a simple hash of the script for identification.
|
|
995
|
-
* Uses a fast, non-cryptographic hash for performance.
|
|
996
|
-
*/
|
|
997
|
-
hashScript(script) {
|
|
998
|
-
let hash = 0;
|
|
999
|
-
for (let i = 0; i < script.length; i++) {
|
|
1000
|
-
const char = script.charCodeAt(i);
|
|
1001
|
-
hash = (hash << 5) - hash + char;
|
|
1002
|
-
hash = hash & hash;
|
|
1003
|
-
}
|
|
1004
|
-
return `sh_${(hash >>> 0).toString(16).padStart(8, "0")}`;
|
|
1005
|
-
}
|
|
1006
|
-
/**
|
|
1007
|
-
* Sanitize error messages to remove sensitive information.
|
|
1008
|
-
*/
|
|
1009
|
-
sanitizeError(error) {
|
|
1010
|
-
if (!error) return "Unknown error";
|
|
1011
|
-
let sanitized = toClientErrorMessage(error);
|
|
1012
|
-
sanitized = sanitized.replace(/:\d+:\d+/g, "");
|
|
1013
|
-
if (sanitized.length > 200) {
|
|
1014
|
-
sanitized = sanitized.substring(0, 200) + "...";
|
|
1015
|
-
}
|
|
1016
|
-
return sanitized.trim();
|
|
1017
|
-
}
|
|
1018
|
-
};
|
|
1019
|
-
AuditLoggerService = __decorateClass([
|
|
1020
|
-
(0, import_sdk3.Provider)({
|
|
1021
|
-
name: "codecall:audit-logger",
|
|
1022
|
-
scope: import_sdk3.ProviderScope.GLOBAL
|
|
1023
|
-
})
|
|
1024
|
-
], AuditLoggerService);
|
|
1025
|
-
|
|
1026
|
-
// plugins/plugin-codecall/src/services/tool-search.service.ts
|
|
1027
|
-
var import_vectoriadb = require("vectoriadb");
|
|
1028
|
-
|
|
1029
|
-
// plugins/plugin-codecall/src/services/synonym-expansion.service.ts
|
|
1030
|
-
var DEFAULT_SYNONYM_GROUPS = [
|
|
1031
|
-
// ===========================================================================
|
|
1032
|
-
// 1. CORE DATA OPERATIONS (CRUD+)
|
|
1033
|
-
// ===========================================================================
|
|
1034
|
-
// Creation / Instantiation
|
|
1035
|
-
[
|
|
1036
|
-
"create",
|
|
1037
|
-
"add",
|
|
1038
|
-
"new",
|
|
1039
|
-
"insert",
|
|
1040
|
-
"make",
|
|
1041
|
-
"append",
|
|
1042
|
-
"register",
|
|
1043
|
-
"generate",
|
|
1044
|
-
"produce",
|
|
1045
|
-
"build",
|
|
1046
|
-
"construct",
|
|
1047
|
-
"provision",
|
|
1048
|
-
"instantiate",
|
|
1049
|
-
"define",
|
|
1050
|
-
"compose",
|
|
1051
|
-
"draft"
|
|
1052
|
-
],
|
|
1053
|
-
// Destructive Removal
|
|
1054
|
-
[
|
|
1055
|
-
"delete",
|
|
1056
|
-
"remove",
|
|
1057
|
-
"destroy",
|
|
1058
|
-
"drop",
|
|
1059
|
-
"erase",
|
|
1060
|
-
"clear",
|
|
1061
|
-
"purge",
|
|
1062
|
-
"discard",
|
|
1063
|
-
"eliminate",
|
|
1064
|
-
"nuke",
|
|
1065
|
-
"unbind",
|
|
1066
|
-
"unregister"
|
|
1067
|
-
],
|
|
1068
|
-
// Retrieval / Access
|
|
1069
|
-
["get", "fetch", "retrieve", "read", "obtain", "load", "pull", "access", "grab", "snag", "receive"],
|
|
1070
|
-
// Modification
|
|
1071
|
-
[
|
|
1072
|
-
"update",
|
|
1073
|
-
"edit",
|
|
1074
|
-
"modify",
|
|
1075
|
-
"change",
|
|
1076
|
-
"patch",
|
|
1077
|
-
"alter",
|
|
1078
|
-
"revise",
|
|
1079
|
-
"refresh",
|
|
1080
|
-
"correct",
|
|
1081
|
-
"amend",
|
|
1082
|
-
"adjust",
|
|
1083
|
-
"tweak",
|
|
1084
|
-
"rectify",
|
|
1085
|
-
"refine"
|
|
1086
|
-
],
|
|
1087
|
-
// Viewing / Listing
|
|
1088
|
-
[
|
|
1089
|
-
"list",
|
|
1090
|
-
"show",
|
|
1091
|
-
"display",
|
|
1092
|
-
"enumerate",
|
|
1093
|
-
"browse",
|
|
1094
|
-
"view",
|
|
1095
|
-
"peek",
|
|
1096
|
-
"index",
|
|
1097
|
-
"catalog",
|
|
1098
|
-
"survey",
|
|
1099
|
-
"inspect",
|
|
1100
|
-
"ls",
|
|
1101
|
-
"dir"
|
|
1102
|
-
],
|
|
1103
|
-
// Searching / Discovery
|
|
1104
|
-
[
|
|
1105
|
-
"find",
|
|
1106
|
-
"search",
|
|
1107
|
-
"lookup",
|
|
1108
|
-
"query",
|
|
1109
|
-
"locate",
|
|
1110
|
-
"filter",
|
|
1111
|
-
"scan",
|
|
1112
|
-
"explore",
|
|
1113
|
-
"investigate",
|
|
1114
|
-
"detect",
|
|
1115
|
-
"scout",
|
|
1116
|
-
"seek"
|
|
1117
|
-
],
|
|
1118
|
-
// Soft Delete / Archival
|
|
1119
|
-
["archive", "shelve", "retire", "hide", "suppress", "mute"],
|
|
1120
|
-
["unarchive", "restore", "recover", "undelete", "unhide"],
|
|
1121
|
-
// ===========================================================================
|
|
1122
|
-
// 2. STATE & LIFECYCLE
|
|
1123
|
-
// ===========================================================================
|
|
1124
|
-
// Activation
|
|
1125
|
-
[
|
|
1126
|
-
"enable",
|
|
1127
|
-
"activate",
|
|
1128
|
-
"start",
|
|
1129
|
-
"turn on",
|
|
1130
|
-
"switch on",
|
|
1131
|
-
"boot",
|
|
1132
|
-
"init",
|
|
1133
|
-
"initialize",
|
|
1134
|
-
"setup",
|
|
1135
|
-
"spin up",
|
|
1136
|
-
"resume",
|
|
1137
|
-
"unpause"
|
|
1138
|
-
],
|
|
1139
|
-
// Deactivation
|
|
1140
|
-
[
|
|
1141
|
-
"disable",
|
|
1142
|
-
"deactivate",
|
|
1143
|
-
"stop",
|
|
1144
|
-
"turn off",
|
|
1145
|
-
"switch off",
|
|
1146
|
-
"shutdown",
|
|
1147
|
-
"halt",
|
|
1148
|
-
"kill",
|
|
1149
|
-
"terminate",
|
|
1150
|
-
"suspend",
|
|
1151
|
-
"pause",
|
|
1152
|
-
"cease"
|
|
1153
|
-
],
|
|
1154
|
-
// Execution
|
|
1155
|
-
["run", "execute", "invoke", "trigger", "launch", "call", "perform", "operate", "handle", "process", "fire"],
|
|
1156
|
-
// Reset cycles
|
|
1157
|
-
["restart", "reboot", "reset", "reload", "bounce", "recycle", "refresh"],
|
|
1158
|
-
// Validation & Check
|
|
1159
|
-
["validate", "verify", "check", "confirm", "assert", "test", "audit", "assess", "healthcheck", "ping"],
|
|
1160
|
-
// Analysis & Math
|
|
1161
|
-
[
|
|
1162
|
-
"analyze",
|
|
1163
|
-
"interpret",
|
|
1164
|
-
"diagnose",
|
|
1165
|
-
"evaluate",
|
|
1166
|
-
"review",
|
|
1167
|
-
"summarize",
|
|
1168
|
-
"count",
|
|
1169
|
-
"calculate",
|
|
1170
|
-
"compute",
|
|
1171
|
-
"measure",
|
|
1172
|
-
"aggregate",
|
|
1173
|
-
"summarise"
|
|
1174
|
-
],
|
|
1175
|
-
// ===========================================================================
|
|
1176
|
-
// 3. TRANSFER, IO & MANIPULATION
|
|
1177
|
-
// ===========================================================================
|
|
1178
|
-
// Duplication
|
|
1179
|
-
["copy", "duplicate", "clone", "replicate", "mirror", "fork", "repro"],
|
|
1180
|
-
// Movement
|
|
1181
|
-
["move", "transfer", "migrate", "relocate", "rename", "shift", "mv", "slide"],
|
|
1182
|
-
// Persistence
|
|
1183
|
-
["save", "store", "write", "persist", "commit", "stash", "record", "log"],
|
|
1184
|
-
// Synchronization
|
|
1185
|
-
["sync", "synchronize", "resync", "reconcile", "align", "pair"],
|
|
1186
|
-
// Import/Export
|
|
1187
|
-
["import", "ingest", "upload", "push", "feed"],
|
|
1188
|
-
["export", "download", "dump", "backup", "extract"],
|
|
1189
|
-
// Connection
|
|
1190
|
-
["connect", "link", "bind", "attach", "join", "bridge", "associate", "mount", "map"],
|
|
1191
|
-
["disconnect", "unlink", "unbind", "detach", "leave", "dissociate", "unmount", "unmap"],
|
|
1192
|
-
// ===========================================================================
|
|
1193
|
-
// 4. DEVOPS, SECURITY & TECHNICAL
|
|
1194
|
-
// ===========================================================================
|
|
1195
|
-
// Auth
|
|
1196
|
-
["login", "log in", "sign in", "authenticate", "auth"],
|
|
1197
|
-
["logout", "log out", "sign out", "disconnect"],
|
|
1198
|
-
// Permissions
|
|
1199
|
-
["approve", "authorize", "grant", "permit", "allow", "sanction", "whitelist"],
|
|
1200
|
-
["deny", "reject", "revoke", "forbid", "block", "ban", "blacklist"],
|
|
1201
|
-
// Encryption
|
|
1202
|
-
["encrypt", "secure", "lock", "seal", "protect", "scramble", "hash"],
|
|
1203
|
-
["decrypt", "unlock", "unseal", "reveal", "decode"],
|
|
1204
|
-
// Deployment
|
|
1205
|
-
["deploy", "release", "ship", "publish", "roll out", "promote", "distribute", "install"],
|
|
1206
|
-
// Development
|
|
1207
|
-
["debug", "troubleshoot", "fix", "repair", "resolve", "trace"],
|
|
1208
|
-
["compile", "transpile", "build", "assemble", "package", "bundle", "minify"],
|
|
1209
|
-
// ===========================================================================
|
|
1210
|
-
// 5. COMMERCE & BUSINESS LOGIC
|
|
1211
|
-
// ===========================================================================
|
|
1212
|
-
// Financial Transactions
|
|
1213
|
-
["buy", "purchase", "order", "pay", "checkout", "spend"],
|
|
1214
|
-
["sell", "refund", "reimburse", "charge", "invoice", "bill"],
|
|
1215
|
-
["subscribe", "upgrade", "upsell"],
|
|
1216
|
-
["unsubscribe", "cancel", "downgrade"],
|
|
1217
|
-
// Scheduling
|
|
1218
|
-
["schedule", "book", "appoint", "reserve", "plan", "calendar"],
|
|
1219
|
-
["reschedule", "postpone", "delay", "defer"],
|
|
1220
|
-
// ===========================================================================
|
|
1221
|
-
// 6. COMMUNICATION & SOCIAL
|
|
1222
|
-
// ===========================================================================
|
|
1223
|
-
// Outbound
|
|
1224
|
-
[
|
|
1225
|
-
"send",
|
|
1226
|
-
"dispatch",
|
|
1227
|
-
"deliver",
|
|
1228
|
-
"transmit",
|
|
1229
|
-
"post",
|
|
1230
|
-
"broadcast",
|
|
1231
|
-
"notify",
|
|
1232
|
-
"alert",
|
|
1233
|
-
"email",
|
|
1234
|
-
"text",
|
|
1235
|
-
"message",
|
|
1236
|
-
"chat"
|
|
1237
|
-
],
|
|
1238
|
-
// Social Interactions
|
|
1239
|
-
["reply", "respond", "answer", "retort"],
|
|
1240
|
-
["share", "forward", "retweet", "repost"],
|
|
1241
|
-
["like", "favorite", "star", "upvote", "heart"],
|
|
1242
|
-
["dislike", "downvote"],
|
|
1243
|
-
["follow", "watch", "track"],
|
|
1244
|
-
["unfollow", "ignore", "mute"],
|
|
1245
|
-
// ===========================================================================
|
|
1246
|
-
// 7. COMMON ENTITIES (NOUNS)
|
|
1247
|
-
// ===========================================================================
|
|
1248
|
-
// Users & Roles
|
|
1249
|
-
[
|
|
1250
|
-
"user",
|
|
1251
|
-
"account",
|
|
1252
|
-
"member",
|
|
1253
|
-
"profile",
|
|
1254
|
-
"identity",
|
|
1255
|
-
"customer",
|
|
1256
|
-
"principal",
|
|
1257
|
-
"admin",
|
|
1258
|
-
"operator",
|
|
1259
|
-
"client",
|
|
1260
|
-
"employee",
|
|
1261
|
-
"staff"
|
|
1262
|
-
],
|
|
1263
|
-
["role", "group", "team", "squad", "unit", "department"],
|
|
1264
|
-
// Data Artifacts
|
|
1265
|
-
["file", "document", "attachment", "blob", "asset", "object", "resource", "content", "media"],
|
|
1266
|
-
["image", "picture", "photo", "screenshot"],
|
|
1267
|
-
["video", "clip", "recording", "footage"],
|
|
1268
|
-
// System Artifacts
|
|
1269
|
-
["message", "notification", "alert", "event", "signal", "webhook", "ping"],
|
|
1270
|
-
["log", "trace", "metric", "telemetry", "audit trail", "history"],
|
|
1271
|
-
["settings", "config", "configuration", "preferences", "options", "params", "env", "environment", "variables"],
|
|
1272
|
-
["permission", "privilege", "access right", "policy", "rule", "scope"],
|
|
1273
|
-
// Business Artifacts
|
|
1274
|
-
["organization", "company", "tenant", "workspace", "org", "project", "repo", "repository"],
|
|
1275
|
-
["product", "item", "sku", "inventory", "stock"],
|
|
1276
|
-
["task", "ticket", "issue", "bug", "story", "epic", "todo", "job", "workitem"],
|
|
1277
|
-
// Identification
|
|
1278
|
-
["id", "identifier", "key", "uuid", "guid", "token", "hash", "fingerprint"]
|
|
1279
|
-
];
|
|
1280
|
-
var SynonymExpansionService = class {
|
|
1281
|
-
synonymMap;
|
|
1282
|
-
maxExpansions;
|
|
1283
|
-
constructor(config = {}) {
|
|
1284
|
-
this.maxExpansions = config.maxExpansionsPerTerm ?? 5;
|
|
1285
|
-
const groups = config.replaceDefaults ? config.additionalSynonyms || [] : [...DEFAULT_SYNONYM_GROUPS, ...config.additionalSynonyms || []];
|
|
1286
|
-
this.synonymMap = this.buildSynonymMap(groups);
|
|
1287
|
-
}
|
|
1288
|
-
/**
|
|
1289
|
-
* Build a bidirectional synonym map from groups.
|
|
1290
|
-
* Each term maps to all other terms in its group(s).
|
|
1291
|
-
*/
|
|
1292
|
-
buildSynonymMap(groups) {
|
|
1293
|
-
const map = /* @__PURE__ */ new Map();
|
|
1294
|
-
for (const group of groups) {
|
|
1295
|
-
const normalizedGroup = group.map((term) => term.toLowerCase());
|
|
1296
|
-
for (const term of normalizedGroup) {
|
|
1297
|
-
if (!map.has(term)) {
|
|
1298
|
-
map.set(term, /* @__PURE__ */ new Set());
|
|
1299
|
-
}
|
|
1300
|
-
const synonyms = map.get(term);
|
|
1301
|
-
for (const synonym of normalizedGroup) {
|
|
1302
|
-
if (synonym !== term) {
|
|
1303
|
-
synonyms.add(synonym);
|
|
1304
|
-
}
|
|
1305
|
-
}
|
|
1306
|
-
}
|
|
1307
|
-
}
|
|
1308
|
-
return map;
|
|
1309
|
-
}
|
|
1310
|
-
/**
|
|
1311
|
-
* Get synonyms for a single term.
|
|
1312
|
-
* Returns empty array if no synonyms found.
|
|
1313
|
-
*
|
|
1314
|
-
* @example
|
|
1315
|
-
* getSynonyms('add') // ['create', 'new', 'insert', 'make']
|
|
1316
|
-
*/
|
|
1317
|
-
getSynonyms(term) {
|
|
1318
|
-
const normalized = term.toLowerCase();
|
|
1319
|
-
const synonyms = this.synonymMap.get(normalized);
|
|
1320
|
-
if (!synonyms) {
|
|
1321
|
-
return [];
|
|
1322
|
-
}
|
|
1323
|
-
return Array.from(synonyms).slice(0, this.maxExpansions);
|
|
1324
|
-
}
|
|
1325
|
-
/**
|
|
1326
|
-
* Expand a query string by adding synonyms for each term.
|
|
1327
|
-
* Returns the expanded query string with original terms and their synonyms.
|
|
1328
|
-
*
|
|
1329
|
-
* @example
|
|
1330
|
-
* expandQuery('add user') // 'add create new insert make user account member profile'
|
|
1331
|
-
*/
|
|
1332
|
-
expandQuery(query) {
|
|
1333
|
-
const terms = query.toLowerCase().split(/\s+/).filter((term) => term.length > 1);
|
|
1334
|
-
const expandedTerms = [];
|
|
1335
|
-
for (const term of terms) {
|
|
1336
|
-
expandedTerms.push(term);
|
|
1337
|
-
const synonyms = this.getSynonyms(term);
|
|
1338
|
-
expandedTerms.push(...synonyms);
|
|
1339
|
-
}
|
|
1340
|
-
return expandedTerms.join(" ");
|
|
1341
|
-
}
|
|
1342
|
-
/**
|
|
1343
|
-
* Check if synonym expansion is available for any term in the query.
|
|
1344
|
-
*/
|
|
1345
|
-
hasExpansions(query) {
|
|
1346
|
-
const terms = query.toLowerCase().split(/\s+/);
|
|
1347
|
-
return terms.some((term) => this.synonymMap.has(term));
|
|
1348
|
-
}
|
|
1349
|
-
/**
|
|
1350
|
-
* Get statistics about the synonym dictionary.
|
|
1351
|
-
*/
|
|
1352
|
-
getStats() {
|
|
1353
|
-
const termCount = this.synonymMap.size;
|
|
1354
|
-
let totalSynonyms = 0;
|
|
1355
|
-
for (const synonyms of this.synonymMap.values()) {
|
|
1356
|
-
totalSynonyms += synonyms.size;
|
|
1357
|
-
}
|
|
1358
|
-
return {
|
|
1359
|
-
termCount,
|
|
1360
|
-
avgSynonymsPerTerm: termCount > 0 ? totalSynonyms / termCount : 0
|
|
1361
|
-
};
|
|
1362
|
-
}
|
|
1363
|
-
};
|
|
1364
|
-
|
|
1365
|
-
// plugins/plugin-codecall/src/services/tool-search.service.ts
|
|
1366
|
-
var STOP_WORDS = /* @__PURE__ */ new Set([
|
|
1367
|
-
// Articles & Determiners
|
|
1368
|
-
"the",
|
|
1369
|
-
"a",
|
|
1370
|
-
"an",
|
|
1371
|
-
"this",
|
|
1372
|
-
"that",
|
|
1373
|
-
"these",
|
|
1374
|
-
"those",
|
|
1375
|
-
// Prepositions
|
|
1376
|
-
"in",
|
|
1377
|
-
"on",
|
|
1378
|
-
"at",
|
|
1379
|
-
"to",
|
|
1380
|
-
"for",
|
|
1381
|
-
"of",
|
|
1382
|
-
"with",
|
|
1383
|
-
"by",
|
|
1384
|
-
"from",
|
|
1385
|
-
"into",
|
|
1386
|
-
"over",
|
|
1387
|
-
"after",
|
|
1388
|
-
"before",
|
|
1389
|
-
"between",
|
|
1390
|
-
"under",
|
|
1391
|
-
"about",
|
|
1392
|
-
"against",
|
|
1393
|
-
"during",
|
|
1394
|
-
"through",
|
|
1395
|
-
// Conjunctions
|
|
1396
|
-
"and",
|
|
1397
|
-
"or",
|
|
1398
|
-
"but",
|
|
1399
|
-
"nor",
|
|
1400
|
-
"so",
|
|
1401
|
-
"yet",
|
|
1402
|
-
"as",
|
|
1403
|
-
"than",
|
|
1404
|
-
"if",
|
|
1405
|
-
"because",
|
|
1406
|
-
"while",
|
|
1407
|
-
"when",
|
|
1408
|
-
"where",
|
|
1409
|
-
"unless",
|
|
1410
|
-
// Pronouns (Subject/Object/Possessive)
|
|
1411
|
-
"i",
|
|
1412
|
-
"me",
|
|
1413
|
-
"my",
|
|
1414
|
-
"mine",
|
|
1415
|
-
"myself",
|
|
1416
|
-
"you",
|
|
1417
|
-
"your",
|
|
1418
|
-
"yours",
|
|
1419
|
-
"yourself",
|
|
1420
|
-
"he",
|
|
1421
|
-
"him",
|
|
1422
|
-
"his",
|
|
1423
|
-
"himself",
|
|
1424
|
-
"she",
|
|
1425
|
-
"her",
|
|
1426
|
-
"hers",
|
|
1427
|
-
"herself",
|
|
1428
|
-
"it",
|
|
1429
|
-
"its",
|
|
1430
|
-
"itself",
|
|
1431
|
-
"we",
|
|
1432
|
-
"us",
|
|
1433
|
-
"our",
|
|
1434
|
-
"ours",
|
|
1435
|
-
"ourselves",
|
|
1436
|
-
"they",
|
|
1437
|
-
"them",
|
|
1438
|
-
"their",
|
|
1439
|
-
"theirs",
|
|
1440
|
-
"themselves",
|
|
1441
|
-
"who",
|
|
1442
|
-
"whom",
|
|
1443
|
-
"whose",
|
|
1444
|
-
"which",
|
|
1445
|
-
"what",
|
|
1446
|
-
// Auxiliary/Linking Verbs (State of being is usually noise, Action is signal)
|
|
1447
|
-
"is",
|
|
1448
|
-
"was",
|
|
1449
|
-
"are",
|
|
1450
|
-
"were",
|
|
1451
|
-
"been",
|
|
1452
|
-
"be",
|
|
1453
|
-
"being",
|
|
1454
|
-
"have",
|
|
1455
|
-
"has",
|
|
1456
|
-
"had",
|
|
1457
|
-
"having",
|
|
1458
|
-
"do",
|
|
1459
|
-
"does",
|
|
1460
|
-
"did",
|
|
1461
|
-
"doing",
|
|
1462
|
-
// "do" is usually auxiliary ("do you have..."). "run" or "execute" is better.
|
|
1463
|
-
"will",
|
|
1464
|
-
"would",
|
|
1465
|
-
"shall",
|
|
1466
|
-
"should",
|
|
1467
|
-
"can",
|
|
1468
|
-
"could",
|
|
1469
|
-
"may",
|
|
1470
|
-
"might",
|
|
1471
|
-
"must",
|
|
1472
|
-
// Quantifiers / Adverbs of degree
|
|
1473
|
-
"all",
|
|
1474
|
-
"any",
|
|
1475
|
-
"both",
|
|
1476
|
-
"each",
|
|
1477
|
-
"few",
|
|
1478
|
-
"more",
|
|
1479
|
-
"most",
|
|
1480
|
-
"other",
|
|
1481
|
-
"some",
|
|
1482
|
-
"such",
|
|
1483
|
-
"no",
|
|
1484
|
-
"nor",
|
|
1485
|
-
"not",
|
|
1486
|
-
"only",
|
|
1487
|
-
"own",
|
|
1488
|
-
"same",
|
|
1489
|
-
"too",
|
|
1490
|
-
"very",
|
|
1491
|
-
"just",
|
|
1492
|
-
"even",
|
|
1493
|
-
// Conversational / Chat Fillers (Common in LLM prompts)
|
|
1494
|
-
"please",
|
|
1495
|
-
"pls",
|
|
1496
|
-
"plz",
|
|
1497
|
-
"thanks",
|
|
1498
|
-
"thank",
|
|
1499
|
-
"thx",
|
|
1500
|
-
"hello",
|
|
1501
|
-
"hi",
|
|
1502
|
-
"hey",
|
|
1503
|
-
"ok",
|
|
1504
|
-
"okay",
|
|
1505
|
-
"yes",
|
|
1506
|
-
"no",
|
|
1507
|
-
"actually",
|
|
1508
|
-
"basically",
|
|
1509
|
-
"literally",
|
|
1510
|
-
"maybe",
|
|
1511
|
-
"perhaps",
|
|
1512
|
-
"now",
|
|
1513
|
-
"then",
|
|
1514
|
-
"here",
|
|
1515
|
-
"there",
|
|
1516
|
-
"again",
|
|
1517
|
-
"once",
|
|
1518
|
-
"back",
|
|
1519
|
-
// "back" can be tricky, but usually implies direction not action
|
|
1520
|
-
// Meta/Structural words
|
|
1521
|
-
"example",
|
|
1522
|
-
"context",
|
|
1523
|
-
"optionally",
|
|
1524
|
-
"optional",
|
|
1525
|
-
// Users rarely search for "optional", they search for the thing itself.
|
|
1526
|
-
"etc",
|
|
1527
|
-
"ie",
|
|
1528
|
-
"eg"
|
|
1529
|
-
]);
|
|
1530
|
-
var DEFAULT_EMBEDDING_MODEL = "Xenova/all-MiniLM-L6-v2";
|
|
1531
|
-
function messageOf(error) {
|
|
1532
|
-
return error instanceof Error ? error.message : String(error);
|
|
1533
|
-
}
|
|
1534
|
-
var ToolSearchService = class _ToolSearchService {
|
|
1535
|
-
static MAX_SUBSCRIPTION_RETRIES = 100;
|
|
1536
|
-
static INITIAL_RETRY_DELAY_MS = 10;
|
|
1537
|
-
static MAX_RETRY_DELAY_MS = 1e3;
|
|
1538
|
-
vectorDB;
|
|
1539
|
-
strategy;
|
|
1540
|
-
initialized = false;
|
|
1541
|
-
mlInitialized = false;
|
|
1542
|
-
config;
|
|
1543
|
-
scope;
|
|
1544
|
-
unsubscribe;
|
|
1545
|
-
synonymService = null;
|
|
1546
|
-
synonymExpansion;
|
|
1547
|
-
/** The reindex in progress: later tool changes queue behind it and `search()` waits for it. */
|
|
1548
|
-
indexing;
|
|
1549
|
-
// Subscription tracking for async initialization
|
|
1550
|
-
subscriptionPromise;
|
|
1551
|
-
subscriptionResolved = false;
|
|
1552
|
-
subscriptionResolve = null;
|
|
1553
|
-
subscriptionReject = null;
|
|
1554
|
-
retryTimeoutId = null;
|
|
1555
|
-
disposed = false;
|
|
1556
|
-
/** `availableWhen` of each indexed tool, by indexed name, for per-caller surface filtering. */
|
|
1557
|
-
availabilityByTool = /* @__PURE__ */ new Map();
|
|
1558
|
-
constructor(config = {}, scope) {
|
|
1559
|
-
this.scope = scope;
|
|
1560
|
-
const embeddingOptions = config.embeddingOptions || {
|
|
1561
|
-
strategy: "tfidf",
|
|
1562
|
-
modelName: DEFAULT_EMBEDDING_MODEL,
|
|
1563
|
-
cacheDir: "./.cache/transformers",
|
|
1564
|
-
useHNSW: false,
|
|
1565
|
-
synonymExpansion: { enabled: true, replaceDefaults: false, maxExpansionsPerTerm: 5 }
|
|
1566
|
-
};
|
|
1567
|
-
this.strategy = config.strategy || embeddingOptions.strategy || "tfidf";
|
|
1568
|
-
this.config = {
|
|
1569
|
-
strategy: this.strategy,
|
|
1570
|
-
embeddingOptions,
|
|
1571
|
-
defaultTopK: config.defaultTopK ?? 8,
|
|
1572
|
-
defaultSimilarityThreshold: config.defaultSimilarityThreshold ?? 0,
|
|
1573
|
-
mode: config.mode ?? "codecall_only",
|
|
1574
|
-
includeTools: config.includeTools
|
|
1575
|
-
};
|
|
1576
|
-
const validModes = ["codecall_only", "codecall_opt_in", "metadata_driven"];
|
|
1577
|
-
if (!validModes.includes(this.config.mode)) {
|
|
1578
|
-
throw new Error(`Invalid CodeCall mode: ${this.config.mode}. Valid modes: ${validModes.join(", ")}`);
|
|
1579
|
-
}
|
|
1580
|
-
if (this.strategy === "ml") {
|
|
1581
|
-
this.vectorDB = new import_vectoriadb.VectoriaDB({
|
|
1582
|
-
modelName: embeddingOptions.modelName || DEFAULT_EMBEDDING_MODEL,
|
|
1583
|
-
cacheDir: embeddingOptions.cacheDir || "./.cache/transformers",
|
|
1584
|
-
defaultTopK: this.config.defaultTopK,
|
|
1585
|
-
defaultSimilarityThreshold: this.config.defaultSimilarityThreshold,
|
|
1586
|
-
useHNSW: embeddingOptions.useHNSW || false
|
|
1587
|
-
});
|
|
1588
|
-
} else {
|
|
1589
|
-
this.vectorDB = this.createTfidfIndex();
|
|
1590
|
-
}
|
|
1591
|
-
this.synonymExpansion = config.synonymExpansion ?? embeddingOptions.synonymExpansion;
|
|
1592
|
-
if (this.strategy === "tfidf") {
|
|
1593
|
-
this.synonymService = this.createSynonymService();
|
|
1594
|
-
}
|
|
1595
|
-
this.subscriptionPromise = new Promise((resolve, reject) => {
|
|
1596
|
-
this.subscriptionResolve = resolve;
|
|
1597
|
-
this.subscriptionReject = reject;
|
|
1598
|
-
});
|
|
1599
|
-
this.setupSubscription();
|
|
1600
|
-
}
|
|
1601
|
-
createTfidfIndex() {
|
|
1602
|
-
return new import_vectoriadb.TFIDFVectoria({
|
|
1603
|
-
defaultTopK: this.config.defaultTopK,
|
|
1604
|
-
defaultSimilarityThreshold: this.config.defaultSimilarityThreshold
|
|
1605
|
-
});
|
|
1606
|
-
}
|
|
1607
|
-
createSynonymService() {
|
|
1608
|
-
const synonymExpansion = this.synonymExpansion;
|
|
1609
|
-
if (synonymExpansion === false || synonymExpansion?.enabled === false) return null;
|
|
1610
|
-
return new SynonymExpansionService(synonymExpansion ?? {});
|
|
1611
|
-
}
|
|
1612
|
-
/**
|
|
1613
|
-
* Ensures the service is subscribed to tool changes before proceeding.
|
|
1614
|
-
* Public methods should call this before accessing tools.
|
|
1615
|
-
*/
|
|
1616
|
-
async ensureSubscribed() {
|
|
1617
|
-
if (this.subscriptionResolved) {
|
|
1618
|
-
return;
|
|
1619
|
-
}
|
|
1620
|
-
await this.subscriptionPromise;
|
|
1621
|
-
}
|
|
1622
|
-
/**
|
|
1623
|
-
* Sets up subscription to tool changes with exponential backoff retry.
|
|
1624
|
-
* Handles the case where scope.tools may not be available yet during plugin initialization.
|
|
1625
|
-
*/
|
|
1626
|
-
setupSubscription(retryCount = 0, delayMs = _ToolSearchService.INITIAL_RETRY_DELAY_MS) {
|
|
1627
|
-
if (this.scope.tools) {
|
|
1628
|
-
this.subscribeToToolChanges();
|
|
1629
|
-
return;
|
|
1630
|
-
}
|
|
1631
|
-
if (retryCount >= _ToolSearchService.MAX_SUBSCRIPTION_RETRIES) {
|
|
1632
|
-
this.scope.logger.warn(
|
|
1633
|
-
"ToolSearchService: scope.tools not available after max retries. Tool search will return incomplete results until tools are registered."
|
|
1634
|
-
);
|
|
1635
|
-
this.markSubscribed();
|
|
1636
|
-
return;
|
|
1637
|
-
}
|
|
1638
|
-
const nextDelay = Math.min(delayMs * 2, _ToolSearchService.MAX_RETRY_DELAY_MS);
|
|
1639
|
-
this.retryTimeoutId = setTimeout(() => {
|
|
1640
|
-
this.retryTimeoutId = null;
|
|
1641
|
-
if (this.disposed) {
|
|
1642
|
-
return;
|
|
1643
|
-
}
|
|
1644
|
-
this.setupSubscription(retryCount + 1, nextDelay);
|
|
1645
|
-
}, delayMs);
|
|
1646
|
-
}
|
|
1647
|
-
/**
|
|
1648
|
-
* Subscribes to tool changes once scope.tools is available.
|
|
1649
|
-
*/
|
|
1650
|
-
subscribeToToolChanges() {
|
|
1651
|
-
this.unsubscribe = this.scope.tools.subscribe({ immediate: true }, (event) => {
|
|
1652
|
-
this.queueReindex(event.snapshot);
|
|
1653
|
-
});
|
|
1654
|
-
this.markSubscribed();
|
|
1655
|
-
}
|
|
1656
|
-
/** Reindex from `tools` once the reindex in progress (if any) is done; a failure is logged, never thrown. */
|
|
1657
|
-
queueReindex(tools) {
|
|
1658
|
-
const reindex = () => this.handleToolChange(tools);
|
|
1659
|
-
const run = (this.indexing ? this.indexing.then(reindex) : reindex()).catch((error) => {
|
|
1660
|
-
this.scope.logger.warn(`CodeCall tool search could not index the tools: ${messageOf(error)}`);
|
|
1661
|
-
});
|
|
1662
|
-
this.indexing = run;
|
|
1663
|
-
void run.then(() => {
|
|
1664
|
-
if (this.indexing === run) this.indexing = void 0;
|
|
1665
|
-
});
|
|
1666
|
-
}
|
|
1667
|
-
/**
|
|
1668
|
-
* Marks the subscription as resolved, allowing pending operations to proceed.
|
|
1669
|
-
*/
|
|
1670
|
-
markSubscribed() {
|
|
1671
|
-
this.subscriptionResolved = true;
|
|
1672
|
-
if (this.subscriptionResolve) {
|
|
1673
|
-
this.subscriptionResolve();
|
|
1674
|
-
this.subscriptionResolve = null;
|
|
1675
|
-
}
|
|
1676
|
-
}
|
|
1677
|
-
/**
|
|
1678
|
-
* Handles tool change events by reindexing all tools from the snapshot. The new index replaces the
|
|
1679
|
-
* current one only once it is built, and a tool that can't be read is skipped, so the other tools
|
|
1680
|
-
* stay searchable.
|
|
1681
|
-
*/
|
|
1682
|
-
async handleToolChange(tools) {
|
|
1683
|
-
if (tools.length > 0 && !this.mlInitialized && this.strategy === "ml" && this.vectorDB instanceof import_vectoriadb.VectoriaDB) {
|
|
1684
|
-
try {
|
|
1685
|
-
await this.vectorDB.initialize();
|
|
1686
|
-
this.mlInitialized = true;
|
|
1687
|
-
} catch (error) {
|
|
1688
|
-
this.fallBackToTfidf(error);
|
|
1689
|
-
}
|
|
1690
|
-
}
|
|
1691
|
-
const availabilityByTool = /* @__PURE__ */ new Map();
|
|
1692
|
-
const documents = tools.flatMap((tool) => this.toDocuments(tool, availabilityByTool));
|
|
1693
|
-
await this.replaceIndex(documents);
|
|
1694
|
-
this.availabilityByTool = availabilityByTool;
|
|
1695
|
-
this.initialized = true;
|
|
1696
|
-
}
|
|
1697
|
-
/** The tool's search document, or none when CodeCall may not execute it or it can't be read. */
|
|
1698
|
-
toDocuments(tool, availabilityByTool) {
|
|
1699
|
-
try {
|
|
1700
|
-
if (!this.shouldIndexTool(tool)) return [];
|
|
1701
|
-
const toolName = tool.name;
|
|
1702
|
-
const document = {
|
|
1703
|
-
id: toolName,
|
|
1704
|
-
text: this.extractSearchableText(tool),
|
|
1705
|
-
metadata: {
|
|
1706
|
-
id: toolName,
|
|
1707
|
-
toolName,
|
|
1708
|
-
qualifiedName: tool.fullName || toolName,
|
|
1709
|
-
appId: this.extractAppId(tool),
|
|
1710
|
-
toolInstance: tool
|
|
1711
|
-
}
|
|
1712
|
-
};
|
|
1713
|
-
availabilityByTool.set(toolName, tool.metadata.availableWhen);
|
|
1714
|
-
return [document];
|
|
1715
|
-
} catch (error) {
|
|
1716
|
-
this.scope.logger.warn(`CodeCall tool search skipped tool "${tool.name}": ${messageOf(error)}`);
|
|
1717
|
-
return [];
|
|
1718
|
-
}
|
|
1719
|
-
}
|
|
1720
|
-
/** Index `documents` in place of the current contents; embeddings that fail fall back to TF-IDF. */
|
|
1721
|
-
async replaceIndex(documents) {
|
|
1722
|
-
if (this.vectorDB instanceof import_vectoriadb.VectoriaDB) {
|
|
1723
|
-
try {
|
|
1724
|
-
this.vectorDB.clear();
|
|
1725
|
-
if (documents.length > 0) await this.vectorDB.addMany(documents);
|
|
1726
|
-
return;
|
|
1727
|
-
} catch (error) {
|
|
1728
|
-
this.fallBackToTfidf(error);
|
|
1729
|
-
}
|
|
1730
|
-
}
|
|
1731
|
-
const index = this.createTfidfIndex();
|
|
1732
|
-
index.addDocuments(documents);
|
|
1733
|
-
index.reindex();
|
|
1734
|
-
this.vectorDB = index;
|
|
1735
|
-
}
|
|
1736
|
-
/** The embedding model could not be loaded or used: search with TF-IDF for the rest of the process. */
|
|
1737
|
-
fallBackToTfidf(error) {
|
|
1738
|
-
const modelName = this.config.embeddingOptions.modelName || DEFAULT_EMBEDDING_MODEL;
|
|
1739
|
-
this.scope.logger.warn(
|
|
1740
|
-
`CodeCall could not use embedding model "${modelName}" (${messageOf(error)}); tool search uses TF-IDF instead`
|
|
1741
|
-
);
|
|
1742
|
-
this.strategy = "tfidf";
|
|
1743
|
-
this.vectorDB = this.createTfidfIndex();
|
|
1744
|
-
this.synonymService = this.createSynonymService();
|
|
1745
|
-
}
|
|
1746
|
-
/**
|
|
1747
|
-
* Whether a tool belongs in the search index: exactly when CodeCall may execute it.
|
|
1748
|
-
* The decision is `codecall:execute`'s own, so search cannot show a tool execution refuses
|
|
1749
|
-
* or hide one it runs (GHSA-6w3j-82v5-6qrr).
|
|
1750
|
-
*/
|
|
1751
|
-
shouldIndexTool(tool) {
|
|
1752
|
-
return checkCodeCallToolPolicy(toCodeCallPolicyTool(tool, void 0, this.scope), this.config).allowed;
|
|
1753
|
-
}
|
|
1754
|
-
/**
|
|
1755
|
-
* Initializes the search service by indexing all tools from the registry.
|
|
1756
|
-
* NOTE: This method is now a no-op. Initialization is handled reactively
|
|
1757
|
-
* via subscription to tool change events in the constructor.
|
|
1758
|
-
* This method exists for interface compatibility.
|
|
1759
|
-
*/
|
|
1760
|
-
async initialize() {
|
|
1761
|
-
}
|
|
1762
|
-
/**
|
|
1763
|
-
* Cleanup subscription and pending retries when service is destroyed
|
|
1764
|
-
*/
|
|
1765
|
-
dispose() {
|
|
1766
|
-
this.disposed = true;
|
|
1767
|
-
if (this.retryTimeoutId) {
|
|
1768
|
-
clearTimeout(this.retryTimeoutId);
|
|
1769
|
-
this.retryTimeoutId = null;
|
|
1770
|
-
}
|
|
1771
|
-
if (this.subscriptionReject) {
|
|
1772
|
-
this.subscriptionReject(new Error("ToolSearchService disposed before subscription completed"));
|
|
1773
|
-
this.subscriptionReject = null;
|
|
1774
|
-
this.subscriptionResolve = null;
|
|
1775
|
-
}
|
|
1776
|
-
if (this.unsubscribe) {
|
|
1777
|
-
this.unsubscribe();
|
|
1778
|
-
this.unsubscribe = void 0;
|
|
1779
|
-
}
|
|
1780
|
-
}
|
|
1781
|
-
/**
|
|
1782
|
-
* Extracts searchable text from a tool instance.
|
|
1783
|
-
* Uses term weighting to improve relevance:
|
|
1784
|
-
* - Description terms are heavily weighted (most important for semantic matching)
|
|
1785
|
-
* - Tool name parts are tokenized and weighted
|
|
1786
|
-
* - Tags provide additional context
|
|
1787
|
-
*/
|
|
1788
|
-
extractSearchableText(tool) {
|
|
1789
|
-
const parts = [];
|
|
1790
|
-
if (tool.name) {
|
|
1791
|
-
const nameParts = tool.name.split(/[:\-_.]/).filter(Boolean);
|
|
1792
|
-
for (const part of nameParts) {
|
|
1793
|
-
parts.push(part, part);
|
|
1794
|
-
}
|
|
1795
|
-
}
|
|
1796
|
-
if (tool.metadata.description) {
|
|
1797
|
-
const description = tool.metadata.description;
|
|
1798
|
-
parts.push(description, description, description);
|
|
1799
|
-
const keyTerms = description.toLowerCase().split(/\s+/).filter((word) => word.length >= 4 && !this.isStopWord(word));
|
|
1800
|
-
parts.push(...keyTerms);
|
|
1801
|
-
}
|
|
1802
|
-
if (tool.metadata.tags && tool.metadata.tags.length > 0) {
|
|
1803
|
-
for (const tag of tool.metadata.tags) {
|
|
1804
|
-
parts.push(tag, tag);
|
|
1805
|
-
}
|
|
1806
|
-
}
|
|
1807
|
-
if (tool.rawInputSchema && typeof tool.rawInputSchema === "object") {
|
|
1808
|
-
const schema = tool.rawInputSchema;
|
|
1809
|
-
if (schema.properties) {
|
|
1810
|
-
parts.push(...Object.keys(schema.properties));
|
|
1811
|
-
}
|
|
1812
|
-
}
|
|
1813
|
-
const examples = tool.metadata?.examples;
|
|
1814
|
-
if (examples && Array.isArray(examples)) {
|
|
1815
|
-
for (const ex of examples) {
|
|
1816
|
-
if (ex.description) {
|
|
1817
|
-
parts.push(ex.description, ex.description);
|
|
1818
|
-
}
|
|
1819
|
-
if (ex.input && typeof ex.input === "object") {
|
|
1820
|
-
for (const [key, value] of Object.entries(ex.input)) {
|
|
1821
|
-
parts.push(key);
|
|
1822
|
-
if (typeof value === "string") {
|
|
1823
|
-
parts.push(value);
|
|
1824
|
-
}
|
|
1825
|
-
}
|
|
1826
|
-
}
|
|
1827
|
-
}
|
|
1828
|
-
}
|
|
1829
|
-
return parts.join(" ");
|
|
1830
|
-
}
|
|
1831
|
-
/**
|
|
1832
|
-
* Checks if a word is a common stop word that should not receive extra weighting.
|
|
1833
|
-
* Uses module-level STOP_WORDS constant to avoid recreating the Set on each call.
|
|
1834
|
-
*/
|
|
1835
|
-
isStopWord(word) {
|
|
1836
|
-
return STOP_WORDS.has(word);
|
|
1837
|
-
}
|
|
1838
|
-
/**
|
|
1839
|
-
* Extracts app ID from tool's owner lineage
|
|
1840
|
-
*/
|
|
1841
|
-
extractAppId(tool) {
|
|
1842
|
-
return codeCallAppIdOf(this.scope, tool);
|
|
1843
|
-
}
|
|
1844
|
-
/**
|
|
1845
|
-
* Searches for tools matching the query
|
|
1846
|
-
* Implements the ToolSearch interface
|
|
1847
|
-
*/
|
|
1848
|
-
async search(query, options = {}) {
|
|
1849
|
-
await this.ensureSubscribed();
|
|
1850
|
-
await this.indexing;
|
|
1851
|
-
const { topK = this.config.defaultTopK, appIds, excludeToolNames = [], surface } = options;
|
|
1852
|
-
const minScore = this.config.defaultSimilarityThreshold;
|
|
1853
|
-
const filter = (metadata) => {
|
|
1854
|
-
if (excludeToolNames.includes(metadata.toolName)) {
|
|
1855
|
-
return false;
|
|
1856
|
-
}
|
|
1857
|
-
if (!isOfferedToCaller(metadata.toolInstance.metadata.availableWhen, surface)) {
|
|
1858
|
-
return false;
|
|
1859
|
-
}
|
|
1860
|
-
if (appIds && appIds.length > 0) {
|
|
1861
|
-
if (!metadata.appId || !appIds.includes(metadata.appId)) {
|
|
1862
|
-
return false;
|
|
1863
|
-
}
|
|
1864
|
-
}
|
|
1865
|
-
return true;
|
|
1866
|
-
};
|
|
1867
|
-
const effectiveQuery = this.synonymService ? this.synonymService.expandQuery(query) : query;
|
|
1868
|
-
const results = await this.vectorDB.search(effectiveQuery, {
|
|
1869
|
-
topK,
|
|
1870
|
-
threshold: minScore,
|
|
1871
|
-
filter
|
|
1872
|
-
});
|
|
1873
|
-
return results.map((result) => ({
|
|
1874
|
-
toolName: result.metadata.toolName,
|
|
1875
|
-
appId: result.metadata.appId,
|
|
1876
|
-
description: result.metadata.toolInstance.metadata.description || "",
|
|
1877
|
-
relevanceScore: result.score
|
|
1878
|
-
}));
|
|
1879
|
-
}
|
|
1880
|
-
/**
|
|
1881
|
-
* Gets all indexed tool names
|
|
1882
|
-
*/
|
|
1883
|
-
getAllToolNames() {
|
|
1884
|
-
if (this.vectorDB instanceof import_vectoriadb.VectoriaDB) {
|
|
1885
|
-
return this.vectorDB.getAll().map((doc) => doc.id);
|
|
1886
|
-
} else {
|
|
1887
|
-
return this.vectorDB.getAllDocumentIds();
|
|
1888
|
-
}
|
|
1889
|
-
}
|
|
1890
|
-
/**
|
|
1891
|
-
* Gets the total number of indexed tools, or of those a caller on `surface` may reach
|
|
1892
|
-
*/
|
|
1893
|
-
getTotalCount(surface) {
|
|
1894
|
-
if (surface !== void 0) {
|
|
1895
|
-
return this.getAllToolNames().filter((toolName) => this.hasTool(toolName, surface)).length;
|
|
1896
|
-
}
|
|
1897
|
-
if (this.vectorDB instanceof import_vectoriadb.VectoriaDB) {
|
|
1898
|
-
return this.vectorDB.size();
|
|
1899
|
-
} else {
|
|
1900
|
-
return this.vectorDB.getDocumentCount();
|
|
1901
|
-
}
|
|
1902
|
-
}
|
|
1903
|
-
/**
|
|
1904
|
-
* Checks if a tool exists in the index, for a caller on `surface` when given
|
|
1905
|
-
*/
|
|
1906
|
-
hasTool(toolName, surface) {
|
|
1907
|
-
const indexed = this.vectorDB instanceof import_vectoriadb.VectoriaDB ? this.vectorDB.has(toolName) : this.vectorDB.hasDocument(toolName);
|
|
1908
|
-
return indexed && isOfferedToCaller(this.availabilityByTool.get(toolName), surface);
|
|
1909
|
-
}
|
|
1910
|
-
/**
|
|
1911
|
-
* Clears the entire index
|
|
1912
|
-
*/
|
|
1913
|
-
clear() {
|
|
1914
|
-
this.vectorDB.clear();
|
|
1915
|
-
this.availabilityByTool = /* @__PURE__ */ new Map();
|
|
1916
|
-
this.initialized = false;
|
|
1917
|
-
}
|
|
1918
|
-
/**
|
|
1919
|
-
* Get the current embedding strategy
|
|
1920
|
-
*/
|
|
1921
|
-
getStrategy() {
|
|
1922
|
-
return this.strategy;
|
|
1923
|
-
}
|
|
1924
|
-
/**
|
|
1925
|
-
* Check if the service is initialized
|
|
1926
|
-
*/
|
|
1927
|
-
isInitialized() {
|
|
1928
|
-
return this.initialized;
|
|
1929
|
-
}
|
|
1930
|
-
};
|
|
1931
|
-
|
|
1932
|
-
// plugins/plugin-codecall/src/services/enclave.service.ts
|
|
1933
|
-
var import_core = require("@enclave-vm/core");
|
|
1934
|
-
var import_sdk4 = require("@frontmcp/sdk");
|
|
1935
|
-
|
|
1936
|
-
// plugins/plugin-codecall/src/security/script-policy.ts
|
|
1937
|
-
var import_ast = require("@enclave-vm/ast");
|
|
1938
|
-
var AGENTSCRIPT_PARSE_OPTIONS = {
|
|
1939
|
-
ecmaVersion: "latest",
|
|
1940
|
-
sourceType: "script",
|
|
1941
|
-
allowReturnOutsideFunction: true,
|
|
1942
|
-
allowAwaitOutsideFunction: true
|
|
1943
|
-
};
|
|
1944
|
-
var PARSE_ATTEMPTS = [
|
|
1945
|
-
{ wrap: (code) => code, parseOptions: AGENTSCRIPT_PARSE_OPTIONS, lineOffset: 0 },
|
|
1946
|
-
{ wrap: (code) => code, parseOptions: { ...AGENTSCRIPT_PARSE_OPTIONS, sourceType: "module" }, lineOffset: 0 },
|
|
1947
|
-
{
|
|
1948
|
-
wrap: (code) => `async function __temp__() {
|
|
1
|
+
"use strict";var __create=Object.create;var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __getProtoOf=Object.getPrototypeOf;var __hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:true})};var __copyProps=(to,from,except,desc)=>{if(from&&typeof from==="object"||typeof from==="function"){for(let key of __getOwnPropNames(from))if(!__hasOwnProp.call(to,key)&&key!==except)__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable})}return to};var __toESM=(mod,isNodeMode,target)=>(target=mod!=null?__create(__getProtoOf(mod)):{},__copyProps(isNodeMode||!mod||!mod.__esModule?__defProp(target,"default",{value:mod,enumerable:true}):target,mod));var __toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:true}),mod);var __decorateClass=(decorators,target,key,kind)=>{var result=kind>1?void 0:kind?__getOwnPropDesc(target,key):target;for(var i=decorators.length-1,decorator;i>=0;i--)if(decorator=decorators[i])result=(kind?decorator(target,key,result):decorator(result))||result;if(kind&&result)__defProp(target,key,result);return result};var index_exports={};__export(index_exports,{AUDIT_EVENT_TYPES:()=>AUDIT_EVENT_TYPES,AuditLoggerService:()=>AuditLoggerService,CodeCallPlugin:()=>CodeCallPlugin,codeCallDirectCallsOptionsSchema:()=>codeCallDirectCallsOptionsSchema,codeCallEmbeddingOptionsSchema:()=>codeCallEmbeddingOptionsSchema,codeCallModeSchema:()=>codeCallModeSchema,codeCallPluginOptionsSchema:()=>codeCallPluginOptionsSchema,codeCallSidecarOptionsSchema:()=>codeCallSidecarOptionsSchema,codeCallVmOptionsSchema:()=>codeCallVmOptionsSchema,codeCallVmPresetSchema:()=>codeCallVmPresetSchema,default:()=>CodeCallPlugin,embeddingStrategySchema:()=>embeddingStrategySchema,synonymExpansionConfigSchema:()=>synonymExpansionConfigSchema});module.exports=__toCommonJS(index_exports);var import_plugin_cache=__toESM(require("@frontmcp/plugin-cache"));var import_sdk11=require("@frontmcp/sdk");var import_lazy_zod=require("@frontmcp/lazy-zod");var directCallsFilterSchema=import_lazy_zod.z.custom(val=>typeof val==="function",{message:"filter must be a function with signature (tool: DirectCallsFilterToolInfo) => boolean"});var includeToolsFilterSchema=import_lazy_zod.z.custom(val=>typeof val==="function",{message:"includeTools must be a function with signature (tool: IncludeToolsFilterToolInfo) => boolean"});var codeCallModeSchema=import_lazy_zod.z.enum(["codecall_only","codecall_opt_in","metadata_driven"]).default("codecall_only");var codeCallVmPresetSchema=import_lazy_zod.z.enum(["locked_down","secure","balanced","experimental"]).default("secure");var DEFAULT_VM_OPTIONS={preset:"secure"};var codeCallVmOptionsSchema=import_lazy_zod.z.object({preset:codeCallVmPresetSchema,timeoutMs:import_lazy_zod.z.number().positive().optional(),allowLoops:import_lazy_zod.z.boolean().optional(),maxSteps:import_lazy_zod.z.number().positive().optional(),disabledBuiltins:import_lazy_zod.z.array(import_lazy_zod.z.string()).optional(),disabledGlobals:import_lazy_zod.z.array(import_lazy_zod.z.string()).optional(),allowConsole:import_lazy_zod.z.boolean().optional(),maxSanitizeDepth:import_lazy_zod.z.number().positive().optional(),maxSanitizeProperties:import_lazy_zod.z.number().positive().optional(),rapidEnumerationThreshold:import_lazy_zod.z.number().int().positive().optional(),rapidEnumerationOverrides:import_lazy_zod.z.record(import_lazy_zod.z.string(),import_lazy_zod.z.number().int().positive()).optional()}).default(()=>DEFAULT_VM_OPTIONS);var codeCallDirectCallsOptionsSchema=import_lazy_zod.z.object({enabled:import_lazy_zod.z.boolean(),allowedTools:import_lazy_zod.z.array(import_lazy_zod.z.string()).optional(),filter:directCallsFilterSchema.optional()});var embeddingStrategySchema=import_lazy_zod.z.enum(["tfidf","ml"]).default("tfidf");var synonymExpansionConfigSchema=import_lazy_zod.z.object({enabled:import_lazy_zod.z.boolean().default(true),additionalSynonyms:import_lazy_zod.z.array(import_lazy_zod.z.array(import_lazy_zod.z.string())).optional(),replaceDefaults:import_lazy_zod.z.boolean().default(false),maxExpansionsPerTerm:import_lazy_zod.z.number().positive().default(5)}).default({enabled:true,replaceDefaults:false,maxExpansionsPerTerm:5});var DEFAULT_EMBEDDING_OPTIONS={strategy:"tfidf",modelName:"Xenova/all-MiniLM-L6-v2",cacheDir:"./.cache/transformers",useHNSW:false,synonymExpansion:{enabled:true,replaceDefaults:false,maxExpansionsPerTerm:5}};var codeCallEmbeddingOptionsSchema=import_lazy_zod.z.object({strategy:embeddingStrategySchema.optional(),modelName:import_lazy_zod.z.string().optional(),cacheDir:import_lazy_zod.z.string().optional(),useHNSW:import_lazy_zod.z.boolean().optional(),synonymExpansion:import_lazy_zod.z.union([import_lazy_zod.z.literal(false),synonymExpansionConfigSchema]).optional()}).optional().transform(opts=>({strategy:opts?.strategy??DEFAULT_EMBEDDING_OPTIONS.strategy,modelName:opts?.modelName??DEFAULT_EMBEDDING_OPTIONS.modelName,cacheDir:opts?.cacheDir??DEFAULT_EMBEDDING_OPTIONS.cacheDir,useHNSW:opts?.useHNSW??DEFAULT_EMBEDDING_OPTIONS.useHNSW,synonymExpansion:opts?.synonymExpansion??DEFAULT_EMBEDDING_OPTIONS.synonymExpansion}));var codeCallSidecarOptionsSchema=import_lazy_zod.z.object({enabled:import_lazy_zod.z.boolean().default(false),maxTotalSize:import_lazy_zod.z.number().positive().optional(),maxReferenceSize:import_lazy_zod.z.number().positive().optional(),extractionThreshold:import_lazy_zod.z.number().positive().optional(),maxResolvedSize:import_lazy_zod.z.number().positive().optional(),allowComposites:import_lazy_zod.z.boolean().optional(),maxScriptLengthWhenDisabled:import_lazy_zod.z.number().positive().nullable().default(64*1024)}).default(()=>({enabled:false,maxScriptLengthWhenDisabled:64*1024}));var codeCallPluginOptionsObjectSchema=import_lazy_zod.z.object({mode:codeCallModeSchema,appIds:import_lazy_zod.z.array(import_lazy_zod.z.string()).optional(),topK:import_lazy_zod.z.number().positive().default(8),maxDefinitions:import_lazy_zod.z.number().int().positive().default(8),includeTools:includeToolsFilterSchema.optional(),directCalls:codeCallDirectCallsOptionsSchema.optional(),vm:codeCallVmOptionsSchema,embedding:codeCallEmbeddingOptionsSchema,sidecar:codeCallSidecarOptionsSchema});var DEFAULT_PLUGIN_OPTIONS={mode:"codecall_only",topK:8,maxDefinitions:8,vm:DEFAULT_VM_OPTIONS,embedding:DEFAULT_EMBEDDING_OPTIONS,sidecar:{enabled:false,maxScriptLengthWhenDisabled:64*1024}};var codeCallPluginOptionsSchema=codeCallPluginOptionsObjectSchema.prefault(DEFAULT_PLUGIN_OPTIONS);var import_sdk=require("@frontmcp/sdk");var CodeCallConfig=class extends import_sdk.BaseConfig{constructor(options={}){const parsedConfig=codeCallPluginOptionsSchema.parse(options);const resolvedVm=resolveVmOptions(parsedConfig.vm);super({...parsedConfig,resolvedVm})}};CodeCallConfig=__decorateClass([(0,import_sdk.Provider)({name:"codecall:config",description:"CodeCall plugin configuration with validated defaults",scope:import_sdk.ProviderScope.GLOBAL})],CodeCallConfig);var MAX_ITERATIONS_PER_LOOP=1e4;function maxToolCallsOf(vmOptions){return vmOptions.maxSteps||100}var SANDBOX_RAPID_ENUMERATION_THRESHOLD=30;function rapidEnumerationThresholdOf(vmOptions){return vmOptions.rapidEnumerationThreshold??SANDBOX_RAPID_ENUMERATION_THRESHOLD}function resolveVmOptions(vmOptions){const preset=vmOptions?.preset??"secure";const base=presetDefaults(preset);return{...base,...vmOptions,disabledBuiltins:vmOptions?.disabledBuiltins??base.disabledBuiltins,disabledGlobals:vmOptions?.disabledGlobals??base.disabledGlobals}}function presetDefaults(preset){switch(preset){case"locked_down":return{preset,timeoutMs:2e3,allowLoops:false,allowConsole:false,maxSteps:2e3,disabledBuiltins:["eval","Function","AsyncFunction"],disabledGlobals:["require","process","fetch","setTimeout","setInterval","setImmediate","global","globalThis"],maxSanitizeDepth:10,maxSanitizeProperties:1e3};case"balanced":return{preset,timeoutMs:5e3,allowLoops:true,allowConsole:true,maxSteps:1e4,disabledBuiltins:["eval","Function","AsyncFunction"],disabledGlobals:["require","process","fetch"],maxSanitizeDepth:50,maxSanitizeProperties:5e3};case"experimental":return{preset,timeoutMs:1e4,allowLoops:true,allowConsole:true,maxSteps:2e4,disabledBuiltins:["eval","Function","AsyncFunction"],disabledGlobals:["require","process"],maxSanitizeDepth:100,maxSanitizeProperties:2e4};case"secure":default:return{preset:"secure",timeoutMs:3500,allowLoops:false,allowConsole:true,maxSteps:5e3,disabledBuiltins:["eval","Function","AsyncFunction"],disabledGlobals:["require","process","fetch","setTimeout","setInterval","setImmediate","global","globalThis"],maxSanitizeDepth:50,maxSanitizeProperties:2e3}}}var import_sdk2=require("@frontmcp/sdk");var CODECALL_DISPATCH=Symbol("frontmcp.codecall.dispatch");function asCodeCallDispatch(ctx){return Object.defineProperty(ctx,CODECALL_DISPATCH,{value:true,enumerable:false})}function isInProcessDispatch(ctx){if((0,import_sdk2.getRunningTool)())return true;if(typeof ctx!=="object"||ctx===null)return false;const marks=ctx;return marks[CODECALL_DISPATCH]===true||marks.internalCall===true}var BLOCKED_NAMESPACE_PATTERNS=Object.freeze([/^system:/,/^internal:/,/^__/]);function isOfferedToCaller(availableWhen,surface){const offered=availableWhen?.surface;return offered===void 0||surface===void 0||offered.includes(surface)}var ALLOWED={allowed:true};function deny(reason){return{allowed:false,reason}}function codeCallAppIdOf(scope,entry){const lineage=scope?.tools?.lineageOf?.(entry)??[];const owners=entry.owner?[...lineage,entry.owner]:lineage;return owners.find(owner=>owner.kind==="app")?.id}function toCodeCallPolicyTool(entry,requestedName,scope){const{metadata}=entry;return{name:entry.name||entry.fullName,fullName:entry.fullName,aliases:requestedName?[requestedName]:void 0,appId:codeCallAppIdOf(scope,entry),description:metadata?.description,tags:metadata?.tags,hidden:metadata?.hideFromDiscovery===true||metadata?.visibility==="hidden"||metadata?.visibility==="internal",codecall:metadata?.codecall,annotations:metadata?.annotations,metadata}}function isPlainData(value){if(Array.isArray(value))return true;const proto=Object.getPrototypeOf(value);return proto===Object.prototype||proto===null}function readOnlyCopy(value,copies){if(typeof value!=="object"||value===null||!isPlainData(value))return value;const existing=copies.get(value);if(existing!==void 0)return existing;const copy=Array.isArray(value)?[]:Object.create(Object.getPrototypeOf(value));copies.set(value,copy);for(const key of Reflect.ownKeys(value)){if(!Object.prototype.propertyIsEnumerable.call(value,key))continue;Object.defineProperty(copy,key,{value:readOnlyCopy(Reflect.get(value,key),copies),enumerable:true,writable:true,configurable:true})}return Object.freeze(copy)}function toToolFilterInfo(tool){const copies=new WeakMap;const annotations=readOnlyCopy(tool.annotations,copies);const metadata=tool.metadata?readOnlyCopy({...tool.metadata,...annotations?{annotations:tool.annotations}:{}},copies):void 0;return{name:tool.name,fullName:tool.fullName,appId:tool.appId,source:tool.codecall?.source,description:tool.description,tags:readOnlyCopy(tool.codecall?.tags??tool.tags,copies),annotations,metadata}}function ownNamesOf(tool){return[tool.name,tool.fullName].filter(candidate=>!!candidate)}function checkCodeCallToolPolicy(tool,config){const{name}=tool;const spellings=[...ownNamesOf(tool),...tool.aliases??[]];if(spellings.some(candidate=>candidate.startsWith("codecall:"))){return deny("CodeCall meta-tools are not callable from CodeCall")}for(const candidate of spellings){if(BLOCKED_NAMESPACE_PATTERNS.some(pattern=>pattern.test(candidate))){return deny(`Tool "${candidate}" is in a namespace CodeCall never calls`)}}if(tool.hidden===true){return deny(`Tool "${name}" is hidden from discovery`)}const enabled=tool.codecall?.enabledInCodeCall;switch(config.mode){case"codecall_only":case"metadata_driven":if(enabled===false){return deny(`Tool "${name}" sets enabledInCodeCall: false`)}break;case"codecall_opt_in":if(enabled!==true){return deny(`Tool "${name}" has not opted in to CodeCall`)}break;default:return deny(`Unknown CodeCall mode: ${String(config.mode)}`)}if(config.includeTools&&!config.includeTools(toToolFilterInfo(tool))){return deny(`Tool "${name}" is excluded by the includeTools filter`)}return ALLOWED}function denyUnknownTool(name){return deny(`Tool "${name}" is not available through CodeCall`)}function resolveCodeCallTool(scope,name){const typedScope=scope;const alias=/[-_]/.test(name)?name.includes("_")?name.replace(/_/g,"-"):name.replace(/-/g,"_"):void 0;const candidates=alias?[name,alias]:[name];const matches=entry=>candidates.includes(entry.fullName)||candidates.includes(entry.name);const local=typedScope.tools?.getTools(true)?.find(matches);if(local)return local;const registries=typedScope.providers?.getRegistries?.("AppRegistry")??[];for(const registry of registries){for(const app of registry.getApps()){if(!app.isRemote)continue;const remote=app.tools.getTools(true).find(matches);if(remote)return remote}}return void 0}function checkDirectCallPolicy(tool,directCalls){if(!directCalls)return ALLOWED;if(directCalls.enabled===false){return deny("Direct tool invocation is disabled")}const{allowedTools}=directCalls;if(allowedTools&&!ownNamesOf(tool).some(ownName=>allowedTools.includes(ownName))){return deny(`Tool "${tool.name}" is not in the direct-call allowlist`)}if(directCalls.filter&&!directCalls.filter(toToolFilterInfo(tool))){return deny(`Tool "${tool.name}" is excluded by the directCalls filter`)}return ALLOWED}function readCodeCallPolicyConfig(config){return{mode:config.get("mode")??"codecall_only",includeTools:config.get("includeTools")}}function checkCodeCallToolAccess(scope,config,name,options={}){const entry=resolveCodeCallTool(scope,name);if(!entry)return denyUnknownTool(name);if(!isOfferedToCaller(entry.metadata?.availableWhen,options.surface)){return deny(`Tool "${name}" is not offered on the caller's surface "${options.surface}"`)}const policyTool=toCodeCallPolicyTool(entry,name,scope);const baseDecision=checkCodeCallToolPolicy(policyTool,readCodeCallPolicyConfig(config));if(!baseDecision.allowed)return baseDecision;if(options.directCall){const directDecision=checkDirectCallPolicy(policyTool,config.get("directCalls"));if(!directDecision.allowed)return directDecision}return{allowed:true,entry}}var EMBEDDED_STACK_FRAME_RE=/\n[ \t]*at\s[^\n]*/g;var QUOTED_PATH_RE=/(['"`])((?:~?\/|[A-Za-z]:[\\/]|\\\\)[^\s'"`\\/][^'"`\n]*)\1/g;var URL_RE=/\b[A-Za-z][A-Za-z0-9+.-]{1,31}:\/\/(?:[^\s'"`<>,;]|[,;](?!~?\/|[A-Za-z]:[\\/]|\\\\))*/g;var QUERY_PATH_VALUE_RE=/([?&][^=&#]*=)(?:~?\/|[A-Za-z]:[\\/]|\\\\)[^&#]*/g;var POSIX_SEGMENT=String.raw`[^\s/\\'"\x60<>|,;:()\[\]{}]+`;var WINDOWS_SEGMENT=String.raw`[^\s/\\'"\x60<>|,;:*?]+`;function segments(segment,separator){const spaced=`${segment}(?: ${segment}){0,2}`;return`(?:(?:${spaced}${separator})+(?:${segment})?|${segment})`}var UNQUOTED_PATH_RE=new RegExp([String.raw`(?<![\w.~/\\)\]-])~?/+${segments(POSIX_SEGMENT,"/+")}`,String.raw`(?<![\w\\/])[A-Za-z]:[\\/]+${segments(WINDOWS_SEGMENT,String.raw`[\\/]+`)}?`,String.raw`(?<![\w\\])\\\\${segments(WINDOWS_SEGMENT,String.raw`[\\/]+`)}`].join("|"),"g");function redactPaths(text){return text.replace(QUOTED_PATH_RE,"$1[path]$1").replace(UNQUOTED_PATH_RE,"[path]")}function toClientErrorMessage(message){if(!message)return"";return redactAbsolutePaths(message.replace(EMBEDDED_STACK_FRAME_RE,""))}function redactAbsolutePaths(text){let result="";let last=0;for(const match of text.matchAll(URL_RE)){const start=match.index??0;result+=redactPaths(text.slice(last,start));result+=/^file:/i.test(match[0])?"[path]":match[0].replace(QUERY_PATH_VALUE_RE,"$1[path]");last=start+match[0].length}return result+redactPaths(text.slice(last))}var TOOL_CALL_ERROR_CODES={NOT_FOUND:"NOT_FOUND",VALIDATION:"VALIDATION",EXECUTION:"EXECUTION",TIMEOUT:"TIMEOUT",ACCESS_DENIED:"ACCESS_DENIED",RATE_LIMITED:"RATE_LIMITED",SELF_REFERENCE:"SELF_REFERENCE"};function createToolCallError(code,toolName,rawMessage){const sanitizedMessage=getSanitizedMessage(code,toolName,rawMessage);return Object.freeze({code,message:sanitizedMessage,toolName})}function getSanitizedMessage(code,toolName,rawMessage){switch(code){case TOOL_CALL_ERROR_CODES.NOT_FOUND:return`Tool "${toolName}" was not found`;case TOOL_CALL_ERROR_CODES.VALIDATION:return rawMessage?sanitizeValidationMessage(rawMessage):`Input validation failed for tool "${toolName}"`;case TOOL_CALL_ERROR_CODES.EXECUTION:return`Tool "${toolName}" execution failed`;case TOOL_CALL_ERROR_CODES.TIMEOUT:return`Tool "${toolName}" execution timed out`;case TOOL_CALL_ERROR_CODES.ACCESS_DENIED:return`Access denied for tool "${toolName}"`;case TOOL_CALL_ERROR_CODES.RATE_LIMITED:return`Tool "${toolName}" was rate limited`;case TOOL_CALL_ERROR_CODES.SELF_REFERENCE:return`Cannot call CodeCall tools from within AgentScript`;default:return`An error occurred while calling "${toolName}"`}}function sanitizeValidationMessage(message){let sanitized=toClientErrorMessage(message);sanitized=sanitized.replace(/\bat line \d+/gi,"");sanitized=sanitized.replace(/\bline \d+/gi,"");sanitized=sanitized.replace(/:\d+:\d+/g,"");if(sanitized.length>200){sanitized=sanitized.substring(0,200)+"..."}return sanitized.trim()}var SelfReferenceError=class extends Error{code=TOOL_CALL_ERROR_CODES.SELF_REFERENCE;toolName;constructor(toolName){super(`Self-reference attack: Attempted to call CodeCall tool "${toolName}" from within AgentScript`);this.name="SelfReferenceError";this.toolName=toolName;Object.freeze(this)}};var CODECALL_TOOL_PREFIX="codecall:";var BLOCKED_CODECALL_TOOLS=Object.freeze(new Set(["codecall:search","codecall:describe","codecall:execute","codecall:invoke"]));function isBlockedSelfReference(toolName){const normalizedName=toolName.toLowerCase().trim();if(normalizedName.startsWith(CODECALL_TOOL_PREFIX)){return true}if(BLOCKED_CODECALL_TOOLS.has(toolName)){return true}return false}function assertNotSelfReference(toolName){if(isBlockedSelfReference(toolName)){throw new SelfReferenceError(toolName)}}var import_sdk3=require("@frontmcp/sdk");var AUDIT_EVENT_TYPES={EXECUTION_START:"codecall:execution:start",EXECUTION_SUCCESS:"codecall:execution:success",EXECUTION_FAILURE:"codecall:execution:failure",EXECUTION_TIMEOUT:"codecall:execution:timeout",TOOL_CALL_START:"codecall:tool:call:start",TOOL_CALL_SUCCESS:"codecall:tool:call:success",TOOL_CALL_FAILURE:"codecall:tool:call:failure",SECURITY_SELF_REFERENCE:"codecall:security:self-reference",SECURITY_ACCESS_DENIED:"codecall:security:access-denied",SECURITY_AST_BLOCKED:"codecall:security:ast-blocked",SEARCH_PERFORMED:"codecall:search:performed",DESCRIBE_PERFORMED:"codecall:describe:performed",INVOKE_PERFORMED:"codecall:invoke:performed"};var AuditLoggerService=class{listeners=new Set;executionCounter=0;subscribe(listener){this.listeners.add(listener);return()=>{this.listeners.delete(listener)}}generateExecutionId(){const timestamp=Date.now().toString(36);const counter=(++this.executionCounter).toString(36).padStart(4,"0");const random=Math.random().toString(36).substring(2,8);return`exec_${timestamp}_${counter}_${random}`}logExecutionStart(executionId,script){this.emit({type:AUDIT_EVENT_TYPES.EXECUTION_START,timestamp:new Date().toISOString(),executionId,data:{scriptHash:this.hashScript(script),scriptLength:script.length}})}logExecutionSuccess(executionId,script,durationMs,toolCallCount){this.emit({type:AUDIT_EVENT_TYPES.EXECUTION_SUCCESS,timestamp:new Date().toISOString(),executionId,durationMs,data:{scriptHash:this.hashScript(script),scriptLength:script.length,toolCallCount}})}logExecutionFailure(executionId,script,durationMs,error){this.emit({type:AUDIT_EVENT_TYPES.EXECUTION_FAILURE,timestamp:new Date().toISOString(),executionId,durationMs,data:{scriptHash:this.hashScript(script),scriptLength:script.length,error:this.sanitizeError(error)}})}logExecutionTimeout(executionId,script,durationMs){this.emit({type:AUDIT_EVENT_TYPES.EXECUTION_TIMEOUT,timestamp:new Date().toISOString(),executionId,durationMs,data:{scriptHash:this.hashScript(script),scriptLength:script.length}})}logToolCallStart(executionId,toolName,callDepth){this.emit({type:AUDIT_EVENT_TYPES.TOOL_CALL_START,timestamp:new Date().toISOString(),executionId,data:{toolName,callDepth}})}logToolCallSuccess(executionId,toolName,callDepth,durationMs){this.emit({type:AUDIT_EVENT_TYPES.TOOL_CALL_SUCCESS,timestamp:new Date().toISOString(),executionId,durationMs,data:{toolName,callDepth}})}logToolCallFailure(executionId,toolName,callDepth,durationMs,errorCode){this.emit({type:AUDIT_EVENT_TYPES.TOOL_CALL_FAILURE,timestamp:new Date().toISOString(),executionId,durationMs,data:{toolName,callDepth,errorCode}})}logSecuritySelfReference(executionId,toolName){this.emit({type:AUDIT_EVENT_TYPES.SECURITY_SELF_REFERENCE,timestamp:new Date().toISOString(),executionId,data:{blocked:toolName,reason:"Self-reference attack: attempted to call CodeCall tool from within AgentScript"}})}logSecurityAccessDenied(executionId,toolName,reason){this.emit({type:AUDIT_EVENT_TYPES.SECURITY_ACCESS_DENIED,timestamp:new Date().toISOString(),executionId,data:{blocked:toolName,reason:this.sanitizeError(reason)}})}logSecurityAstBlocked(executionId,pattern,reason){this.emit({type:AUDIT_EVENT_TYPES.SECURITY_AST_BLOCKED,timestamp:new Date().toISOString(),executionId,data:{blocked:pattern,reason:this.sanitizeError(reason)}})}logSearch(executionId,query,resultCount,durationMs){this.emit({type:AUDIT_EVENT_TYPES.SEARCH_PERFORMED,timestamp:new Date().toISOString(),executionId,durationMs,data:{queryLength:query.length,resultCount}})}logDescribe(executionId,toolNames,durationMs){this.emit({type:AUDIT_EVENT_TYPES.DESCRIBE_PERFORMED,timestamp:new Date().toISOString(),executionId,durationMs,data:{toolCount:toolNames.length,toolNames:toolNames.slice(0,10)}})}logInvoke(executionId,toolName,success,durationMs){this.emit({type:AUDIT_EVENT_TYPES.INVOKE_PERFORMED,timestamp:new Date().toISOString(),executionId,durationMs,data:{toolName,success}})}emit(event){const frozenEvent=Object.freeze({...event,data:Object.freeze({...event.data})});for(const listener of this.listeners){try{listener(frozenEvent)}catch{}}}hashScript(script){let hash=0;for(let i=0;i<script.length;i++){const char=script.charCodeAt(i);hash=(hash<<5)-hash+char;hash=hash&hash}return`sh_${(hash>>>0).toString(16).padStart(8,"0")}`}sanitizeError(error){if(!error)return"Unknown error";let sanitized=toClientErrorMessage(error);sanitized=sanitized.replace(/:\d+:\d+/g,"");if(sanitized.length>200){sanitized=sanitized.substring(0,200)+"..."}return sanitized.trim()}};AuditLoggerService=__decorateClass([(0,import_sdk3.Provider)({name:"codecall:audit-logger",scope:import_sdk3.ProviderScope.GLOBAL})],AuditLoggerService);var import_vectoriadb=require("vectoriadb");var DEFAULT_SYNONYM_GROUPS=[["create","add","new","insert","make","append","register","generate","produce","build","construct","provision","instantiate","define","compose","draft"],["delete","remove","destroy","drop","erase","clear","purge","discard","eliminate","nuke","unbind","unregister"],["get","fetch","retrieve","read","obtain","load","pull","access","grab","snag","receive"],["update","edit","modify","change","patch","alter","revise","refresh","correct","amend","adjust","tweak","rectify","refine"],["list","show","display","enumerate","browse","view","peek","index","catalog","survey","inspect","ls","dir"],["find","search","lookup","query","locate","filter","scan","explore","investigate","detect","scout","seek"],["archive","shelve","retire","hide","suppress","mute"],["unarchive","restore","recover","undelete","unhide"],["enable","activate","start","turn on","switch on","boot","init","initialize","setup","spin up","resume","unpause"],["disable","deactivate","stop","turn off","switch off","shutdown","halt","kill","terminate","suspend","pause","cease"],["run","execute","invoke","trigger","launch","call","perform","operate","handle","process","fire"],["restart","reboot","reset","reload","bounce","recycle","refresh"],["validate","verify","check","confirm","assert","test","audit","assess","healthcheck","ping"],["analyze","interpret","diagnose","evaluate","review","summarize","count","calculate","compute","measure","aggregate","summarise"],["copy","duplicate","clone","replicate","mirror","fork","repro"],["move","transfer","migrate","relocate","rename","shift","mv","slide"],["save","store","write","persist","commit","stash","record","log"],["sync","synchronize","resync","reconcile","align","pair"],["import","ingest","upload","push","feed"],["export","download","dump","backup","extract"],["connect","link","bind","attach","join","bridge","associate","mount","map"],["disconnect","unlink","unbind","detach","leave","dissociate","unmount","unmap"],["login","log in","sign in","authenticate","auth"],["logout","log out","sign out","disconnect"],["approve","authorize","grant","permit","allow","sanction","whitelist"],["deny","reject","revoke","forbid","block","ban","blacklist"],["encrypt","secure","lock","seal","protect","scramble","hash"],["decrypt","unlock","unseal","reveal","decode"],["deploy","release","ship","publish","roll out","promote","distribute","install"],["debug","troubleshoot","fix","repair","resolve","trace"],["compile","transpile","build","assemble","package","bundle","minify"],["buy","purchase","order","pay","checkout","spend"],["sell","refund","reimburse","charge","invoice","bill"],["subscribe","upgrade","upsell"],["unsubscribe","cancel","downgrade"],["schedule","book","appoint","reserve","plan","calendar"],["reschedule","postpone","delay","defer"],["send","dispatch","deliver","transmit","post","broadcast","notify","alert","email","text","message","chat"],["reply","respond","answer","retort"],["share","forward","retweet","repost"],["like","favorite","star","upvote","heart"],["dislike","downvote"],["follow","watch","track"],["unfollow","ignore","mute"],["user","account","member","profile","identity","customer","principal","admin","operator","client","employee","staff"],["role","group","team","squad","unit","department"],["file","document","attachment","blob","asset","object","resource","content","media"],["image","picture","photo","screenshot"],["video","clip","recording","footage"],["message","notification","alert","event","signal","webhook","ping"],["log","trace","metric","telemetry","audit trail","history"],["settings","config","configuration","preferences","options","params","env","environment","variables"],["permission","privilege","access right","policy","rule","scope"],["organization","company","tenant","workspace","org","project","repo","repository"],["product","item","sku","inventory","stock"],["task","ticket","issue","bug","story","epic","todo","job","workitem"],["id","identifier","key","uuid","guid","token","hash","fingerprint"]];var SynonymExpansionService=class{synonymMap;maxExpansions;constructor(config={}){this.maxExpansions=config.maxExpansionsPerTerm??5;const groups=config.replaceDefaults?config.additionalSynonyms||[]:[...DEFAULT_SYNONYM_GROUPS,...config.additionalSynonyms||[]];this.synonymMap=this.buildSynonymMap(groups)}buildSynonymMap(groups){const map=new Map;for(const group of groups){const normalizedGroup=group.map(term=>term.toLowerCase());for(const term of normalizedGroup){if(!map.has(term)){map.set(term,new Set)}const synonyms=map.get(term);for(const synonym of normalizedGroup){if(synonym!==term){synonyms.add(synonym)}}}}return map}getSynonyms(term){const normalized=term.toLowerCase();const synonyms=this.synonymMap.get(normalized);if(!synonyms){return[]}return Array.from(synonyms).slice(0,this.maxExpansions)}expandQuery(query){const terms=query.toLowerCase().split(/\s+/).filter(term=>term.length>1);const expandedTerms=[];for(const term of terms){expandedTerms.push(term);const synonyms=this.getSynonyms(term);expandedTerms.push(...synonyms)}return expandedTerms.join(" ")}hasExpansions(query){const terms=query.toLowerCase().split(/\s+/);return terms.some(term=>this.synonymMap.has(term))}getStats(){const termCount=this.synonymMap.size;let totalSynonyms=0;for(const synonyms of this.synonymMap.values()){totalSynonyms+=synonyms.size}return{termCount,avgSynonymsPerTerm:termCount>0?totalSynonyms/termCount:0}}};var STOP_WORDS=new Set(["the","a","an","this","that","these","those","in","on","at","to","for","of","with","by","from","into","over","after","before","between","under","about","against","during","through","and","or","but","nor","so","yet","as","than","if","because","while","when","where","unless","i","me","my","mine","myself","you","your","yours","yourself","he","him","his","himself","she","her","hers","herself","it","its","itself","we","us","our","ours","ourselves","they","them","their","theirs","themselves","who","whom","whose","which","what","is","was","are","were","been","be","being","have","has","had","having","do","does","did","doing","will","would","shall","should","can","could","may","might","must","all","any","both","each","few","more","most","other","some","such","no","nor","not","only","own","same","too","very","just","even","please","pls","plz","thanks","thank","thx","hello","hi","hey","ok","okay","yes","no","actually","basically","literally","maybe","perhaps","now","then","here","there","again","once","back","example","context","optionally","optional","etc","ie","eg"]);var DEFAULT_EMBEDDING_MODEL="Xenova/all-MiniLM-L6-v2";function messageOf(error){return error instanceof Error?error.message:String(error)}var ToolSearchService=class _ToolSearchService{static MAX_SUBSCRIPTION_RETRIES=100;static INITIAL_RETRY_DELAY_MS=10;static MAX_RETRY_DELAY_MS=1e3;vectorDB;strategy;initialized=false;mlInitialized=false;config;scope;unsubscribe;synonymService=null;synonymExpansion;indexing;subscriptionPromise;subscriptionResolved=false;subscriptionResolve=null;subscriptionReject=null;retryTimeoutId=null;disposed=false;availabilityByTool=new Map;constructor(config={},scope){this.scope=scope;const embeddingOptions=config.embeddingOptions||{strategy:"tfidf",modelName:DEFAULT_EMBEDDING_MODEL,cacheDir:"./.cache/transformers",useHNSW:false,synonymExpansion:{enabled:true,replaceDefaults:false,maxExpansionsPerTerm:5}};this.strategy=config.strategy||embeddingOptions.strategy||"tfidf";this.config={strategy:this.strategy,embeddingOptions,defaultTopK:config.defaultTopK??8,defaultSimilarityThreshold:config.defaultSimilarityThreshold??0,mode:config.mode??"codecall_only",includeTools:config.includeTools};const validModes=["codecall_only","codecall_opt_in","metadata_driven"];if(!validModes.includes(this.config.mode)){throw new Error(`Invalid CodeCall mode: ${this.config.mode}. Valid modes: ${validModes.join(", ")}`)}if(this.strategy==="ml"){this.vectorDB=new import_vectoriadb.VectoriaDB({modelName:embeddingOptions.modelName||DEFAULT_EMBEDDING_MODEL,cacheDir:embeddingOptions.cacheDir||"./.cache/transformers",defaultTopK:this.config.defaultTopK,defaultSimilarityThreshold:this.config.defaultSimilarityThreshold,useHNSW:embeddingOptions.useHNSW||false})}else{this.vectorDB=this.createTfidfIndex()}this.synonymExpansion=config.synonymExpansion??embeddingOptions.synonymExpansion;if(this.strategy==="tfidf"){this.synonymService=this.createSynonymService()}this.subscriptionPromise=new Promise((resolve,reject)=>{this.subscriptionResolve=resolve;this.subscriptionReject=reject});this.setupSubscription()}createTfidfIndex(){return new import_vectoriadb.TFIDFVectoria({defaultTopK:this.config.defaultTopK,defaultSimilarityThreshold:this.config.defaultSimilarityThreshold})}createSynonymService(){const synonymExpansion=this.synonymExpansion;if(synonymExpansion===false||synonymExpansion?.enabled===false)return null;return new SynonymExpansionService(synonymExpansion??{})}async ensureSubscribed(){if(this.subscriptionResolved){return}await this.subscriptionPromise}setupSubscription(retryCount=0,delayMs=_ToolSearchService.INITIAL_RETRY_DELAY_MS){if(this.scope.tools){this.subscribeToToolChanges();return}if(retryCount>=_ToolSearchService.MAX_SUBSCRIPTION_RETRIES){this.scope.logger.warn("ToolSearchService: scope.tools not available after max retries. Tool search will return incomplete results until tools are registered.");this.markSubscribed();return}const nextDelay=Math.min(delayMs*2,_ToolSearchService.MAX_RETRY_DELAY_MS);this.retryTimeoutId=setTimeout(()=>{this.retryTimeoutId=null;if(this.disposed){return}this.setupSubscription(retryCount+1,nextDelay)},delayMs)}subscribeToToolChanges(){this.unsubscribe=this.scope.tools.subscribe({immediate:true},event=>{this.queueReindex(event.snapshot)});this.markSubscribed()}queueReindex(tools){const reindex=()=>this.handleToolChange(tools);const run=(this.indexing?this.indexing.then(reindex):reindex()).catch(error=>{this.scope.logger.warn(`CodeCall tool search could not index the tools: ${messageOf(error)}`)});this.indexing=run;void run.then(()=>{if(this.indexing===run)this.indexing=void 0})}markSubscribed(){this.subscriptionResolved=true;if(this.subscriptionResolve){this.subscriptionResolve();this.subscriptionResolve=null}}async handleToolChange(tools){if(tools.length>0&&!this.mlInitialized&&this.strategy==="ml"&&this.vectorDB instanceof import_vectoriadb.VectoriaDB){try{await this.vectorDB.initialize();this.mlInitialized=true}catch(error){this.fallBackToTfidf(error)}}const availabilityByTool=new Map;const documents=tools.flatMap(tool=>this.toDocuments(tool,availabilityByTool));await this.replaceIndex(documents);this.availabilityByTool=availabilityByTool;this.initialized=true}toDocuments(tool,availabilityByTool){try{if(!this.shouldIndexTool(tool))return[];const toolName=tool.name;const document={id:toolName,text:this.extractSearchableText(tool),metadata:{id:toolName,toolName,qualifiedName:tool.fullName||toolName,appId:this.extractAppId(tool),toolInstance:tool}};availabilityByTool.set(toolName,tool.metadata.availableWhen);return[document]}catch(error){this.scope.logger.warn(`CodeCall tool search skipped tool "${tool.name}": ${messageOf(error)}`);return[]}}async replaceIndex(documents){if(this.vectorDB instanceof import_vectoriadb.VectoriaDB){try{this.vectorDB.clear();if(documents.length>0)await this.vectorDB.addMany(documents);return}catch(error){this.fallBackToTfidf(error)}}const index=this.createTfidfIndex();index.addDocuments(documents);index.reindex();this.vectorDB=index}fallBackToTfidf(error){const modelName=this.config.embeddingOptions.modelName||DEFAULT_EMBEDDING_MODEL;this.scope.logger.warn(`CodeCall could not use embedding model "${modelName}" (${messageOf(error)}); tool search uses TF-IDF instead`);this.strategy="tfidf";this.vectorDB=this.createTfidfIndex();this.synonymService=this.createSynonymService()}shouldIndexTool(tool){return checkCodeCallToolPolicy(toCodeCallPolicyTool(tool,void 0,this.scope),this.config).allowed}async initialize(){}dispose(){this.disposed=true;if(this.retryTimeoutId){clearTimeout(this.retryTimeoutId);this.retryTimeoutId=null}if(this.subscriptionReject){this.subscriptionReject(new Error("ToolSearchService disposed before subscription completed"));this.subscriptionReject=null;this.subscriptionResolve=null}if(this.unsubscribe){this.unsubscribe();this.unsubscribe=void 0}}extractSearchableText(tool){const parts=[];if(tool.name){const nameParts=tool.name.split(/[:\-_.]/).filter(Boolean);for(const part of nameParts){parts.push(part,part)}}if(tool.metadata.description){const description=tool.metadata.description;parts.push(description,description,description);const keyTerms=description.toLowerCase().split(/\s+/).filter(word=>word.length>=4&&!this.isStopWord(word));parts.push(...keyTerms)}if(tool.metadata.tags&&tool.metadata.tags.length>0){for(const tag of tool.metadata.tags){parts.push(tag,tag)}}if(tool.rawInputSchema&&typeof tool.rawInputSchema==="object"){const schema=tool.rawInputSchema;if(schema.properties){parts.push(...Object.keys(schema.properties))}}const examples=tool.metadata?.examples;if(examples&&Array.isArray(examples)){for(const ex of examples){if(ex.description){parts.push(ex.description,ex.description)}if(ex.input&&typeof ex.input==="object"){for(const[key,value]of Object.entries(ex.input)){parts.push(key);if(typeof value==="string"){parts.push(value)}}}}}return parts.join(" ")}isStopWord(word){return STOP_WORDS.has(word)}extractAppId(tool){return codeCallAppIdOf(this.scope,tool)}async search(query,options={}){await this.ensureSubscribed();await this.indexing;const{topK=this.config.defaultTopK,appIds,excludeToolNames=[],surface}=options;const minScore=this.config.defaultSimilarityThreshold;const filter=metadata=>{if(excludeToolNames.includes(metadata.toolName)){return false}if(!isOfferedToCaller(metadata.toolInstance.metadata.availableWhen,surface)){return false}if(appIds&&appIds.length>0){if(!metadata.appId||!appIds.includes(metadata.appId)){return false}}return true};const effectiveQuery=this.synonymService?this.synonymService.expandQuery(query):query;const results=await this.vectorDB.search(effectiveQuery,{topK,threshold:minScore,filter});return results.map(result=>({toolName:result.metadata.toolName,appId:result.metadata.appId,description:result.metadata.toolInstance.metadata.description||"",relevanceScore:result.score}))}getAllToolNames(){if(this.vectorDB instanceof import_vectoriadb.VectoriaDB){return this.vectorDB.getAll().map(doc=>doc.id)}else{return this.vectorDB.getAllDocumentIds()}}getTotalCount(surface){if(surface!==void 0){return this.getAllToolNames().filter(toolName=>this.hasTool(toolName,surface)).length}if(this.vectorDB instanceof import_vectoriadb.VectoriaDB){return this.vectorDB.size()}else{return this.vectorDB.getDocumentCount()}}hasTool(toolName,surface){const indexed=this.vectorDB instanceof import_vectoriadb.VectoriaDB?this.vectorDB.has(toolName):this.vectorDB.hasDocument(toolName);return indexed&&isOfferedToCaller(this.availabilityByTool.get(toolName),surface)}clear(){this.vectorDB.clear();this.availabilityByTool=new Map;this.initialized=false}getStrategy(){return this.strategy}isInitialized(){return this.initialized}};var import_core=require("@enclave-vm/core");var import_sdk4=require("@frontmcp/sdk");var import_ast=require("@enclave-vm/ast");var AGENTSCRIPT_PARSE_OPTIONS={ecmaVersion:"latest",sourceType:"script",allowReturnOutsideFunction:true,allowAwaitOutsideFunction:true};var PARSE_ATTEMPTS=[{wrap:code=>code,parseOptions:AGENTSCRIPT_PARSE_OPTIONS,lineOffset:0},{wrap:code=>code,parseOptions:{...AGENTSCRIPT_PARSE_OPTIONS,sourceType:"module"},lineOffset:0},{wrap:code=>`async function __temp__() {
|
|
1949
2
|
${code}
|
|
1950
|
-
}`,
|
|
1951
|
-
parseOptions: AGENTSCRIPT_PARSE_OPTIONS,
|
|
1952
|
-
lineOffset: 1
|
|
1953
|
-
}
|
|
1954
|
-
];
|
|
1955
|
-
var NON_REFERENCE_KEYS = /* @__PURE__ */ new Set(["type", "loc", "start", "end", "range", "label"]);
|
|
1956
|
-
function isAstNode(value) {
|
|
1957
|
-
return typeof value === "object" && value !== null && typeof value.type === "string";
|
|
1958
|
-
}
|
|
1959
|
-
function isPropertyName(parent, key) {
|
|
1960
|
-
if (!parent || parent["computed"]) return false;
|
|
1961
|
-
if (parent.type === "MemberExpression") return key === "property";
|
|
1962
|
-
return key === "key" && ["Property", "MethodDefinition", "PropertyDefinition"].includes(parent.type);
|
|
1963
|
-
}
|
|
1964
|
-
function visitIdentifierReferences(node, visit, parent, key = "") {
|
|
1965
|
-
if (node.type === "Identifier") {
|
|
1966
|
-
if (!isPropertyName(parent, key)) visit(node);
|
|
1967
|
-
return;
|
|
1968
|
-
}
|
|
1969
|
-
for (const [childKey, child] of Object.entries(node)) {
|
|
1970
|
-
if (NON_REFERENCE_KEYS.has(childKey)) continue;
|
|
1971
|
-
const children = Array.isArray(child) ? child : [child];
|
|
1972
|
-
for (const childNode of children) {
|
|
1973
|
-
if (isAstNode(childNode)) visitIdentifierReferences(childNode, visit, node, childKey);
|
|
1974
|
-
}
|
|
1975
|
-
}
|
|
1976
|
-
}
|
|
1977
|
-
var DisallowedGlobalsRule = class {
|
|
1978
|
-
constructor(messages) {
|
|
1979
|
-
this.messages = messages;
|
|
1980
|
-
}
|
|
1981
|
-
messages;
|
|
1982
|
-
name = "codecall-disallowed-globals";
|
|
1983
|
-
description = "Globals CodeCall scripts may not use";
|
|
1984
|
-
defaultSeverity = import_ast.ValidationSeverity.ERROR;
|
|
1985
|
-
enabledByDefault = true;
|
|
1986
|
-
validate(context) {
|
|
1987
|
-
visitIdentifierReferences(context.ast, (identifier) => {
|
|
1988
|
-
const message = identifier.name === void 0 ? void 0 : this.messages.get(identifier.name);
|
|
1989
|
-
if (message === void 0) return;
|
|
1990
|
-
context.report({
|
|
1991
|
-
code: "DISALLOWED_IDENTIFIER",
|
|
1992
|
-
message,
|
|
1993
|
-
location: identifier.loc ? { line: identifier.loc.start.line, column: identifier.loc.start.column } : void 0,
|
|
1994
|
-
data: { identifier: identifier.name }
|
|
1995
|
-
});
|
|
1996
|
-
});
|
|
1997
|
-
}
|
|
1998
|
-
};
|
|
1999
|
-
function disallowedGlobalMessages({ disabledBuiltins, disabledGlobals }) {
|
|
2000
|
-
return new Map([
|
|
2001
|
-
...disabledBuiltins.map((name) => [name, `${name} is disabled by vm.disabledBuiltins`]),
|
|
2002
|
-
...disabledGlobals.map((name) => [name, `${name} is disabled by vm.disabledGlobals`]),
|
|
2003
|
-
["console", "console is not available in CodeCall scripts; use mcpLog(level, message)"]
|
|
2004
|
-
]);
|
|
2005
|
-
}
|
|
2006
|
-
function scriptPolicyRules(options) {
|
|
2007
|
-
const rules = [new DisallowedGlobalsRule(disallowedGlobalMessages(options))];
|
|
2008
|
-
if (!options.allowLoops) {
|
|
2009
|
-
rules.push(
|
|
2010
|
-
new import_ast.ForbiddenLoopRule({
|
|
2011
|
-
allowFor: false,
|
|
2012
|
-
allowForOf: true,
|
|
2013
|
-
allowWhile: false,
|
|
2014
|
-
allowDoWhile: false,
|
|
2015
|
-
allowForIn: false,
|
|
2016
|
-
message: "Only for-of loops are allowed (vm.allowLoops is false)"
|
|
2017
|
-
})
|
|
2018
|
-
);
|
|
2019
|
-
}
|
|
2020
|
-
return rules;
|
|
2021
|
-
}
|
|
2022
|
-
async function findScriptPolicyIssues(code, options) {
|
|
2023
|
-
const validator = new import_ast.JSAstValidator(scriptPolicyRules(options));
|
|
2024
|
-
for (const attempt of PARSE_ATTEMPTS) {
|
|
2025
|
-
const result = await validator.validate(attempt.wrap(code), {
|
|
2026
|
-
parseOptions: attempt.parseOptions,
|
|
2027
|
-
preScan: { enabled: false }
|
|
2028
|
-
});
|
|
2029
|
-
if (result.parseError) continue;
|
|
2030
|
-
return result.issues.map(
|
|
2031
|
-
(issue) => issue.location && attempt.lineOffset > 0 ? { ...issue, location: { ...issue.location, line: issue.location.line - attempt.lineOffset } } : issue
|
|
2032
|
-
);
|
|
2033
|
-
}
|
|
2034
|
-
return [];
|
|
2035
|
-
}
|
|
2036
|
-
|
|
2037
|
-
// plugins/plugin-codecall/src/utils/build-tool-namespaces.ts
|
|
2038
|
-
var IDENT_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
2039
|
-
var PROTOTYPE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
2040
|
-
var RESERVED_NAMESPACES = /* @__PURE__ */ new Set([
|
|
2041
|
-
"console",
|
|
2042
|
-
"Math",
|
|
2043
|
-
"JSON",
|
|
2044
|
-
"Object",
|
|
2045
|
-
"Array",
|
|
2046
|
-
"String",
|
|
2047
|
-
"Number",
|
|
2048
|
-
"Boolean",
|
|
2049
|
-
"Promise",
|
|
2050
|
-
"Symbol",
|
|
2051
|
-
"Map",
|
|
2052
|
-
"Set",
|
|
2053
|
-
"WeakMap",
|
|
2054
|
-
"WeakSet",
|
|
2055
|
-
"Date",
|
|
2056
|
-
"Error",
|
|
2057
|
-
"RegExp",
|
|
2058
|
-
"globalThis",
|
|
2059
|
-
"global",
|
|
2060
|
-
"window",
|
|
2061
|
-
"self",
|
|
2062
|
-
"undefined",
|
|
2063
|
-
"null",
|
|
2064
|
-
"true",
|
|
2065
|
-
"false",
|
|
2066
|
-
"callTool",
|
|
2067
|
-
"getTool",
|
|
2068
|
-
"mcpLog",
|
|
2069
|
-
"mcpNotify"
|
|
2070
|
-
]);
|
|
2071
|
-
var UNBINDABLE_NAMESPACES = new Set(
|
|
2072
|
-
[
|
|
2073
|
-
// Reserved words and strict-mode restricted bindings
|
|
2074
|
-
"break case catch class const continue debugger default delete do else enum export extends finally for",
|
|
2075
|
-
"function if import in instanceof new return super switch this throw try typeof var void while with yield",
|
|
2076
|
-
"let static implements interface package private protected public await eval arguments NaN Infinity",
|
|
2077
|
-
// AgentScript globals
|
|
2078
|
-
"parallel isNaN isFinite parseInt parseFloat encodeURI encodeURIComponent decodeURI decodeURIComponent",
|
|
2079
|
-
// Identifiers the AgentScript validator refuses
|
|
2080
|
-
"process require module exports Buffer Function AsyncFunction GeneratorFunction Reflect Proxy TypeError",
|
|
2081
|
-
"ReferenceError SyntaxError RangeError URIError EvalError AggregateError fetch XMLHttpRequest WebSocket",
|
|
2082
|
-
"localStorage sessionStorage indexedDB crypto performance structuredClone AbortController AbortSignal",
|
|
2083
|
-
"MessageChannel MessagePort BroadcastChannel TextEncoder TextDecoder Intl setTimeout setInterval",
|
|
2084
|
-
"setImmediate clearTimeout clearInterval clearImmediate queueMicrotask WebAssembly Worker SharedWorker",
|
|
2085
|
-
"ServiceWorker WeakRef FinalizationRegistry BigInt Atomics SharedArrayBuffer ArrayBuffer DataView",
|
|
2086
|
-
"importScripts ShadowRealm Iterator AsyncIterator"
|
|
2087
|
-
].join(" ").split(" ")
|
|
2088
|
-
);
|
|
2089
|
-
var UNCALLABLE_METHODS = new Set(
|
|
2090
|
-
[
|
|
2091
|
-
"process require module exports Buffer eval Function AsyncFunction GeneratorFunction arguments RegExp",
|
|
2092
|
-
"Promise Symbol Proxy Reflect Error TypeError ReferenceError SyntaxError RangeError URIError EvalError",
|
|
2093
|
-
"AggregateError fetch XMLHttpRequest WebSocket localStorage sessionStorage indexedDB crypto performance",
|
|
2094
|
-
"structuredClone AbortController AbortSignal MessageChannel MessagePort BroadcastChannel TextEncoder",
|
|
2095
|
-
"TextDecoder Intl setTimeout setInterval setImmediate clearTimeout clearInterval clearImmediate",
|
|
2096
|
-
"queueMicrotask WebAssembly Worker SharedWorker ServiceWorker WeakMap WeakSet WeakRef FinalizationRegistry",
|
|
2097
|
-
"Map Set Atomics SharedArrayBuffer importScripts ShadowRealm Iterator AsyncIterator"
|
|
2098
|
-
].join(" ").split(" ")
|
|
2099
|
-
);
|
|
2100
|
-
var SANDBOX_TOOL_NAME_RE = /^[a-zA-Z][a-zA-Z0-9:._-]*$/;
|
|
2101
|
-
var MAX_SANDBOX_TOOL_NAME_LENGTH = 256;
|
|
2102
|
-
function isBindableNamespace(ns, reservedGlobals) {
|
|
2103
|
-
return IDENT_RE.test(ns) && !PROTOTYPE_KEYS.has(ns) && !ns.startsWith("__") && !RESERVED_NAMESPACES.has(ns) && !UNBINDABLE_NAMESPACES.has(ns) && !reservedGlobals.has(ns);
|
|
2104
|
-
}
|
|
2105
|
-
function isBindableMethod(ns, method, toolName) {
|
|
2106
|
-
return IDENT_RE.test(method) && !PROTOTYPE_KEYS.has(method) && !method.startsWith("__") && !UNCALLABLE_METHODS.has(method) && toolName === `${ns}.${method}` && toolName.length <= MAX_SANDBOX_TOOL_NAME_LENGTH && SANDBOX_TOOL_NAME_RE.test(toolName);
|
|
2107
|
-
}
|
|
2108
|
-
function buildToolNamespaces(tools) {
|
|
2109
|
-
const namespaces = /* @__PURE__ */ Object.create(null);
|
|
2110
|
-
const skipped = [];
|
|
2111
|
-
for (const tool of tools) {
|
|
2112
|
-
const name = tool?.name;
|
|
2113
|
-
if (typeof name !== "string" || name.length === 0) continue;
|
|
2114
|
-
const dot = name.indexOf(".");
|
|
2115
|
-
if (dot <= 0 || dot === name.length - 1) {
|
|
2116
|
-
skipped.push({ name, reason: "no-namespace-prefix" });
|
|
2117
|
-
continue;
|
|
2118
|
-
}
|
|
2119
|
-
const ns = name.slice(0, dot);
|
|
2120
|
-
const method = name.slice(dot + 1);
|
|
2121
|
-
if (!IDENT_RE.test(ns) || !IDENT_RE.test(method)) {
|
|
2122
|
-
skipped.push({ name, reason: "invalid-identifier" });
|
|
2123
|
-
continue;
|
|
2124
|
-
}
|
|
2125
|
-
if (PROTOTYPE_KEYS.has(ns) || PROTOTYPE_KEYS.has(method)) {
|
|
2126
|
-
skipped.push({ name, reason: "prototype-key" });
|
|
2127
|
-
continue;
|
|
2128
|
-
}
|
|
2129
|
-
if (RESERVED_NAMESPACES.has(ns) || UNBINDABLE_NAMESPACES.has(ns) || ns.startsWith("__")) {
|
|
2130
|
-
skipped.push({ name, reason: "reserved-namespace" });
|
|
2131
|
-
continue;
|
|
2132
|
-
}
|
|
2133
|
-
if (!isBindableMethod(ns, method, name)) {
|
|
2134
|
-
skipped.push({ name, reason: "unsupported-name" });
|
|
2135
|
-
continue;
|
|
2136
|
-
}
|
|
2137
|
-
const bucket = namespaces[ns] ?? (namespaces[ns] = /* @__PURE__ */ Object.create(null));
|
|
2138
|
-
if (Object.prototype.hasOwnProperty.call(bucket, method)) {
|
|
2139
|
-
skipped.push({ name, reason: "duplicate-method" });
|
|
2140
|
-
continue;
|
|
2141
|
-
}
|
|
2142
|
-
bucket[method] = name;
|
|
2143
|
-
}
|
|
2144
|
-
return { namespaces, skipped };
|
|
2145
|
-
}
|
|
2146
|
-
function toSandboxToolNamespaces(namespaces, reservedGlobals = []) {
|
|
2147
|
-
if (!namespaces) return void 0;
|
|
2148
|
-
const reserved = new Set(reservedGlobals);
|
|
2149
|
-
const bindable = /* @__PURE__ */ Object.create(null);
|
|
2150
|
-
let count = 0;
|
|
2151
|
-
for (const ns of Object.keys(namespaces)) {
|
|
2152
|
-
if (!isBindableNamespace(ns, reserved)) continue;
|
|
2153
|
-
const methods = namespaces[ns];
|
|
2154
|
-
const bucket = /* @__PURE__ */ Object.create(null);
|
|
2155
|
-
let methodCount = 0;
|
|
2156
|
-
for (const method of Object.keys(methods)) {
|
|
2157
|
-
const toolName = methods[method];
|
|
2158
|
-
if (typeof toolName !== "string" || !isBindableMethod(ns, method, toolName)) continue;
|
|
2159
|
-
bucket[method] = toolName;
|
|
2160
|
-
methodCount += 1;
|
|
2161
|
-
}
|
|
2162
|
-
if (methodCount > 0) {
|
|
2163
|
-
bindable[ns] = bucket;
|
|
2164
|
-
count += 1;
|
|
2165
|
-
}
|
|
2166
|
-
}
|
|
2167
|
-
return count > 0 ? bindable : void 0;
|
|
2168
|
-
}
|
|
2169
|
-
|
|
2170
|
-
// plugins/plugin-codecall/src/utils/script-lines.ts
|
|
2171
|
-
var import_ast2 = require("@enclave-vm/ast");
|
|
2172
|
-
var acorn = __toESM(require("acorn"));
|
|
2173
|
-
var PARSE_OPTIONS = { ecmaVersion: "latest", locations: true };
|
|
2174
|
-
var NON_CHILD_KEYS = /* @__PURE__ */ new Set(["type", "loc", "start", "end", "range"]);
|
|
2175
|
-
function isNode(value) {
|
|
2176
|
-
return typeof value === "object" && value !== null && typeof value.type === "string";
|
|
2177
|
-
}
|
|
2178
|
-
function isAddedByTransform(node) {
|
|
2179
|
-
if (node.type === "VariableDeclaration") {
|
|
2180
|
-
const [declaration] = node["declarations"] ?? [];
|
|
2181
|
-
const id = declaration?.["id"];
|
|
2182
|
-
return typeof id?.["name"] === "string" && id["name"].startsWith("__iter_");
|
|
2183
|
-
}
|
|
2184
|
-
if (node.type === "IfStatement") {
|
|
2185
|
-
const right = node["test"]?.["right"];
|
|
2186
|
-
return right?.type === "Identifier" && right["name"] === "__maxIterations";
|
|
2187
|
-
}
|
|
2188
|
-
return false;
|
|
2189
|
-
}
|
|
2190
|
-
function parseScript(script) {
|
|
2191
|
-
try {
|
|
2192
|
-
return { body: parseBody(script, "script"), offset: 0 };
|
|
2193
|
-
} catch {
|
|
2194
|
-
try {
|
|
2195
|
-
return { body: parseBody(script, "module"), offset: 0 };
|
|
2196
|
-
} catch {
|
|
2197
|
-
const wrapped = parseBody(`async function __temp__() {
|
|
3
|
+
}`,parseOptions:AGENTSCRIPT_PARSE_OPTIONS,lineOffset:1}];var NON_REFERENCE_KEYS=new Set(["type","loc","start","end","range","label"]);function isAstNode(value){return typeof value==="object"&&value!==null&&typeof value.type==="string"}function isPropertyName(parent,key){if(!parent||parent["computed"])return false;if(parent.type==="MemberExpression")return key==="property";return key==="key"&&["Property","MethodDefinition","PropertyDefinition"].includes(parent.type)}function visitIdentifierReferences(node,visit,parent,key=""){if(node.type==="Identifier"){if(!isPropertyName(parent,key))visit(node);return}for(const[childKey,child]of Object.entries(node)){if(NON_REFERENCE_KEYS.has(childKey))continue;const children=Array.isArray(child)?child:[child];for(const childNode of children){if(isAstNode(childNode))visitIdentifierReferences(childNode,visit,node,childKey)}}}var DisallowedGlobalsRule=class{constructor(messages){this.messages=messages}messages;name="codecall-disallowed-globals";description="Globals CodeCall scripts may not use";defaultSeverity=import_ast.ValidationSeverity.ERROR;enabledByDefault=true;validate(context){visitIdentifierReferences(context.ast,identifier=>{const message=identifier.name===void 0?void 0:this.messages.get(identifier.name);if(message===void 0)return;context.report({code:"DISALLOWED_IDENTIFIER",message,location:identifier.loc?{line:identifier.loc.start.line,column:identifier.loc.start.column}:void 0,data:{identifier:identifier.name}})})}};function disallowedGlobalMessages({disabledBuiltins,disabledGlobals}){return new Map([...disabledBuiltins.map(name=>[name,`${name} is disabled by vm.disabledBuiltins`]),...disabledGlobals.map(name=>[name,`${name} is disabled by vm.disabledGlobals`]),["console","console is not available in CodeCall scripts; use mcpLog(level, message)"]])}function scriptPolicyRules(options){const rules=[new DisallowedGlobalsRule(disallowedGlobalMessages(options))];if(!options.allowLoops){rules.push(new import_ast.ForbiddenLoopRule({allowFor:false,allowForOf:true,allowWhile:false,allowDoWhile:false,allowForIn:false,message:"Only for-of loops are allowed (vm.allowLoops is false)"}))}return rules}async function findScriptPolicyIssues(code,options){const validator=new import_ast.JSAstValidator(scriptPolicyRules(options));for(const attempt of PARSE_ATTEMPTS){const result=await validator.validate(attempt.wrap(code),{parseOptions:attempt.parseOptions,preScan:{enabled:false}});if(result.parseError)continue;return result.issues.map(issue=>issue.location&&attempt.lineOffset>0?{...issue,location:{...issue.location,line:issue.location.line-attempt.lineOffset}}:issue)}return[]}var IDENT_RE=/^[A-Za-z_$][A-Za-z0-9_$]*$/;var PROTOTYPE_KEYS=new Set(["__proto__","constructor","prototype"]);var RESERVED_NAMESPACES=new Set(["console","Math","JSON","Object","Array","String","Number","Boolean","Promise","Symbol","Map","Set","WeakMap","WeakSet","Date","Error","RegExp","globalThis","global","window","self","undefined","null","true","false","callTool","getTool","mcpLog","mcpNotify"]);var UNBINDABLE_NAMESPACES=new Set(["break case catch class const continue debugger default delete do else enum export extends finally for","function if import in instanceof new return super switch this throw try typeof var void while with yield","let static implements interface package private protected public await eval arguments NaN Infinity","parallel isNaN isFinite parseInt parseFloat encodeURI encodeURIComponent decodeURI decodeURIComponent","process require module exports Buffer Function AsyncFunction GeneratorFunction Reflect Proxy TypeError","ReferenceError SyntaxError RangeError URIError EvalError AggregateError fetch XMLHttpRequest WebSocket","localStorage sessionStorage indexedDB crypto performance structuredClone AbortController AbortSignal","MessageChannel MessagePort BroadcastChannel TextEncoder TextDecoder Intl setTimeout setInterval","setImmediate clearTimeout clearInterval clearImmediate queueMicrotask WebAssembly Worker SharedWorker","ServiceWorker WeakRef FinalizationRegistry BigInt Atomics SharedArrayBuffer ArrayBuffer DataView","importScripts ShadowRealm Iterator AsyncIterator"].join(" ").split(" "));var UNCALLABLE_METHODS=new Set(["process require module exports Buffer eval Function AsyncFunction GeneratorFunction arguments RegExp","Promise Symbol Proxy Reflect Error TypeError ReferenceError SyntaxError RangeError URIError EvalError","AggregateError fetch XMLHttpRequest WebSocket localStorage sessionStorage indexedDB crypto performance","structuredClone AbortController AbortSignal MessageChannel MessagePort BroadcastChannel TextEncoder","TextDecoder Intl setTimeout setInterval setImmediate clearTimeout clearInterval clearImmediate","queueMicrotask WebAssembly Worker SharedWorker ServiceWorker WeakMap WeakSet WeakRef FinalizationRegistry","Map Set Atomics SharedArrayBuffer importScripts ShadowRealm Iterator AsyncIterator"].join(" ").split(" "));var SANDBOX_TOOL_NAME_RE=/^[a-zA-Z][a-zA-Z0-9:._-]*$/;var MAX_SANDBOX_TOOL_NAME_LENGTH=256;function isBindableNamespace(ns,reservedGlobals){return IDENT_RE.test(ns)&&!PROTOTYPE_KEYS.has(ns)&&!ns.startsWith("__")&&!RESERVED_NAMESPACES.has(ns)&&!UNBINDABLE_NAMESPACES.has(ns)&&!reservedGlobals.has(ns)}function isBindableMethod(ns,method,toolName){return IDENT_RE.test(method)&&!PROTOTYPE_KEYS.has(method)&&!method.startsWith("__")&&!UNCALLABLE_METHODS.has(method)&&toolName===`${ns}.${method}`&&toolName.length<=MAX_SANDBOX_TOOL_NAME_LENGTH&&SANDBOX_TOOL_NAME_RE.test(toolName)}function buildToolNamespaces(tools){const namespaces=Object.create(null);const skipped=[];for(const tool of tools){const name=tool?.name;if(typeof name!=="string"||name.length===0)continue;const dot=name.indexOf(".");if(dot<=0||dot===name.length-1){skipped.push({name,reason:"no-namespace-prefix"});continue}const ns=name.slice(0,dot);const method=name.slice(dot+1);if(!IDENT_RE.test(ns)||!IDENT_RE.test(method)){skipped.push({name,reason:"invalid-identifier"});continue}if(PROTOTYPE_KEYS.has(ns)||PROTOTYPE_KEYS.has(method)){skipped.push({name,reason:"prototype-key"});continue}if(RESERVED_NAMESPACES.has(ns)||UNBINDABLE_NAMESPACES.has(ns)||ns.startsWith("__")){skipped.push({name,reason:"reserved-namespace"});continue}if(!isBindableMethod(ns,method,name)){skipped.push({name,reason:"unsupported-name"});continue}const bucket=namespaces[ns]??(namespaces[ns]=Object.create(null));if(Object.prototype.hasOwnProperty.call(bucket,method)){skipped.push({name,reason:"duplicate-method"});continue}bucket[method]=name}return{namespaces,skipped}}function toSandboxToolNamespaces(namespaces,reservedGlobals=[]){if(!namespaces)return void 0;const reserved=new Set(reservedGlobals);const bindable=Object.create(null);let count=0;for(const ns of Object.keys(namespaces)){if(!isBindableNamespace(ns,reserved))continue;const methods=namespaces[ns];const bucket=Object.create(null);let methodCount=0;for(const method of Object.keys(methods)){const toolName=methods[method];if(typeof toolName!=="string"||!isBindableMethod(ns,method,toolName))continue;bucket[method]=toolName;methodCount+=1}if(methodCount>0){bindable[ns]=bucket;count+=1}}return count>0?bindable:void 0}var import_ast2=require("@enclave-vm/ast");var acorn=__toESM(require("acorn"));var PARSE_OPTIONS={ecmaVersion:"latest",locations:true};var NON_CHILD_KEYS=new Set(["type","loc","start","end","range"]);function isNode(value){return typeof value==="object"&&value!==null&&typeof value.type==="string"}function isAddedByTransform(node){if(node.type==="VariableDeclaration"){const[declaration]=node["declarations"]??[];const id=declaration?.["id"];return typeof id?.["name"]==="string"&&id["name"].startsWith("__iter_")}if(node.type==="IfStatement"){const right=node["test"]?.["right"];return right?.type==="Identifier"&&right["name"]==="__maxIterations"}return false}function parseScript(script){try{return{body:parseBody(script,"script"),offset:0}}catch{try{return{body:parseBody(script,"module"),offset:0}}catch{const wrapped=parseBody(`async function __temp__() {
|
|
2198
4
|
${script}
|
|
2199
|
-
}`, "script");
|
|
2200
|
-
|
|
2201
|
-
const block = fn?.["body"];
|
|
2202
|
-
return { body: block?.["body"] ?? [], offset: 1 };
|
|
2203
|
-
}
|
|
2204
|
-
}
|
|
2205
|
-
}
|
|
2206
|
-
function parseBody(code, sourceType) {
|
|
2207
|
-
const program = acorn.parse(code, { ...PARSE_OPTIONS, sourceType });
|
|
2208
|
-
return program["body"] ?? [];
|
|
2209
|
-
}
|
|
2210
|
-
function treesOf(script) {
|
|
2211
|
-
try {
|
|
2212
|
-
const wrap = !(0, import_ast2.isWrappedInMain)(script);
|
|
2213
|
-
const printed = parseBody((0, import_ast2.transformAgentScript)(script, { wrapInMain: wrap }), "script");
|
|
2214
|
-
const { body, offset } = parseScript(script);
|
|
2215
|
-
if (!wrap) return { printed, script: body, offset };
|
|
2216
|
-
const main = printed[0]?.["body"];
|
|
2217
|
-
return { printed: main?.["body"] ?? [], script: body, offset };
|
|
2218
|
-
} catch {
|
|
2219
|
-
return void 0;
|
|
2220
|
-
}
|
|
2221
|
-
}
|
|
2222
|
-
function pairLists(printed, script, depth, out, offset) {
|
|
2223
|
-
const kept = printed.filter((node) => !(isNode(node) && isAddedByTransform(node)));
|
|
2224
|
-
if (kept.length !== script.length) return;
|
|
2225
|
-
kept.forEach((node, index) => {
|
|
2226
|
-
const own = script[index];
|
|
2227
|
-
if (isNode(node) && isNode(own)) pairNodes(node, own, depth, out, offset);
|
|
2228
|
-
});
|
|
2229
|
-
}
|
|
2230
|
-
function pairNodes(printed, script, depth, out, offset) {
|
|
2231
|
-
if (printed.type === "ReturnStatement" && script.type === "ExpressionStatement") {
|
|
2232
|
-
record(printed, script, depth, out, offset);
|
|
2233
|
-
const argument = printed["argument"];
|
|
2234
|
-
const expression = script["expression"];
|
|
2235
|
-
if (isNode(argument) && isNode(expression)) pairNodes(argument, expression, depth + 1, out, offset);
|
|
2236
|
-
return;
|
|
2237
|
-
}
|
|
2238
|
-
if (printed.type !== script.type) return;
|
|
2239
|
-
record(printed, script, depth, out, offset);
|
|
2240
|
-
for (const key of Object.keys(printed)) {
|
|
2241
|
-
if (NON_CHILD_KEYS.has(key)) continue;
|
|
2242
|
-
const printedChild = printed[key];
|
|
2243
|
-
const scriptChild = script[key];
|
|
2244
|
-
if (Array.isArray(printedChild) && Array.isArray(scriptChild)) {
|
|
2245
|
-
pairLists(printedChild, scriptChild, depth + 1, out, offset);
|
|
2246
|
-
} else if (isNode(printedChild) && isNode(scriptChild)) {
|
|
2247
|
-
pairNodes(printedChild, scriptChild, depth + 1, out, offset);
|
|
2248
|
-
}
|
|
2249
|
-
}
|
|
2250
|
-
}
|
|
2251
|
-
function record(printed, script, depth, out, offset) {
|
|
2252
|
-
if (!printed.loc || !script.loc) return;
|
|
2253
|
-
out.push({
|
|
2254
|
-
printedStart: printed.loc.start.line,
|
|
2255
|
-
printedEnd: printed.loc.end.line,
|
|
2256
|
-
scriptLine: script.loc.start.line - offset,
|
|
2257
|
-
depth
|
|
2258
|
-
});
|
|
2259
|
-
}
|
|
2260
|
-
function validatedLineMapper(script) {
|
|
2261
|
-
const trees = treesOf(script);
|
|
2262
|
-
if (!trees) return () => void 0;
|
|
2263
|
-
const pairs = [];
|
|
2264
|
-
pairLists(trees.printed, trees.script, 0, pairs, trees.offset);
|
|
2265
|
-
return (printedLine) => {
|
|
2266
|
-
const starting = pairs.filter((pair) => pair.printedStart === printedLine);
|
|
2267
|
-
const candidates = starting.length > 0 ? starting : pairs.filter((pair) => pair.printedStart <= printedLine && printedLine <= pair.printedEnd);
|
|
2268
|
-
const best = candidates.reduce(
|
|
2269
|
-
(deepest, pair) => !deepest || pair.depth > deepest.depth ? pair : deepest,
|
|
2270
|
-
void 0
|
|
2271
|
-
);
|
|
2272
|
-
return best && best.scriptLine >= 1 ? best.scriptLine : void 0;
|
|
2273
|
-
};
|
|
2274
|
-
}
|
|
2275
|
-
var ISSUE_LINE_RE = / \(line (\d+)\)/g;
|
|
2276
|
-
function withScriptLines(message, script) {
|
|
2277
|
-
if (!message.includes("(line ")) return message;
|
|
2278
|
-
const lineOf = validatedLineMapper(script);
|
|
2279
|
-
return message.replace(ISSUE_LINE_RE, (_match, printed) => {
|
|
2280
|
-
const line = lineOf(Number(printed));
|
|
2281
|
-
return line === void 0 ? "" : ` (line ${line})`;
|
|
2282
|
-
});
|
|
2283
|
-
}
|
|
2284
|
-
|
|
2285
|
-
// plugins/plugin-codecall/src/services/enclave.service.ts
|
|
2286
|
-
function toolFailureMessage(error, toolName) {
|
|
2287
|
-
if (typeof error === "string" && error) return error;
|
|
2288
|
-
const message = error?.message;
|
|
2289
|
-
return typeof message === "string" && message ? message : `Tool call failed: ${toolName}`;
|
|
2290
|
-
}
|
|
2291
|
-
function toolFailureName(error) {
|
|
2292
|
-
const name = error && typeof error === "object" ? error.name : void 0;
|
|
2293
|
-
return typeof name === "string" && name ? name.slice(0, 128) : "ToolError";
|
|
2294
|
-
}
|
|
2295
|
-
var ITERATION_LIMIT_PREFIX = "Maximum iteration limit exceeded";
|
|
2296
|
-
var ITERATION_LIMIT_ERROR = {
|
|
2297
|
-
name: "Error",
|
|
2298
|
-
message: `${ITERATION_LIMIT_PREFIX} (${MAX_ITERATIONS_PER_LOOP}). This limit prevents infinite loops.`
|
|
2299
|
-
};
|
|
2300
|
-
var PARSE_FAILURE_PREFIX = "Failed to parse AgentScript code: ";
|
|
2301
|
-
var PARSE_POSITION_RE = /\((\d+):(\d+)\)$/;
|
|
2302
|
-
function parseFailureOf(message) {
|
|
2303
|
-
const match = PARSE_POSITION_RE.exec(message);
|
|
2304
|
-
const line = match ? Number(match[1]) - 1 : 0;
|
|
2305
|
-
if (!match || line < 1) return { message };
|
|
2306
|
-
const column = Number(match[2]);
|
|
2307
|
-
return { message: `${message.slice(0, match.index)}(${line}:${column})`, location: { line, column } };
|
|
2308
|
-
}
|
|
2309
|
-
var ScriptTooLargeError = class extends Error {
|
|
2310
|
-
code = "SCRIPT_TOO_LARGE";
|
|
2311
|
-
scriptLength;
|
|
2312
|
-
maxLength;
|
|
2313
|
-
constructor(scriptLength, maxLength) {
|
|
2314
|
-
super(
|
|
2315
|
-
`Script length (${scriptLength} characters) exceeds maximum allowed length (${maxLength} characters). Enable sidecar to handle large data, or reduce script size.`
|
|
2316
|
-
);
|
|
2317
|
-
this.name = "ScriptTooLargeError";
|
|
2318
|
-
this.scriptLength = scriptLength;
|
|
2319
|
-
this.maxLength = maxLength;
|
|
2320
|
-
}
|
|
2321
|
-
};
|
|
2322
|
-
var EnclaveService = class {
|
|
2323
|
-
vmOptions;
|
|
2324
|
-
sidecarOptions;
|
|
2325
|
-
constructor(config) {
|
|
2326
|
-
const all = config.getAll();
|
|
2327
|
-
this.vmOptions = all.resolvedVm;
|
|
2328
|
-
this.sidecarOptions = all.sidecar;
|
|
2329
|
-
}
|
|
2330
|
-
/**
|
|
2331
|
-
* Execute AgentScript code in the enclave
|
|
2332
|
-
*
|
|
2333
|
-
* @param code - The AgentScript code to execute (raw, not transformed)
|
|
2334
|
-
* @param environment - The VM environment with callTool, getTool, etc.
|
|
2335
|
-
* @returns Execution result with success/error and logs
|
|
2336
|
-
* @throws ScriptTooLargeError if script exceeds max length and sidecar is disabled
|
|
2337
|
-
*/
|
|
2338
|
-
async execute(code, environment) {
|
|
2339
|
-
const logs = [];
|
|
2340
|
-
if (!this.sidecarOptions.enabled && this.sidecarOptions.maxScriptLengthWhenDisabled !== null) {
|
|
2341
|
-
const maxLength = this.sidecarOptions.maxScriptLengthWhenDisabled;
|
|
2342
|
-
if (code.length > maxLength) {
|
|
2343
|
-
throw new ScriptTooLargeError(code.length, maxLength);
|
|
2344
|
-
}
|
|
2345
|
-
}
|
|
2346
|
-
const policyIssues = await findScriptPolicyIssues(code, this.vmOptions);
|
|
2347
|
-
if (policyIssues.length > 0) {
|
|
2348
|
-
return {
|
|
2349
|
-
success: false,
|
|
2350
|
-
error: {
|
|
2351
|
-
message: `AgentScript validation failed:
|
|
2352
|
-
${policyIssues.map((issue) => `${issue.code}${issue.location ? ` (line ${issue.location.line})` : ""}: ${issue.message}`).join("\n")}`,
|
|
2353
|
-
name: "ValidationError",
|
|
2354
|
-
code: "VALIDATION_ERROR",
|
|
2355
|
-
blockedPatterns: [...new Set(policyIssues.map((issue) => issue.code))]
|
|
2356
|
-
},
|
|
2357
|
-
logs,
|
|
2358
|
-
timedOut: false,
|
|
2359
|
-
stats: { duration: 0, toolCallCount: 0, iterationCount: 0 }
|
|
2360
|
-
};
|
|
2361
|
-
}
|
|
2362
|
-
const toolFailures = [];
|
|
2363
|
-
const toolHandler = async (toolName, args) => {
|
|
2364
|
-
try {
|
|
2365
|
-
return await environment.callTool(toolName, args);
|
|
2366
|
-
} catch (error) {
|
|
2367
|
-
const code2 = error?.code;
|
|
2368
|
-
toolFailures.push({
|
|
2369
|
-
toolName,
|
|
2370
|
-
name: toolFailureName(error),
|
|
2371
|
-
message: toolFailureMessage(error, toolName),
|
|
2372
|
-
...typeof code2 === "string" ? { code: code2 } : {}
|
|
2373
|
-
});
|
|
2374
|
-
throw error;
|
|
2375
|
-
}
|
|
2376
|
-
};
|
|
2377
|
-
const sidecar = this.sidecarOptions.enabled ? {
|
|
2378
|
-
enabled: true,
|
|
2379
|
-
maxTotalSize: this.sidecarOptions.maxTotalSize,
|
|
2380
|
-
maxReferenceSize: this.sidecarOptions.maxReferenceSize,
|
|
2381
|
-
extractionThreshold: this.sidecarOptions.extractionThreshold,
|
|
2382
|
-
maxResolvedSize: this.sidecarOptions.maxResolvedSize,
|
|
2383
|
-
allowComposites: this.sidecarOptions.allowComposites
|
|
2384
|
-
} : void 0;
|
|
2385
|
-
const { mcpLog, mcpNotify } = environment;
|
|
2386
|
-
const globals = {
|
|
2387
|
-
// Provide getTool as a custom global
|
|
2388
|
-
getTool: environment.getTool,
|
|
2389
|
-
// Provide logging functions if available
|
|
2390
|
-
...mcpLog ? {
|
|
2391
|
-
mcpLog: (level, message, metadata) => {
|
|
2392
|
-
mcpLog(level, message, metadata);
|
|
2393
|
-
logs.push(`[mcp:${level}] ${message}`);
|
|
2394
|
-
}
|
|
2395
|
-
} : {},
|
|
2396
|
-
...mcpNotify ? {
|
|
2397
|
-
mcpNotify: (event, payload) => {
|
|
2398
|
-
mcpNotify(event, payload);
|
|
2399
|
-
logs.push(`[notify] ${event}`);
|
|
2400
|
-
}
|
|
2401
|
-
} : {}
|
|
2402
|
-
// Note: enclave-vm v2.0.0+ provides its own __safe_console internally with rate limiting
|
|
2403
|
-
// and output size limits. Passing console in globals causes "Cannot redefine property"
|
|
2404
|
-
// errors due to Double VM architecture. Console output from user scripts goes to stdout
|
|
2405
|
-
// via enclave's internal console, not to this logs array. Only mcpLog/mcpNotify are captured.
|
|
2406
|
-
};
|
|
2407
|
-
const { rapidEnumerationThreshold, rapidEnumerationOverrides } = this.vmOptions;
|
|
2408
|
-
const options = {
|
|
2409
|
-
timeout: this.vmOptions.timeoutMs,
|
|
2410
|
-
maxToolCalls: maxToolCallsOf(this.vmOptions),
|
|
2411
|
-
maxIterations: MAX_ITERATIONS_PER_LOOP,
|
|
2412
|
-
maxSanitizeDepth: this.vmOptions.maxSanitizeDepth,
|
|
2413
|
-
maxSanitizeProperties: this.vmOptions.maxSanitizeProperties,
|
|
2414
|
-
toolHandler,
|
|
2415
|
-
validate: true,
|
|
2416
|
-
transform: true,
|
|
2417
|
-
sidecar,
|
|
2418
|
-
// Error stacks name no host file, whatever stage raised them.
|
|
2419
|
-
sanitizeStackTraces: true,
|
|
2420
|
-
// Allow functions in globals since we intentionally provide getTool, mcpLog, mcpNotify, and console
|
|
2421
|
-
allowFunctionsInGlobals: true,
|
|
2422
|
-
globals,
|
|
2423
|
-
// Tool namespaces (`acme.getUser()` for a tool named `acme.getUser`) are built by the sandbox
|
|
2424
|
-
// itself: a method call is exactly `callTool('acme.getUser', args, options)`, with the
|
|
2425
|
-
// sandbox's tool-call cap, rate limit, suspicious-sequence checks and `throwOnError`.
|
|
2426
|
-
toolNamespaces: toSandboxToolNamespaces(environment.toolNamespaces, Object.keys(globals)),
|
|
2427
|
-
doubleVm: {
|
|
2428
|
-
parentValidation: {
|
|
2429
|
-
...rapidEnumerationThreshold !== void 0 && { rapidEnumerationThreshold },
|
|
2430
|
-
...rapidEnumerationOverrides !== void 0 && { rapidEnumerationOverrides }
|
|
2431
|
-
}
|
|
2432
|
-
}
|
|
2433
|
-
};
|
|
2434
|
-
const enclave = createEnclave(options);
|
|
2435
|
-
try {
|
|
2436
|
-
const result = await enclave.run(code);
|
|
2437
|
-
return this.mapEnclaveResult(result, logs, toolFailures, code);
|
|
2438
|
-
} finally {
|
|
2439
|
-
enclave.dispose();
|
|
2440
|
-
}
|
|
2441
|
-
}
|
|
2442
|
-
/**
|
|
2443
|
-
* Map Enclave ExecutionResult to EnclaveExecutionResult
|
|
2444
|
-
*/
|
|
2445
|
-
mapEnclaveResult(result, logs, toolFailures = [], script = "") {
|
|
2446
|
-
const stats = {
|
|
2447
|
-
duration: result.stats.duration,
|
|
2448
|
-
toolCallCount: result.stats.toolCallCount,
|
|
2449
|
-
iterationCount: result.stats.iterationCount
|
|
2450
|
-
};
|
|
2451
|
-
if (result.success) {
|
|
2452
|
-
return { success: true, result: result.value, logs, timedOut: false, stats };
|
|
2453
|
-
}
|
|
2454
|
-
const reportedError = result.error ?? { name: "Error", message: "Script execution failed" };
|
|
2455
|
-
const toolFailure = [...toolFailures].reverse().find((failure) => failure.message === reportedError.message && failure.name === reportedError.name);
|
|
2456
|
-
const error = !toolFailure && reportedError.message?.startsWith(ITERATION_LIMIT_PREFIX) ? { ...reportedError, ...ITERATION_LIMIT_ERROR } : reportedError;
|
|
2457
|
-
if (error.code === "ENCLAVE_ERROR" && error.message?.startsWith(PARSE_FAILURE_PREFIX)) {
|
|
2458
|
-
const { message, location } = parseFailureOf(error.message);
|
|
2459
|
-
return {
|
|
2460
|
-
success: false,
|
|
2461
|
-
error: { message, name: "SyntaxError", code: "SYNTAX_ERROR", ...location ? { location } : {} },
|
|
2462
|
-
logs,
|
|
2463
|
-
timedOut: false,
|
|
2464
|
-
stats
|
|
2465
|
-
};
|
|
2466
|
-
}
|
|
2467
|
-
if (toolFailure) {
|
|
2468
|
-
return {
|
|
2469
|
-
success: false,
|
|
2470
|
-
error: {
|
|
2471
|
-
message: error.message,
|
|
2472
|
-
name: error.name,
|
|
2473
|
-
...toolFailure.code ? { code: toolFailure.code } : {},
|
|
2474
|
-
toolName: toolFailure.toolName
|
|
2475
|
-
},
|
|
2476
|
-
logs,
|
|
2477
|
-
timedOut: false,
|
|
2478
|
-
stats
|
|
2479
|
-
};
|
|
2480
|
-
}
|
|
2481
|
-
const timedOut = error.message?.includes("timed out") || error.code === "TIMEOUT";
|
|
2482
|
-
if (error.code === "VALIDATION_ERROR") {
|
|
2483
|
-
const issues = error.data?.issues ?? [];
|
|
2484
|
-
const blockedPatterns = [...new Set(issues.map((issue) => issue.code).filter((code) => !!code))];
|
|
2485
|
-
return {
|
|
2486
|
-
success: false,
|
|
2487
|
-
error: {
|
|
2488
|
-
// The enclave names lines of the code it validated (the script wrapped and printed again),
|
|
2489
|
-
// not the script's own.
|
|
2490
|
-
message: withScriptLines(error.message, script),
|
|
2491
|
-
name: "ValidationError",
|
|
2492
|
-
code: error.code,
|
|
2493
|
-
...blockedPatterns.length > 0 ? { blockedPatterns } : {}
|
|
2494
|
-
},
|
|
2495
|
-
logs,
|
|
2496
|
-
timedOut: false,
|
|
2497
|
-
stats
|
|
2498
|
-
};
|
|
2499
|
-
}
|
|
2500
|
-
return {
|
|
2501
|
-
success: false,
|
|
2502
|
-
error: {
|
|
2503
|
-
message: error.message,
|
|
2504
|
-
name: error.name,
|
|
2505
|
-
stack: error.stack,
|
|
2506
|
-
code: error.code
|
|
2507
|
-
},
|
|
2508
|
-
logs,
|
|
2509
|
-
timedOut,
|
|
2510
|
-
stats
|
|
2511
|
-
};
|
|
2512
|
-
}
|
|
2513
|
-
};
|
|
2514
|
-
EnclaveService = __decorateClass([
|
|
2515
|
-
(0, import_sdk4.Provider)({
|
|
2516
|
-
name: "codecall:enclave",
|
|
2517
|
-
description: "Executes AgentScript code in a secure enclave",
|
|
2518
|
-
scope: import_sdk4.ProviderScope.GLOBAL
|
|
2519
|
-
})
|
|
2520
|
-
], EnclaveService);
|
|
2521
|
-
function createEnclave(options) {
|
|
2522
|
-
try {
|
|
2523
|
-
return new import_core.Enclave(options);
|
|
2524
|
-
} catch (error) {
|
|
2525
|
-
if (!options.toolNamespaces || !(error instanceof TypeError) || !error.message.startsWith("Invalid toolNamespaces")) {
|
|
2526
|
-
throw error;
|
|
2527
|
-
}
|
|
2528
|
-
return new import_core.Enclave({ ...options, toolNamespaces: void 0 });
|
|
2529
|
-
}
|
|
2530
|
-
}
|
|
2531
|
-
|
|
2532
|
-
// plugins/plugin-codecall/src/tools/search.tool.ts
|
|
2533
|
-
var import_sdk5 = require("@frontmcp/sdk");
|
|
2534
|
-
|
|
2535
|
-
// plugins/plugin-codecall/src/tools/search.schema.ts
|
|
2536
|
-
var import_lazy_zod2 = require("@frontmcp/lazy-zod");
|
|
2537
|
-
var DEFAULT_MIN_RELEVANCE_SCORE = 0.1;
|
|
2538
|
-
function buildSearchToolDescription(topK) {
|
|
2539
|
-
return `Find tools by splitting user request into atomic actions.
|
|
5
|
+
}`,"script");const fn=wrapped[0];const block=fn?.["body"];return{body:block?.["body"]??[],offset:1}}}}function parseBody(code,sourceType){const program=acorn.parse(code,{...PARSE_OPTIONS,sourceType});return program["body"]??[]}function treesOf(script){try{const wrap=!(0,import_ast2.isWrappedInMain)(script);const printed=parseBody((0,import_ast2.transformAgentScript)(script,{wrapInMain:wrap}),"script");const{body,offset}=parseScript(script);if(!wrap)return{printed,script:body,offset};const main=printed[0]?.["body"];return{printed:main?.["body"]??[],script:body,offset}}catch{return void 0}}function pairLists(printed,script,depth,out,offset){const kept=printed.filter(node=>!(isNode(node)&&isAddedByTransform(node)));if(kept.length!==script.length)return;kept.forEach((node,index)=>{const own=script[index];if(isNode(node)&&isNode(own))pairNodes(node,own,depth,out,offset)})}function pairNodes(printed,script,depth,out,offset){if(printed.type==="ReturnStatement"&&script.type==="ExpressionStatement"){record(printed,script,depth,out,offset);const argument=printed["argument"];const expression=script["expression"];if(isNode(argument)&&isNode(expression))pairNodes(argument,expression,depth+1,out,offset);return}if(printed.type!==script.type)return;record(printed,script,depth,out,offset);for(const key of Object.keys(printed)){if(NON_CHILD_KEYS.has(key))continue;const printedChild=printed[key];const scriptChild=script[key];if(Array.isArray(printedChild)&&Array.isArray(scriptChild)){pairLists(printedChild,scriptChild,depth+1,out,offset)}else if(isNode(printedChild)&&isNode(scriptChild)){pairNodes(printedChild,scriptChild,depth+1,out,offset)}}}function record(printed,script,depth,out,offset){if(!printed.loc||!script.loc)return;out.push({printedStart:printed.loc.start.line,printedEnd:printed.loc.end.line,scriptLine:script.loc.start.line-offset,depth})}function validatedLineMapper(script){const trees=treesOf(script);if(!trees)return()=>void 0;const pairs=[];pairLists(trees.printed,trees.script,0,pairs,trees.offset);return printedLine=>{const starting=pairs.filter(pair=>pair.printedStart===printedLine);const candidates=starting.length>0?starting:pairs.filter(pair=>pair.printedStart<=printedLine&&printedLine<=pair.printedEnd);const best=candidates.reduce((deepest,pair)=>!deepest||pair.depth>deepest.depth?pair:deepest,void 0);return best&&best.scriptLine>=1?best.scriptLine:void 0}}var ISSUE_LINE_RE=/ \(line (\d+)\)/g;function withScriptLines(message,script){if(!message.includes("(line "))return message;const lineOf=validatedLineMapper(script);return message.replace(ISSUE_LINE_RE,(_match,printed)=>{const line=lineOf(Number(printed));return line===void 0?"":` (line ${line})`})}function toolFailureMessage(error,toolName){if(typeof error==="string"&&error)return error;const message=error?.message;return typeof message==="string"&&message?message:`Tool call failed: ${toolName}`}function toolFailureName(error){const name=error&&typeof error==="object"?error.name:void 0;return typeof name==="string"&&name?name.slice(0,128):"ToolError"}var ITERATION_LIMIT_PREFIX="Maximum iteration limit exceeded";var ITERATION_LIMIT_ERROR={name:"Error",message:`${ITERATION_LIMIT_PREFIX} (${MAX_ITERATIONS_PER_LOOP}). This limit prevents infinite loops.`};var PARSE_FAILURE_PREFIX="Failed to parse AgentScript code: ";var PARSE_POSITION_RE=/\((\d+):(\d+)\)$/;function parseFailureOf(message){const match=PARSE_POSITION_RE.exec(message);const line=match?Number(match[1])-1:0;if(!match||line<1)return{message};const column=Number(match[2]);return{message:`${message.slice(0,match.index)}(${line}:${column})`,location:{line,column}}}var ScriptTooLargeError=class extends Error{code="SCRIPT_TOO_LARGE";scriptLength;maxLength;constructor(scriptLength,maxLength){super(`Script length (${scriptLength} characters) exceeds maximum allowed length (${maxLength} characters). Enable sidecar to handle large data, or reduce script size.`);this.name="ScriptTooLargeError";this.scriptLength=scriptLength;this.maxLength=maxLength}};var EnclaveService=class{vmOptions;sidecarOptions;constructor(config){const all=config.getAll();this.vmOptions=all.resolvedVm;this.sidecarOptions=all.sidecar}async execute(code,environment){const logs=[];if(!this.sidecarOptions.enabled&&this.sidecarOptions.maxScriptLengthWhenDisabled!==null){const maxLength=this.sidecarOptions.maxScriptLengthWhenDisabled;if(code.length>maxLength){throw new ScriptTooLargeError(code.length,maxLength)}}const policyIssues=await findScriptPolicyIssues(code,this.vmOptions);if(policyIssues.length>0){return{success:false,error:{message:`AgentScript validation failed:
|
|
6
|
+
${policyIssues.map(issue=>`${issue.code}${issue.location?` (line ${issue.location.line})`:""}: ${issue.message}`).join("\n")}`,name:"ValidationError",code:"VALIDATION_ERROR",blockedPatterns:[...new Set(policyIssues.map(issue=>issue.code))]},logs,timedOut:false,stats:{duration:0,toolCallCount:0,iterationCount:0}}}const toolFailures=[];const toolHandler=async(toolName,args)=>{try{return await environment.callTool(toolName,args)}catch(error){const code2=error?.code;toolFailures.push({toolName,name:toolFailureName(error),message:toolFailureMessage(error,toolName),...typeof code2==="string"?{code:code2}:{}});throw error}};const sidecar=this.sidecarOptions.enabled?{enabled:true,maxTotalSize:this.sidecarOptions.maxTotalSize,maxReferenceSize:this.sidecarOptions.maxReferenceSize,extractionThreshold:this.sidecarOptions.extractionThreshold,maxResolvedSize:this.sidecarOptions.maxResolvedSize,allowComposites:this.sidecarOptions.allowComposites}:void 0;const{mcpLog,mcpNotify}=environment;const globals={getTool:environment.getTool,...mcpLog?{mcpLog:(level,message,metadata)=>{mcpLog(level,message,metadata);logs.push(`[mcp:${level}] ${message}`)}}:{},...mcpNotify?{mcpNotify:(event,payload)=>{mcpNotify(event,payload);logs.push(`[notify] ${event}`)}}:{}};const{rapidEnumerationThreshold,rapidEnumerationOverrides}=this.vmOptions;const options={timeout:this.vmOptions.timeoutMs,maxToolCalls:maxToolCallsOf(this.vmOptions),maxIterations:MAX_ITERATIONS_PER_LOOP,maxSanitizeDepth:this.vmOptions.maxSanitizeDepth,maxSanitizeProperties:this.vmOptions.maxSanitizeProperties,toolHandler,validate:true,transform:true,sidecar,sanitizeStackTraces:true,allowFunctionsInGlobals:true,globals,toolNamespaces:toSandboxToolNamespaces(environment.toolNamespaces,Object.keys(globals)),doubleVm:{parentValidation:{...rapidEnumerationThreshold!==void 0&&{rapidEnumerationThreshold},...rapidEnumerationOverrides!==void 0&&{rapidEnumerationOverrides}}}};const enclave=createEnclave(options);try{const result=await enclave.run(code);return this.mapEnclaveResult(result,logs,toolFailures,code)}finally{enclave.dispose()}}mapEnclaveResult(result,logs,toolFailures=[],script=""){const stats={duration:result.stats.duration,toolCallCount:result.stats.toolCallCount,iterationCount:result.stats.iterationCount};if(result.success){return{success:true,result:result.value,logs,timedOut:false,stats}}const reportedError=result.error??{name:"Error",message:"Script execution failed"};const toolFailure=[...toolFailures].reverse().find(failure=>failure.message===reportedError.message&&failure.name===reportedError.name);const error=!toolFailure&&reportedError.message?.startsWith(ITERATION_LIMIT_PREFIX)?{...reportedError,...ITERATION_LIMIT_ERROR}:reportedError;if(error.code==="ENCLAVE_ERROR"&&error.message?.startsWith(PARSE_FAILURE_PREFIX)){const{message,location}=parseFailureOf(error.message);return{success:false,error:{message,name:"SyntaxError",code:"SYNTAX_ERROR",...location?{location}:{}},logs,timedOut:false,stats}}if(toolFailure){return{success:false,error:{message:error.message,name:error.name,...toolFailure.code?{code:toolFailure.code}:{},toolName:toolFailure.toolName},logs,timedOut:false,stats}}const timedOut=error.message?.includes("timed out")||error.code==="TIMEOUT";if(error.code==="VALIDATION_ERROR"){const issues=error.data?.issues??[];const blockedPatterns=[...new Set(issues.map(issue=>issue.code).filter(code=>!!code))];return{success:false,error:{message:withScriptLines(error.message,script),name:"ValidationError",code:error.code,...blockedPatterns.length>0?{blockedPatterns}:{}},logs,timedOut:false,stats}}return{success:false,error:{message:error.message,name:error.name,stack:error.stack,code:error.code},logs,timedOut,stats}}};EnclaveService=__decorateClass([(0,import_sdk4.Provider)({name:"codecall:enclave",description:"Executes AgentScript code in a secure enclave",scope:import_sdk4.ProviderScope.GLOBAL})],EnclaveService);function createEnclave(options){try{return new import_core.Enclave(options)}catch(error){if(!options.toolNamespaces||!(error instanceof TypeError)||!error.message.startsWith("Invalid toolNamespaces")){throw error}return new import_core.Enclave({...options,toolNamespaces:void 0})}}var import_sdk5=require("@frontmcp/sdk");var import_lazy_zod2=require("@frontmcp/lazy-zod");var DEFAULT_MIN_RELEVANCE_SCORE=.1;function buildSearchToolDescription(topK){return`Find tools by splitting user request into atomic actions.
|
|
2540
7
|
|
|
2541
8
|
DECOMPOSE: "delete users and send email" \u2192 queries: ["delete user", "send email"]
|
|
2542
9
|
DECOMPOSE: "get order and refund" \u2192 queries: ["get order", "calculate refund"]
|
|
@@ -2553,140 +20,7 @@ INPUT:
|
|
|
2553
20
|
|
|
2554
21
|
OUTPUT: Flat deduplicated tool list. relevanceScore: 0.5+=good, 0.7+=strong match.
|
|
2555
22
|
|
|
2556
|
-
FLOW: search \u2192 describe \u2192 execute/invoke
|
|
2557
|
-
}
|
|
2558
|
-
var searchToolDescription = buildSearchToolDescription(codeCallPluginOptionsSchema.parse({}).topK);
|
|
2559
|
-
var searchToolInputSchema = {
|
|
2560
|
-
queries: import_lazy_zod2.z.array(import_lazy_zod2.z.string().min(2).max(256)).min(1).max(10).describe("Atomic action queries. Split complex requests into simple actions."),
|
|
2561
|
-
appIds: import_lazy_zod2.z.array(import_lazy_zod2.z.string()).max(10).optional().describe("Filter by app IDs"),
|
|
2562
|
-
excludeToolNames: import_lazy_zod2.z.array(import_lazy_zod2.z.string()).max(50).optional().describe("Skip already-known tool names"),
|
|
2563
|
-
topK: import_lazy_zod2.z.number().int().positive().max(50).optional().describe("Results per query (defaults to the server's CodeCall topK, 8 unless configured)"),
|
|
2564
|
-
minRelevanceScore: import_lazy_zod2.z.number().min(0).max(1).optional().default(DEFAULT_MIN_RELEVANCE_SCORE).describe(`Minimum relevance threshold (default ${DEFAULT_MIN_RELEVANCE_SCORE})`)
|
|
2565
|
-
};
|
|
2566
|
-
var searchToolOutputSchema = import_lazy_zod2.z.object({
|
|
2567
|
-
tools: import_lazy_zod2.z.array(
|
|
2568
|
-
import_lazy_zod2.z.object({
|
|
2569
|
-
name: import_lazy_zod2.z.string().describe('Tool name (e.g., "users:list")'),
|
|
2570
|
-
appId: import_lazy_zod2.z.string().optional().describe("App ID"),
|
|
2571
|
-
description: import_lazy_zod2.z.string().describe("What this tool does"),
|
|
2572
|
-
relevanceScore: import_lazy_zod2.z.number().min(0).max(1).describe("Match score (0-1)"),
|
|
2573
|
-
matchedQueries: import_lazy_zod2.z.array(import_lazy_zod2.z.string()).describe("Which queries matched this tool")
|
|
2574
|
-
})
|
|
2575
|
-
).describe("Deduplicated tools sorted by relevance"),
|
|
2576
|
-
warnings: import_lazy_zod2.z.array(
|
|
2577
|
-
import_lazy_zod2.z.object({
|
|
2578
|
-
type: import_lazy_zod2.z.enum(["excluded_tool_not_found", "no_results", "low_relevance"]).describe("Warning type"),
|
|
2579
|
-
message: import_lazy_zod2.z.string().describe("Warning message"),
|
|
2580
|
-
affectedTools: import_lazy_zod2.z.array(import_lazy_zod2.z.string()).optional().describe("Affected tool names")
|
|
2581
|
-
})
|
|
2582
|
-
).describe("Search warnings"),
|
|
2583
|
-
totalAvailableTools: import_lazy_zod2.z.number().int().nonnegative().describe("Total tools in index")
|
|
2584
|
-
});
|
|
2585
|
-
|
|
2586
|
-
// plugins/plugin-codecall/src/tools/search.tool.ts
|
|
2587
|
-
var SearchTool = class extends import_sdk5.ToolContext {
|
|
2588
|
-
async execute(input) {
|
|
2589
|
-
const { queries, appIds, excludeToolNames = [], topK, minRelevanceScore = DEFAULT_MIN_RELEVANCE_SCORE } = input;
|
|
2590
|
-
const searchService = this.get(ToolSearchService);
|
|
2591
|
-
const warnings = [];
|
|
2592
|
-
const audit = this.tryGet(AuditLoggerService);
|
|
2593
|
-
const executionId = audit ? audit.generateExecutionId() : "";
|
|
2594
|
-
const startedAt = Date.now();
|
|
2595
|
-
const surface = (0, import_sdk5.getCallSurface)();
|
|
2596
|
-
const nonExistentExcludedTools = excludeToolNames.filter(
|
|
2597
|
-
(toolName) => !searchService.hasTool(toolName, surface)
|
|
2598
|
-
);
|
|
2599
|
-
if (nonExistentExcludedTools.length > 0) {
|
|
2600
|
-
warnings.push({
|
|
2601
|
-
type: "excluded_tool_not_found",
|
|
2602
|
-
message: `Excluded tools not found: ${nonExistentExcludedTools.join(", ")}`,
|
|
2603
|
-
affectedTools: nonExistentExcludedTools
|
|
2604
|
-
});
|
|
2605
|
-
}
|
|
2606
|
-
const toolMap = /* @__PURE__ */ new Map();
|
|
2607
|
-
let lowRelevanceCount = 0;
|
|
2608
|
-
for (const query of queries) {
|
|
2609
|
-
const searchResults = await searchService.search(query, {
|
|
2610
|
-
topK,
|
|
2611
|
-
appIds,
|
|
2612
|
-
excludeToolNames,
|
|
2613
|
-
surface
|
|
2614
|
-
});
|
|
2615
|
-
for (const result of searchResults) {
|
|
2616
|
-
if (result.relevanceScore < minRelevanceScore) {
|
|
2617
|
-
lowRelevanceCount++;
|
|
2618
|
-
continue;
|
|
2619
|
-
}
|
|
2620
|
-
const existing = toolMap.get(result.toolName);
|
|
2621
|
-
if (existing) {
|
|
2622
|
-
existing.matchedQueries.push(query);
|
|
2623
|
-
existing.relevanceScore = Math.max(existing.relevanceScore, result.relevanceScore);
|
|
2624
|
-
} else {
|
|
2625
|
-
toolMap.set(result.toolName, {
|
|
2626
|
-
name: result.toolName,
|
|
2627
|
-
appId: result.appId,
|
|
2628
|
-
description: result.description,
|
|
2629
|
-
relevanceScore: result.relevanceScore,
|
|
2630
|
-
matchedQueries: [query]
|
|
2631
|
-
});
|
|
2632
|
-
}
|
|
2633
|
-
}
|
|
2634
|
-
}
|
|
2635
|
-
const tools = Array.from(toolMap.values()).sort((a, b) => b.relevanceScore - a.relevanceScore).map((tool) => ({
|
|
2636
|
-
name: tool.name,
|
|
2637
|
-
appId: tool.appId,
|
|
2638
|
-
description: tool.description,
|
|
2639
|
-
relevanceScore: tool.relevanceScore,
|
|
2640
|
-
matchedQueries: tool.matchedQueries
|
|
2641
|
-
}));
|
|
2642
|
-
if (tools.length === 0) {
|
|
2643
|
-
warnings.push({
|
|
2644
|
-
type: "no_results",
|
|
2645
|
-
message: `No tools found for queries: ${queries.join(", ")}${appIds?.length ? ` in apps: ${appIds.join(", ")}` : ""}`
|
|
2646
|
-
});
|
|
2647
|
-
}
|
|
2648
|
-
if (lowRelevanceCount > 0 && tools.length > 0) {
|
|
2649
|
-
warnings.push({
|
|
2650
|
-
type: "low_relevance",
|
|
2651
|
-
message: `${lowRelevanceCount} result(s) filtered due to relevance below ${minRelevanceScore}`
|
|
2652
|
-
});
|
|
2653
|
-
}
|
|
2654
|
-
audit?.logSearch(executionId, queries.join(" "), tools.length, Date.now() - startedAt);
|
|
2655
|
-
return {
|
|
2656
|
-
tools,
|
|
2657
|
-
warnings,
|
|
2658
|
-
totalAvailableTools: searchService.getTotalCount(surface)
|
|
2659
|
-
};
|
|
2660
|
-
}
|
|
2661
|
-
};
|
|
2662
|
-
SearchTool = __decorateClass([
|
|
2663
|
-
(0, import_sdk5.Tool)({
|
|
2664
|
-
name: "codecall:search",
|
|
2665
|
-
cache: {
|
|
2666
|
-
ttl: 60,
|
|
2667
|
-
// 1 minute
|
|
2668
|
-
slideWindow: false
|
|
2669
|
-
},
|
|
2670
|
-
codecall: {
|
|
2671
|
-
enabledInCodeCall: false,
|
|
2672
|
-
visibleInListTools: true
|
|
2673
|
-
},
|
|
2674
|
-
description: searchToolDescription,
|
|
2675
|
-
inputSchema: searchToolInputSchema,
|
|
2676
|
-
outputSchema: searchToolOutputSchema,
|
|
2677
|
-
annotations: {
|
|
2678
|
-
readOnlyHint: true,
|
|
2679
|
-
openWorldHint: true
|
|
2680
|
-
}
|
|
2681
|
-
})
|
|
2682
|
-
], SearchTool);
|
|
2683
|
-
|
|
2684
|
-
// plugins/plugin-codecall/src/tools/search-skills.tool.ts
|
|
2685
|
-
var import_sdk6 = require("@frontmcp/sdk");
|
|
2686
|
-
|
|
2687
|
-
// plugins/plugin-codecall/src/tools/search-skills.schema.ts
|
|
2688
|
-
var import_lazy_zod3 = require("@frontmcp/lazy-zod");
|
|
2689
|
-
var searchSkillsToolDescription = `Search for EXECUTABLE skills. Each result returns the skill's description, tags, and the openapi operation IDs it can call from within AgentScript.
|
|
23
|
+
FLOW: search \u2192 describe \u2192 execute/invoke`}var searchToolDescription=buildSearchToolDescription(codeCallPluginOptionsSchema.parse({}).topK);var searchToolInputSchema={queries:import_lazy_zod2.z.array(import_lazy_zod2.z.string().min(2).max(256)).min(1).max(10).describe("Atomic action queries. Split complex requests into simple actions."),appIds:import_lazy_zod2.z.array(import_lazy_zod2.z.string()).max(10).optional().describe("Filter by app IDs"),excludeToolNames:import_lazy_zod2.z.array(import_lazy_zod2.z.string()).max(50).optional().describe("Skip already-known tool names"),topK:import_lazy_zod2.z.number().int().positive().max(50).optional().describe("Results per query (defaults to the server's CodeCall topK, 8 unless configured)"),minRelevanceScore:import_lazy_zod2.z.number().min(0).max(1).optional().default(DEFAULT_MIN_RELEVANCE_SCORE).describe(`Minimum relevance threshold (default ${DEFAULT_MIN_RELEVANCE_SCORE})`)};var searchToolOutputSchema=import_lazy_zod2.z.object({tools:import_lazy_zod2.z.array(import_lazy_zod2.z.object({name:import_lazy_zod2.z.string().describe('Tool name (e.g., "users:list")'),appId:import_lazy_zod2.z.string().optional().describe("App ID"),description:import_lazy_zod2.z.string().describe("What this tool does"),relevanceScore:import_lazy_zod2.z.number().min(0).max(1).describe("Match score (0-1)"),matchedQueries:import_lazy_zod2.z.array(import_lazy_zod2.z.string()).describe("Which queries matched this tool")})).describe("Deduplicated tools sorted by relevance"),warnings:import_lazy_zod2.z.array(import_lazy_zod2.z.object({type:import_lazy_zod2.z.enum(["excluded_tool_not_found","no_results","low_relevance"]).describe("Warning type"),message:import_lazy_zod2.z.string().describe("Warning message"),affectedTools:import_lazy_zod2.z.array(import_lazy_zod2.z.string()).optional().describe("Affected tool names")})).describe("Search warnings"),totalAvailableTools:import_lazy_zod2.z.number().int().nonnegative().describe("Total tools in index")});var SearchTool=class extends import_sdk5.ToolContext{async execute(input){const{queries,appIds,excludeToolNames=[],topK,minRelevanceScore=DEFAULT_MIN_RELEVANCE_SCORE}=input;const searchService=this.get(ToolSearchService);const warnings=[];const audit=this.tryGet(AuditLoggerService);const executionId=audit?audit.generateExecutionId():"";const startedAt=Date.now();const surface=(0,import_sdk5.getCallSurface)();const nonExistentExcludedTools=excludeToolNames.filter(toolName=>!searchService.hasTool(toolName,surface));if(nonExistentExcludedTools.length>0){warnings.push({type:"excluded_tool_not_found",message:`Excluded tools not found: ${nonExistentExcludedTools.join(", ")}`,affectedTools:nonExistentExcludedTools})}const toolMap=new Map;let lowRelevanceCount=0;for(const query of queries){const searchResults=await searchService.search(query,{topK,appIds,excludeToolNames,surface});for(const result of searchResults){if(result.relevanceScore<minRelevanceScore){lowRelevanceCount++;continue}const existing=toolMap.get(result.toolName);if(existing){existing.matchedQueries.push(query);existing.relevanceScore=Math.max(existing.relevanceScore,result.relevanceScore)}else{toolMap.set(result.toolName,{name:result.toolName,appId:result.appId,description:result.description,relevanceScore:result.relevanceScore,matchedQueries:[query]})}}}const tools=Array.from(toolMap.values()).sort((a,b)=>b.relevanceScore-a.relevanceScore).map(tool=>({name:tool.name,appId:tool.appId,description:tool.description,relevanceScore:tool.relevanceScore,matchedQueries:tool.matchedQueries}));if(tools.length===0){warnings.push({type:"no_results",message:`No tools found for queries: ${queries.join(", ")}${appIds?.length?` in apps: ${appIds.join(", ")}`:""}`})}if(lowRelevanceCount>0&&tools.length>0){warnings.push({type:"low_relevance",message:`${lowRelevanceCount} result(s) filtered due to relevance below ${minRelevanceScore}`})}audit?.logSearch(executionId,queries.join(" "),tools.length,Date.now()-startedAt);return{tools,warnings,totalAvailableTools:searchService.getTotalCount(surface)}}};SearchTool=__decorateClass([(0,import_sdk5.Tool)({name:"codecall:search",cache:{ttl:60,slideWindow:false},codecall:{enabledInCodeCall:false,visibleInListTools:true},description:searchToolDescription,inputSchema:searchToolInputSchema,outputSchema:searchToolOutputSchema,annotations:{readOnlyHint:true,openWorldHint:true}})],SearchTool);var import_sdk6=require("@frontmcp/sdk");var import_lazy_zod3=require("@frontmcp/lazy-zod");var searchSkillsToolDescription=`Search for EXECUTABLE skills. Each result returns the skill's description, tags, and the openapi operation IDs it can call from within AgentScript.
|
|
2690
24
|
|
|
2691
25
|
DECOMPOSE complex requests into atomic queries. AVOID re-searching: use excludeSkillNames.
|
|
2692
26
|
|
|
@@ -2699,146 +33,7 @@ INPUT:
|
|
|
2699
33
|
|
|
2700
34
|
OUTPUT: Flat deduplicated executable skill list. Each entry includes the operationIds the skill is allowed to call (via the markdown harvester). The agent can use those operationIds directly in execute() AgentScript via the generated namespaces (e.g. acme.getOrder({...})).
|
|
2701
35
|
|
|
2702
|
-
FLOW: searchSkills \u2192 describe \u2192 execute`;
|
|
2703
|
-
var searchSkillsToolInputSchema = {
|
|
2704
|
-
queries: import_lazy_zod3.z.array(import_lazy_zod3.z.string().min(2).max(256)).min(1).max(10).describe("Atomic skill queries. Split complex requests into simple actions."),
|
|
2705
|
-
tags: import_lazy_zod3.z.array(import_lazy_zod3.z.string().min(1).max(64)).max(16).optional().describe("Filter to skills with any of these tags"),
|
|
2706
|
-
excludeSkillNames: import_lazy_zod3.z.array(import_lazy_zod3.z.string()).max(50).optional().describe("Skip already-known skill names"),
|
|
2707
|
-
topK: import_lazy_zod3.z.number().int().positive().max(50).optional().default(5).describe("Results per query (default 5)"),
|
|
2708
|
-
minRelevanceScore: import_lazy_zod3.z.number().min(0).max(1).optional().default(0.1).describe("Minimum relevance threshold (default 0.1)")
|
|
2709
|
-
};
|
|
2710
|
-
var referencedOperationSchema = import_lazy_zod3.z.object({
|
|
2711
|
-
spec: import_lazy_zod3.z.string().describe('OpenAPI spec id (e.g. "acme")'),
|
|
2712
|
-
operationId: import_lazy_zod3.z.string().describe('OpenAPI operation id (e.g. "getOrder")')
|
|
2713
|
-
});
|
|
2714
|
-
var skillSearchHitSchema = import_lazy_zod3.z.object({
|
|
2715
|
-
name: import_lazy_zod3.z.string().describe("Skill name"),
|
|
2716
|
-
description: import_lazy_zod3.z.string().describe("Short description of what the skill does"),
|
|
2717
|
-
tags: import_lazy_zod3.z.array(import_lazy_zod3.z.string()).describe("Tags carried by the skill"),
|
|
2718
|
-
/**
|
|
2719
|
-
* OpenAPI operations the skill is allowed to call. Inlined so the agent
|
|
2720
|
-
* can author AgentScript from a single search response.
|
|
2721
|
-
*/
|
|
2722
|
-
operations: import_lazy_zod3.z.array(referencedOperationSchema).describe("OpenAPI operations the skill can call"),
|
|
2723
|
-
/** Decorator-declared tools (for skills built the legacy way). */
|
|
2724
|
-
tools: import_lazy_zod3.z.array(import_lazy_zod3.z.string()).describe("Tool names the skill declares (if any)"),
|
|
2725
|
-
relevanceScore: import_lazy_zod3.z.number().min(0).max(1).describe("Match score (0-1)"),
|
|
2726
|
-
matchedQueries: import_lazy_zod3.z.array(import_lazy_zod3.z.string()).describe("Which queries matched this skill"),
|
|
2727
|
-
source: import_lazy_zod3.z.enum(["local", "external"]).describe("Where the skill was loaded from")
|
|
2728
|
-
});
|
|
2729
|
-
var searchSkillsToolOutputSchema = import_lazy_zod3.z.object({
|
|
2730
|
-
skills: import_lazy_zod3.z.array(skillSearchHitSchema).describe("Deduplicated executable skills, sorted by relevance"),
|
|
2731
|
-
warnings: import_lazy_zod3.z.array(
|
|
2732
|
-
import_lazy_zod3.z.object({
|
|
2733
|
-
type: import_lazy_zod3.z.enum(["no_results", "low_relevance", "excluded_skill_not_found"]).describe("Warning type"),
|
|
2734
|
-
message: import_lazy_zod3.z.string().describe("Warning message"),
|
|
2735
|
-
affectedSkills: import_lazy_zod3.z.array(import_lazy_zod3.z.string()).optional().describe("Affected skill names")
|
|
2736
|
-
})
|
|
2737
|
-
).describe("Search warnings"),
|
|
2738
|
-
totalExecutableSkills: import_lazy_zod3.z.number().int().nonnegative().describe("Total executable skills available")
|
|
2739
|
-
});
|
|
2740
|
-
|
|
2741
|
-
// plugins/plugin-codecall/src/tools/search-skills.tool.ts
|
|
2742
|
-
var SearchSkillsTool = class extends import_sdk6.ToolContext {
|
|
2743
|
-
async execute(input) {
|
|
2744
|
-
const { queries, tags, excludeSkillNames = [], topK = 5, minRelevanceScore = 0.1 } = input;
|
|
2745
|
-
const skillRegistry = this.scope.skills;
|
|
2746
|
-
const executableSkills = await (0, import_sdk6.filterServableSkills)(this.scope, skillRegistry.getExecutableSkills());
|
|
2747
|
-
const executableSet = new Set(executableSkills.map((s) => s.name));
|
|
2748
|
-
const totalExecutableSkills = executableSkills.length;
|
|
2749
|
-
const warnings = [];
|
|
2750
|
-
const nonExistentExcluded = excludeSkillNames.filter((n) => !executableSet.has(n));
|
|
2751
|
-
if (nonExistentExcluded.length > 0) {
|
|
2752
|
-
warnings.push({
|
|
2753
|
-
type: "excluded_skill_not_found",
|
|
2754
|
-
message: `Excluded skills not found: ${nonExistentExcluded.join(", ")}`,
|
|
2755
|
-
affectedSkills: nonExistentExcluded
|
|
2756
|
-
});
|
|
2757
|
-
}
|
|
2758
|
-
const matches = /* @__PURE__ */ new Map();
|
|
2759
|
-
let lowRelevanceCount = 0;
|
|
2760
|
-
const excludedSet = new Set(excludeSkillNames);
|
|
2761
|
-
const perQueryResults = await Promise.all(
|
|
2762
|
-
queries.map(
|
|
2763
|
-
(query) => skillRegistry.search(query, { topK, tags, minScore: minRelevanceScore }).then((results) => ({ query, results }))
|
|
2764
|
-
)
|
|
2765
|
-
);
|
|
2766
|
-
for (const { query, results } of perQueryResults) {
|
|
2767
|
-
for (const result of results) {
|
|
2768
|
-
const name = result.metadata.name;
|
|
2769
|
-
if (!executableSet.has(name)) continue;
|
|
2770
|
-
if (excludedSet.has(name)) continue;
|
|
2771
|
-
if (result.score < minRelevanceScore) {
|
|
2772
|
-
lowRelevanceCount++;
|
|
2773
|
-
continue;
|
|
2774
|
-
}
|
|
2775
|
-
const existing = matches.get(name);
|
|
2776
|
-
if (existing) {
|
|
2777
|
-
existing.matchedQueries.push(query);
|
|
2778
|
-
existing.relevanceScore = Math.max(existing.relevanceScore, result.score);
|
|
2779
|
-
} else {
|
|
2780
|
-
const ops = result.metadata.referencedOperations ?? [];
|
|
2781
|
-
const toolNames = (result.metadata.tools ?? []).map((t) => {
|
|
2782
|
-
if (typeof t === "string") return t;
|
|
2783
|
-
if (typeof t === "object" && t !== null && "name" in t) return t.name;
|
|
2784
|
-
return null;
|
|
2785
|
-
}).filter((n) => typeof n === "string");
|
|
2786
|
-
matches.set(name, {
|
|
2787
|
-
name,
|
|
2788
|
-
description: result.metadata.description,
|
|
2789
|
-
tags: result.metadata.tags ?? [],
|
|
2790
|
-
operations: ops.map((op) => ({ spec: op.spec, operationId: op.operationId })),
|
|
2791
|
-
tools: toolNames,
|
|
2792
|
-
relevanceScore: result.score,
|
|
2793
|
-
matchedQueries: [query],
|
|
2794
|
-
source: result.source
|
|
2795
|
-
});
|
|
2796
|
-
}
|
|
2797
|
-
}
|
|
2798
|
-
}
|
|
2799
|
-
const skills = Array.from(matches.values()).sort((a, b) => b.relevanceScore - a.relevanceScore);
|
|
2800
|
-
if (skills.length === 0) {
|
|
2801
|
-
warnings.push({
|
|
2802
|
-
type: "no_results",
|
|
2803
|
-
message: `No executable skills found for queries: ${queries.join(", ")}${tags?.length ? ` with tags: ${tags.join(", ")}` : ""}`
|
|
2804
|
-
});
|
|
2805
|
-
}
|
|
2806
|
-
if (lowRelevanceCount > 0 && skills.length > 0) {
|
|
2807
|
-
warnings.push({
|
|
2808
|
-
type: "low_relevance",
|
|
2809
|
-
message: `${lowRelevanceCount} result(s) filtered due to relevance below ${minRelevanceScore}`
|
|
2810
|
-
});
|
|
2811
|
-
}
|
|
2812
|
-
return { skills, warnings, totalExecutableSkills };
|
|
2813
|
-
}
|
|
2814
|
-
};
|
|
2815
|
-
SearchSkillsTool = __decorateClass([
|
|
2816
|
-
(0, import_sdk6.Tool)({
|
|
2817
|
-
name: "codecall:searchSkills",
|
|
2818
|
-
cache: {
|
|
2819
|
-
ttl: 60,
|
|
2820
|
-
slideWindow: false
|
|
2821
|
-
},
|
|
2822
|
-
codecall: {
|
|
2823
|
-
enabledInCodeCall: false,
|
|
2824
|
-
visibleInListTools: true
|
|
2825
|
-
},
|
|
2826
|
-
description: searchSkillsToolDescription,
|
|
2827
|
-
inputSchema: searchSkillsToolInputSchema,
|
|
2828
|
-
outputSchema: searchSkillsToolOutputSchema,
|
|
2829
|
-
annotations: {
|
|
2830
|
-
readOnlyHint: true,
|
|
2831
|
-
openWorldHint: true
|
|
2832
|
-
}
|
|
2833
|
-
})
|
|
2834
|
-
], SearchSkillsTool);
|
|
2835
|
-
|
|
2836
|
-
// plugins/plugin-codecall/src/tools/search-knowledge.tool.ts
|
|
2837
|
-
var import_sdk7 = require("@frontmcp/sdk");
|
|
2838
|
-
|
|
2839
|
-
// plugins/plugin-codecall/src/tools/search-knowledge.schema.ts
|
|
2840
|
-
var import_lazy_zod4 = require("@frontmcp/lazy-zod");
|
|
2841
|
-
var searchKnowledgeToolDescription = `Search for KNOWLEDGE-ONLY skills \u2014 domain context the agent should read before deciding what to do. These skills have no tools and no openapi operation refs; they are pure prose / references / examples.
|
|
36
|
+
FLOW: searchSkills \u2192 describe \u2192 execute`;var searchSkillsToolInputSchema={queries:import_lazy_zod3.z.array(import_lazy_zod3.z.string().min(2).max(256)).min(1).max(10).describe("Atomic skill queries. Split complex requests into simple actions."),tags:import_lazy_zod3.z.array(import_lazy_zod3.z.string().min(1).max(64)).max(16).optional().describe("Filter to skills with any of these tags"),excludeSkillNames:import_lazy_zod3.z.array(import_lazy_zod3.z.string()).max(50).optional().describe("Skip already-known skill names"),topK:import_lazy_zod3.z.number().int().positive().max(50).optional().default(5).describe("Results per query (default 5)"),minRelevanceScore:import_lazy_zod3.z.number().min(0).max(1).optional().default(.1).describe("Minimum relevance threshold (default 0.1)")};var referencedOperationSchema=import_lazy_zod3.z.object({spec:import_lazy_zod3.z.string().describe('OpenAPI spec id (e.g. "acme")'),operationId:import_lazy_zod3.z.string().describe('OpenAPI operation id (e.g. "getOrder")')});var skillSearchHitSchema=import_lazy_zod3.z.object({name:import_lazy_zod3.z.string().describe("Skill name"),description:import_lazy_zod3.z.string().describe("Short description of what the skill does"),tags:import_lazy_zod3.z.array(import_lazy_zod3.z.string()).describe("Tags carried by the skill"),operations:import_lazy_zod3.z.array(referencedOperationSchema).describe("OpenAPI operations the skill can call"),tools:import_lazy_zod3.z.array(import_lazy_zod3.z.string()).describe("Tool names the skill declares (if any)"),relevanceScore:import_lazy_zod3.z.number().min(0).max(1).describe("Match score (0-1)"),matchedQueries:import_lazy_zod3.z.array(import_lazy_zod3.z.string()).describe("Which queries matched this skill"),source:import_lazy_zod3.z.enum(["local","external"]).describe("Where the skill was loaded from")});var searchSkillsToolOutputSchema=import_lazy_zod3.z.object({skills:import_lazy_zod3.z.array(skillSearchHitSchema).describe("Deduplicated executable skills, sorted by relevance"),warnings:import_lazy_zod3.z.array(import_lazy_zod3.z.object({type:import_lazy_zod3.z.enum(["no_results","low_relevance","excluded_skill_not_found"]).describe("Warning type"),message:import_lazy_zod3.z.string().describe("Warning message"),affectedSkills:import_lazy_zod3.z.array(import_lazy_zod3.z.string()).optional().describe("Affected skill names")})).describe("Search warnings"),totalExecutableSkills:import_lazy_zod3.z.number().int().nonnegative().describe("Total executable skills available")});var SearchSkillsTool=class extends import_sdk6.ToolContext{async execute(input){const{queries,tags,excludeSkillNames=[],topK=5,minRelevanceScore=.1}=input;const skillRegistry=this.scope.skills;const executableSkills=await(0,import_sdk6.filterServableSkills)(this.scope,skillRegistry.getExecutableSkills());const executableSet=new Set(executableSkills.map(s=>s.name));const totalExecutableSkills=executableSkills.length;const warnings=[];const nonExistentExcluded=excludeSkillNames.filter(n=>!executableSet.has(n));if(nonExistentExcluded.length>0){warnings.push({type:"excluded_skill_not_found",message:`Excluded skills not found: ${nonExistentExcluded.join(", ")}`,affectedSkills:nonExistentExcluded})}const matches=new Map;let lowRelevanceCount=0;const excludedSet=new Set(excludeSkillNames);const perQueryResults=await Promise.all(queries.map(query=>skillRegistry.search(query,{topK,tags,minScore:minRelevanceScore}).then(results=>({query,results}))));for(const{query,results}of perQueryResults){for(const result of results){const name=result.metadata.name;if(!executableSet.has(name))continue;if(excludedSet.has(name))continue;if(result.score<minRelevanceScore){lowRelevanceCount++;continue}const existing=matches.get(name);if(existing){existing.matchedQueries.push(query);existing.relevanceScore=Math.max(existing.relevanceScore,result.score)}else{const ops=result.metadata.referencedOperations??[];const toolNames=(result.metadata.tools??[]).map(t=>{if(typeof t==="string")return t;if(typeof t==="object"&&t!==null&&"name"in t)return t.name;return null}).filter(n=>typeof n==="string");matches.set(name,{name,description:result.metadata.description,tags:result.metadata.tags??[],operations:ops.map(op=>({spec:op.spec,operationId:op.operationId})),tools:toolNames,relevanceScore:result.score,matchedQueries:[query],source:result.source})}}}const skills=Array.from(matches.values()).sort((a,b)=>b.relevanceScore-a.relevanceScore);if(skills.length===0){warnings.push({type:"no_results",message:`No executable skills found for queries: ${queries.join(", ")}${tags?.length?` with tags: ${tags.join(", ")}`:""}`})}if(lowRelevanceCount>0&&skills.length>0){warnings.push({type:"low_relevance",message:`${lowRelevanceCount} result(s) filtered due to relevance below ${minRelevanceScore}`})}return{skills,warnings,totalExecutableSkills}}};SearchSkillsTool=__decorateClass([(0,import_sdk6.Tool)({name:"codecall:searchSkills",cache:{ttl:60,slideWindow:false},codecall:{enabledInCodeCall:false,visibleInListTools:true},description:searchSkillsToolDescription,inputSchema:searchSkillsToolInputSchema,outputSchema:searchSkillsToolOutputSchema,annotations:{readOnlyHint:true,openWorldHint:true}})],SearchSkillsTool);var import_sdk7=require("@frontmcp/sdk");var import_lazy_zod4=require("@frontmcp/lazy-zod");var searchKnowledgeToolDescription=`Search for KNOWLEDGE-ONLY skills \u2014 domain context the agent should read before deciding what to do. These skills have no tools and no openapi operation refs; they are pure prose / references / examples.
|
|
2842
37
|
|
|
2843
38
|
USE WHEN: the agent needs background to interpret a request, validate eligibility, or recall a procedure that isn't yet executable.
|
|
2844
39
|
|
|
@@ -2851,781 +46,36 @@ INPUT:
|
|
|
2851
46
|
|
|
2852
47
|
OUTPUT: Deduplicated knowledge skill list with description + tags. To read the body, follow up with describe(skillName) or the skill:// resource URI.
|
|
2853
48
|
|
|
2854
|
-
FLOW: searchKnowledge \u2192 describe (for body) \u2192 continue with searchSkills`;
|
|
2855
|
-
var
|
|
2856
|
-
queries: import_lazy_zod4.z.array(import_lazy_zod4.z.string().min(2).max(256)).min(1).max(10).describe("Atomic context queries."),
|
|
2857
|
-
tags: import_lazy_zod4.z.array(import_lazy_zod4.z.string().min(1).max(64)).max(16).optional().describe("Filter to skills with any of these tags"),
|
|
2858
|
-
excludeSkillNames: import_lazy_zod4.z.array(import_lazy_zod4.z.string()).max(50).optional().describe("Skip already-loaded knowledge skill names"),
|
|
2859
|
-
topK: import_lazy_zod4.z.number().int().positive().max(50).optional().default(5).describe("Results per query (default 5)"),
|
|
2860
|
-
minRelevanceScore: import_lazy_zod4.z.number().min(0).max(1).optional().default(0.1).describe("Minimum relevance threshold (default 0.1)")
|
|
2861
|
-
};
|
|
2862
|
-
var knowledgeHitSchema = import_lazy_zod4.z.object({
|
|
2863
|
-
name: import_lazy_zod4.z.string().describe("Skill name"),
|
|
2864
|
-
description: import_lazy_zod4.z.string().describe("Short description of what the knowledge covers"),
|
|
2865
|
-
tags: import_lazy_zod4.z.array(import_lazy_zod4.z.string()).describe("Tags carried by the skill"),
|
|
2866
|
-
relevanceScore: import_lazy_zod4.z.number().min(0).max(1).describe("Match score (0-1)"),
|
|
2867
|
-
matchedQueries: import_lazy_zod4.z.array(import_lazy_zod4.z.string()).describe("Which queries matched this knowledge"),
|
|
2868
|
-
source: import_lazy_zod4.z.enum(["local", "external"]).describe("Where the skill was loaded from")
|
|
2869
|
-
});
|
|
2870
|
-
var searchKnowledgeToolOutputSchema = import_lazy_zod4.z.object({
|
|
2871
|
-
knowledge: import_lazy_zod4.z.array(knowledgeHitSchema).describe("Deduplicated knowledge skills, sorted by relevance"),
|
|
2872
|
-
warnings: import_lazy_zod4.z.array(
|
|
2873
|
-
import_lazy_zod4.z.object({
|
|
2874
|
-
type: import_lazy_zod4.z.enum(["no_results", "low_relevance", "excluded_skill_not_found"]).describe("Warning type"),
|
|
2875
|
-
message: import_lazy_zod4.z.string().describe("Warning message"),
|
|
2876
|
-
affectedSkills: import_lazy_zod4.z.array(import_lazy_zod4.z.string()).optional().describe("Affected skill names")
|
|
2877
|
-
})
|
|
2878
|
-
).describe("Search warnings"),
|
|
2879
|
-
totalKnowledgeSkills: import_lazy_zod4.z.number().int().nonnegative().describe("Total knowledge-only skills available")
|
|
2880
|
-
});
|
|
2881
|
-
|
|
2882
|
-
// plugins/plugin-codecall/src/tools/search-knowledge.tool.ts
|
|
2883
|
-
var SearchKnowledgeTool = class extends import_sdk7.ToolContext {
|
|
2884
|
-
async execute(input) {
|
|
2885
|
-
const { queries, tags, excludeSkillNames = [], topK = 5, minRelevanceScore = 0.1 } = input;
|
|
2886
|
-
const skillRegistry = this.scope.skills;
|
|
2887
|
-
const knowledgeSkills = await (0, import_sdk7.filterServableSkills)(this.scope, skillRegistry.getKnowledgeOnlySkills());
|
|
2888
|
-
const knowledgeSet = new Set(knowledgeSkills.map((s) => s.name));
|
|
2889
|
-
const totalKnowledgeSkills = knowledgeSkills.length;
|
|
2890
|
-
const warnings = [];
|
|
2891
|
-
const nonExistentExcluded = excludeSkillNames.filter((n) => !knowledgeSet.has(n));
|
|
2892
|
-
if (nonExistentExcluded.length > 0) {
|
|
2893
|
-
warnings.push({
|
|
2894
|
-
type: "excluded_skill_not_found",
|
|
2895
|
-
message: `Excluded knowledge skills not found: ${nonExistentExcluded.join(", ")}`,
|
|
2896
|
-
affectedSkills: nonExistentExcluded
|
|
2897
|
-
});
|
|
2898
|
-
}
|
|
2899
|
-
const matches = /* @__PURE__ */ new Map();
|
|
2900
|
-
let lowRelevanceCount = 0;
|
|
2901
|
-
const excludedSet = new Set(excludeSkillNames);
|
|
2902
|
-
const perQueryResults = await Promise.all(
|
|
2903
|
-
queries.map(
|
|
2904
|
-
(query) => skillRegistry.search(query, { topK, tags, minScore: minRelevanceScore }).then((results) => ({ query, results }))
|
|
2905
|
-
)
|
|
2906
|
-
);
|
|
2907
|
-
for (const { query, results } of perQueryResults) {
|
|
2908
|
-
for (const result of results) {
|
|
2909
|
-
const name = result.metadata.name;
|
|
2910
|
-
if (!knowledgeSet.has(name)) continue;
|
|
2911
|
-
if (excludedSet.has(name)) continue;
|
|
2912
|
-
if (result.score < minRelevanceScore) {
|
|
2913
|
-
lowRelevanceCount++;
|
|
2914
|
-
continue;
|
|
2915
|
-
}
|
|
2916
|
-
const existing = matches.get(name);
|
|
2917
|
-
if (existing) {
|
|
2918
|
-
existing.matchedQueries.push(query);
|
|
2919
|
-
existing.relevanceScore = Math.max(existing.relevanceScore, result.score);
|
|
2920
|
-
} else {
|
|
2921
|
-
matches.set(name, {
|
|
2922
|
-
name,
|
|
2923
|
-
description: result.metadata.description,
|
|
2924
|
-
tags: result.metadata.tags ?? [],
|
|
2925
|
-
relevanceScore: result.score,
|
|
2926
|
-
matchedQueries: [query],
|
|
2927
|
-
source: result.source
|
|
2928
|
-
});
|
|
2929
|
-
}
|
|
2930
|
-
}
|
|
2931
|
-
}
|
|
2932
|
-
const knowledge = Array.from(matches.values()).sort((a, b) => b.relevanceScore - a.relevanceScore);
|
|
2933
|
-
if (knowledge.length === 0) {
|
|
2934
|
-
warnings.push({
|
|
2935
|
-
type: "no_results",
|
|
2936
|
-
message: `No knowledge skills found for queries: ${queries.join(", ")}${tags?.length ? ` with tags: ${tags.join(", ")}` : ""}`
|
|
2937
|
-
});
|
|
2938
|
-
}
|
|
2939
|
-
if (lowRelevanceCount > 0 && knowledge.length > 0) {
|
|
2940
|
-
warnings.push({
|
|
2941
|
-
type: "low_relevance",
|
|
2942
|
-
message: `${lowRelevanceCount} result(s) filtered due to relevance below ${minRelevanceScore}`
|
|
2943
|
-
});
|
|
2944
|
-
}
|
|
2945
|
-
return { knowledge, warnings, totalKnowledgeSkills };
|
|
2946
|
-
}
|
|
2947
|
-
};
|
|
2948
|
-
SearchKnowledgeTool = __decorateClass([
|
|
2949
|
-
(0, import_sdk7.Tool)({
|
|
2950
|
-
name: "codecall:searchKnowledge",
|
|
2951
|
-
cache: {
|
|
2952
|
-
ttl: 60,
|
|
2953
|
-
slideWindow: false
|
|
2954
|
-
},
|
|
2955
|
-
codecall: {
|
|
2956
|
-
enabledInCodeCall: false,
|
|
2957
|
-
visibleInListTools: true
|
|
2958
|
-
},
|
|
2959
|
-
description: searchKnowledgeToolDescription,
|
|
2960
|
-
inputSchema: searchKnowledgeToolInputSchema,
|
|
2961
|
-
outputSchema: searchKnowledgeToolOutputSchema,
|
|
2962
|
-
annotations: {
|
|
2963
|
-
readOnlyHint: true,
|
|
2964
|
-
openWorldHint: true
|
|
2965
|
-
}
|
|
2966
|
-
})
|
|
2967
|
-
], SearchKnowledgeTool);
|
|
2968
|
-
|
|
2969
|
-
// plugins/plugin-codecall/src/tools/describe.tool.ts
|
|
2970
|
-
var import_lazy_zod6 = require("@frontmcp/lazy-zod");
|
|
2971
|
-
var import_sdk8 = require("@frontmcp/sdk");
|
|
2972
|
-
|
|
2973
|
-
// plugins/plugin-codecall/src/utils/describe.utils.ts
|
|
2974
|
-
var INTENT_PATTERNS = {
|
|
2975
|
-
create: /^(create|add|new|insert|make|append|register|generate|produce|build|construct|provision|instantiate|define|compose|draft)/i,
|
|
2976
|
-
delete: /^(delete|remove|destroy|drop|erase|clear|purge|discard|eliminate|unbind|unregister)/i,
|
|
2977
|
-
get: /^(get|fetch|retrieve|read|obtain|load|pull|access|grab|receive)/i,
|
|
2978
|
-
update: /^(update|edit|modify|change|patch|set|alter|revise|adjust|amend|correct|fix|refresh|sync|upgrade|downgrade)/i,
|
|
2979
|
-
list: /^(list|all|index|enumerate|show|display|view|browse|scan|inventory)/i,
|
|
2980
|
-
search: /^(search|find|query|lookup|locate|discover|explore|seek|match|filter)/i
|
|
2981
|
-
};
|
|
2982
|
-
function detectToolIntent(toolName, description) {
|
|
2983
|
-
const parts = toolName.split(":");
|
|
2984
|
-
const actionPart = parts.length > 1 ? parts[parts.length - 1] : toolName;
|
|
2985
|
-
for (const [intent, pattern] of Object.entries(INTENT_PATTERNS)) {
|
|
2986
|
-
if (pattern.test(actionPart)) {
|
|
2987
|
-
return intent;
|
|
2988
|
-
}
|
|
2989
|
-
}
|
|
2990
|
-
if (description) {
|
|
2991
|
-
const descLower = description.toLowerCase();
|
|
2992
|
-
if (/creates?\s|adding\s|inserts?/i.test(descLower)) return "create";
|
|
2993
|
-
if (/deletes?\s|removes?\s|destroys?/i.test(descLower)) return "delete";
|
|
2994
|
-
if (/gets?\s|fetche?s?\s|retrieves?/i.test(descLower)) return "get";
|
|
2995
|
-
if (/updates?\s|modif(?:y|ies)\s|edits?/i.test(descLower)) return "update";
|
|
2996
|
-
if (/lists?\s|shows?\s|displays?/i.test(descLower)) return "list";
|
|
2997
|
-
if (/search(?:es)?\s|find(?:s)?\s|quer(?:y|ies)/i.test(descLower)) return "search";
|
|
2998
|
-
}
|
|
2999
|
-
return "unknown";
|
|
3000
|
-
}
|
|
3001
|
-
function generateBasicExample(toolName, inputSchema) {
|
|
3002
|
-
const params = generateSampleParams(inputSchema);
|
|
3003
|
-
const paramsStr = params ? JSON.stringify(params, null, 2) : "{}";
|
|
3004
|
-
return {
|
|
3005
|
-
description: `Basic usage of ${toolName}`,
|
|
3006
|
-
code: `const result = await callTool('${toolName}', ${paramsStr});
|
|
3007
|
-
return result;`
|
|
3008
|
-
};
|
|
3009
|
-
}
|
|
3010
|
-
function generateSampleParams(schema) {
|
|
3011
|
-
if (!schema || schema.type !== "object" || !schema.properties) {
|
|
3012
|
-
return null;
|
|
3013
|
-
}
|
|
3014
|
-
const params = {};
|
|
3015
|
-
const required = new Set(schema.required || []);
|
|
3016
|
-
for (const [key, propSchema] of Object.entries(schema.properties)) {
|
|
3017
|
-
if (typeof propSchema === "boolean") continue;
|
|
3018
|
-
if (!required.has(key)) continue;
|
|
3019
|
-
params[key] = getSampleValue(propSchema, key);
|
|
3020
|
-
}
|
|
3021
|
-
return Object.keys(params).length > 0 ? params : null;
|
|
3022
|
-
}
|
|
3023
|
-
function fitString(schema, value) {
|
|
3024
|
-
let fitted = value;
|
|
3025
|
-
if (schema.maxLength !== void 0 && fitted.length > schema.maxLength) {
|
|
3026
|
-
fitted = fitted.slice(0, Math.max(0, schema.maxLength));
|
|
3027
|
-
}
|
|
3028
|
-
if (schema.minLength !== void 0 && fitted.length < schema.minLength) {
|
|
3029
|
-
fitted = fitted.padEnd(schema.minLength, "x");
|
|
3030
|
-
}
|
|
3031
|
-
return fitted;
|
|
3032
|
-
}
|
|
3033
|
-
function isFreeTextString(schema) {
|
|
3034
|
-
return schema?.type === "string" && schema.enum === void 0 && schema.const === void 0 && schema.default === void 0 && schema.pattern === void 0 && schema.format === void 0;
|
|
3035
|
-
}
|
|
3036
|
-
function acceptsNumber(schema, value) {
|
|
3037
|
-
if (schema.const !== void 0) return schema.const === value;
|
|
3038
|
-
if (schema.enum !== void 0) return schema.enum.includes(value);
|
|
3039
|
-
if (schema.minimum !== void 0 && value < schema.minimum) return false;
|
|
3040
|
-
if (schema.maximum !== void 0 && value > schema.maximum) return false;
|
|
3041
|
-
return true;
|
|
3042
|
-
}
|
|
3043
|
-
function pickNumber(schema, preferred) {
|
|
3044
|
-
const accepted = preferred.find((value) => acceptsNumber(schema, value));
|
|
3045
|
-
if (accepted !== void 0) return accepted;
|
|
3046
|
-
const named = [schema.const, schema.enum?.[0], schema.minimum, schema.maximum].find(
|
|
3047
|
-
(value) => typeof value === "number" && acceptsNumber(schema, value)
|
|
3048
|
-
);
|
|
3049
|
-
return named;
|
|
3050
|
-
}
|
|
3051
|
-
function formatInlineArgs(args) {
|
|
3052
|
-
const entries = Object.entries(args).map(([key, value]) => {
|
|
3053
|
-
const name = /^[A-Za-z_$][\w$]*$/.test(key) ? key : JSON.stringify(key);
|
|
3054
|
-
const plain = typeof value === "string" && [...value].every((ch) => ch !== "'" && ch !== "\\" && ch >= " ");
|
|
3055
|
-
const literal = plain ? `'${value}'` : JSON.stringify(value);
|
|
3056
|
-
return `${name}: ${literal}`;
|
|
3057
|
-
});
|
|
3058
|
-
return entries.length > 0 ? `{ ${entries.join(", ")} }` : "{}";
|
|
3059
|
-
}
|
|
3060
|
-
function getSampleValue(schema, key) {
|
|
3061
|
-
if (schema.default !== void 0) {
|
|
3062
|
-
return schema.default;
|
|
3063
|
-
}
|
|
3064
|
-
if (schema.enum && schema.enum.length > 0) {
|
|
3065
|
-
return schema.enum[0];
|
|
3066
|
-
}
|
|
3067
|
-
if (schema.const !== void 0) {
|
|
3068
|
-
return schema.const;
|
|
3069
|
-
}
|
|
3070
|
-
const type = Array.isArray(schema.type) ? schema.type[0] : schema.type;
|
|
3071
|
-
switch (type) {
|
|
3072
|
-
case "string":
|
|
3073
|
-
if (key.toLowerCase().includes("id")) return fitString(schema, "abc123");
|
|
3074
|
-
if (key.toLowerCase().includes("email")) return fitString(schema, "user@example.com");
|
|
3075
|
-
if (key.toLowerCase().includes("name")) return fitString(schema, "Example");
|
|
3076
|
-
if (key.toLowerCase().includes("url")) return fitString(schema, "https://example.com");
|
|
3077
|
-
return fitString(schema, "string");
|
|
3078
|
-
case "number":
|
|
3079
|
-
case "integer":
|
|
3080
|
-
if (key.toLowerCase().includes("limit")) return 10;
|
|
3081
|
-
if (key.toLowerCase().includes("offset")) return 0;
|
|
3082
|
-
if (key.toLowerCase().includes("page")) return 1;
|
|
3083
|
-
return 0;
|
|
3084
|
-
case "boolean":
|
|
3085
|
-
return true;
|
|
3086
|
-
case "array":
|
|
3087
|
-
return [];
|
|
3088
|
-
case "object":
|
|
3089
|
-
return {};
|
|
3090
|
-
default:
|
|
3091
|
-
return null;
|
|
3092
|
-
}
|
|
3093
|
-
}
|
|
3094
|
-
var PAGINATION_PROPERTIES = ["limit", "offset", "page", "pagesize", "cursor"];
|
|
3095
|
-
function isPaginationProperty(name) {
|
|
3096
|
-
return PAGINATION_PROPERTIES.includes(name.toLowerCase());
|
|
3097
|
-
}
|
|
3098
|
-
function hasPaginationParams(schema) {
|
|
3099
|
-
if (!schema || schema.type !== "object" || !schema.properties) {
|
|
3100
|
-
return false;
|
|
3101
|
-
}
|
|
3102
|
-
return Object.keys(schema.properties).some(isPaginationProperty);
|
|
3103
|
-
}
|
|
3104
|
-
function inputProperties(schema) {
|
|
3105
|
-
if (!schema || schema.type !== "object" || !schema.properties) {
|
|
3106
|
-
return {};
|
|
3107
|
-
}
|
|
3108
|
-
const properties = {};
|
|
3109
|
-
for (const [key, propSchema] of Object.entries(schema.properties)) {
|
|
3110
|
-
if (typeof propSchema !== "boolean") properties[key] = propSchema;
|
|
3111
|
-
}
|
|
3112
|
-
return properties;
|
|
3113
|
-
}
|
|
3114
|
-
function buildExampleArgs(schema, keys, values = {}) {
|
|
3115
|
-
const properties = inputProperties(schema);
|
|
3116
|
-
const args = {};
|
|
3117
|
-
for (const key of [...keys, ...schema?.required ?? []]) {
|
|
3118
|
-
const propSchema = properties[key];
|
|
3119
|
-
if (!propSchema || key in args) continue;
|
|
3120
|
-
args[key] = key in values ? values[key] : getSampleValue(propSchema, key);
|
|
3121
|
-
}
|
|
3122
|
-
return args;
|
|
3123
|
-
}
|
|
3124
|
-
function formatExampleArgs(args) {
|
|
3125
|
-
return Object.keys(args).length > 0 ? JSON.stringify(args, null, 2) : "{}";
|
|
3126
|
-
}
|
|
3127
|
-
function getFilterProperties(schema) {
|
|
3128
|
-
if (!schema || schema.type !== "object" || !schema.properties) {
|
|
3129
|
-
return [];
|
|
3130
|
-
}
|
|
3131
|
-
return Object.keys(schema.properties).filter(
|
|
3132
|
-
(p) => p.toLowerCase().includes("filter") || p.toLowerCase().includes("query") || p.toLowerCase().includes("search") || p.toLowerCase() === "status" || p.toLowerCase() === "type" || p.toLowerCase() === "role"
|
|
3133
|
-
);
|
|
3134
|
-
}
|
|
3135
|
-
function generatePaginationExample(toolName, inputSchema) {
|
|
3136
|
-
const description = `Pagination example for ${toolName}`;
|
|
3137
|
-
const props = Object.keys(inputProperties(inputSchema));
|
|
3138
|
-
const limitKey = props.find((p) => p.toLowerCase() === "limit");
|
|
3139
|
-
const offsetKey = props.find((p) => p.toLowerCase() === "offset");
|
|
3140
|
-
if (limitKey && offsetKey) {
|
|
3141
|
-
const properties = inputProperties(inputSchema);
|
|
3142
|
-
const limit = pickNumber(properties[limitKey], [10]);
|
|
3143
|
-
const firstOffset = pickNumber(properties[offsetKey], [0]);
|
|
3144
|
-
const values = {};
|
|
3145
|
-
if (limit !== void 0) values[limitKey] = limit;
|
|
3146
|
-
if (firstOffset !== void 0) values[offsetKey] = firstOffset;
|
|
3147
|
-
const firstPage = buildExampleArgs(inputSchema, [limitKey, offsetKey], values);
|
|
3148
|
-
const nextOffset = [limit ?? 10, 10, 20, ...properties[offsetKey].enum ?? []].find(
|
|
3149
|
-
(value) => typeof value === "number" && value !== firstPage[offsetKey] && acceptsNumber(properties[offsetKey], value)
|
|
3150
|
-
);
|
|
3151
|
-
if (nextOffset !== void 0) {
|
|
3152
|
-
const secondPage = { ...firstPage, [offsetKey]: nextOffset };
|
|
3153
|
-
return {
|
|
3154
|
-
description,
|
|
3155
|
-
code: `// Fetch first page
|
|
49
|
+
FLOW: searchKnowledge \u2192 describe (for body) \u2192 continue with searchSkills`;var searchKnowledgeToolInputSchema={queries:import_lazy_zod4.z.array(import_lazy_zod4.z.string().min(2).max(256)).min(1).max(10).describe("Atomic context queries."),tags:import_lazy_zod4.z.array(import_lazy_zod4.z.string().min(1).max(64)).max(16).optional().describe("Filter to skills with any of these tags"),excludeSkillNames:import_lazy_zod4.z.array(import_lazy_zod4.z.string()).max(50).optional().describe("Skip already-loaded knowledge skill names"),topK:import_lazy_zod4.z.number().int().positive().max(50).optional().default(5).describe("Results per query (default 5)"),minRelevanceScore:import_lazy_zod4.z.number().min(0).max(1).optional().default(.1).describe("Minimum relevance threshold (default 0.1)")};var knowledgeHitSchema=import_lazy_zod4.z.object({name:import_lazy_zod4.z.string().describe("Skill name"),description:import_lazy_zod4.z.string().describe("Short description of what the knowledge covers"),tags:import_lazy_zod4.z.array(import_lazy_zod4.z.string()).describe("Tags carried by the skill"),relevanceScore:import_lazy_zod4.z.number().min(0).max(1).describe("Match score (0-1)"),matchedQueries:import_lazy_zod4.z.array(import_lazy_zod4.z.string()).describe("Which queries matched this knowledge"),source:import_lazy_zod4.z.enum(["local","external"]).describe("Where the skill was loaded from")});var searchKnowledgeToolOutputSchema=import_lazy_zod4.z.object({knowledge:import_lazy_zod4.z.array(knowledgeHitSchema).describe("Deduplicated knowledge skills, sorted by relevance"),warnings:import_lazy_zod4.z.array(import_lazy_zod4.z.object({type:import_lazy_zod4.z.enum(["no_results","low_relevance","excluded_skill_not_found"]).describe("Warning type"),message:import_lazy_zod4.z.string().describe("Warning message"),affectedSkills:import_lazy_zod4.z.array(import_lazy_zod4.z.string()).optional().describe("Affected skill names")})).describe("Search warnings"),totalKnowledgeSkills:import_lazy_zod4.z.number().int().nonnegative().describe("Total knowledge-only skills available")});var SearchKnowledgeTool=class extends import_sdk7.ToolContext{async execute(input){const{queries,tags,excludeSkillNames=[],topK=5,minRelevanceScore=.1}=input;const skillRegistry=this.scope.skills;const knowledgeSkills=await(0,import_sdk7.filterServableSkills)(this.scope,skillRegistry.getKnowledgeOnlySkills());const knowledgeSet=new Set(knowledgeSkills.map(s=>s.name));const totalKnowledgeSkills=knowledgeSkills.length;const warnings=[];const nonExistentExcluded=excludeSkillNames.filter(n=>!knowledgeSet.has(n));if(nonExistentExcluded.length>0){warnings.push({type:"excluded_skill_not_found",message:`Excluded knowledge skills not found: ${nonExistentExcluded.join(", ")}`,affectedSkills:nonExistentExcluded})}const matches=new Map;let lowRelevanceCount=0;const excludedSet=new Set(excludeSkillNames);const perQueryResults=await Promise.all(queries.map(query=>skillRegistry.search(query,{topK,tags,minScore:minRelevanceScore}).then(results=>({query,results}))));for(const{query,results}of perQueryResults){for(const result of results){const name=result.metadata.name;if(!knowledgeSet.has(name))continue;if(excludedSet.has(name))continue;if(result.score<minRelevanceScore){lowRelevanceCount++;continue}const existing=matches.get(name);if(existing){existing.matchedQueries.push(query);existing.relevanceScore=Math.max(existing.relevanceScore,result.score)}else{matches.set(name,{name,description:result.metadata.description,tags:result.metadata.tags??[],relevanceScore:result.score,matchedQueries:[query],source:result.source})}}}const knowledge=Array.from(matches.values()).sort((a,b)=>b.relevanceScore-a.relevanceScore);if(knowledge.length===0){warnings.push({type:"no_results",message:`No knowledge skills found for queries: ${queries.join(", ")}${tags?.length?` with tags: ${tags.join(", ")}`:""}`})}if(lowRelevanceCount>0&&knowledge.length>0){warnings.push({type:"low_relevance",message:`${lowRelevanceCount} result(s) filtered due to relevance below ${minRelevanceScore}`})}return{knowledge,warnings,totalKnowledgeSkills}}};SearchKnowledgeTool=__decorateClass([(0,import_sdk7.Tool)({name:"codecall:searchKnowledge",cache:{ttl:60,slideWindow:false},codecall:{enabledInCodeCall:false,visibleInListTools:true},description:searchKnowledgeToolDescription,inputSchema:searchKnowledgeToolInputSchema,outputSchema:searchKnowledgeToolOutputSchema,annotations:{readOnlyHint:true,openWorldHint:true}})],SearchKnowledgeTool);var import_lazy_zod6=require("@frontmcp/lazy-zod");var import_sdk8=require("@frontmcp/sdk");var INTENT_PATTERNS={create:/^(create|add|new|insert|make|append|register|generate|produce|build|construct|provision|instantiate|define|compose|draft)/i,delete:/^(delete|remove|destroy|drop|erase|clear|purge|discard|eliminate|unbind|unregister)/i,get:/^(get|fetch|retrieve|read|obtain|load|pull|access|grab|receive)/i,update:/^(update|edit|modify|change|patch|set|alter|revise|adjust|amend|correct|fix|refresh|sync|upgrade|downgrade)/i,list:/^(list|all|index|enumerate|show|display|view|browse|scan|inventory)/i,search:/^(search|find|query|lookup|locate|discover|explore|seek|match|filter)/i};function detectToolIntent(toolName,description){const parts=toolName.split(":");const actionPart=parts.length>1?parts[parts.length-1]:toolName;for(const[intent,pattern]of Object.entries(INTENT_PATTERNS)){if(pattern.test(actionPart)){return intent}}if(description){const descLower=description.toLowerCase();if(/creates?\s|adding\s|inserts?/i.test(descLower))return"create";if(/deletes?\s|removes?\s|destroys?/i.test(descLower))return"delete";if(/gets?\s|fetche?s?\s|retrieves?/i.test(descLower))return"get";if(/updates?\s|modif(?:y|ies)\s|edits?/i.test(descLower))return"update";if(/lists?\s|shows?\s|displays?/i.test(descLower))return"list";if(/search(?:es)?\s|find(?:s)?\s|quer(?:y|ies)/i.test(descLower))return"search"}return"unknown"}function generateBasicExample(toolName,inputSchema){const params=generateSampleParams(inputSchema);const paramsStr=params?JSON.stringify(params,null,2):"{}";return{description:`Basic usage of ${toolName}`,code:`const result = await callTool('${toolName}', ${paramsStr});
|
|
50
|
+
return result;`}}function generateSampleParams(schema){if(!schema||schema.type!=="object"||!schema.properties){return null}const params={};const required=new Set(schema.required||[]);for(const[key,propSchema]of Object.entries(schema.properties)){if(typeof propSchema==="boolean")continue;if(!required.has(key))continue;params[key]=getSampleValue(propSchema,key)}return Object.keys(params).length>0?params:null}function fitString(schema,value){let fitted=value;if(schema.maxLength!==void 0&&fitted.length>schema.maxLength){fitted=fitted.slice(0,Math.max(0,schema.maxLength))}if(schema.minLength!==void 0&&fitted.length<schema.minLength){fitted=fitted.padEnd(schema.minLength,"x")}return fitted}function isFreeTextString(schema){return schema?.type==="string"&&schema.enum===void 0&&schema.const===void 0&&schema.default===void 0&&schema.pattern===void 0&&schema.format===void 0}function acceptsNumber(schema,value){if(schema.const!==void 0)return schema.const===value;if(schema.enum!==void 0)return schema.enum.includes(value);if(schema.minimum!==void 0&&value<schema.minimum)return false;if(schema.maximum!==void 0&&value>schema.maximum)return false;return true}function pickNumber(schema,preferred){const accepted=preferred.find(value=>acceptsNumber(schema,value));if(accepted!==void 0)return accepted;const named=[schema.const,schema.enum?.[0],schema.minimum,schema.maximum].find(value=>typeof value==="number"&&acceptsNumber(schema,value));return named}function formatInlineArgs(args){const entries=Object.entries(args).map(([key,value])=>{const name=/^[A-Za-z_$][\w$]*$/.test(key)?key:JSON.stringify(key);const plain=typeof value==="string"&&[...value].every(ch=>ch!=="'"&&ch!=="\\"&&ch>=" ");const literal=plain?`'${value}'`:JSON.stringify(value);return`${name}: ${literal}`});return entries.length>0?`{ ${entries.join(", ")} }`:"{}"}function getSampleValue(schema,key){if(schema.default!==void 0){return schema.default}if(schema.enum&&schema.enum.length>0){return schema.enum[0]}if(schema.const!==void 0){return schema.const}const type=Array.isArray(schema.type)?schema.type[0]:schema.type;switch(type){case"string":if(key.toLowerCase().includes("id"))return fitString(schema,"abc123");if(key.toLowerCase().includes("email"))return fitString(schema,"user@example.com");if(key.toLowerCase().includes("name"))return fitString(schema,"Example");if(key.toLowerCase().includes("url"))return fitString(schema,"https://example.com");return fitString(schema,"string");case"number":case"integer":if(key.toLowerCase().includes("limit"))return 10;if(key.toLowerCase().includes("offset"))return 0;if(key.toLowerCase().includes("page"))return 1;return 0;case"boolean":return true;case"array":return[];case"object":return{};default:return null}}var PAGINATION_PROPERTIES=["limit","offset","page","pagesize","cursor"];function isPaginationProperty(name){return PAGINATION_PROPERTIES.includes(name.toLowerCase())}function hasPaginationParams(schema){if(!schema||schema.type!=="object"||!schema.properties){return false}return Object.keys(schema.properties).some(isPaginationProperty)}function inputProperties(schema){if(!schema||schema.type!=="object"||!schema.properties){return{}}const properties={};for(const[key,propSchema]of Object.entries(schema.properties)){if(typeof propSchema!=="boolean")properties[key]=propSchema}return properties}function buildExampleArgs(schema,keys,values={}){const properties=inputProperties(schema);const args={};for(const key of[...keys,...schema?.required??[]]){const propSchema=properties[key];if(!propSchema||key in args)continue;args[key]=key in values?values[key]:getSampleValue(propSchema,key)}return args}function formatExampleArgs(args){return Object.keys(args).length>0?JSON.stringify(args,null,2):"{}"}function getFilterProperties(schema){if(!schema||schema.type!=="object"||!schema.properties){return[]}return Object.keys(schema.properties).filter(p=>p.toLowerCase().includes("filter")||p.toLowerCase().includes("query")||p.toLowerCase().includes("search")||p.toLowerCase()==="status"||p.toLowerCase()==="type"||p.toLowerCase()==="role")}function generatePaginationExample(toolName,inputSchema){const description=`Pagination example for ${toolName}`;const props=Object.keys(inputProperties(inputSchema));const limitKey=props.find(p=>p.toLowerCase()==="limit");const offsetKey=props.find(p=>p.toLowerCase()==="offset");if(limitKey&&offsetKey){const properties=inputProperties(inputSchema);const limit=pickNumber(properties[limitKey],[10]);const firstOffset=pickNumber(properties[offsetKey],[0]);const values={};if(limit!==void 0)values[limitKey]=limit;if(firstOffset!==void 0)values[offsetKey]=firstOffset;const firstPage=buildExampleArgs(inputSchema,[limitKey,offsetKey],values);const nextOffset=[limit??10,10,20,...properties[offsetKey].enum??[]].find(value=>typeof value==="number"&&value!==firstPage[offsetKey]&&acceptsNumber(properties[offsetKey],value));if(nextOffset!==void 0){const secondPage={...firstPage,[offsetKey]:nextOffset};return{description,code:`// Fetch first page
|
|
3156
51
|
const page1 = await callTool('${toolName}', ${formatExampleArgs(firstPage)});
|
|
3157
52
|
|
|
3158
53
|
// Fetch second page
|
|
3159
54
|
const page2 = await callTool('${toolName}', ${formatExampleArgs(secondPage)});
|
|
3160
55
|
|
|
3161
56
|
// Combine results
|
|
3162
|
-
return [...page1.items, ...page2.items];`
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
return
|
|
3169
|
-
};
|
|
3170
|
-
}
|
|
3171
|
-
const args = buildExampleArgs(inputSchema, props.filter(isPaginationProperty));
|
|
3172
|
-
return {
|
|
3173
|
-
description,
|
|
3174
|
-
code: `const page = await callTool('${toolName}', ${formatExampleArgs(args)});
|
|
3175
|
-
return page.items || page;`
|
|
3176
|
-
};
|
|
3177
|
-
}
|
|
3178
|
-
function extractEntityName(toolName) {
|
|
3179
|
-
const parts = toolName.split(":");
|
|
3180
|
-
const entity = parts.length > 1 ? parts[0] : toolName;
|
|
3181
|
-
return entity.endsWith("s") && !entity.endsWith("ss") ? entity.slice(0, -1) : entity;
|
|
3182
|
-
}
|
|
3183
|
-
function generateCreateExample(toolName, inputSchema) {
|
|
3184
|
-
const entity = extractEntityName(toolName);
|
|
3185
|
-
const params = generateSampleParams(inputSchema);
|
|
3186
|
-
const paramsStr = params ? JSON.stringify(params, null, 2) : "{ /* required fields */ }";
|
|
3187
|
-
return {
|
|
3188
|
-
description: `Create a new ${entity}`,
|
|
3189
|
-
code: `const result = await callTool('${toolName}', ${paramsStr});
|
|
3190
|
-
return result;`
|
|
3191
|
-
};
|
|
3192
|
-
}
|
|
3193
|
-
function idArgs(schema, idParam) {
|
|
3194
|
-
const idSchema = inputProperties(schema)[idParam];
|
|
3195
|
-
const values = isFreeTextString(idSchema) ? { [idParam]: fitString(idSchema, "abc123") } : {};
|
|
3196
|
-
return buildExampleArgs(schema, [idParam], values);
|
|
3197
|
-
}
|
|
3198
|
-
function generateGetExample(toolName, inputSchema) {
|
|
3199
|
-
const entity = extractEntityName(toolName);
|
|
3200
|
-
const idParam = findIdParameter(inputSchema);
|
|
3201
|
-
if (idParam) {
|
|
3202
|
-
return {
|
|
3203
|
-
description: `Get ${entity} by ${idParam}`,
|
|
3204
|
-
code: `const ${entity} = await callTool('${toolName}', ${formatInlineArgs(idArgs(inputSchema, idParam))});
|
|
3205
|
-
return ${entity};`
|
|
3206
|
-
};
|
|
3207
|
-
}
|
|
3208
|
-
const params = generateSampleParams(inputSchema);
|
|
3209
|
-
const paramsStr = params ? JSON.stringify(params, null, 2) : "{}";
|
|
3210
|
-
return {
|
|
3211
|
-
description: `Get ${entity} details`,
|
|
3212
|
-
code: `const ${entity} = await callTool('${toolName}', ${paramsStr});
|
|
3213
|
-
return ${entity};`
|
|
3214
|
-
};
|
|
3215
|
-
}
|
|
3216
|
-
function generateListExample(toolName, inputSchema) {
|
|
3217
|
-
const entity = extractEntityName(toolName);
|
|
3218
|
-
return {
|
|
3219
|
-
description: `List all ${entity}s`,
|
|
3220
|
-
code: `const result = await callTool('${toolName}', ${formatExampleArgs(buildExampleArgs(inputSchema, []))});
|
|
3221
|
-
return result.items || result;`
|
|
3222
|
-
};
|
|
3223
|
-
}
|
|
3224
|
-
function generateUpdateExample(toolName, inputSchema) {
|
|
3225
|
-
const entity = extractEntityName(toolName);
|
|
3226
|
-
const idParam = findIdParameter(inputSchema);
|
|
3227
|
-
const updateFields = generateUpdateFields(inputSchema);
|
|
3228
|
-
const fieldsStr = updateFields ? JSON.stringify(updateFields, null, 2).replace(/\n/g, "\n ") : "{ /* fields to update */ }";
|
|
3229
|
-
if (idParam) {
|
|
3230
|
-
const identifiers = formatInlineArgs(idArgs(inputSchema, idParam)).slice(2, -2);
|
|
3231
|
-
return {
|
|
3232
|
-
description: `Update ${entity} by ${idParam}`,
|
|
3233
|
-
code: `const updated = await callTool('${toolName}', {
|
|
57
|
+
return [...page1.items, ...page2.items];`}}return{description,code:`const page = await callTool('${toolName}', ${formatExampleArgs(firstPage)});
|
|
58
|
+
return page.items || page;`}}const args=buildExampleArgs(inputSchema,props.filter(isPaginationProperty));return{description,code:`const page = await callTool('${toolName}', ${formatExampleArgs(args)});
|
|
59
|
+
return page.items || page;`}}function extractEntityName(toolName){const parts=toolName.split(":");const entity=parts.length>1?parts[0]:toolName;return entity.endsWith("s")&&!entity.endsWith("ss")?entity.slice(0,-1):entity}function generateCreateExample(toolName,inputSchema){const entity=extractEntityName(toolName);const params=generateSampleParams(inputSchema);const paramsStr=params?JSON.stringify(params,null,2):"{ /* required fields */ }";return{description:`Create a new ${entity}`,code:`const result = await callTool('${toolName}', ${paramsStr});
|
|
60
|
+
return result;`}}function idArgs(schema,idParam){const idSchema=inputProperties(schema)[idParam];const values=isFreeTextString(idSchema)?{[idParam]:fitString(idSchema,"abc123")}:{};return buildExampleArgs(schema,[idParam],values)}function generateGetExample(toolName,inputSchema){const entity=extractEntityName(toolName);const idParam=findIdParameter(inputSchema);if(idParam){return{description:`Get ${entity} by ${idParam}`,code:`const ${entity} = await callTool('${toolName}', ${formatInlineArgs(idArgs(inputSchema,idParam))});
|
|
61
|
+
return ${entity};`}}const params=generateSampleParams(inputSchema);const paramsStr=params?JSON.stringify(params,null,2):"{}";return{description:`Get ${entity} details`,code:`const ${entity} = await callTool('${toolName}', ${paramsStr});
|
|
62
|
+
return ${entity};`}}function generateListExample(toolName,inputSchema){const entity=extractEntityName(toolName);return{description:`List all ${entity}s`,code:`const result = await callTool('${toolName}', ${formatExampleArgs(buildExampleArgs(inputSchema,[]))});
|
|
63
|
+
return result.items || result;`}}function generateUpdateExample(toolName,inputSchema){const entity=extractEntityName(toolName);const idParam=findIdParameter(inputSchema);const updateFields=generateUpdateFields(inputSchema);const fieldsStr=updateFields?JSON.stringify(updateFields,null,2).replace(/\n/g,"\n "):"{ /* fields to update */ }";if(idParam){const identifiers=formatInlineArgs(idArgs(inputSchema,idParam)).slice(2,-2);return{description:`Update ${entity} by ${idParam}`,code:`const updated = await callTool('${toolName}', {
|
|
3234
64
|
${identifiers},
|
|
3235
65
|
...${fieldsStr}
|
|
3236
66
|
});
|
|
3237
|
-
return updated;`
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
code: `const updated = await callTool('${toolName}', ${fieldsStr});
|
|
3243
|
-
return updated;`
|
|
3244
|
-
};
|
|
3245
|
-
}
|
|
3246
|
-
function generateDeleteExample(toolName, inputSchema) {
|
|
3247
|
-
const entity = extractEntityName(toolName);
|
|
3248
|
-
const idParam = findIdParameter(inputSchema);
|
|
3249
|
-
if (idParam) {
|
|
3250
|
-
return {
|
|
3251
|
-
description: `Delete ${entity} by ${idParam}`,
|
|
3252
|
-
code: `const result = await callTool('${toolName}', ${formatInlineArgs(idArgs(inputSchema, idParam))});
|
|
3253
|
-
return result;`
|
|
3254
|
-
};
|
|
3255
|
-
}
|
|
3256
|
-
const params = generateSampleParams(inputSchema);
|
|
3257
|
-
const paramsStr = params ? JSON.stringify(params, null, 2) : "{ /* identifier */ }";
|
|
3258
|
-
return {
|
|
3259
|
-
description: `Delete ${entity}`,
|
|
3260
|
-
code: `const result = await callTool('${toolName}', ${paramsStr});
|
|
3261
|
-
return result;`
|
|
3262
|
-
};
|
|
3263
|
-
}
|
|
3264
|
-
function generateSearchExample(toolName, inputSchema) {
|
|
3265
|
-
const entity = extractEntityName(toolName);
|
|
3266
|
-
const searchParam = findQueryParameter(inputSchema) ?? getFilterProperties(inputSchema)[0];
|
|
3267
|
-
const searchSchema = searchParam ? inputProperties(inputSchema)[searchParam] : void 0;
|
|
3268
|
-
const required = new Set(inputSchema?.required ?? []);
|
|
3269
|
-
const unfillable = searchSchema?.type === "string" && (searchSchema.pattern !== void 0 || searchSchema.format !== void 0) && searchSchema.enum === void 0 && searchSchema.const === void 0 && searchSchema.default === void 0 && !required.has(searchParam ?? "");
|
|
3270
|
-
const args = searchParam && !unfillable ? buildExampleArgs(
|
|
3271
|
-
inputSchema,
|
|
3272
|
-
[searchParam],
|
|
3273
|
-
isFreeTextString(searchSchema) && searchSchema ? { [searchParam]: fitString(searchSchema, "search term") } : {}
|
|
3274
|
-
) : buildExampleArgs(inputSchema, []);
|
|
3275
|
-
return {
|
|
3276
|
-
description: `Search for ${entity}s`,
|
|
3277
|
-
code: `const results = await callTool('${toolName}', ${formatExampleArgs(args)});
|
|
3278
|
-
return results.items || results;`
|
|
3279
|
-
};
|
|
3280
|
-
}
|
|
3281
|
-
function findIdParameter(schema) {
|
|
3282
|
-
if (!schema || schema.type !== "object" || !schema.properties) {
|
|
3283
|
-
return null;
|
|
3284
|
-
}
|
|
3285
|
-
const props = Object.keys(schema.properties);
|
|
3286
|
-
const required = new Set(schema.required || []);
|
|
3287
|
-
const idPatterns = ["id", "Id", "ID", "_id", "uuid", "key"];
|
|
3288
|
-
for (const pattern of idPatterns) {
|
|
3289
|
-
const found = props.find((p) => (p === pattern || p.endsWith(pattern)) && required.has(p));
|
|
3290
|
-
if (found) return found;
|
|
3291
|
-
}
|
|
3292
|
-
for (const pattern of idPatterns) {
|
|
3293
|
-
const found = props.find((p) => p === pattern || p.endsWith(pattern));
|
|
3294
|
-
if (found) return found;
|
|
3295
|
-
}
|
|
3296
|
-
return null;
|
|
3297
|
-
}
|
|
3298
|
-
function findQueryParameter(schema) {
|
|
3299
|
-
if (!schema || schema.type !== "object" || !schema.properties) {
|
|
3300
|
-
return null;
|
|
3301
|
-
}
|
|
3302
|
-
const props = Object.keys(schema.properties);
|
|
3303
|
-
const queryPatterns = ["query", "search", "q", "term", "keyword", "filter"];
|
|
3304
|
-
for (const pattern of queryPatterns) {
|
|
3305
|
-
const found = props.find((p) => p.toLowerCase() === pattern || p.toLowerCase().includes(pattern));
|
|
3306
|
-
if (found) return found;
|
|
3307
|
-
}
|
|
3308
|
-
return null;
|
|
3309
|
-
}
|
|
3310
|
-
function generateUpdateFields(schema) {
|
|
3311
|
-
if (!schema || schema.type !== "object" || !schema.properties) {
|
|
3312
|
-
return null;
|
|
3313
|
-
}
|
|
3314
|
-
const fields = {};
|
|
3315
|
-
const idPatterns = ["id", "Id", "ID", "_id", "uuid", "key"];
|
|
3316
|
-
for (const [key, propSchema] of Object.entries(schema.properties)) {
|
|
3317
|
-
if (typeof propSchema === "boolean") continue;
|
|
3318
|
-
const isIdField = idPatterns.some((p) => key === p || key.endsWith(p));
|
|
3319
|
-
if (isIdField) continue;
|
|
3320
|
-
if (Object.keys(fields).length < 2) {
|
|
3321
|
-
fields[key] = getSampleValue(propSchema, key);
|
|
3322
|
-
}
|
|
3323
|
-
}
|
|
3324
|
-
return Object.keys(fields).length > 0 ? fields : null;
|
|
3325
|
-
}
|
|
3326
|
-
function generateSmartExample(toolName, inputSchema, description) {
|
|
3327
|
-
const intent = detectToolIntent(toolName, description);
|
|
3328
|
-
switch (intent) {
|
|
3329
|
-
case "create":
|
|
3330
|
-
return generateCreateExample(toolName, inputSchema);
|
|
3331
|
-
case "get":
|
|
3332
|
-
return generateGetExample(toolName, inputSchema);
|
|
3333
|
-
case "list":
|
|
3334
|
-
return hasPaginationParams(inputSchema) ? generatePaginationExample(toolName, inputSchema) : generateListExample(toolName, inputSchema);
|
|
3335
|
-
case "update":
|
|
3336
|
-
return generateUpdateExample(toolName, inputSchema);
|
|
3337
|
-
case "delete":
|
|
3338
|
-
return generateDeleteExample(toolName, inputSchema);
|
|
3339
|
-
case "search":
|
|
3340
|
-
return generateSearchExample(toolName, inputSchema);
|
|
3341
|
-
default:
|
|
3342
|
-
return generateBasicExample(toolName, inputSchema);
|
|
3343
|
-
}
|
|
3344
|
-
}
|
|
3345
|
-
|
|
3346
|
-
// plugins/plugin-codecall/src/utils/plain-json.ts
|
|
3347
|
-
function toPlainJson(value) {
|
|
3348
|
-
try {
|
|
3349
|
-
const serialized = JSON.stringify(value);
|
|
3350
|
-
if (serialized === void 0) return void 0;
|
|
3351
|
-
return JSON.parse(serialized);
|
|
3352
|
-
} catch {
|
|
3353
|
-
return void 0;
|
|
3354
|
-
}
|
|
3355
|
-
}
|
|
3356
|
-
|
|
3357
|
-
// plugins/plugin-codecall/src/utils/mcp-result.ts
|
|
3358
|
-
function extractResultFromCallToolResult(mcpResult) {
|
|
3359
|
-
if (mcpResult.isError) {
|
|
3360
|
-
const errorContent = mcpResult.content?.[0];
|
|
3361
|
-
if (errorContent && "text" in errorContent) {
|
|
3362
|
-
throw new Error(errorContent.text);
|
|
3363
|
-
}
|
|
3364
|
-
throw new Error("Tool execution failed");
|
|
3365
|
-
}
|
|
3366
|
-
const content = mcpResult.content;
|
|
3367
|
-
if (!content || content.length === 0) {
|
|
3368
|
-
return void 0;
|
|
3369
|
-
}
|
|
3370
|
-
if (content.length === 1 && content[0].type === "text") {
|
|
3371
|
-
try {
|
|
3372
|
-
return JSON.parse(content[0].text);
|
|
3373
|
-
} catch {
|
|
3374
|
-
return content[0].text;
|
|
3375
|
-
}
|
|
3376
|
-
}
|
|
3377
|
-
return toPlainJson(content);
|
|
3378
|
-
}
|
|
3379
|
-
|
|
3380
|
-
// plugins/plugin-codecall/src/tools/describe.schema.ts
|
|
3381
|
-
var import_lazy_zod5 = require("@frontmcp/lazy-zod");
|
|
3382
|
-
var import_protocol = require("@frontmcp/protocol");
|
|
3383
|
-
var describeToolDescription = `Get input/output schemas for tools from search results.
|
|
67
|
+
return updated;`}}return{description:`Update ${entity}`,code:`const updated = await callTool('${toolName}', ${fieldsStr});
|
|
68
|
+
return updated;`}}function generateDeleteExample(toolName,inputSchema){const entity=extractEntityName(toolName);const idParam=findIdParameter(inputSchema);if(idParam){return{description:`Delete ${entity} by ${idParam}`,code:`const result = await callTool('${toolName}', ${formatInlineArgs(idArgs(inputSchema,idParam))});
|
|
69
|
+
return result;`}}const params=generateSampleParams(inputSchema);const paramsStr=params?JSON.stringify(params,null,2):"{ /* identifier */ }";return{description:`Delete ${entity}`,code:`const result = await callTool('${toolName}', ${paramsStr});
|
|
70
|
+
return result;`}}function generateSearchExample(toolName,inputSchema){const entity=extractEntityName(toolName);const searchParam=findQueryParameter(inputSchema)??getFilterProperties(inputSchema)[0];const searchSchema=searchParam?inputProperties(inputSchema)[searchParam]:void 0;const required=new Set(inputSchema?.required??[]);const unfillable=searchSchema?.type==="string"&&(searchSchema.pattern!==void 0||searchSchema.format!==void 0)&&searchSchema.enum===void 0&&searchSchema.const===void 0&&searchSchema.default===void 0&&!required.has(searchParam??"");const args=searchParam&&!unfillable?buildExampleArgs(inputSchema,[searchParam],isFreeTextString(searchSchema)&&searchSchema?{[searchParam]:fitString(searchSchema,"search term")}:{}):buildExampleArgs(inputSchema,[]);return{description:`Search for ${entity}s`,code:`const results = await callTool('${toolName}', ${formatExampleArgs(args)});
|
|
71
|
+
return results.items || results;`}}function findIdParameter(schema){if(!schema||schema.type!=="object"||!schema.properties){return null}const props=Object.keys(schema.properties);const required=new Set(schema.required||[]);const idPatterns=["id","Id","ID","_id","uuid","key"];for(const pattern of idPatterns){const found=props.find(p=>(p===pattern||p.endsWith(pattern))&&required.has(p));if(found)return found}for(const pattern of idPatterns){const found=props.find(p=>p===pattern||p.endsWith(pattern));if(found)return found}return null}function findQueryParameter(schema){if(!schema||schema.type!=="object"||!schema.properties){return null}const props=Object.keys(schema.properties);const queryPatterns=["query","search","q","term","keyword","filter"];for(const pattern of queryPatterns){const found=props.find(p=>p.toLowerCase()===pattern||p.toLowerCase().includes(pattern));if(found)return found}return null}function generateUpdateFields(schema){if(!schema||schema.type!=="object"||!schema.properties){return null}const fields={};const idPatterns=["id","Id","ID","_id","uuid","key"];for(const[key,propSchema]of Object.entries(schema.properties)){if(typeof propSchema==="boolean")continue;const isIdField=idPatterns.some(p=>key===p||key.endsWith(p));if(isIdField)continue;if(Object.keys(fields).length<2){fields[key]=getSampleValue(propSchema,key)}}return Object.keys(fields).length>0?fields:null}function generateSmartExample(toolName,inputSchema,description){const intent=detectToolIntent(toolName,description);switch(intent){case"create":return generateCreateExample(toolName,inputSchema);case"get":return generateGetExample(toolName,inputSchema);case"list":return hasPaginationParams(inputSchema)?generatePaginationExample(toolName,inputSchema):generateListExample(toolName,inputSchema);case"update":return generateUpdateExample(toolName,inputSchema);case"delete":return generateDeleteExample(toolName,inputSchema);case"search":return generateSearchExample(toolName,inputSchema);default:return generateBasicExample(toolName,inputSchema)}}function toPlainJson(value){try{const serialized=JSON.stringify(value);if(serialized===void 0)return void 0;return JSON.parse(serialized)}catch{return void 0}}function extractResultFromCallToolResult(mcpResult){if(mcpResult.isError){const errorContent=mcpResult.content?.[0];if(errorContent&&"text"in errorContent){throw new Error(errorContent.text)}throw new Error("Tool execution failed")}const content=mcpResult.content;if(!content||content.length===0){return void 0}if(content.length===1&&content[0].type==="text"){try{return JSON.parse(content[0].text)}catch{return content[0].text}}return toPlainJson(content)}var import_lazy_zod5=require("@frontmcp/lazy-zod");var import_protocol=require("@frontmcp/protocol");var describeToolDescription=`Get input/output schemas for tools from search results.
|
|
3384
72
|
|
|
3385
73
|
INPUT: toolNames: string[] - tool names from search, at most the server's maxDefinitions (8 unless configured) per call
|
|
3386
74
|
OUTPUT per tool: inputSchema (JSON Schema), outputSchema (JSON Schema), usageExamples (up to 5 callTool examples)
|
|
3387
75
|
|
|
3388
76
|
IMPORTANT: If notFound array is non-empty \u2192 re-search with corrected queries.
|
|
3389
|
-
FLOW: search \u2192 describe \u2192 execute/invoke`;
|
|
3390
|
-
|
|
3391
|
-
toolNames: import_lazy_zod5.z.array(import_lazy_zod5.z.string()).min(1).superRefine((toolNames, ctx) => {
|
|
3392
|
-
const seen = /* @__PURE__ */ new Set();
|
|
3393
|
-
const duplicates = /* @__PURE__ */ new Set();
|
|
3394
|
-
for (const name of toolNames) {
|
|
3395
|
-
if (seen.has(name)) {
|
|
3396
|
-
duplicates.add(name);
|
|
3397
|
-
}
|
|
3398
|
-
seen.add(name);
|
|
3399
|
-
}
|
|
3400
|
-
if (duplicates.size > 0) {
|
|
3401
|
-
ctx.addIssue({
|
|
3402
|
-
code: import_lazy_zod5.z.ZodIssueCode.custom,
|
|
3403
|
-
message: `Duplicate tool names are not allowed: ${Array.from(duplicates).join(", ")}`
|
|
3404
|
-
});
|
|
3405
|
-
}
|
|
3406
|
-
}).describe(
|
|
3407
|
-
'Array of unique tool names (from codecall:search results) to fetch their detailed schemas and usage examples. Example: ["users:list", "billing:getInvoice"]'
|
|
3408
|
-
)
|
|
3409
|
-
};
|
|
3410
|
-
var describeToolOutputSchema = import_lazy_zod5.z.object({
|
|
3411
|
-
tools: import_lazy_zod5.z.array(
|
|
3412
|
-
import_lazy_zod5.z.object({
|
|
3413
|
-
name: import_lazy_zod5.z.string().describe("Tool name to be used in callTool() within codecall:execute scripts"),
|
|
3414
|
-
appId: import_lazy_zod5.z.string().describe("The app ID this tool belongs to"),
|
|
3415
|
-
description: import_lazy_zod5.z.string().describe("Detailed description of what this tool does"),
|
|
3416
|
-
inputSchema: import_lazy_zod5.z.record(import_lazy_zod5.z.string(), import_lazy_zod5.z.unknown()).nullable().describe("JSON Schema object describing the tool input parameters"),
|
|
3417
|
-
outputSchema: import_lazy_zod5.z.record(import_lazy_zod5.z.string(), import_lazy_zod5.z.unknown()).nullable().describe("JSON Schema object describing the tool output structure"),
|
|
3418
|
-
annotations: import_protocol.ToolAnnotationsSchema.optional().describe("MCP tool annotations (metadata)"),
|
|
3419
|
-
usageExamples: import_lazy_zod5.z.array(
|
|
3420
|
-
import_lazy_zod5.z.object({
|
|
3421
|
-
description: import_lazy_zod5.z.string().describe("Description of what this example demonstrates"),
|
|
3422
|
-
code: import_lazy_zod5.z.string().describe(
|
|
3423
|
-
'JavaScript code example showing how to call this tool using callTool(). Format: const result = await callTool("tool:name", { ...params });'
|
|
3424
|
-
)
|
|
3425
|
-
})
|
|
3426
|
-
).max(5).describe("Up to 5 practical examples of how to use this tool in a codecall:execute script")
|
|
3427
|
-
})
|
|
3428
|
-
).describe("Array of tool descriptions with schemas and usage examples"),
|
|
3429
|
-
notFound: import_lazy_zod5.z.array(import_lazy_zod5.z.string()).optional().describe("Tool names that were requested but not found in the index. Check these for typos.")
|
|
3430
|
-
});
|
|
3431
|
-
|
|
3432
|
-
// plugins/plugin-codecall/src/tools/describe.tool.ts
|
|
3433
|
-
var DescribeTool = class extends import_sdk8.ToolContext {
|
|
3434
|
-
async execute(input) {
|
|
3435
|
-
const { toolNames } = input;
|
|
3436
|
-
const audit = this.tryGet(AuditLoggerService);
|
|
3437
|
-
const executionId = audit ? audit.generateExecutionId() : "";
|
|
3438
|
-
const startedAt = Date.now();
|
|
3439
|
-
const config = this.get(CodeCallConfig);
|
|
3440
|
-
const maxDefinitions = config.get("maxDefinitions");
|
|
3441
|
-
const tools = [];
|
|
3442
|
-
const notFound = [];
|
|
3443
|
-
const surface = (0, import_sdk8.getCallSurface)();
|
|
3444
|
-
for (const toolName of toolNames) {
|
|
3445
|
-
if (isBlockedSelfReference(toolName)) {
|
|
3446
|
-
notFound.push(toolName);
|
|
3447
|
-
continue;
|
|
3448
|
-
}
|
|
3449
|
-
const access = checkCodeCallToolAccess(this.scope, config, toolName, { surface });
|
|
3450
|
-
if (!access.allowed) {
|
|
3451
|
-
audit?.logSecurityAccessDenied(executionId, toolName, access.reason);
|
|
3452
|
-
notFound.push(toolName);
|
|
3453
|
-
continue;
|
|
3454
|
-
}
|
|
3455
|
-
const tool = access.entry;
|
|
3456
|
-
if (tools.length >= maxDefinitions) {
|
|
3457
|
-
throw new import_sdk8.InvalidInputError(
|
|
3458
|
-
`codecall:describe describes at most ${maxDefinitions} tools per call; describe the rest in another call`
|
|
3459
|
-
);
|
|
3460
|
-
}
|
|
3461
|
-
const appId = this.extractAppId(tool);
|
|
3462
|
-
const inputSchema = this.getInputSchema(tool);
|
|
3463
|
-
const outputSchema = this.toJsonSchema(tool.rawOutputSchema ?? tool.outputSchema);
|
|
3464
|
-
const usageExamples = this.generateExamples(tool, inputSchema ?? void 0);
|
|
3465
|
-
tools.push({
|
|
3466
|
-
name: tool.name,
|
|
3467
|
-
appId,
|
|
3468
|
-
description: tool.metadata?.description || `Tool: ${tool.name}`,
|
|
3469
|
-
inputSchema: inputSchema || null,
|
|
3470
|
-
outputSchema: outputSchema || null,
|
|
3471
|
-
annotations: tool.metadata?.annotations,
|
|
3472
|
-
usageExamples
|
|
3473
|
-
});
|
|
3474
|
-
}
|
|
3475
|
-
audit?.logDescribe(executionId, toolNames, Date.now() - startedAt);
|
|
3476
|
-
return {
|
|
3477
|
-
tools,
|
|
3478
|
-
notFound: notFound.length > 0 ? notFound : void 0
|
|
3479
|
-
};
|
|
3480
|
-
}
|
|
3481
|
-
/**
|
|
3482
|
-
* Get the input schema for a tool, converting from Zod to JSON Schema.
|
|
3483
|
-
* This ensures that property descriptions from .describe() are included.
|
|
3484
|
-
*
|
|
3485
|
-
* Priority:
|
|
3486
|
-
* 1. Convert from tool.inputSchema (Zod) to get descriptions
|
|
3487
|
-
* 2. Fall back to rawInputSchema if conversion fails
|
|
3488
|
-
* 3. Return null if no schema available
|
|
3489
|
-
*/
|
|
3490
|
-
getInputSchema(tool) {
|
|
3491
|
-
if (tool.inputSchema && typeof tool.inputSchema === "object" && Object.keys(tool.inputSchema).length > 0) {
|
|
3492
|
-
try {
|
|
3493
|
-
const firstValue = Object.values(tool.inputSchema)[0];
|
|
3494
|
-
if (firstValue instanceof import_lazy_zod6.ZodType) {
|
|
3495
|
-
return (0, import_lazy_zod6.toJSONSchema)(import_lazy_zod6.z.object(tool.inputSchema));
|
|
3496
|
-
}
|
|
3497
|
-
} catch {
|
|
3498
|
-
}
|
|
3499
|
-
}
|
|
3500
|
-
if (tool.rawInputSchema) {
|
|
3501
|
-
return tool.rawInputSchema;
|
|
3502
|
-
}
|
|
3503
|
-
return null;
|
|
3504
|
-
}
|
|
3505
|
-
/**
|
|
3506
|
-
* Convert a schema to JSON Schema format.
|
|
3507
|
-
* Handles Zod schemas, raw shapes, and already-JSON-Schema objects.
|
|
3508
|
-
*
|
|
3509
|
-
* Uses Zod v4's built-in z.toJSONSchema() for conversion.
|
|
3510
|
-
*/
|
|
3511
|
-
toJsonSchema(schema) {
|
|
3512
|
-
if (!schema) {
|
|
3513
|
-
return null;
|
|
3514
|
-
}
|
|
3515
|
-
if (schema instanceof import_lazy_zod6.ZodType) {
|
|
3516
|
-
try {
|
|
3517
|
-
return (0, import_lazy_zod6.toJSONSchema)(schema);
|
|
3518
|
-
} catch {
|
|
3519
|
-
return null;
|
|
3520
|
-
}
|
|
3521
|
-
}
|
|
3522
|
-
if (typeof schema === "object" && schema !== null && !Array.isArray(schema)) {
|
|
3523
|
-
const obj = schema;
|
|
3524
|
-
const firstValue = Object.values(obj)[0];
|
|
3525
|
-
if (firstValue instanceof import_lazy_zod6.ZodType) {
|
|
3526
|
-
try {
|
|
3527
|
-
return (0, import_lazy_zod6.toJSONSchema)(import_lazy_zod6.z.object(obj));
|
|
3528
|
-
} catch {
|
|
3529
|
-
return null;
|
|
3530
|
-
}
|
|
3531
|
-
}
|
|
3532
|
-
if ("type" in obj || "properties" in obj || "$schema" in obj) {
|
|
3533
|
-
return schema;
|
|
3534
|
-
}
|
|
3535
|
-
}
|
|
3536
|
-
if (typeof schema === "string") {
|
|
3537
|
-
return null;
|
|
3538
|
-
}
|
|
3539
|
-
if (Array.isArray(schema)) {
|
|
3540
|
-
return null;
|
|
3541
|
-
}
|
|
3542
|
-
return null;
|
|
3543
|
-
}
|
|
3544
|
-
/**
|
|
3545
|
-
* Extract app ID from tool metadata or owner.
|
|
3546
|
-
*/
|
|
3547
|
-
extractAppId(tool) {
|
|
3548
|
-
if (tool.metadata?.codecall?.appId) {
|
|
3549
|
-
return tool.metadata.codecall.appId;
|
|
3550
|
-
}
|
|
3551
|
-
if (tool.metadata?.source) {
|
|
3552
|
-
return tool.metadata.source;
|
|
3553
|
-
}
|
|
3554
|
-
if (tool.owner?.id) {
|
|
3555
|
-
return tool.owner.id;
|
|
3556
|
-
}
|
|
3557
|
-
const nameParts = tool.name?.split(":");
|
|
3558
|
-
if (nameParts && nameParts.length > 1) {
|
|
3559
|
-
return nameParts[0];
|
|
3560
|
-
}
|
|
3561
|
-
return "unknown";
|
|
3562
|
-
}
|
|
3563
|
-
/**
|
|
3564
|
-
* Generate up to 5 usage examples for a tool.
|
|
3565
|
-
*
|
|
3566
|
-
* Priority:
|
|
3567
|
-
* 1. User-provided examples from @Tool decorator metadata (up to 5)
|
|
3568
|
-
* 2. Without any, one smart intent-based example built from the input schema. It is never added
|
|
3569
|
-
* next to the tool's own examples: those show how the tool is called, and a generated one
|
|
3570
|
-
* only guesses (#647).
|
|
3571
|
-
* 3. Returns at least 1 example
|
|
3572
|
-
*/
|
|
3573
|
-
generateExamples(tool, inputSchema) {
|
|
3574
|
-
const result = [];
|
|
3575
|
-
const examples = tool.metadata?.examples;
|
|
3576
|
-
if (examples && Array.isArray(examples)) {
|
|
3577
|
-
for (const ex of examples.slice(0, 5)) {
|
|
3578
|
-
result.push({
|
|
3579
|
-
description: ex.description || "Example usage",
|
|
3580
|
-
code: `const result = await callTool('${tool.name}', ${JSON.stringify(ex.input, null, 2)});
|
|
3581
|
-
return result;`
|
|
3582
|
-
});
|
|
3583
|
-
}
|
|
3584
|
-
}
|
|
3585
|
-
if (result.length === 0) {
|
|
3586
|
-
result.push(generateSmartExample(tool.name, inputSchema, tool.metadata?.description));
|
|
3587
|
-
}
|
|
3588
|
-
return result.slice(0, 5);
|
|
3589
|
-
}
|
|
3590
|
-
};
|
|
3591
|
-
DescribeTool = __decorateClass([
|
|
3592
|
-
(0, import_sdk8.Tool)({
|
|
3593
|
-
name: "codecall:describe",
|
|
3594
|
-
cache: {
|
|
3595
|
-
ttl: 60,
|
|
3596
|
-
// 1 minute
|
|
3597
|
-
slideWindow: false
|
|
3598
|
-
},
|
|
3599
|
-
codecall: {
|
|
3600
|
-
enabledInCodeCall: false,
|
|
3601
|
-
visibleInListTools: true
|
|
3602
|
-
},
|
|
3603
|
-
description: describeToolDescription,
|
|
3604
|
-
inputSchema: describeToolInputSchema,
|
|
3605
|
-
outputSchema: describeToolOutputSchema,
|
|
3606
|
-
annotations: {
|
|
3607
|
-
readOnlyHint: true,
|
|
3608
|
-
openWorldHint: true
|
|
3609
|
-
}
|
|
3610
|
-
})
|
|
3611
|
-
], DescribeTool);
|
|
3612
|
-
|
|
3613
|
-
// plugins/plugin-codecall/src/tools/execute.tool.ts
|
|
3614
|
-
var import_sdk9 = require("@frontmcp/sdk");
|
|
3615
|
-
|
|
3616
|
-
// plugins/plugin-codecall/src/tools/execute.schema.ts
|
|
3617
|
-
var import_lazy_zod7 = require("@frontmcp/lazy-zod");
|
|
3618
|
-
var MIN_EXECUTE_SCRIPT_LENGTH = 'return callTool("a",{})'.length;
|
|
3619
|
-
var ALWAYS_BLOCKED_NAMES = ["eval", "require", "fetch", "setTimeout", "process", "globalThis"];
|
|
3620
|
-
function buildExecuteToolDescription(vmOptions) {
|
|
3621
|
-
const loops = vmOptions.allowLoops ? "for, for-of" : "for-of";
|
|
3622
|
-
const blockedLoops = vmOptions.allowLoops ? "while, do-while" : "while, do-while, for";
|
|
3623
|
-
const blockedNames = /* @__PURE__ */ new Set([...ALWAYS_BLOCKED_NAMES, ...vmOptions.disabledBuiltins, ...vmOptions.disabledGlobals]);
|
|
3624
|
-
const namespaces = ["Math", "JSON"].filter((name) => !blockedNames.has(name)).map((name) => `${name}.*, `);
|
|
3625
|
-
const timeoutSeconds = vmOptions.timeoutMs / 1e3;
|
|
3626
|
-
const maxToolCalls = maxToolCallsOf(vmOptions);
|
|
3627
|
-
const callsPerTool = rapidEnumerationThresholdOf(vmOptions);
|
|
3628
|
-
return `Execute AgentScript (safe JS subset) for multi-tool orchestration.
|
|
77
|
+
FLOW: search \u2192 describe \u2192 execute/invoke`;var describeToolInputSchema={toolNames:import_lazy_zod5.z.array(import_lazy_zod5.z.string()).min(1).superRefine((toolNames,ctx)=>{const seen=new Set;const duplicates=new Set;for(const name of toolNames){if(seen.has(name)){duplicates.add(name)}seen.add(name)}if(duplicates.size>0){ctx.addIssue({code:import_lazy_zod5.z.ZodIssueCode.custom,message:`Duplicate tool names are not allowed: ${Array.from(duplicates).join(", ")}`})}}).describe('Array of unique tool names (from codecall:search results) to fetch their detailed schemas and usage examples. Example: ["users:list", "billing:getInvoice"]')};var describeToolOutputSchema=import_lazy_zod5.z.object({tools:import_lazy_zod5.z.array(import_lazy_zod5.z.object({name:import_lazy_zod5.z.string().describe("Tool name to be used in callTool() within codecall:execute scripts"),appId:import_lazy_zod5.z.string().describe("The app ID this tool belongs to"),description:import_lazy_zod5.z.string().describe("Detailed description of what this tool does"),inputSchema:import_lazy_zod5.z.record(import_lazy_zod5.z.string(),import_lazy_zod5.z.unknown()).nullable().describe("JSON Schema object describing the tool input parameters"),outputSchema:import_lazy_zod5.z.record(import_lazy_zod5.z.string(),import_lazy_zod5.z.unknown()).nullable().describe("JSON Schema object describing the tool output structure"),annotations:import_protocol.ToolAnnotationsSchema.optional().describe("MCP tool annotations (metadata)"),usageExamples:import_lazy_zod5.z.array(import_lazy_zod5.z.object({description:import_lazy_zod5.z.string().describe("Description of what this example demonstrates"),code:import_lazy_zod5.z.string().describe('JavaScript code example showing how to call this tool using callTool(). Format: const result = await callTool("tool:name", { ...params });')})).max(5).describe("Up to 5 practical examples of how to use this tool in a codecall:execute script")})).describe("Array of tool descriptions with schemas and usage examples"),notFound:import_lazy_zod5.z.array(import_lazy_zod5.z.string()).optional().describe("Tool names that were requested but not found in the index. Check these for typos.")});var DescribeTool=class extends import_sdk8.ToolContext{async execute(input){const{toolNames}=input;const audit=this.tryGet(AuditLoggerService);const executionId=audit?audit.generateExecutionId():"";const startedAt=Date.now();const config=this.get(CodeCallConfig);const maxDefinitions=config.get("maxDefinitions");const tools=[];const notFound=[];const surface=(0,import_sdk8.getCallSurface)();for(const toolName of toolNames){if(isBlockedSelfReference(toolName)){notFound.push(toolName);continue}const access=checkCodeCallToolAccess(this.scope,config,toolName,{surface});if(!access.allowed){audit?.logSecurityAccessDenied(executionId,toolName,access.reason);notFound.push(toolName);continue}const tool=access.entry;if(tools.length>=maxDefinitions){throw new import_sdk8.InvalidInputError(`codecall:describe describes at most ${maxDefinitions} tools per call; describe the rest in another call`)}const appId=this.extractAppId(tool);const inputSchema=this.getInputSchema(tool);const outputSchema=this.toJsonSchema(tool.rawOutputSchema??tool.outputSchema);const usageExamples=this.generateExamples(tool,inputSchema??void 0);tools.push({name:tool.name,appId,description:tool.metadata?.description||`Tool: ${tool.name}`,inputSchema:inputSchema||null,outputSchema:outputSchema||null,annotations:tool.metadata?.annotations,usageExamples})}audit?.logDescribe(executionId,toolNames,Date.now()-startedAt);return{tools,notFound:notFound.length>0?notFound:void 0}}getInputSchema(tool){if(tool.inputSchema&&typeof tool.inputSchema==="object"&&Object.keys(tool.inputSchema).length>0){try{const firstValue=Object.values(tool.inputSchema)[0];if(firstValue instanceof import_lazy_zod6.ZodType){return(0,import_lazy_zod6.toJSONSchema)(import_lazy_zod6.z.object(tool.inputSchema))}}catch{}}if(tool.rawInputSchema){return tool.rawInputSchema}return null}toJsonSchema(schema){if(!schema){return null}if(schema instanceof import_lazy_zod6.ZodType){try{return(0,import_lazy_zod6.toJSONSchema)(schema)}catch{return null}}if(typeof schema==="object"&&schema!==null&&!Array.isArray(schema)){const obj=schema;const firstValue=Object.values(obj)[0];if(firstValue instanceof import_lazy_zod6.ZodType){try{return(0,import_lazy_zod6.toJSONSchema)(import_lazy_zod6.z.object(obj))}catch{return null}}if("type"in obj||"properties"in obj||"$schema"in obj){return schema}}if(typeof schema==="string"){return null}if(Array.isArray(schema)){return null}return null}extractAppId(tool){if(tool.metadata?.codecall?.appId){return tool.metadata.codecall.appId}if(tool.metadata?.source){return tool.metadata.source}if(tool.owner?.id){return tool.owner.id}const nameParts=tool.name?.split(":");if(nameParts&&nameParts.length>1){return nameParts[0]}return"unknown"}generateExamples(tool,inputSchema){const result=[];const examples=tool.metadata?.examples;if(examples&&Array.isArray(examples)){for(const ex of examples.slice(0,5)){result.push({description:ex.description||"Example usage",code:`const result = await callTool('${tool.name}', ${JSON.stringify(ex.input,null,2)});
|
|
78
|
+
return result;`})}}if(result.length===0){result.push(generateSmartExample(tool.name,inputSchema,tool.metadata?.description))}return result.slice(0,5)}};DescribeTool=__decorateClass([(0,import_sdk8.Tool)({name:"codecall:describe",cache:{ttl:60,slideWindow:false},codecall:{enabledInCodeCall:false,visibleInListTools:true},description:describeToolDescription,inputSchema:describeToolInputSchema,outputSchema:describeToolOutputSchema,annotations:{readOnlyHint:true,openWorldHint:true}})],DescribeTool);var import_sdk9=require("@frontmcp/sdk");var import_lazy_zod7=require("@frontmcp/lazy-zod");var MIN_EXECUTE_SCRIPT_LENGTH='return callTool("a",{})'.length;var ALWAYS_BLOCKED_NAMES=["eval","require","fetch","setTimeout","process","globalThis"];function buildExecuteToolDescription(vmOptions){const loops=vmOptions.allowLoops?"for, for-of":"for-of";const blockedLoops=vmOptions.allowLoops?"while, do-while":"while, do-while, for";const blockedNames=new Set([...ALWAYS_BLOCKED_NAMES,...vmOptions.disabledBuiltins,...vmOptions.disabledGlobals]);const namespaces=["Math","JSON"].filter(name=>!blockedNames.has(name)).map(name=>`${name}.*, `);const timeoutSeconds=vmOptions.timeoutMs/1e3;const maxToolCalls=maxToolCallsOf(vmOptions);const callsPerTool=rapidEnumerationThresholdOf(vmOptions);return`Execute AgentScript (safe JS subset) for multi-tool orchestration.
|
|
3629
79
|
|
|
3630
80
|
API: await callTool(name, args, opts?)
|
|
3631
81
|
- Default: throws on error
|
|
@@ -3645,377 +95,7 @@ BLOCKED: ${blockedLoops}, console (use mcpLog), function decl, ${[...blockedName
|
|
|
3645
95
|
|
|
3646
96
|
ERRORS: NOT_FOUND | VALIDATION | EXECUTION | TIMEOUT | ACCESS_DENIED | RATE_LIMITED
|
|
3647
97
|
STATUS: ok | syntax_error | illegal_access | runtime_error | tool_error | timeout
|
|
3648
|
-
LIMITS: ${MAX_ITERATIONS_PER_LOOP} iterations per loop, ${timeoutSeconds}s timeout, ${maxToolCalls} tool calls, ${callsPerTool} calls to one tool per 2s (parallel() included)`;
|
|
3649
|
-
}
|
|
3650
|
-
var executeToolDescription = buildExecuteToolDescription(resolveVmOptions());
|
|
3651
|
-
var executeToolInputSchema = {
|
|
3652
|
-
script: import_lazy_zod7.z.string().min(MIN_EXECUTE_SCRIPT_LENGTH).max(100 * 1024).describe(
|
|
3653
|
-
"JavaScript code to execute in the sandbox. Must return a value (implicitly or via explicit return). Use callTool(name, input) to invoke tools."
|
|
3654
|
-
),
|
|
3655
|
-
allowedTools: import_lazy_zod7.z.array(import_lazy_zod7.z.string()).optional().describe(
|
|
3656
|
-
'Optional whitelist of tool names that can be called from this script. If not provided, all indexed tools are available. Example: ["users:list", "billing:getInvoice"]'
|
|
3657
|
-
)
|
|
3658
|
-
};
|
|
3659
|
-
var syntaxErrorPayloadSchema = import_lazy_zod7.z.object({
|
|
3660
|
-
message: import_lazy_zod7.z.string(),
|
|
3661
|
-
location: import_lazy_zod7.z.object({
|
|
3662
|
-
line: import_lazy_zod7.z.number(),
|
|
3663
|
-
column: import_lazy_zod7.z.number()
|
|
3664
|
-
}).optional()
|
|
3665
|
-
});
|
|
3666
|
-
var illegalAccessErrorPayloadSchema = import_lazy_zod7.z.object({
|
|
3667
|
-
message: import_lazy_zod7.z.string(),
|
|
3668
|
-
kind: import_lazy_zod7.z.union([
|
|
3669
|
-
import_lazy_zod7.z.literal("IllegalBuiltinAccess"),
|
|
3670
|
-
import_lazy_zod7.z.literal("DisallowedGlobal"),
|
|
3671
|
-
import_lazy_zod7.z.string()
|
|
3672
|
-
// same as your original type: 'A' | 'B' | string
|
|
3673
|
-
])
|
|
3674
|
-
});
|
|
3675
|
-
var runtimeErrorPayloadSchema = import_lazy_zod7.z.object({
|
|
3676
|
-
source: import_lazy_zod7.z.literal("script"),
|
|
3677
|
-
message: import_lazy_zod7.z.string(),
|
|
3678
|
-
name: import_lazy_zod7.z.string().optional(),
|
|
3679
|
-
/** @deprecated Never set: stack traces name server files, so results don't carry them. */
|
|
3680
|
-
stack: import_lazy_zod7.z.string().optional()
|
|
3681
|
-
});
|
|
3682
|
-
var toolErrorPayloadSchema = import_lazy_zod7.z.object({
|
|
3683
|
-
source: import_lazy_zod7.z.literal("tool"),
|
|
3684
|
-
toolName: import_lazy_zod7.z.string(),
|
|
3685
|
-
/**
|
|
3686
|
-
* @deprecated Never set: the sandbox resolves sidecar references in a call's arguments before
|
|
3687
|
-
* the tool sees them, so they may hold data the script itself never had.
|
|
3688
|
-
*/
|
|
3689
|
-
toolInput: import_lazy_zod7.z.unknown().optional(),
|
|
3690
|
-
message: import_lazy_zod7.z.string(),
|
|
3691
|
-
code: import_lazy_zod7.z.string().optional(),
|
|
3692
|
-
/** @deprecated Never set: the enclave's error data is not sanitized for clients. */
|
|
3693
|
-
details: import_lazy_zod7.z.unknown().optional()
|
|
3694
|
-
});
|
|
3695
|
-
var timeoutErrorPayloadSchema = import_lazy_zod7.z.object({
|
|
3696
|
-
message: import_lazy_zod7.z.string()
|
|
3697
|
-
});
|
|
3698
|
-
var codeCallOkResultSchema = import_lazy_zod7.z.object({
|
|
3699
|
-
status: import_lazy_zod7.z.literal("ok"),
|
|
3700
|
-
result: import_lazy_zod7.z.unknown(),
|
|
3701
|
-
logs: import_lazy_zod7.z.array(import_lazy_zod7.z.string()).optional()
|
|
3702
|
-
});
|
|
3703
|
-
var codeCallSyntaxErrorResultSchema = import_lazy_zod7.z.object({
|
|
3704
|
-
status: import_lazy_zod7.z.literal("syntax_error"),
|
|
3705
|
-
error: syntaxErrorPayloadSchema
|
|
3706
|
-
});
|
|
3707
|
-
var codeCallIllegalAccessResultSchema = import_lazy_zod7.z.object({
|
|
3708
|
-
status: import_lazy_zod7.z.literal("illegal_access"),
|
|
3709
|
-
error: illegalAccessErrorPayloadSchema
|
|
3710
|
-
});
|
|
3711
|
-
var codeCallRuntimeErrorResultSchema = import_lazy_zod7.z.object({
|
|
3712
|
-
status: import_lazy_zod7.z.literal("runtime_error"),
|
|
3713
|
-
error: runtimeErrorPayloadSchema
|
|
3714
|
-
});
|
|
3715
|
-
var codeCallToolErrorResultSchema = import_lazy_zod7.z.object({
|
|
3716
|
-
status: import_lazy_zod7.z.literal("tool_error"),
|
|
3717
|
-
error: toolErrorPayloadSchema
|
|
3718
|
-
});
|
|
3719
|
-
var codeCallTimeoutResultSchema = import_lazy_zod7.z.object({
|
|
3720
|
-
status: import_lazy_zod7.z.literal("timeout"),
|
|
3721
|
-
error: timeoutErrorPayloadSchema
|
|
3722
|
-
});
|
|
3723
|
-
var executeToolOutputSchema = import_lazy_zod7.z.discriminatedUnion("status", [
|
|
3724
|
-
codeCallOkResultSchema,
|
|
3725
|
-
codeCallSyntaxErrorResultSchema,
|
|
3726
|
-
codeCallIllegalAccessResultSchema,
|
|
3727
|
-
codeCallRuntimeErrorResultSchema,
|
|
3728
|
-
codeCallToolErrorResultSchema,
|
|
3729
|
-
codeCallTimeoutResultSchema
|
|
3730
|
-
]);
|
|
3731
|
-
|
|
3732
|
-
// plugins/plugin-codecall/src/tools/execute.tool.ts
|
|
3733
|
-
function getErrorCode(error) {
|
|
3734
|
-
if (!(error instanceof Error)) {
|
|
3735
|
-
return TOOL_CALL_ERROR_CODES.EXECUTION;
|
|
3736
|
-
}
|
|
3737
|
-
const { code, statusCode } = error;
|
|
3738
|
-
if (code === "INVALID_INPUT") {
|
|
3739
|
-
return TOOL_CALL_ERROR_CODES.VALIDATION;
|
|
3740
|
-
}
|
|
3741
|
-
if (statusCode === 429) {
|
|
3742
|
-
return TOOL_CALL_ERROR_CODES.RATE_LIMITED;
|
|
3743
|
-
}
|
|
3744
|
-
if (error.name === "ZodError" || error.message?.includes("validation")) {
|
|
3745
|
-
return TOOL_CALL_ERROR_CODES.VALIDATION;
|
|
3746
|
-
}
|
|
3747
|
-
if (error.message?.includes("timeout") || error.message?.includes("timed out")) {
|
|
3748
|
-
return TOOL_CALL_ERROR_CODES.TIMEOUT;
|
|
3749
|
-
}
|
|
3750
|
-
if (error.name === "ToolNotFoundError" || error.message?.includes("not found")) {
|
|
3751
|
-
return TOOL_CALL_ERROR_CODES.NOT_FOUND;
|
|
3752
|
-
}
|
|
3753
|
-
return TOOL_CALL_ERROR_CODES.EXECUTION;
|
|
3754
|
-
}
|
|
3755
|
-
function publicMessageOf(error) {
|
|
3756
|
-
const { getPublicMessage } = error;
|
|
3757
|
-
return typeof getPublicMessage === "function" ? getPublicMessage.call(error) : error.message;
|
|
3758
|
-
}
|
|
3759
|
-
var ExecuteTool = class extends import_sdk9.ToolContext {
|
|
3760
|
-
/**
|
|
3761
|
-
* Resolve the server-side CodeCall policy for a tool name (GHSA-6w3j-82v5-6qrr).
|
|
3762
|
-
*
|
|
3763
|
-
* Shares its decision with discovery and with `codecall:invoke`, so the three cannot
|
|
3764
|
-
* diverge. A name matching no registered tool is denied rather than passed through —
|
|
3765
|
-
* otherwise it would skip every metadata-driven check and reach `tools:call-tool`
|
|
3766
|
-
* unexamined.
|
|
3767
|
-
*/
|
|
3768
|
-
checkToolPolicy(name, surface) {
|
|
3769
|
-
return checkCodeCallToolAccess(this.scope, this.get(CodeCallConfig), name, { surface });
|
|
3770
|
-
}
|
|
3771
|
-
async execute(input) {
|
|
3772
|
-
const { script, allowedTools } = input;
|
|
3773
|
-
const callerSurface = (0, import_sdk9.getCallSurface)();
|
|
3774
|
-
const audit = this.tryGet(AuditLoggerService);
|
|
3775
|
-
const executionId = audit ? audit.generateExecutionId() : "";
|
|
3776
|
-
const callDepth = 1;
|
|
3777
|
-
let toolCallCount = 0;
|
|
3778
|
-
const allowedToolSet = allowedTools ? new Set(allowedTools) : null;
|
|
3779
|
-
const environment = {
|
|
3780
|
-
callTool: async (name, toolInput, options) => {
|
|
3781
|
-
const throwOnError = options?.throwOnError !== false;
|
|
3782
|
-
if (isBlockedSelfReference(name)) {
|
|
3783
|
-
audit?.logSecuritySelfReference(executionId, name);
|
|
3784
|
-
}
|
|
3785
|
-
assertNotSelfReference(name);
|
|
3786
|
-
const decision = this.checkToolPolicy(name, callerSurface);
|
|
3787
|
-
if (!decision.allowed) {
|
|
3788
|
-
audit?.logSecurityAccessDenied(executionId, name, decision.reason);
|
|
3789
|
-
const error = createToolCallError(TOOL_CALL_ERROR_CODES.ACCESS_DENIED, name, decision.reason);
|
|
3790
|
-
if (throwOnError) {
|
|
3791
|
-
throw error;
|
|
3792
|
-
}
|
|
3793
|
-
return { success: false, error };
|
|
3794
|
-
}
|
|
3795
|
-
if (allowedToolSet && !allowedToolSet.has(name)) {
|
|
3796
|
-
audit?.logSecurityAccessDenied(executionId, name, "not in the caller-supplied allowedTools list");
|
|
3797
|
-
const error = createToolCallError(TOOL_CALL_ERROR_CODES.ACCESS_DENIED, name);
|
|
3798
|
-
if (throwOnError) {
|
|
3799
|
-
throw error;
|
|
3800
|
-
}
|
|
3801
|
-
return { success: false, error };
|
|
3802
|
-
}
|
|
3803
|
-
toolCallCount += 1;
|
|
3804
|
-
audit?.logToolCallStart(executionId, name, callDepth);
|
|
3805
|
-
const toolCallStartedAt = Date.now();
|
|
3806
|
-
try {
|
|
3807
|
-
const request = {
|
|
3808
|
-
method: "tools/call",
|
|
3809
|
-
params: {
|
|
3810
|
-
name,
|
|
3811
|
-
arguments: toolInput
|
|
3812
|
-
}
|
|
3813
|
-
};
|
|
3814
|
-
const ctx = asCodeCallDispatch({
|
|
3815
|
-
authInfo: this.authInfo,
|
|
3816
|
-
surface: callerSurface
|
|
3817
|
-
});
|
|
3818
|
-
const mcpResult = await this.scope.runFlow("tools:call-tool", { request, ctx });
|
|
3819
|
-
if (!mcpResult) {
|
|
3820
|
-
audit?.logToolCallFailure(
|
|
3821
|
-
executionId,
|
|
3822
|
-
name,
|
|
3823
|
-
callDepth,
|
|
3824
|
-
Date.now() - toolCallStartedAt,
|
|
3825
|
-
TOOL_CALL_ERROR_CODES.EXECUTION
|
|
3826
|
-
);
|
|
3827
|
-
const error = createToolCallError(TOOL_CALL_ERROR_CODES.EXECUTION, name, "Flow returned no result");
|
|
3828
|
-
if (throwOnError) {
|
|
3829
|
-
throw error;
|
|
3830
|
-
}
|
|
3831
|
-
return { success: false, error };
|
|
3832
|
-
}
|
|
3833
|
-
const result = extractResultFromCallToolResult(mcpResult);
|
|
3834
|
-
audit?.logToolCallSuccess(executionId, name, callDepth, Date.now() - toolCallStartedAt);
|
|
3835
|
-
if (throwOnError) {
|
|
3836
|
-
return result;
|
|
3837
|
-
}
|
|
3838
|
-
return { success: true, data: result };
|
|
3839
|
-
} catch (error) {
|
|
3840
|
-
const errorCode = getErrorCode(error);
|
|
3841
|
-
const rawMessage = error instanceof Error ? publicMessageOf(error) : void 0;
|
|
3842
|
-
audit?.logToolCallFailure(executionId, name, callDepth, Date.now() - toolCallStartedAt, errorCode);
|
|
3843
|
-
const sanitizedError = createToolCallError(errorCode, name, rawMessage);
|
|
3844
|
-
if (throwOnError) {
|
|
3845
|
-
throw sanitizedError;
|
|
3846
|
-
}
|
|
3847
|
-
return { success: false, error: sanitizedError };
|
|
3848
|
-
}
|
|
3849
|
-
},
|
|
3850
|
-
getTool: (name) => {
|
|
3851
|
-
try {
|
|
3852
|
-
if (isBlockedSelfReference(name)) {
|
|
3853
|
-
audit?.logSecuritySelfReference(executionId, name);
|
|
3854
|
-
return void 0;
|
|
3855
|
-
}
|
|
3856
|
-
const introspectionAccess = this.checkToolPolicy(name, callerSurface);
|
|
3857
|
-
if (!introspectionAccess.allowed) {
|
|
3858
|
-
audit?.logSecurityAccessDenied(executionId, name, introspectionAccess.reason);
|
|
3859
|
-
return void 0;
|
|
3860
|
-
}
|
|
3861
|
-
if (allowedToolSet && !allowedToolSet.has(name)) return void 0;
|
|
3862
|
-
const tool = introspectionAccess.entry;
|
|
3863
|
-
return toPlainJson({
|
|
3864
|
-
name: tool.name,
|
|
3865
|
-
description: tool.metadata?.description,
|
|
3866
|
-
inputSchema: tool.getInputJsonSchema?.() ?? null,
|
|
3867
|
-
outputSchema: tool.getOutputJsonSchema?.() ?? null
|
|
3868
|
-
});
|
|
3869
|
-
} catch {
|
|
3870
|
-
return void 0;
|
|
3871
|
-
}
|
|
3872
|
-
},
|
|
3873
|
-
console: this.get(CodeCallConfig).get("resolvedVm.allowConsole") ? console : void 0,
|
|
3874
|
-
mcpLog: (level, message, metadata) => {
|
|
3875
|
-
this.logger?.[level](message, metadata);
|
|
3876
|
-
},
|
|
3877
|
-
mcpNotify: (event, payload) => {
|
|
3878
|
-
this.logger?.debug("Notification sent", { event, payload });
|
|
3879
|
-
}
|
|
3880
|
-
};
|
|
3881
|
-
try {
|
|
3882
|
-
const policyConfig = readCodeCallPolicyConfig(this.get(CodeCallConfig));
|
|
3883
|
-
const callableTools = this.scope.tools.getTools(true).filter(
|
|
3884
|
-
(tool) => checkCodeCallToolPolicy(toCodeCallPolicyTool(tool, void 0, this.scope), policyConfig).allowed
|
|
3885
|
-
);
|
|
3886
|
-
const { namespaces, skipped } = buildToolNamespaces(callableTools);
|
|
3887
|
-
environment.toolNamespaces = namespaces;
|
|
3888
|
-
if (skipped.length > 0) {
|
|
3889
|
-
this.logger?.debug?.("codecall: tools skipped during namespace generation", {
|
|
3890
|
-
count: skipped.length,
|
|
3891
|
-
// Cap the debug payload so a huge skip list doesn't bloat logs.
|
|
3892
|
-
sample: skipped.slice(0, 25)
|
|
3893
|
-
});
|
|
3894
|
-
}
|
|
3895
|
-
} catch (error) {
|
|
3896
|
-
this.logger?.warn?.("codecall: failed to build tool namespaces", {
|
|
3897
|
-
error: error instanceof Error ? error.message : String(error)
|
|
3898
|
-
});
|
|
3899
|
-
}
|
|
3900
|
-
const enclaveService = this.get(EnclaveService);
|
|
3901
|
-
const config = this.get(CodeCallConfig);
|
|
3902
|
-
const startedAt = Date.now();
|
|
3903
|
-
const elapsed = (reported) => reported ?? Date.now() - startedAt;
|
|
3904
|
-
audit?.logExecutionStart(executionId, script);
|
|
3905
|
-
try {
|
|
3906
|
-
const executionResult = await enclaveService.execute(script, environment);
|
|
3907
|
-
const durationMs = elapsed(executionResult.stats?.duration);
|
|
3908
|
-
if (executionResult.timedOut) {
|
|
3909
|
-
audit?.logExecutionTimeout(executionId, script, durationMs);
|
|
3910
|
-
return {
|
|
3911
|
-
status: "timeout",
|
|
3912
|
-
error: {
|
|
3913
|
-
message: `Script execution timed out after ${config.getAll().resolvedVm.timeoutMs}ms`
|
|
3914
|
-
}
|
|
3915
|
-
};
|
|
3916
|
-
}
|
|
3917
|
-
if (!executionResult.success) {
|
|
3918
|
-
const error = executionResult.error;
|
|
3919
|
-
if (error.code === "SYNTAX_ERROR") {
|
|
3920
|
-
audit?.logExecutionFailure(executionId, script, durationMs, error.message);
|
|
3921
|
-
return {
|
|
3922
|
-
status: "syntax_error",
|
|
3923
|
-
error: {
|
|
3924
|
-
message: toClientErrorMessage(error.message) || "Syntax error in script",
|
|
3925
|
-
...error.location ? { location: error.location } : {}
|
|
3926
|
-
}
|
|
3927
|
-
};
|
|
3928
|
-
}
|
|
3929
|
-
if (error.code === "VALIDATION_ERROR" || error.name === "ValidationError") {
|
|
3930
|
-
audit?.logSecurityAstBlocked(executionId, error.blockedPatterns?.join(", ") ?? "UNKNOWN", error.message);
|
|
3931
|
-
audit?.logExecutionFailure(executionId, script, durationMs, error.message);
|
|
3932
|
-
return {
|
|
3933
|
-
status: "illegal_access",
|
|
3934
|
-
error: {
|
|
3935
|
-
kind: "IllegalBuiltinAccess",
|
|
3936
|
-
message: error.message
|
|
3937
|
-
}
|
|
3938
|
-
};
|
|
3939
|
-
}
|
|
3940
|
-
if (error.toolName) {
|
|
3941
|
-
audit?.logExecutionFailure(executionId, script, durationMs, error.message);
|
|
3942
|
-
return {
|
|
3943
|
-
status: "tool_error",
|
|
3944
|
-
error: {
|
|
3945
|
-
source: "tool",
|
|
3946
|
-
toolName: error.toolName,
|
|
3947
|
-
message: toClientErrorMessage(error.message),
|
|
3948
|
-
code: error.code
|
|
3949
|
-
// No `details`: the enclave's error data is not sanitized for clients. No `toolInput`:
|
|
3950
|
-
// the arguments the tool saw may hold sidecar-resolved data the script never had.
|
|
3951
|
-
}
|
|
3952
|
-
};
|
|
3953
|
-
}
|
|
3954
|
-
audit?.logExecutionFailure(executionId, script, durationMs, error.message);
|
|
3955
|
-
return {
|
|
3956
|
-
status: "runtime_error",
|
|
3957
|
-
error: {
|
|
3958
|
-
source: "script",
|
|
3959
|
-
message: toClientErrorMessage(error.message),
|
|
3960
|
-
name: error.name
|
|
3961
|
-
}
|
|
3962
|
-
};
|
|
3963
|
-
}
|
|
3964
|
-
audit?.logExecutionSuccess(executionId, script, durationMs, toolCallCount);
|
|
3965
|
-
return {
|
|
3966
|
-
status: "ok",
|
|
3967
|
-
result: executionResult.result,
|
|
3968
|
-
logs: executionResult.logs.length > 0 ? executionResult.logs : void 0
|
|
3969
|
-
};
|
|
3970
|
-
} catch (error) {
|
|
3971
|
-
const errorName = error instanceof Error ? error.name : "Error";
|
|
3972
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3973
|
-
audit?.logExecutionFailure(executionId, script, elapsed(), errorMessage);
|
|
3974
|
-
const errorLoc = error.loc;
|
|
3975
|
-
if (errorName === "SyntaxError" || errorMessage?.includes("syntax")) {
|
|
3976
|
-
return {
|
|
3977
|
-
status: "syntax_error",
|
|
3978
|
-
error: {
|
|
3979
|
-
message: toClientErrorMessage(errorMessage) || "Syntax error in script",
|
|
3980
|
-
location: errorLoc ? { line: errorLoc.line, column: errorLoc.column } : void 0
|
|
3981
|
-
}
|
|
3982
|
-
};
|
|
3983
|
-
}
|
|
3984
|
-
return {
|
|
3985
|
-
status: "runtime_error",
|
|
3986
|
-
error: {
|
|
3987
|
-
source: "script",
|
|
3988
|
-
message: toClientErrorMessage(errorMessage) || "An unexpected error occurred during script execution",
|
|
3989
|
-
name: errorName
|
|
3990
|
-
}
|
|
3991
|
-
};
|
|
3992
|
-
}
|
|
3993
|
-
}
|
|
3994
|
-
};
|
|
3995
|
-
ExecuteTool = __decorateClass([
|
|
3996
|
-
(0, import_sdk9.Tool)({
|
|
3997
|
-
name: "codecall:execute",
|
|
3998
|
-
cache: {
|
|
3999
|
-
ttl: 0,
|
|
4000
|
-
// No caching - each execution is unique
|
|
4001
|
-
slideWindow: false
|
|
4002
|
-
},
|
|
4003
|
-
codecall: {
|
|
4004
|
-
enabledInCodeCall: false,
|
|
4005
|
-
visibleInListTools: true
|
|
4006
|
-
},
|
|
4007
|
-
description: executeToolDescription,
|
|
4008
|
-
inputSchema: executeToolInputSchema,
|
|
4009
|
-
outputSchema: executeToolOutputSchema
|
|
4010
|
-
})
|
|
4011
|
-
], ExecuteTool);
|
|
4012
|
-
|
|
4013
|
-
// plugins/plugin-codecall/src/tools/invoke.tool.ts
|
|
4014
|
-
var import_sdk10 = require("@frontmcp/sdk");
|
|
4015
|
-
|
|
4016
|
-
// plugins/plugin-codecall/src/tools/invoke.schema.ts
|
|
4017
|
-
var import_lazy_zod8 = require("@frontmcp/lazy-zod");
|
|
4018
|
-
var invokeToolDescription = `Call ONE tool directly. Returns standard MCP CallToolResult.
|
|
98
|
+
LIMITS: ${MAX_ITERATIONS_PER_LOOP} iterations per loop, ${timeoutSeconds}s timeout, ${maxToolCalls} tool calls, ${callsPerTool} calls to one tool per 2s (parallel() included)`}var executeToolDescription=buildExecuteToolDescription(resolveVmOptions());var executeToolInputSchema={script:import_lazy_zod7.z.string().min(MIN_EXECUTE_SCRIPT_LENGTH).max(100*1024).describe("JavaScript code to execute in the sandbox. Must return a value (implicitly or via explicit return). Use callTool(name, input) to invoke tools."),allowedTools:import_lazy_zod7.z.array(import_lazy_zod7.z.string()).optional().describe('Optional whitelist of tool names that can be called from this script. If not provided, all indexed tools are available. Example: ["users:list", "billing:getInvoice"]')};var syntaxErrorPayloadSchema=import_lazy_zod7.z.object({message:import_lazy_zod7.z.string(),location:import_lazy_zod7.z.object({line:import_lazy_zod7.z.number(),column:import_lazy_zod7.z.number()}).optional()});var illegalAccessErrorPayloadSchema=import_lazy_zod7.z.object({message:import_lazy_zod7.z.string(),kind:import_lazy_zod7.z.union([import_lazy_zod7.z.literal("IllegalBuiltinAccess"),import_lazy_zod7.z.literal("DisallowedGlobal"),import_lazy_zod7.z.string()])});var runtimeErrorPayloadSchema=import_lazy_zod7.z.object({source:import_lazy_zod7.z.literal("script"),message:import_lazy_zod7.z.string(),name:import_lazy_zod7.z.string().optional(),stack:import_lazy_zod7.z.string().optional()});var toolErrorPayloadSchema=import_lazy_zod7.z.object({source:import_lazy_zod7.z.literal("tool"),toolName:import_lazy_zod7.z.string(),toolInput:import_lazy_zod7.z.unknown().optional(),message:import_lazy_zod7.z.string(),code:import_lazy_zod7.z.string().optional(),details:import_lazy_zod7.z.unknown().optional()});var timeoutErrorPayloadSchema=import_lazy_zod7.z.object({message:import_lazy_zod7.z.string()});var codeCallOkResultSchema=import_lazy_zod7.z.object({status:import_lazy_zod7.z.literal("ok"),result:import_lazy_zod7.z.unknown(),logs:import_lazy_zod7.z.array(import_lazy_zod7.z.string()).optional()});var codeCallSyntaxErrorResultSchema=import_lazy_zod7.z.object({status:import_lazy_zod7.z.literal("syntax_error"),error:syntaxErrorPayloadSchema});var codeCallIllegalAccessResultSchema=import_lazy_zod7.z.object({status:import_lazy_zod7.z.literal("illegal_access"),error:illegalAccessErrorPayloadSchema});var codeCallRuntimeErrorResultSchema=import_lazy_zod7.z.object({status:import_lazy_zod7.z.literal("runtime_error"),error:runtimeErrorPayloadSchema});var codeCallToolErrorResultSchema=import_lazy_zod7.z.object({status:import_lazy_zod7.z.literal("tool_error"),error:toolErrorPayloadSchema});var codeCallTimeoutResultSchema=import_lazy_zod7.z.object({status:import_lazy_zod7.z.literal("timeout"),error:timeoutErrorPayloadSchema});var executeToolOutputSchema=import_lazy_zod7.z.discriminatedUnion("status",[codeCallOkResultSchema,codeCallSyntaxErrorResultSchema,codeCallIllegalAccessResultSchema,codeCallRuntimeErrorResultSchema,codeCallToolErrorResultSchema,codeCallTimeoutResultSchema]);function getErrorCode(error){if(!(error instanceof Error)){return TOOL_CALL_ERROR_CODES.EXECUTION}const{code,statusCode}=error;if(code==="INVALID_INPUT"){return TOOL_CALL_ERROR_CODES.VALIDATION}if(statusCode===429){return TOOL_CALL_ERROR_CODES.RATE_LIMITED}if(error.name==="ZodError"||error.message?.includes("validation")){return TOOL_CALL_ERROR_CODES.VALIDATION}if(error.message?.includes("timeout")||error.message?.includes("timed out")){return TOOL_CALL_ERROR_CODES.TIMEOUT}if(error.name==="ToolNotFoundError"||error.message?.includes("not found")){return TOOL_CALL_ERROR_CODES.NOT_FOUND}return TOOL_CALL_ERROR_CODES.EXECUTION}function publicMessageOf(error){const{getPublicMessage}=error;return typeof getPublicMessage==="function"?getPublicMessage.call(error):error.message}var ExecuteTool=class extends import_sdk9.ToolContext{checkToolPolicy(name,surface){return checkCodeCallToolAccess(this.scope,this.get(CodeCallConfig),name,{surface})}async execute(input){const{script,allowedTools}=input;const callerSurface=(0,import_sdk9.getCallSurface)();const audit=this.tryGet(AuditLoggerService);const executionId=audit?audit.generateExecutionId():"";const callDepth=1;let toolCallCount=0;const allowedToolSet=allowedTools?new Set(allowedTools):null;const environment={callTool:async(name,toolInput,options)=>{const throwOnError=options?.throwOnError!==false;if(isBlockedSelfReference(name)){audit?.logSecuritySelfReference(executionId,name)}assertNotSelfReference(name);const decision=this.checkToolPolicy(name,callerSurface);if(!decision.allowed){audit?.logSecurityAccessDenied(executionId,name,decision.reason);const error=createToolCallError(TOOL_CALL_ERROR_CODES.ACCESS_DENIED,name,decision.reason);if(throwOnError){throw error}return{success:false,error}}if(allowedToolSet&&!allowedToolSet.has(name)){audit?.logSecurityAccessDenied(executionId,name,"not in the caller-supplied allowedTools list");const error=createToolCallError(TOOL_CALL_ERROR_CODES.ACCESS_DENIED,name);if(throwOnError){throw error}return{success:false,error}}toolCallCount+=1;audit?.logToolCallStart(executionId,name,callDepth);const toolCallStartedAt=Date.now();try{const request={method:"tools/call",params:{name,arguments:toolInput}};const ctx=asCodeCallDispatch({authInfo:this.authInfo,surface:callerSurface});const mcpResult=await this.scope.runFlow("tools:call-tool",{request,ctx});if(!mcpResult){audit?.logToolCallFailure(executionId,name,callDepth,Date.now()-toolCallStartedAt,TOOL_CALL_ERROR_CODES.EXECUTION);const error=createToolCallError(TOOL_CALL_ERROR_CODES.EXECUTION,name,"Flow returned no result");if(throwOnError){throw error}return{success:false,error}}const result=extractResultFromCallToolResult(mcpResult);audit?.logToolCallSuccess(executionId,name,callDepth,Date.now()-toolCallStartedAt);if(throwOnError){return result}return{success:true,data:result}}catch(error){const errorCode=getErrorCode(error);const rawMessage=error instanceof Error?publicMessageOf(error):void 0;audit?.logToolCallFailure(executionId,name,callDepth,Date.now()-toolCallStartedAt,errorCode);const sanitizedError=createToolCallError(errorCode,name,rawMessage);if(throwOnError){throw sanitizedError}return{success:false,error:sanitizedError}}},getTool:name=>{try{if(isBlockedSelfReference(name)){audit?.logSecuritySelfReference(executionId,name);return void 0}const introspectionAccess=this.checkToolPolicy(name,callerSurface);if(!introspectionAccess.allowed){audit?.logSecurityAccessDenied(executionId,name,introspectionAccess.reason);return void 0}if(allowedToolSet&&!allowedToolSet.has(name))return void 0;const tool=introspectionAccess.entry;return toPlainJson({name:tool.name,description:tool.metadata?.description,inputSchema:tool.getInputJsonSchema?.()??null,outputSchema:tool.getOutputJsonSchema?.()??null})}catch{return void 0}},console:this.get(CodeCallConfig).get("resolvedVm.allowConsole")?console:void 0,mcpLog:(level,message,metadata)=>{this.logger?.[level](message,metadata)},mcpNotify:(event,payload)=>{this.logger?.debug("Notification sent",{event,payload})}};try{const policyConfig=readCodeCallPolicyConfig(this.get(CodeCallConfig));const callableTools=this.scope.tools.getTools(true).filter(tool=>checkCodeCallToolPolicy(toCodeCallPolicyTool(tool,void 0,this.scope),policyConfig).allowed);const{namespaces,skipped}=buildToolNamespaces(callableTools);environment.toolNamespaces=namespaces;if(skipped.length>0){this.logger?.debug?.("codecall: tools skipped during namespace generation",{count:skipped.length,sample:skipped.slice(0,25)})}}catch(error){this.logger?.warn?.("codecall: failed to build tool namespaces",{error:error instanceof Error?error.message:String(error)})}const enclaveService=this.get(EnclaveService);const config=this.get(CodeCallConfig);const startedAt=Date.now();const elapsed=reported=>reported??Date.now()-startedAt;audit?.logExecutionStart(executionId,script);try{const executionResult=await enclaveService.execute(script,environment);const durationMs=elapsed(executionResult.stats?.duration);if(executionResult.timedOut){audit?.logExecutionTimeout(executionId,script,durationMs);return{status:"timeout",error:{message:`Script execution timed out after ${config.getAll().resolvedVm.timeoutMs}ms`}}}if(!executionResult.success){const error=executionResult.error;if(error.code==="SYNTAX_ERROR"){audit?.logExecutionFailure(executionId,script,durationMs,error.message);return{status:"syntax_error",error:{message:toClientErrorMessage(error.message)||"Syntax error in script",...error.location?{location:error.location}:{}}}}if(error.code==="VALIDATION_ERROR"||error.name==="ValidationError"){audit?.logSecurityAstBlocked(executionId,error.blockedPatterns?.join(", ")??"UNKNOWN",error.message);audit?.logExecutionFailure(executionId,script,durationMs,error.message);return{status:"illegal_access",error:{kind:"IllegalBuiltinAccess",message:error.message}}}if(error.toolName){audit?.logExecutionFailure(executionId,script,durationMs,error.message);return{status:"tool_error",error:{source:"tool",toolName:error.toolName,message:toClientErrorMessage(error.message),code:error.code}}}audit?.logExecutionFailure(executionId,script,durationMs,error.message);return{status:"runtime_error",error:{source:"script",message:toClientErrorMessage(error.message),name:error.name}}}audit?.logExecutionSuccess(executionId,script,durationMs,toolCallCount);return{status:"ok",result:executionResult.result,logs:executionResult.logs.length>0?executionResult.logs:void 0}}catch(error){const errorName=error instanceof Error?error.name:"Error";const errorMessage=error instanceof Error?error.message:String(error);audit?.logExecutionFailure(executionId,script,elapsed(),errorMessage);const errorLoc=error.loc;if(errorName==="SyntaxError"||errorMessage?.includes("syntax")){return{status:"syntax_error",error:{message:toClientErrorMessage(errorMessage)||"Syntax error in script",location:errorLoc?{line:errorLoc.line,column:errorLoc.column}:void 0}}}return{status:"runtime_error",error:{source:"script",message:toClientErrorMessage(errorMessage)||"An unexpected error occurred during script execution",name:errorName}}}}};ExecuteTool=__decorateClass([(0,import_sdk9.Tool)({name:"codecall:execute",cache:{ttl:0,slideWindow:false},codecall:{enabledInCodeCall:false,visibleInListTools:true},description:executeToolDescription,inputSchema:executeToolInputSchema,outputSchema:executeToolOutputSchema})],ExecuteTool);var import_sdk10=require("@frontmcp/sdk");var import_lazy_zod8=require("@frontmcp/lazy-zod");var invokeToolDescription=`Call ONE tool directly. Returns standard MCP CallToolResult.
|
|
4019
99
|
|
|
4020
100
|
USE invoke: single tool, no transformation
|
|
4021
101
|
USE execute: multiple tools, loops, filtering, joining
|
|
@@ -4024,304 +104,4 @@ INPUT: tool (string), input (object matching tool schema)
|
|
|
4024
104
|
OUTPUT: MCP CallToolResult (same as standard tool call)
|
|
4025
105
|
ERRORS: tool_not_found (\u2192 re-search) | validation_error | execution_error | permission_denied
|
|
4026
106
|
|
|
4027
|
-
FLOW: search \u2192 describe \u2192 invoke`;
|
|
4028
|
-
var invokeToolInputSchema = {
|
|
4029
|
-
tool: import_lazy_zod8.z.string().describe(
|
|
4030
|
-
'The name of the tool to invoke (e.g., "users:getById", "billing:getInvoice"). Must be a tool you discovered via codecall:search.'
|
|
4031
|
-
),
|
|
4032
|
-
input: import_lazy_zod8.z.record(import_lazy_zod8.z.string(), import_lazy_zod8.z.unknown()).describe(
|
|
4033
|
-
"The input parameters for the tool. Structure must match the tool's input schema (check codecall:describe for schema details)."
|
|
4034
|
-
)
|
|
4035
|
-
};
|
|
4036
|
-
|
|
4037
|
-
// plugins/plugin-codecall/src/tools/invoke.tool.ts
|
|
4038
|
-
function buildErrorResult(message) {
|
|
4039
|
-
return {
|
|
4040
|
-
content: [{ type: "text", text: message }],
|
|
4041
|
-
isError: true
|
|
4042
|
-
};
|
|
4043
|
-
}
|
|
4044
|
-
var InvokeTool = class extends import_sdk10.ToolContext {
|
|
4045
|
-
async execute(input) {
|
|
4046
|
-
const { tool: toolName, input: toolInput } = input;
|
|
4047
|
-
const audit = this.tryGet(AuditLoggerService);
|
|
4048
|
-
const executionId = audit ? audit.generateExecutionId() : "";
|
|
4049
|
-
const startedAt = Date.now();
|
|
4050
|
-
if (isBlockedSelfReference(toolName)) {
|
|
4051
|
-
audit?.logSecuritySelfReference(executionId, toolName);
|
|
4052
|
-
return buildErrorResult(
|
|
4053
|
-
`Tool "${toolName}" cannot be invoked directly. CodeCall tools are internal and not accessible via codecall:invoke.`
|
|
4054
|
-
);
|
|
4055
|
-
}
|
|
4056
|
-
const surface = (0, import_sdk10.getCallSurface)();
|
|
4057
|
-
const decision = checkCodeCallToolAccess(this.scope, this.get(CodeCallConfig), toolName, {
|
|
4058
|
-
directCall: true,
|
|
4059
|
-
surface
|
|
4060
|
-
});
|
|
4061
|
-
if (!decision.allowed) {
|
|
4062
|
-
audit?.logSecurityAccessDenied(executionId, toolName, decision.reason);
|
|
4063
|
-
return buildErrorResult(`Tool "${toolName}" is not available. Use codecall:search to discover available tools.`);
|
|
4064
|
-
}
|
|
4065
|
-
const request = {
|
|
4066
|
-
method: "tools/call",
|
|
4067
|
-
params: {
|
|
4068
|
-
name: toolName,
|
|
4069
|
-
arguments: toolInput
|
|
4070
|
-
}
|
|
4071
|
-
};
|
|
4072
|
-
const ctx = asCodeCallDispatch({
|
|
4073
|
-
authInfo: this.authInfo,
|
|
4074
|
-
surface
|
|
4075
|
-
});
|
|
4076
|
-
const result = await this.scope.runFlow("tools:call-tool", { request, ctx });
|
|
4077
|
-
if (!result) {
|
|
4078
|
-
audit?.logInvoke(executionId, toolName, false, Date.now() - startedAt);
|
|
4079
|
-
return buildErrorResult(`Tool "${toolName}" not found. Use codecall:search to discover available tools.`);
|
|
4080
|
-
}
|
|
4081
|
-
audit?.logInvoke(executionId, toolName, true, Date.now() - startedAt);
|
|
4082
|
-
return result;
|
|
4083
|
-
}
|
|
4084
|
-
};
|
|
4085
|
-
InvokeTool = __decorateClass([
|
|
4086
|
-
(0, import_sdk10.Tool)({
|
|
4087
|
-
name: "codecall:invoke",
|
|
4088
|
-
cache: {
|
|
4089
|
-
ttl: 0,
|
|
4090
|
-
// No caching - each invocation is unique
|
|
4091
|
-
slideWindow: false
|
|
4092
|
-
},
|
|
4093
|
-
codecall: {
|
|
4094
|
-
enabledInCodeCall: false,
|
|
4095
|
-
visibleInListTools: true
|
|
4096
|
-
},
|
|
4097
|
-
description: invokeToolDescription,
|
|
4098
|
-
inputSchema: invokeToolInputSchema
|
|
4099
|
-
})
|
|
4100
|
-
], InvokeTool);
|
|
4101
|
-
|
|
4102
|
-
// plugins/plugin-codecall/src/codecall.plugin.ts
|
|
4103
|
-
function auditLogFields(event) {
|
|
4104
|
-
const { executionId, durationMs, data } = event;
|
|
4105
|
-
return durationMs === void 0 ? { executionId, ...data } : { executionId, durationMs, ...data };
|
|
4106
|
-
}
|
|
4107
|
-
function callContextOf(flowCtx) {
|
|
4108
|
-
const rawInput = flowCtx.rawInput;
|
|
4109
|
-
return typeof rawInput === "object" && rawInput !== null ? rawInput.ctx : void 0;
|
|
4110
|
-
}
|
|
4111
|
-
var CodeCallPlugin = class extends import_sdk11.DynamicPlugin {
|
|
4112
|
-
options;
|
|
4113
|
-
cachedLogger;
|
|
4114
|
-
getLogger() {
|
|
4115
|
-
if (!this.cachedLogger) {
|
|
4116
|
-
this.cachedLogger = this.get(import_sdk11.FrontMcpLogger).child("CodeCall");
|
|
4117
|
-
}
|
|
4118
|
-
return this.cachedLogger;
|
|
4119
|
-
}
|
|
4120
|
-
constructor(options = {}) {
|
|
4121
|
-
super();
|
|
4122
|
-
this.options = codeCallPluginOptionsSchema.parse(options);
|
|
4123
|
-
}
|
|
4124
|
-
/**
|
|
4125
|
-
* Dynamic providers allow you to configure the plugin with custom options
|
|
4126
|
-
* without touching the plugin decorator.
|
|
4127
|
-
*/
|
|
4128
|
-
static dynamicProviders(options) {
|
|
4129
|
-
const parsedOptions = codeCallPluginOptionsSchema.parse(options);
|
|
4130
|
-
const config = new CodeCallConfig(parsedOptions);
|
|
4131
|
-
return [
|
|
4132
|
-
{
|
|
4133
|
-
name: "codecall:config",
|
|
4134
|
-
provide: CodeCallConfig,
|
|
4135
|
-
useValue: config
|
|
4136
|
-
},
|
|
4137
|
-
{
|
|
4138
|
-
name: "codecall:enclave",
|
|
4139
|
-
provide: EnclaveService,
|
|
4140
|
-
inject: () => [CodeCallConfig],
|
|
4141
|
-
useFactory: async (cfg) => {
|
|
4142
|
-
return new EnclaveService(cfg);
|
|
4143
|
-
}
|
|
4144
|
-
},
|
|
4145
|
-
{
|
|
4146
|
-
// GHSA-adjacent: production.mdx promised operators these events and nothing emitted them,
|
|
4147
|
-
// because the service was never registered. The subscription lives here, in the factory,
|
|
4148
|
-
// for a reason: there is no provider teardown hook in the SDK, so subscribing anywhere
|
|
4149
|
-
// per-request would grow the listener Set for the life of the process.
|
|
4150
|
-
name: "codecall:audit-logger",
|
|
4151
|
-
provide: AuditLoggerService,
|
|
4152
|
-
inject: () => [import_sdk11.ScopeEntry],
|
|
4153
|
-
useFactory: (scope) => {
|
|
4154
|
-
const audit = new AuditLoggerService();
|
|
4155
|
-
const logger = scope.logger.child("codecall:audit");
|
|
4156
|
-
audit.subscribe((event) => logger.info(event.type, auditLogFields(event)));
|
|
4157
|
-
return audit;
|
|
4158
|
-
}
|
|
4159
|
-
},
|
|
4160
|
-
{
|
|
4161
|
-
name: "codecall:tool-search",
|
|
4162
|
-
provide: ToolSearchService,
|
|
4163
|
-
inject: () => [import_sdk11.ScopeEntry],
|
|
4164
|
-
useFactory: async (scope) => {
|
|
4165
|
-
return new ToolSearchService(
|
|
4166
|
-
{
|
|
4167
|
-
embeddingOptions: parsedOptions.embedding,
|
|
4168
|
-
defaultTopK: parsedOptions.topK,
|
|
4169
|
-
mode: parsedOptions.mode,
|
|
4170
|
-
includeTools: parsedOptions["includeTools"]
|
|
4171
|
-
},
|
|
4172
|
-
scope
|
|
4173
|
-
);
|
|
4174
|
-
}
|
|
4175
|
-
}
|
|
4176
|
-
];
|
|
4177
|
-
}
|
|
4178
|
-
/**
|
|
4179
|
-
* The CodeCall meta-tools. `codecall:search` and `codecall:execute` describe the `topK` and the
|
|
4180
|
-
* script limits these options give, since the model plans its calls from those descriptions.
|
|
4181
|
-
*/
|
|
4182
|
-
static dynamicTools(options) {
|
|
4183
|
-
const config = new CodeCallConfig(codeCallPluginOptionsSchema.parse(options)).getAll();
|
|
4184
|
-
class ConfiguredSearchTool extends SearchTool {
|
|
4185
|
-
}
|
|
4186
|
-
class ConfiguredExecuteTool extends ExecuteTool {
|
|
4187
|
-
}
|
|
4188
|
-
Reflect.defineMetadata(
|
|
4189
|
-
import_sdk11.FrontMcpToolTokens.description,
|
|
4190
|
-
buildSearchToolDescription(config.topK),
|
|
4191
|
-
ConfiguredSearchTool
|
|
4192
|
-
);
|
|
4193
|
-
Reflect.defineMetadata(
|
|
4194
|
-
import_sdk11.FrontMcpToolTokens.description,
|
|
4195
|
-
buildExecuteToolDescription(config.resolvedVm),
|
|
4196
|
-
ConfiguredExecuteTool
|
|
4197
|
-
);
|
|
4198
|
-
return [
|
|
4199
|
-
ConfiguredSearchTool,
|
|
4200
|
-
SearchSkillsTool,
|
|
4201
|
-
SearchKnowledgeTool,
|
|
4202
|
-
DescribeTool,
|
|
4203
|
-
ConfiguredExecuteTool,
|
|
4204
|
-
InvokeTool
|
|
4205
|
-
];
|
|
4206
|
-
}
|
|
4207
|
-
async adjustListTools(flowCtx) {
|
|
4208
|
-
const logger = this.getLogger();
|
|
4209
|
-
const { resolvedTools } = flowCtx.state;
|
|
4210
|
-
logger.verbose("adjustListTools hook called", { mode: this.options.mode });
|
|
4211
|
-
logger.verbose("adjustListTools: tools before filter", { count: resolvedTools?.length ?? 0 });
|
|
4212
|
-
if (!resolvedTools || resolvedTools.length === 0) {
|
|
4213
|
-
logger.verbose("adjustListTools: no tools to filter, returning early");
|
|
4214
|
-
return;
|
|
4215
|
-
}
|
|
4216
|
-
const scope = this.tryGetScope();
|
|
4217
|
-
const filteredTools = resolvedTools.filter(
|
|
4218
|
-
({ tool }) => !this.judges(scope, { tool }) || this.shouldShowInListTools(tool, this.options.mode)
|
|
4219
|
-
);
|
|
4220
|
-
logger.verbose("adjustListTools: tools after filter", { count: filteredTools.length });
|
|
4221
|
-
flowCtx.state.set("resolvedTools", filteredTools);
|
|
4222
|
-
}
|
|
4223
|
-
async refuseDirectCallOfHiddenTool(flowCtx) {
|
|
4224
|
-
const { tool } = flowCtx.state;
|
|
4225
|
-
if (!tool || tool.owner?.kind === "scope") return;
|
|
4226
|
-
if (this.isDirectlyCallable(tool)) return;
|
|
4227
|
-
if (isInProcessDispatch(callContextOf(flowCtx))) return;
|
|
4228
|
-
this.getLogger().verbose("refused a direct tools/call of a tool CodeCall hides", { tool: tool.fullName });
|
|
4229
|
-
throw new import_sdk11.ToolNotFoundError(flowCtx.state.input?.name ?? tool.name);
|
|
4230
|
-
}
|
|
4231
|
-
/**
|
|
4232
|
-
* Whether a client may call the tool directly: it is listed, and a tool the SDK keeps out of `tools/list`
|
|
4233
|
-
* (`visibility: 'hidden'`) also opts in with `visibleInListTools: true`, in every mode.
|
|
4234
|
-
*/
|
|
4235
|
-
isDirectlyCallable(tool) {
|
|
4236
|
-
if (!this.managesApp(tool)) return true;
|
|
4237
|
-
if (!this.shouldShowInListTools(tool, this.options.mode)) return false;
|
|
4238
|
-
if ((0, import_sdk11.resolveToolVisibility)(tool.metadata) !== "hidden") return true;
|
|
4239
|
-
return this.getCodeCallMetadata(tool)?.visibleInListTools === true;
|
|
4240
|
-
}
|
|
4241
|
-
/** Whether the tool's app is one `appIds` puts under `codecall_only`; every app is, without `appIds`. */
|
|
4242
|
-
managesApp(tool) {
|
|
4243
|
-
const managedAppIds = this.options.appIds;
|
|
4244
|
-
if (this.options.mode !== "codecall_only" || !managedAppIds || managedAppIds.length === 0) return true;
|
|
4245
|
-
const toolOwnerAppId = tool.owner?.kind === "app" ? tool.owner.id : void 0;
|
|
4246
|
-
return toolOwnerAppId !== void 0 && managedAppIds.includes(toolOwnerAppId);
|
|
4247
|
-
}
|
|
4248
|
-
/** Whether this instance's direct-call gate runs for the tool, so the listing hides only what that gate refuses. */
|
|
4249
|
-
judges(scope, entry) {
|
|
4250
|
-
return !scope?.hooks || (0, import_sdk11.isEntryGatedBy)(scope, entry, this);
|
|
4251
|
-
}
|
|
4252
|
-
tryGetScope() {
|
|
4253
|
-
try {
|
|
4254
|
-
return this.get(import_sdk11.ScopeEntry);
|
|
4255
|
-
} catch {
|
|
4256
|
-
return void 0;
|
|
4257
|
-
}
|
|
4258
|
-
}
|
|
4259
|
-
/**
|
|
4260
|
-
* Determine if a tool should be visible in list_tools based on mode.
|
|
4261
|
-
*
|
|
4262
|
-
* When `appIds` is configured, `codecall_only` mode only hides tools from
|
|
4263
|
-
* those specific apps — tools from other apps remain visible.
|
|
4264
|
-
*
|
|
4265
|
-
* @param tool - The tool entry to check
|
|
4266
|
-
* @param mode - The current CodeCall mode
|
|
4267
|
-
* @returns true if tool should be visible
|
|
4268
|
-
*/
|
|
4269
|
-
shouldShowInListTools(tool, mode) {
|
|
4270
|
-
if (this.isCodeCallTool(tool)) {
|
|
4271
|
-
return true;
|
|
4272
|
-
}
|
|
4273
|
-
const codecallMeta = this.getCodeCallMetadata(tool);
|
|
4274
|
-
switch (mode) {
|
|
4275
|
-
case "codecall_only":
|
|
4276
|
-
return !this.managesApp(tool) || codecallMeta?.visibleInListTools === true;
|
|
4277
|
-
case "codecall_opt_in":
|
|
4278
|
-
case "metadata_driven":
|
|
4279
|
-
return codecallMeta?.visibleInListTools !== false;
|
|
4280
|
-
default:
|
|
4281
|
-
return true;
|
|
4282
|
-
}
|
|
4283
|
-
}
|
|
4284
|
-
/**
|
|
4285
|
-
* Check if a tool is a CodeCall meta-tool.
|
|
4286
|
-
* CodeCall meta-tools always remain visible.
|
|
4287
|
-
*/
|
|
4288
|
-
isCodeCallTool(tool) {
|
|
4289
|
-
const name = tool.name || tool.fullName;
|
|
4290
|
-
return typeof name === "string" && name.startsWith("codecall:");
|
|
4291
|
-
}
|
|
4292
|
-
/**
|
|
4293
|
-
* Extract CodeCall-specific metadata from a tool.
|
|
4294
|
-
*/
|
|
4295
|
-
getCodeCallMetadata(tool) {
|
|
4296
|
-
return tool.metadata?.["codecall"];
|
|
4297
|
-
}
|
|
4298
|
-
};
|
|
4299
|
-
__decorateClass([
|
|
4300
|
-
import_sdk11.ListToolsHook.Did("resolveConflicts", { priority: 1e3 })
|
|
4301
|
-
], CodeCallPlugin.prototype, "adjustListTools", 1);
|
|
4302
|
-
__decorateClass([
|
|
4303
|
-
import_sdk11.ToolHook.Did("findTool", { priority: 10, appliesTo: "uncovered-apps" })
|
|
4304
|
-
], CodeCallPlugin.prototype, "refuseDirectCallOfHiddenTool", 1);
|
|
4305
|
-
CodeCallPlugin = __decorateClass([
|
|
4306
|
-
(0, import_sdk11.Plugin)({
|
|
4307
|
-
name: "codecall",
|
|
4308
|
-
description: "CodeCall plugin: AgentScript-based meta-tools for orchestrating MCP tools",
|
|
4309
|
-
providers: [],
|
|
4310
|
-
plugins: [import_plugin_cache.default]
|
|
4311
|
-
})
|
|
4312
|
-
], CodeCallPlugin);
|
|
4313
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
4314
|
-
0 && (module.exports = {
|
|
4315
|
-
AUDIT_EVENT_TYPES,
|
|
4316
|
-
AuditLoggerService,
|
|
4317
|
-
CodeCallPlugin,
|
|
4318
|
-
codeCallDirectCallsOptionsSchema,
|
|
4319
|
-
codeCallEmbeddingOptionsSchema,
|
|
4320
|
-
codeCallModeSchema,
|
|
4321
|
-
codeCallPluginOptionsSchema,
|
|
4322
|
-
codeCallSidecarOptionsSchema,
|
|
4323
|
-
codeCallVmOptionsSchema,
|
|
4324
|
-
codeCallVmPresetSchema,
|
|
4325
|
-
embeddingStrategySchema,
|
|
4326
|
-
synonymExpansionConfigSchema
|
|
4327
|
-
});
|
|
107
|
+
FLOW: search \u2192 describe \u2192 invoke`;var invokeToolInputSchema={tool:import_lazy_zod8.z.string().describe('The name of the tool to invoke (e.g., "users:getById", "billing:getInvoice"). Must be a tool you discovered via codecall:search.'),input:import_lazy_zod8.z.record(import_lazy_zod8.z.string(),import_lazy_zod8.z.unknown()).describe("The input parameters for the tool. Structure must match the tool's input schema (check codecall:describe for schema details).")};function buildErrorResult(message){return{content:[{type:"text",text:message}],isError:true}}var InvokeTool=class extends import_sdk10.ToolContext{async execute(input){const{tool:toolName,input:toolInput}=input;const audit=this.tryGet(AuditLoggerService);const executionId=audit?audit.generateExecutionId():"";const startedAt=Date.now();if(isBlockedSelfReference(toolName)){audit?.logSecuritySelfReference(executionId,toolName);return buildErrorResult(`Tool "${toolName}" cannot be invoked directly. CodeCall tools are internal and not accessible via codecall:invoke.`)}const surface=(0,import_sdk10.getCallSurface)();const decision=checkCodeCallToolAccess(this.scope,this.get(CodeCallConfig),toolName,{directCall:true,surface});if(!decision.allowed){audit?.logSecurityAccessDenied(executionId,toolName,decision.reason);return buildErrorResult(`Tool "${toolName}" is not available. Use codecall:search to discover available tools.`)}const request={method:"tools/call",params:{name:toolName,arguments:toolInput}};const ctx=asCodeCallDispatch({authInfo:this.authInfo,surface});const result=await this.scope.runFlow("tools:call-tool",{request,ctx});if(!result){audit?.logInvoke(executionId,toolName,false,Date.now()-startedAt);return buildErrorResult(`Tool "${toolName}" not found. Use codecall:search to discover available tools.`)}audit?.logInvoke(executionId,toolName,true,Date.now()-startedAt);return result}};InvokeTool=__decorateClass([(0,import_sdk10.Tool)({name:"codecall:invoke",cache:{ttl:0,slideWindow:false},codecall:{enabledInCodeCall:false,visibleInListTools:true},description:invokeToolDescription,inputSchema:invokeToolInputSchema})],InvokeTool);function auditLogFields(event){const{executionId,durationMs,data}=event;return durationMs===void 0?{executionId,...data}:{executionId,durationMs,...data}}function callContextOf(flowCtx){const rawInput=flowCtx.rawInput;return typeof rawInput==="object"&&rawInput!==null?rawInput.ctx:void 0}var CodeCallPlugin=class extends import_sdk11.DynamicPlugin{options;cachedLogger;getLogger(){if(!this.cachedLogger){this.cachedLogger=this.get(import_sdk11.FrontMcpLogger).child("CodeCall")}return this.cachedLogger}constructor(options={}){super();this.options=codeCallPluginOptionsSchema.parse(options)}static dynamicProviders(options){const parsedOptions=codeCallPluginOptionsSchema.parse(options);const config=new CodeCallConfig(parsedOptions);return[{name:"codecall:config",provide:CodeCallConfig,useValue:config},{name:"codecall:enclave",provide:EnclaveService,inject:()=>[CodeCallConfig],useFactory:async cfg=>{return new EnclaveService(cfg)}},{name:"codecall:audit-logger",provide:AuditLoggerService,inject:()=>[import_sdk11.ScopeEntry],useFactory:scope=>{const audit=new AuditLoggerService;const logger=scope.logger.child("codecall:audit");audit.subscribe(event=>logger.info(event.type,auditLogFields(event)));return audit}},{name:"codecall:tool-search",provide:ToolSearchService,inject:()=>[import_sdk11.ScopeEntry],useFactory:async scope=>{return new ToolSearchService({embeddingOptions:parsedOptions.embedding,defaultTopK:parsedOptions.topK,mode:parsedOptions.mode,includeTools:parsedOptions["includeTools"]},scope)}}]}static dynamicTools(options){const config=new CodeCallConfig(codeCallPluginOptionsSchema.parse(options)).getAll();class ConfiguredSearchTool extends SearchTool{}class ConfiguredExecuteTool extends ExecuteTool{}Reflect.defineMetadata(import_sdk11.FrontMcpToolTokens.description,buildSearchToolDescription(config.topK),ConfiguredSearchTool);Reflect.defineMetadata(import_sdk11.FrontMcpToolTokens.description,buildExecuteToolDescription(config.resolvedVm),ConfiguredExecuteTool);return[ConfiguredSearchTool,SearchSkillsTool,SearchKnowledgeTool,DescribeTool,ConfiguredExecuteTool,InvokeTool]}async adjustListTools(flowCtx){const logger=this.getLogger();const{resolvedTools}=flowCtx.state;logger.verbose("adjustListTools hook called",{mode:this.options.mode});logger.verbose("adjustListTools: tools before filter",{count:resolvedTools?.length??0});if(!resolvedTools||resolvedTools.length===0){logger.verbose("adjustListTools: no tools to filter, returning early");return}const scope=this.tryGetScope();const filteredTools=resolvedTools.filter(({tool})=>!this.judges(scope,{tool})||this.shouldShowInListTools(tool,this.options.mode));logger.verbose("adjustListTools: tools after filter",{count:filteredTools.length});flowCtx.state.set("resolvedTools",filteredTools)}async refuseDirectCallOfHiddenTool(flowCtx){const{tool}=flowCtx.state;if(!tool||tool.owner?.kind==="scope")return;if(this.isDirectlyCallable(tool))return;if(isInProcessDispatch(callContextOf(flowCtx)))return;this.getLogger().verbose("refused a direct tools/call of a tool CodeCall hides",{tool:tool.fullName});throw new import_sdk11.ToolNotFoundError(flowCtx.state.input?.name??tool.name)}isDirectlyCallable(tool){if(!this.managesApp(tool))return true;if(!this.shouldShowInListTools(tool,this.options.mode))return false;if((0,import_sdk11.resolveToolVisibility)(tool.metadata)!=="hidden")return true;return this.getCodeCallMetadata(tool)?.visibleInListTools===true}managesApp(tool){const managedAppIds=this.options.appIds;if(this.options.mode!=="codecall_only"||!managedAppIds||managedAppIds.length===0)return true;const toolOwnerAppId=tool.owner?.kind==="app"?tool.owner.id:void 0;return toolOwnerAppId!==void 0&&managedAppIds.includes(toolOwnerAppId)}judges(scope,entry){return!scope?.hooks||(0,import_sdk11.isEntryGatedBy)(scope,entry,this)}tryGetScope(){try{return this.get(import_sdk11.ScopeEntry)}catch{return void 0}}shouldShowInListTools(tool,mode){if(this.isCodeCallTool(tool)){return true}const codecallMeta=this.getCodeCallMetadata(tool);switch(mode){case"codecall_only":return!this.managesApp(tool)||codecallMeta?.visibleInListTools===true;case"codecall_opt_in":case"metadata_driven":return codecallMeta?.visibleInListTools!==false;default:return true}}isCodeCallTool(tool){const name=tool.name||tool.fullName;return typeof name==="string"&&name.startsWith("codecall:")}getCodeCallMetadata(tool){return tool.metadata?.["codecall"]}};__decorateClass([import_sdk11.ListToolsHook.Did("resolveConflicts",{priority:1e3})],CodeCallPlugin.prototype,"adjustListTools",1);__decorateClass([import_sdk11.ToolHook.Did("findTool",{priority:10,appliesTo:"uncovered-apps"})],CodeCallPlugin.prototype,"refuseDirectCallOfHiddenTool",1);CodeCallPlugin=__decorateClass([(0,import_sdk11.Plugin)({name:"codecall",description:"CodeCall plugin: AgentScript-based meta-tools for orchestrating MCP tools",providers:[],plugins:[import_plugin_cache.default]})],CodeCallPlugin);0&&(module.exports={AUDIT_EVENT_TYPES,AuditLoggerService,CodeCallPlugin,codeCallDirectCallsOptionsSchema,codeCallEmbeddingOptionsSchema,codeCallModeSchema,codeCallPluginOptionsSchema,codeCallSidecarOptionsSchema,codeCallVmOptionsSchema,codeCallVmPresetSchema,embeddingStrategySchema,synonymExpansionConfigSchema});
|