@frontmcp/plugin-codecall 1.8.2 → 1.8.4
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/codecall.symbol.d.ts +16 -14
- package/codecall.symbol.d.ts.map +1 -1
- package/codecall.types.d.ts +28 -5
- package/codecall.types.d.ts.map +1 -1
- package/errors/tool-call.errors.d.ts.map +1 -1
- package/esm/index.mjs +389 -183
- package/esm/package.json +6 -6
- package/index.js +382 -178
- package/package.json +6 -6
- package/security/codecall-tool-policy.d.ts +30 -2
- package/security/codecall-tool-policy.d.ts.map +1 -1
- package/services/audit-logger.service.d.ts.map +1 -1
- package/services/enclave.service.d.ts +5 -0
- package/services/enclave.service.d.ts.map +1 -1
- package/services/output-sanitizer.d.ts.map +1 -1
- package/services/tool-search.service.d.ts +8 -12
- package/services/tool-search.service.d.ts.map +1 -1
- package/tools/describe.tool.d.ts.map +1 -1
- package/tools/execute.schema.d.ts.map +1 -1
- package/tools/execute.tool.d.ts.map +1 -1
- package/tools/invoke.tool.d.ts.map +1 -1
- package/tools/search.tool.d.ts.map +1 -1
- package/utils/build-tool-namespaces.d.ts +25 -21
- package/utils/build-tool-namespaces.d.ts.map +1 -1
- package/utils/client-error-message.d.ts +11 -0
- package/utils/client-error-message.d.ts.map +1 -0
package/esm/index.mjs
CHANGED
|
@@ -374,6 +374,46 @@ function presetDefaults(preset) {
|
|
|
374
374
|
|
|
375
375
|
// plugins/plugin-codecall/src/services/audit-logger.service.ts
|
|
376
376
|
import { Provider as Provider2, ProviderScope as ProviderScope2 } from "@frontmcp/sdk";
|
|
377
|
+
|
|
378
|
+
// plugins/plugin-codecall/src/utils/client-error-message.ts
|
|
379
|
+
var EMBEDDED_STACK_FRAME_RE = /\n[ \t]*at\s[^\n]*/g;
|
|
380
|
+
var QUOTED_PATH_RE = /(['"`])((?:~?\/|[A-Za-z]:[\\/]|\\\\)[^\s'"`\\/][^'"`\n]*)\1/g;
|
|
381
|
+
var URL_RE = /\b[A-Za-z][A-Za-z0-9+.-]{1,31}:\/\/(?:[^\s'"`<>,;]|[,;](?!~?\/|[A-Za-z]:[\\/]|\\\\))*/g;
|
|
382
|
+
var QUERY_PATH_VALUE_RE = /([?&][^=&#]*=)(?:~?\/|[A-Za-z]:[\\/]|\\\\)[^&#]*/g;
|
|
383
|
+
var POSIX_SEGMENT = String.raw`[^\s/\\'"\x60<>|,;:()\[\]{}]+`;
|
|
384
|
+
var WINDOWS_SEGMENT = String.raw`[^\s/\\'"\x60<>|,;:*?]+`;
|
|
385
|
+
function segments(segment, separator) {
|
|
386
|
+
const spaced = `${segment}(?: ${segment}){0,2}`;
|
|
387
|
+
return `(?:(?:${spaced}${separator})+(?:${segment})?|${segment})`;
|
|
388
|
+
}
|
|
389
|
+
var UNQUOTED_PATH_RE = new RegExp(
|
|
390
|
+
[
|
|
391
|
+
String.raw`(?<![\w.~/\\)\]-])~?/+${segments(POSIX_SEGMENT, "/+")}`,
|
|
392
|
+
String.raw`(?<![\w\\/])[A-Za-z]:[\\/]+${segments(WINDOWS_SEGMENT, String.raw`[\\/]+`)}?`,
|
|
393
|
+
String.raw`(?<![\w\\])\\\\${segments(WINDOWS_SEGMENT, String.raw`[\\/]+`)}`
|
|
394
|
+
].join("|"),
|
|
395
|
+
"g"
|
|
396
|
+
);
|
|
397
|
+
function redactPaths(text) {
|
|
398
|
+
return text.replace(QUOTED_PATH_RE, "$1[path]$1").replace(UNQUOTED_PATH_RE, "[path]");
|
|
399
|
+
}
|
|
400
|
+
function toClientErrorMessage(message) {
|
|
401
|
+
if (!message) return "";
|
|
402
|
+
return redactAbsolutePaths(message.replace(EMBEDDED_STACK_FRAME_RE, ""));
|
|
403
|
+
}
|
|
404
|
+
function redactAbsolutePaths(text) {
|
|
405
|
+
let result = "";
|
|
406
|
+
let last = 0;
|
|
407
|
+
for (const match of text.matchAll(URL_RE)) {
|
|
408
|
+
const start = match.index ?? 0;
|
|
409
|
+
result += redactPaths(text.slice(last, start));
|
|
410
|
+
result += /^file:/i.test(match[0]) ? "[path]" : match[0].replace(QUERY_PATH_VALUE_RE, "$1[path]");
|
|
411
|
+
last = start + match[0].length;
|
|
412
|
+
}
|
|
413
|
+
return result + redactPaths(text.slice(last));
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// plugins/plugin-codecall/src/services/audit-logger.service.ts
|
|
377
417
|
var AUDIT_EVENT_TYPES = {
|
|
378
418
|
/** Script execution started */
|
|
379
419
|
EXECUTION_START: "codecall:execution:start",
|
|
@@ -650,9 +690,8 @@ var AuditLoggerService = class {
|
|
|
650
690
|
*/
|
|
651
691
|
sanitizeError(error) {
|
|
652
692
|
if (!error) return "Unknown error";
|
|
653
|
-
let sanitized = error
|
|
693
|
+
let sanitized = toClientErrorMessage(error);
|
|
654
694
|
sanitized = sanitized.replace(/:\d+:\d+/g, "");
|
|
655
|
-
sanitized = sanitized.replace(/\n\s*at .*/g, "");
|
|
656
695
|
if (sanitized.length > 200) {
|
|
657
696
|
sanitized = sanitized.substring(0, 200) + "...";
|
|
658
697
|
}
|
|
@@ -671,6 +710,10 @@ import { TFIDFVectoria, VectoriaDB } from "vectoriadb";
|
|
|
671
710
|
|
|
672
711
|
// plugins/plugin-codecall/src/security/codecall-tool-policy.ts
|
|
673
712
|
var BLOCKED_NAMESPACE_PATTERNS = Object.freeze([/^system:/, /^internal:/, /^__/]);
|
|
713
|
+
function isOfferedToCaller(availableWhen, surface) {
|
|
714
|
+
const offered = availableWhen?.surface;
|
|
715
|
+
return offered === void 0 || surface === void 0 || offered.includes(surface);
|
|
716
|
+
}
|
|
674
717
|
var ALLOWED = { allowed: true };
|
|
675
718
|
function deny(reason) {
|
|
676
719
|
return { allowed: false, reason };
|
|
@@ -691,16 +734,46 @@ function toCodeCallPolicyTool(entry, requestedName, scope) {
|
|
|
691
734
|
tags: metadata?.tags,
|
|
692
735
|
// `internal` tools refuse every external tools/call, CodeCall's included, so no surface may offer them.
|
|
693
736
|
hidden: metadata?.hideFromDiscovery === true || metadata?.visibility === "hidden" || metadata?.visibility === "internal",
|
|
694
|
-
codecall: metadata?.codecall
|
|
737
|
+
codecall: metadata?.codecall,
|
|
738
|
+
annotations: metadata?.annotations,
|
|
739
|
+
metadata
|
|
695
740
|
};
|
|
696
741
|
}
|
|
742
|
+
function isPlainData(value) {
|
|
743
|
+
if (Array.isArray(value)) return true;
|
|
744
|
+
const proto = Object.getPrototypeOf(value);
|
|
745
|
+
return proto === Object.prototype || proto === null;
|
|
746
|
+
}
|
|
747
|
+
function readOnlyCopy(value, copies) {
|
|
748
|
+
if (typeof value !== "object" || value === null || !isPlainData(value)) return value;
|
|
749
|
+
const existing = copies.get(value);
|
|
750
|
+
if (existing !== void 0) return existing;
|
|
751
|
+
const copy = Array.isArray(value) ? [] : Object.create(Object.getPrototypeOf(value));
|
|
752
|
+
copies.set(value, copy);
|
|
753
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
754
|
+
if (!Object.prototype.propertyIsEnumerable.call(value, key)) continue;
|
|
755
|
+
Object.defineProperty(copy, key, {
|
|
756
|
+
value: readOnlyCopy(Reflect.get(value, key), copies),
|
|
757
|
+
enumerable: true,
|
|
758
|
+
writable: true,
|
|
759
|
+
configurable: true
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
return Object.freeze(copy);
|
|
763
|
+
}
|
|
697
764
|
function toToolFilterInfo(tool) {
|
|
765
|
+
const copies = /* @__PURE__ */ new WeakMap();
|
|
766
|
+
const annotations = readOnlyCopy(tool.annotations, copies);
|
|
767
|
+
const metadata = tool.metadata ? readOnlyCopy({ ...tool.metadata, ...annotations ? { annotations: tool.annotations } : {} }, copies) : void 0;
|
|
698
768
|
return {
|
|
699
769
|
name: tool.name,
|
|
770
|
+
fullName: tool.fullName,
|
|
700
771
|
appId: tool.appId,
|
|
701
772
|
source: tool.codecall?.source,
|
|
702
773
|
description: tool.description,
|
|
703
|
-
tags: tool.codecall?.tags ?? tool.tags
|
|
774
|
+
tags: readOnlyCopy(tool.codecall?.tags ?? tool.tags, copies),
|
|
775
|
+
annotations,
|
|
776
|
+
metadata
|
|
704
777
|
};
|
|
705
778
|
}
|
|
706
779
|
function ownNamesOf(tool) {
|
|
@@ -787,6 +860,9 @@ function readCodeCallPolicyConfig(config) {
|
|
|
787
860
|
function checkCodeCallToolAccess(scope, config, name, options = {}) {
|
|
788
861
|
const entry = resolveCodeCallTool(scope, name);
|
|
789
862
|
if (!entry) return denyUnknownTool(name);
|
|
863
|
+
if (!isOfferedToCaller(entry.metadata?.availableWhen, options.surface)) {
|
|
864
|
+
return deny(`Tool "${name}" is not offered on the caller's surface "${options.surface}"`);
|
|
865
|
+
}
|
|
790
866
|
const policyTool = toCodeCallPolicyTool(entry, name, scope);
|
|
791
867
|
const baseDecision = checkCodeCallToolPolicy(policyTool, readCodeCallPolicyConfig(config));
|
|
792
868
|
if (!baseDecision.allowed) return baseDecision;
|
|
@@ -1320,6 +1396,8 @@ var ToolSearchService = class _ToolSearchService {
|
|
|
1320
1396
|
subscriptionReject = null;
|
|
1321
1397
|
retryTimeoutId = null;
|
|
1322
1398
|
disposed = false;
|
|
1399
|
+
/** `availableWhen` of each indexed tool, by indexed name, for per-caller surface filtering. */
|
|
1400
|
+
availabilityByTool = /* @__PURE__ */ new Map();
|
|
1323
1401
|
constructor(config = {}, scope) {
|
|
1324
1402
|
this.scope = scope;
|
|
1325
1403
|
const embeddingOptions = config.embeddingOptions || {
|
|
@@ -1429,6 +1507,7 @@ var ToolSearchService = class _ToolSearchService {
|
|
|
1429
1507
|
*/
|
|
1430
1508
|
async handleToolChange(tools) {
|
|
1431
1509
|
this.vectorDB.clear();
|
|
1510
|
+
this.availabilityByTool = /* @__PURE__ */ new Map();
|
|
1432
1511
|
if (tools.length === 0) {
|
|
1433
1512
|
this.initialized = true;
|
|
1434
1513
|
return;
|
|
@@ -1443,6 +1522,7 @@ var ToolSearchService = class _ToolSearchService {
|
|
|
1443
1522
|
return;
|
|
1444
1523
|
}
|
|
1445
1524
|
const documents = filteredTools.map((tool) => {
|
|
1525
|
+
this.availabilityByTool.set(tool.name, tool.metadata.availableWhen);
|
|
1446
1526
|
const searchableText = this.extractSearchableText(tool);
|
|
1447
1527
|
const appId = this.extractAppId(tool);
|
|
1448
1528
|
const toolName = tool.name;
|
|
@@ -1571,12 +1651,15 @@ var ToolSearchService = class _ToolSearchService {
|
|
|
1571
1651
|
*/
|
|
1572
1652
|
async search(query, options = {}) {
|
|
1573
1653
|
await this.ensureSubscribed();
|
|
1574
|
-
const { topK = this.config.defaultTopK, appIds, excludeToolNames = [] } = options;
|
|
1654
|
+
const { topK = this.config.defaultTopK, appIds, excludeToolNames = [], surface } = options;
|
|
1575
1655
|
const minScore = this.config.defaultSimilarityThreshold;
|
|
1576
1656
|
const filter = (metadata) => {
|
|
1577
1657
|
if (excludeToolNames.includes(metadata.toolName)) {
|
|
1578
1658
|
return false;
|
|
1579
1659
|
}
|
|
1660
|
+
if (!isOfferedToCaller(metadata.toolInstance.metadata.availableWhen, surface)) {
|
|
1661
|
+
return false;
|
|
1662
|
+
}
|
|
1580
1663
|
if (appIds && appIds.length > 0) {
|
|
1581
1664
|
if (!metadata.appId || !appIds.includes(metadata.appId)) {
|
|
1582
1665
|
return false;
|
|
@@ -1608,9 +1691,12 @@ var ToolSearchService = class _ToolSearchService {
|
|
|
1608
1691
|
}
|
|
1609
1692
|
}
|
|
1610
1693
|
/**
|
|
1611
|
-
* Gets the total number of indexed tools
|
|
1694
|
+
* Gets the total number of indexed tools, or of those a caller on `surface` may reach
|
|
1612
1695
|
*/
|
|
1613
|
-
getTotalCount() {
|
|
1696
|
+
getTotalCount(surface) {
|
|
1697
|
+
if (surface !== void 0) {
|
|
1698
|
+
return this.getAllToolNames().filter((toolName) => this.hasTool(toolName, surface)).length;
|
|
1699
|
+
}
|
|
1614
1700
|
if (this.vectorDB instanceof VectoriaDB) {
|
|
1615
1701
|
return this.vectorDB.size();
|
|
1616
1702
|
} else {
|
|
@@ -1618,20 +1704,18 @@ var ToolSearchService = class _ToolSearchService {
|
|
|
1618
1704
|
}
|
|
1619
1705
|
}
|
|
1620
1706
|
/**
|
|
1621
|
-
* Checks if a tool exists in the index
|
|
1707
|
+
* Checks if a tool exists in the index, for a caller on `surface` when given
|
|
1622
1708
|
*/
|
|
1623
|
-
hasTool(toolName) {
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
} else {
|
|
1627
|
-
return this.vectorDB.hasDocument(toolName);
|
|
1628
|
-
}
|
|
1709
|
+
hasTool(toolName, surface) {
|
|
1710
|
+
const indexed = this.vectorDB instanceof VectoriaDB ? this.vectorDB.has(toolName) : this.vectorDB.hasDocument(toolName);
|
|
1711
|
+
return indexed && isOfferedToCaller(this.availabilityByTool.get(toolName), surface);
|
|
1629
1712
|
}
|
|
1630
1713
|
/**
|
|
1631
1714
|
* Clears the entire index
|
|
1632
1715
|
*/
|
|
1633
1716
|
clear() {
|
|
1634
1717
|
this.vectorDB.clear();
|
|
1718
|
+
this.availabilityByTool = /* @__PURE__ */ new Map();
|
|
1635
1719
|
this.initialized = false;
|
|
1636
1720
|
}
|
|
1637
1721
|
/**
|
|
@@ -1649,8 +1733,163 @@ var ToolSearchService = class _ToolSearchService {
|
|
|
1649
1733
|
};
|
|
1650
1734
|
|
|
1651
1735
|
// plugins/plugin-codecall/src/services/enclave.service.ts
|
|
1652
|
-
import {
|
|
1736
|
+
import {
|
|
1737
|
+
Enclave
|
|
1738
|
+
} from "@enclave-vm/core";
|
|
1653
1739
|
import { Provider as Provider3, ProviderScope as ProviderScope3 } from "@frontmcp/sdk";
|
|
1740
|
+
|
|
1741
|
+
// plugins/plugin-codecall/src/utils/build-tool-namespaces.ts
|
|
1742
|
+
var IDENT_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
1743
|
+
var PROTOTYPE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
1744
|
+
var RESERVED_NAMESPACES = /* @__PURE__ */ new Set([
|
|
1745
|
+
"console",
|
|
1746
|
+
"Math",
|
|
1747
|
+
"JSON",
|
|
1748
|
+
"Object",
|
|
1749
|
+
"Array",
|
|
1750
|
+
"String",
|
|
1751
|
+
"Number",
|
|
1752
|
+
"Boolean",
|
|
1753
|
+
"Promise",
|
|
1754
|
+
"Symbol",
|
|
1755
|
+
"Map",
|
|
1756
|
+
"Set",
|
|
1757
|
+
"WeakMap",
|
|
1758
|
+
"WeakSet",
|
|
1759
|
+
"Date",
|
|
1760
|
+
"Error",
|
|
1761
|
+
"RegExp",
|
|
1762
|
+
"globalThis",
|
|
1763
|
+
"global",
|
|
1764
|
+
"window",
|
|
1765
|
+
"self",
|
|
1766
|
+
"undefined",
|
|
1767
|
+
"null",
|
|
1768
|
+
"true",
|
|
1769
|
+
"false",
|
|
1770
|
+
"callTool",
|
|
1771
|
+
"getTool",
|
|
1772
|
+
"mcpLog",
|
|
1773
|
+
"mcpNotify"
|
|
1774
|
+
]);
|
|
1775
|
+
var UNBINDABLE_NAMESPACES = new Set(
|
|
1776
|
+
[
|
|
1777
|
+
// Reserved words and strict-mode restricted bindings
|
|
1778
|
+
"break case catch class const continue debugger default delete do else enum export extends finally for",
|
|
1779
|
+
"function if import in instanceof new return super switch this throw try typeof var void while with yield",
|
|
1780
|
+
"let static implements interface package private protected public await eval arguments NaN Infinity",
|
|
1781
|
+
// AgentScript globals
|
|
1782
|
+
"parallel isNaN isFinite parseInt parseFloat encodeURI encodeURIComponent decodeURI decodeURIComponent",
|
|
1783
|
+
// Identifiers the AgentScript validator refuses
|
|
1784
|
+
"process require module exports Buffer Function AsyncFunction GeneratorFunction Reflect Proxy TypeError",
|
|
1785
|
+
"ReferenceError SyntaxError RangeError URIError EvalError AggregateError fetch XMLHttpRequest WebSocket",
|
|
1786
|
+
"localStorage sessionStorage indexedDB crypto performance structuredClone AbortController AbortSignal",
|
|
1787
|
+
"MessageChannel MessagePort BroadcastChannel TextEncoder TextDecoder Intl setTimeout setInterval",
|
|
1788
|
+
"setImmediate clearTimeout clearInterval clearImmediate queueMicrotask WebAssembly Worker SharedWorker",
|
|
1789
|
+
"ServiceWorker WeakRef FinalizationRegistry BigInt Atomics SharedArrayBuffer ArrayBuffer DataView",
|
|
1790
|
+
"importScripts ShadowRealm Iterator AsyncIterator"
|
|
1791
|
+
].join(" ").split(" ")
|
|
1792
|
+
);
|
|
1793
|
+
var UNCALLABLE_METHODS = new Set(
|
|
1794
|
+
[
|
|
1795
|
+
"process require module exports Buffer eval Function AsyncFunction GeneratorFunction arguments RegExp",
|
|
1796
|
+
"Promise Symbol Proxy Reflect Error TypeError ReferenceError SyntaxError RangeError URIError EvalError",
|
|
1797
|
+
"AggregateError fetch XMLHttpRequest WebSocket localStorage sessionStorage indexedDB crypto performance",
|
|
1798
|
+
"structuredClone AbortController AbortSignal MessageChannel MessagePort BroadcastChannel TextEncoder",
|
|
1799
|
+
"TextDecoder Intl setTimeout setInterval setImmediate clearTimeout clearInterval clearImmediate",
|
|
1800
|
+
"queueMicrotask WebAssembly Worker SharedWorker ServiceWorker WeakMap WeakSet WeakRef FinalizationRegistry",
|
|
1801
|
+
"Map Set Atomics SharedArrayBuffer importScripts ShadowRealm Iterator AsyncIterator"
|
|
1802
|
+
].join(" ").split(" ")
|
|
1803
|
+
);
|
|
1804
|
+
var SANDBOX_TOOL_NAME_RE = /^[a-zA-Z][a-zA-Z0-9:._-]*$/;
|
|
1805
|
+
var MAX_SANDBOX_TOOL_NAME_LENGTH = 256;
|
|
1806
|
+
function isBindableNamespace(ns, reservedGlobals) {
|
|
1807
|
+
return IDENT_RE.test(ns) && !PROTOTYPE_KEYS.has(ns) && !ns.startsWith("__") && !RESERVED_NAMESPACES.has(ns) && !UNBINDABLE_NAMESPACES.has(ns) && !reservedGlobals.has(ns);
|
|
1808
|
+
}
|
|
1809
|
+
function isBindableMethod(ns, method, toolName) {
|
|
1810
|
+
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);
|
|
1811
|
+
}
|
|
1812
|
+
function buildToolNamespaces(tools) {
|
|
1813
|
+
const namespaces = /* @__PURE__ */ Object.create(null);
|
|
1814
|
+
const skipped = [];
|
|
1815
|
+
for (const tool of tools) {
|
|
1816
|
+
const name = tool?.name;
|
|
1817
|
+
if (typeof name !== "string" || name.length === 0) continue;
|
|
1818
|
+
const dot = name.indexOf(".");
|
|
1819
|
+
if (dot <= 0 || dot === name.length - 1) {
|
|
1820
|
+
skipped.push({ name, reason: "no-namespace-prefix" });
|
|
1821
|
+
continue;
|
|
1822
|
+
}
|
|
1823
|
+
const ns = name.slice(0, dot);
|
|
1824
|
+
const method = name.slice(dot + 1);
|
|
1825
|
+
if (!IDENT_RE.test(ns) || !IDENT_RE.test(method)) {
|
|
1826
|
+
skipped.push({ name, reason: "invalid-identifier" });
|
|
1827
|
+
continue;
|
|
1828
|
+
}
|
|
1829
|
+
if (PROTOTYPE_KEYS.has(ns) || PROTOTYPE_KEYS.has(method)) {
|
|
1830
|
+
skipped.push({ name, reason: "prototype-key" });
|
|
1831
|
+
continue;
|
|
1832
|
+
}
|
|
1833
|
+
if (RESERVED_NAMESPACES.has(ns) || UNBINDABLE_NAMESPACES.has(ns) || ns.startsWith("__")) {
|
|
1834
|
+
skipped.push({ name, reason: "reserved-namespace" });
|
|
1835
|
+
continue;
|
|
1836
|
+
}
|
|
1837
|
+
if (!isBindableMethod(ns, method, name)) {
|
|
1838
|
+
skipped.push({ name, reason: "unsupported-name" });
|
|
1839
|
+
continue;
|
|
1840
|
+
}
|
|
1841
|
+
const bucket = namespaces[ns] ?? (namespaces[ns] = /* @__PURE__ */ Object.create(null));
|
|
1842
|
+
if (Object.prototype.hasOwnProperty.call(bucket, method)) {
|
|
1843
|
+
skipped.push({ name, reason: "duplicate-method" });
|
|
1844
|
+
continue;
|
|
1845
|
+
}
|
|
1846
|
+
bucket[method] = name;
|
|
1847
|
+
}
|
|
1848
|
+
return { namespaces, skipped };
|
|
1849
|
+
}
|
|
1850
|
+
function toSandboxToolNamespaces(namespaces, reservedGlobals = []) {
|
|
1851
|
+
if (!namespaces) return void 0;
|
|
1852
|
+
const reserved = new Set(reservedGlobals);
|
|
1853
|
+
const bindable = /* @__PURE__ */ Object.create(null);
|
|
1854
|
+
let count = 0;
|
|
1855
|
+
for (const ns of Object.keys(namespaces)) {
|
|
1856
|
+
if (!isBindableNamespace(ns, reserved)) continue;
|
|
1857
|
+
const methods = namespaces[ns];
|
|
1858
|
+
const bucket = /* @__PURE__ */ Object.create(null);
|
|
1859
|
+
let methodCount = 0;
|
|
1860
|
+
for (const method of Object.keys(methods)) {
|
|
1861
|
+
const toolName = methods[method];
|
|
1862
|
+
if (typeof toolName !== "string" || !isBindableMethod(ns, method, toolName)) continue;
|
|
1863
|
+
bucket[method] = toolName;
|
|
1864
|
+
methodCount += 1;
|
|
1865
|
+
}
|
|
1866
|
+
if (methodCount > 0) {
|
|
1867
|
+
bindable[ns] = bucket;
|
|
1868
|
+
count += 1;
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
return count > 0 ? bindable : void 0;
|
|
1872
|
+
}
|
|
1873
|
+
|
|
1874
|
+
// plugins/plugin-codecall/src/services/enclave.service.ts
|
|
1875
|
+
function toolFailureMessage(error, toolName) {
|
|
1876
|
+
if (typeof error === "string" && error) return error;
|
|
1877
|
+
const message = error?.message;
|
|
1878
|
+
return typeof message === "string" && message ? message : `Tool call failed: ${toolName}`;
|
|
1879
|
+
}
|
|
1880
|
+
function toolFailureName(error) {
|
|
1881
|
+
const name = error && typeof error === "object" ? error.name : void 0;
|
|
1882
|
+
return typeof name === "string" && name ? name.slice(0, 128) : "ToolError";
|
|
1883
|
+
}
|
|
1884
|
+
var PARSE_FAILURE_PREFIX = "Failed to parse AgentScript code: ";
|
|
1885
|
+
var PARSE_POSITION_RE = /\((\d+):(\d+)\)$/;
|
|
1886
|
+
function parseFailureOf(message) {
|
|
1887
|
+
const match = PARSE_POSITION_RE.exec(message);
|
|
1888
|
+
const line = match ? Number(match[1]) - 1 : 0;
|
|
1889
|
+
if (!match || line < 1) return { message };
|
|
1890
|
+
const column = Number(match[2]);
|
|
1891
|
+
return { message: `${message.slice(0, match.index)}(${line}:${column})`, location: { line, column } };
|
|
1892
|
+
}
|
|
1654
1893
|
var ScriptTooLargeError = class extends Error {
|
|
1655
1894
|
code = "SCRIPT_TOO_LARGE";
|
|
1656
1895
|
scriptLength;
|
|
@@ -1688,8 +1927,20 @@ var EnclaveService = class {
|
|
|
1688
1927
|
throw new ScriptTooLargeError(code.length, maxLength);
|
|
1689
1928
|
}
|
|
1690
1929
|
}
|
|
1930
|
+
const toolFailures = [];
|
|
1691
1931
|
const toolHandler = async (toolName, args) => {
|
|
1692
|
-
|
|
1932
|
+
try {
|
|
1933
|
+
return await environment.callTool(toolName, args);
|
|
1934
|
+
} catch (error) {
|
|
1935
|
+
const code2 = error?.code;
|
|
1936
|
+
toolFailures.push({
|
|
1937
|
+
toolName,
|
|
1938
|
+
name: toolFailureName(error),
|
|
1939
|
+
message: toolFailureMessage(error, toolName),
|
|
1940
|
+
...typeof code2 === "string" ? { code: code2 } : {}
|
|
1941
|
+
});
|
|
1942
|
+
throw error;
|
|
1943
|
+
}
|
|
1693
1944
|
};
|
|
1694
1945
|
const sidecar = this.sidecarOptions.enabled ? {
|
|
1695
1946
|
enabled: true,
|
|
@@ -1699,11 +1950,29 @@ var EnclaveService = class {
|
|
|
1699
1950
|
maxResolvedSize: this.sidecarOptions.maxResolvedSize,
|
|
1700
1951
|
allowComposites: this.sidecarOptions.allowComposites
|
|
1701
1952
|
} : void 0;
|
|
1702
|
-
const
|
|
1703
|
-
const
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1953
|
+
const { mcpLog, mcpNotify } = environment;
|
|
1954
|
+
const globals = {
|
|
1955
|
+
// Provide getTool as a custom global
|
|
1956
|
+
getTool: environment.getTool,
|
|
1957
|
+
// Provide logging functions if available
|
|
1958
|
+
...mcpLog ? {
|
|
1959
|
+
mcpLog: (level, message, metadata) => {
|
|
1960
|
+
mcpLog(level, message, metadata);
|
|
1961
|
+
logs.push(`[mcp:${level}] ${message}`);
|
|
1962
|
+
}
|
|
1963
|
+
} : {},
|
|
1964
|
+
...mcpNotify ? {
|
|
1965
|
+
mcpNotify: (event, payload) => {
|
|
1966
|
+
mcpNotify(event, payload);
|
|
1967
|
+
logs.push(`[notify] ${event}`);
|
|
1968
|
+
}
|
|
1969
|
+
} : {}
|
|
1970
|
+
// Note: enclave-vm v2.0.0+ provides its own __safe_console internally with rate limiting
|
|
1971
|
+
// and output size limits. Passing console in globals causes "Cannot redefine property"
|
|
1972
|
+
// errors due to Double VM architecture. Console output from user scripts goes to stdout
|
|
1973
|
+
// via enclave's internal console, not to this logs array. Only mcpLog/mcpNotify are captured.
|
|
1974
|
+
};
|
|
1975
|
+
const options = {
|
|
1707
1976
|
timeout: this.vmOptions.timeoutMs,
|
|
1708
1977
|
maxToolCalls: this.vmOptions.maxSteps || 100,
|
|
1709
1978
|
maxIterations: 1e4,
|
|
@@ -1713,38 +1982,20 @@ var EnclaveService = class {
|
|
|
1713
1982
|
validate: true,
|
|
1714
1983
|
transform: true,
|
|
1715
1984
|
sidecar,
|
|
1985
|
+
// Error stacks name no host file, whatever stage raised them.
|
|
1986
|
+
sanitizeStackTraces: true,
|
|
1716
1987
|
// Allow functions in globals since we intentionally provide getTool, mcpLog, mcpNotify, and console
|
|
1717
1988
|
allowFunctionsInGlobals: true,
|
|
1718
|
-
globals
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
getTool: environment.getTool,
|
|
1726
|
-
// Provide logging functions if available
|
|
1727
|
-
...environment.mcpLog ? {
|
|
1728
|
-
mcpLog: (level, message, metadata) => {
|
|
1729
|
-
environment.mcpLog(level, message, metadata);
|
|
1730
|
-
logs.push(`[mcp:${level}] ${message}`);
|
|
1731
|
-
}
|
|
1732
|
-
} : {},
|
|
1733
|
-
...environment.mcpNotify ? {
|
|
1734
|
-
mcpNotify: (event, payload) => {
|
|
1735
|
-
environment.mcpNotify(event, payload);
|
|
1736
|
-
logs.push(`[notify] ${event}`);
|
|
1737
|
-
}
|
|
1738
|
-
} : {}
|
|
1739
|
-
// Note: enclave-vm v2.0.0+ provides its own __safe_console internally with rate limiting
|
|
1740
|
-
// and output size limits. Passing console in globals causes "Cannot redefine property"
|
|
1741
|
-
// errors due to Double VM architecture. Console output from user scripts goes to stdout
|
|
1742
|
-
// via enclave's internal console, not to this logs array. Only mcpLog/mcpNotify are captured.
|
|
1743
|
-
}
|
|
1744
|
-
});
|
|
1989
|
+
globals,
|
|
1990
|
+
// Tool namespaces (`acme.getUser()` for a tool named `acme.getUser`) are built by the sandbox
|
|
1991
|
+
// itself: a method call is exactly `callTool('acme.getUser', args, options)`, with the
|
|
1992
|
+
// sandbox's tool-call cap, rate limit, suspicious-sequence checks and `throwOnError`.
|
|
1993
|
+
toolNamespaces: toSandboxToolNamespaces(environment.toolNamespaces, Object.keys(globals))
|
|
1994
|
+
};
|
|
1995
|
+
const enclave = createEnclave(options);
|
|
1745
1996
|
try {
|
|
1746
1997
|
const result = await enclave.run(code);
|
|
1747
|
-
return this.mapEnclaveResult(result, logs);
|
|
1998
|
+
return this.mapEnclaveResult(result, logs, toolFailures);
|
|
1748
1999
|
} finally {
|
|
1749
2000
|
enclave.dispose();
|
|
1750
2001
|
}
|
|
@@ -1752,58 +2003,56 @@ var EnclaveService = class {
|
|
|
1752
2003
|
/**
|
|
1753
2004
|
* Map Enclave ExecutionResult to EnclaveExecutionResult
|
|
1754
2005
|
*/
|
|
1755
|
-
mapEnclaveResult(result, logs) {
|
|
2006
|
+
mapEnclaveResult(result, logs, toolFailures = []) {
|
|
2007
|
+
const stats = {
|
|
2008
|
+
duration: result.stats.duration,
|
|
2009
|
+
toolCallCount: result.stats.toolCallCount,
|
|
2010
|
+
iterationCount: result.stats.iterationCount
|
|
2011
|
+
};
|
|
1756
2012
|
if (result.success) {
|
|
2013
|
+
return { success: true, result: result.value, logs, timedOut: false, stats };
|
|
2014
|
+
}
|
|
2015
|
+
const error = result.error ?? { name: "Error", message: "Script execution failed" };
|
|
2016
|
+
if (error.code === "ENCLAVE_ERROR" && error.message?.startsWith(PARSE_FAILURE_PREFIX)) {
|
|
2017
|
+
const { message, location } = parseFailureOf(error.message);
|
|
1757
2018
|
return {
|
|
1758
|
-
success:
|
|
1759
|
-
|
|
2019
|
+
success: false,
|
|
2020
|
+
error: { message, name: "SyntaxError", code: "SYNTAX_ERROR", ...location ? { location } : {} },
|
|
1760
2021
|
logs,
|
|
1761
2022
|
timedOut: false,
|
|
1762
|
-
stats
|
|
1763
|
-
duration: result.stats.duration,
|
|
1764
|
-
toolCallCount: result.stats.toolCallCount,
|
|
1765
|
-
iterationCount: result.stats.iterationCount
|
|
1766
|
-
}
|
|
2023
|
+
stats
|
|
1767
2024
|
};
|
|
1768
2025
|
}
|
|
1769
|
-
const
|
|
1770
|
-
|
|
1771
|
-
if (error.code === "VALIDATION_ERROR") {
|
|
1772
|
-
const issues = error.data?.issues ?? [];
|
|
1773
|
-
const blockedPatterns = [...new Set(issues.map((issue) => issue.code).filter((code) => !!code))];
|
|
2026
|
+
const toolFailure = [...toolFailures].reverse().find((failure) => failure.message === error.message && failure.name === error.name);
|
|
2027
|
+
if (toolFailure) {
|
|
1774
2028
|
return {
|
|
1775
2029
|
success: false,
|
|
1776
2030
|
error: {
|
|
1777
2031
|
message: error.message,
|
|
1778
|
-
name:
|
|
1779
|
-
code:
|
|
1780
|
-
|
|
2032
|
+
name: error.name,
|
|
2033
|
+
...toolFailure.code ? { code: toolFailure.code } : {},
|
|
2034
|
+
toolName: toolFailure.toolName
|
|
1781
2035
|
},
|
|
1782
2036
|
logs,
|
|
1783
2037
|
timedOut: false,
|
|
1784
|
-
stats
|
|
1785
|
-
duration: result.stats.duration,
|
|
1786
|
-
toolCallCount: result.stats.toolCallCount,
|
|
1787
|
-
iterationCount: result.stats.iterationCount
|
|
1788
|
-
}
|
|
2038
|
+
stats
|
|
1789
2039
|
};
|
|
1790
2040
|
}
|
|
1791
|
-
const
|
|
1792
|
-
|
|
1793
|
-
|
|
2041
|
+
const timedOut = error.message?.includes("timed out") || error.code === "TIMEOUT";
|
|
2042
|
+
if (error.code === "VALIDATION_ERROR") {
|
|
2043
|
+
const issues = error.data?.issues ?? [];
|
|
2044
|
+
const blockedPatterns = [...new Set(issues.map((issue) => issue.code).filter((code) => !!code))];
|
|
1794
2045
|
return {
|
|
1795
2046
|
success: false,
|
|
1796
2047
|
error: {
|
|
1797
2048
|
message: error.message,
|
|
1798
|
-
name:
|
|
1799
|
-
stack: error.stack,
|
|
2049
|
+
name: "ValidationError",
|
|
1800
2050
|
code: error.code,
|
|
1801
|
-
|
|
1802
|
-
toolInput: errorData?.["toolInput"],
|
|
1803
|
-
details: errorData?.["details"]
|
|
2051
|
+
...blockedPatterns.length > 0 ? { blockedPatterns } : {}
|
|
1804
2052
|
},
|
|
1805
2053
|
logs,
|
|
1806
|
-
timedOut
|
|
2054
|
+
timedOut: false,
|
|
2055
|
+
stats
|
|
1807
2056
|
};
|
|
1808
2057
|
}
|
|
1809
2058
|
return {
|
|
@@ -1816,11 +2065,7 @@ var EnclaveService = class {
|
|
|
1816
2065
|
},
|
|
1817
2066
|
logs,
|
|
1818
2067
|
timedOut,
|
|
1819
|
-
stats
|
|
1820
|
-
duration: result.stats.duration,
|
|
1821
|
-
toolCallCount: result.stats.toolCallCount,
|
|
1822
|
-
iterationCount: result.stats.iterationCount
|
|
1823
|
-
}
|
|
2068
|
+
stats
|
|
1824
2069
|
};
|
|
1825
2070
|
}
|
|
1826
2071
|
};
|
|
@@ -1831,9 +2076,19 @@ EnclaveService = __decorateClass([
|
|
|
1831
2076
|
scope: ProviderScope3.GLOBAL
|
|
1832
2077
|
})
|
|
1833
2078
|
], EnclaveService);
|
|
2079
|
+
function createEnclave(options) {
|
|
2080
|
+
try {
|
|
2081
|
+
return new Enclave(options);
|
|
2082
|
+
} catch (error) {
|
|
2083
|
+
if (!options.toolNamespaces || !(error instanceof TypeError) || !error.message.startsWith("Invalid toolNamespaces")) {
|
|
2084
|
+
throw error;
|
|
2085
|
+
}
|
|
2086
|
+
return new Enclave({ ...options, toolNamespaces: void 0 });
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
1834
2089
|
|
|
1835
2090
|
// plugins/plugin-codecall/src/tools/search.tool.ts
|
|
1836
|
-
import { Tool, ToolContext } from "@frontmcp/sdk";
|
|
2091
|
+
import { getCallSurface, Tool, ToolContext } from "@frontmcp/sdk";
|
|
1837
2092
|
|
|
1838
2093
|
// plugins/plugin-codecall/src/tools/search.schema.ts
|
|
1839
2094
|
import { z as z2 } from "@frontmcp/lazy-zod";
|
|
@@ -1891,7 +2146,10 @@ var SearchTool = class extends ToolContext {
|
|
|
1891
2146
|
const audit = this.tryGet(AuditLoggerService);
|
|
1892
2147
|
const executionId = audit ? audit.generateExecutionId() : "";
|
|
1893
2148
|
const startedAt = Date.now();
|
|
1894
|
-
const
|
|
2149
|
+
const surface = getCallSurface();
|
|
2150
|
+
const nonExistentExcludedTools = excludeToolNames.filter(
|
|
2151
|
+
(toolName) => !searchService.hasTool(toolName, surface)
|
|
2152
|
+
);
|
|
1895
2153
|
if (nonExistentExcludedTools.length > 0) {
|
|
1896
2154
|
warnings.push({
|
|
1897
2155
|
type: "excluded_tool_not_found",
|
|
@@ -1905,7 +2163,8 @@ var SearchTool = class extends ToolContext {
|
|
|
1905
2163
|
const searchResults = await searchService.search(query, {
|
|
1906
2164
|
topK,
|
|
1907
2165
|
appIds,
|
|
1908
|
-
excludeToolNames
|
|
2166
|
+
excludeToolNames,
|
|
2167
|
+
surface
|
|
1909
2168
|
});
|
|
1910
2169
|
for (const result of searchResults) {
|
|
1911
2170
|
if (result.relevanceScore < minRelevanceScore) {
|
|
@@ -1950,7 +2209,7 @@ var SearchTool = class extends ToolContext {
|
|
|
1950
2209
|
return {
|
|
1951
2210
|
tools,
|
|
1952
2211
|
warnings,
|
|
1953
|
-
totalAvailableTools: searchService.getTotalCount()
|
|
2212
|
+
totalAvailableTools: searchService.getTotalCount(surface)
|
|
1954
2213
|
};
|
|
1955
2214
|
}
|
|
1956
2215
|
};
|
|
@@ -2263,7 +2522,7 @@ SearchKnowledgeTool = __decorateClass([
|
|
|
2263
2522
|
|
|
2264
2523
|
// plugins/plugin-codecall/src/tools/describe.tool.ts
|
|
2265
2524
|
import { toJSONSchema, z as z6, ZodType } from "@frontmcp/lazy-zod";
|
|
2266
|
-
import { Tool as Tool4, ToolContext as ToolContext4 } from "@frontmcp/sdk";
|
|
2525
|
+
import { getCallSurface as getCallSurface2, Tool as Tool4, ToolContext as ToolContext4 } from "@frontmcp/sdk";
|
|
2267
2526
|
|
|
2268
2527
|
// plugins/plugin-codecall/src/errors/tool-call.errors.ts
|
|
2269
2528
|
var TOOL_CALL_ERROR_CODES = {
|
|
@@ -2301,11 +2560,10 @@ function getSanitizedMessage(code, toolName, rawMessage) {
|
|
|
2301
2560
|
}
|
|
2302
2561
|
}
|
|
2303
2562
|
function sanitizeValidationMessage(message) {
|
|
2304
|
-
let sanitized = message
|
|
2563
|
+
let sanitized = toClientErrorMessage(message);
|
|
2305
2564
|
sanitized = sanitized.replace(/\bat line \d+/gi, "");
|
|
2306
2565
|
sanitized = sanitized.replace(/\bline \d+/gi, "");
|
|
2307
2566
|
sanitized = sanitized.replace(/:\d+:\d+/g, "");
|
|
2308
|
-
sanitized = sanitized.replace(/\n\s*at .*/g, "");
|
|
2309
2567
|
if (sanitized.length > 200) {
|
|
2310
2568
|
sanitized = sanitized.substring(0, 200) + "...";
|
|
2311
2569
|
}
|
|
@@ -2343,75 +2601,6 @@ function assertNotSelfReference(toolName) {
|
|
|
2343
2601
|
}
|
|
2344
2602
|
}
|
|
2345
2603
|
|
|
2346
|
-
// plugins/plugin-codecall/src/utils/build-tool-namespaces.ts
|
|
2347
|
-
var IDENT_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
2348
|
-
var PROTOTYPE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
2349
|
-
var RESERVED_NAMESPACES = /* @__PURE__ */ new Set([
|
|
2350
|
-
"console",
|
|
2351
|
-
"Math",
|
|
2352
|
-
"JSON",
|
|
2353
|
-
"Object",
|
|
2354
|
-
"Array",
|
|
2355
|
-
"String",
|
|
2356
|
-
"Number",
|
|
2357
|
-
"Boolean",
|
|
2358
|
-
"Promise",
|
|
2359
|
-
"Symbol",
|
|
2360
|
-
"Map",
|
|
2361
|
-
"Set",
|
|
2362
|
-
"WeakMap",
|
|
2363
|
-
"WeakSet",
|
|
2364
|
-
"Date",
|
|
2365
|
-
"Error",
|
|
2366
|
-
"RegExp",
|
|
2367
|
-
"globalThis",
|
|
2368
|
-
"global",
|
|
2369
|
-
"window",
|
|
2370
|
-
"self",
|
|
2371
|
-
"undefined",
|
|
2372
|
-
"null",
|
|
2373
|
-
"true",
|
|
2374
|
-
"false",
|
|
2375
|
-
"callTool",
|
|
2376
|
-
"getTool",
|
|
2377
|
-
"mcpLog",
|
|
2378
|
-
"mcpNotify"
|
|
2379
|
-
]);
|
|
2380
|
-
function buildToolNamespaces(tools, callTool) {
|
|
2381
|
-
const namespaces = /* @__PURE__ */ Object.create(null);
|
|
2382
|
-
const skipped = [];
|
|
2383
|
-
for (const tool of tools) {
|
|
2384
|
-
const name = tool?.name;
|
|
2385
|
-
if (typeof name !== "string" || name.length === 0) continue;
|
|
2386
|
-
const dot = name.indexOf(".");
|
|
2387
|
-
if (dot <= 0 || dot === name.length - 1) {
|
|
2388
|
-
skipped.push({ name, reason: "no-namespace-prefix" });
|
|
2389
|
-
continue;
|
|
2390
|
-
}
|
|
2391
|
-
const ns = name.slice(0, dot);
|
|
2392
|
-
const method = name.slice(dot + 1);
|
|
2393
|
-
if (!IDENT_RE.test(ns) || !IDENT_RE.test(method)) {
|
|
2394
|
-
skipped.push({ name, reason: "invalid-identifier" });
|
|
2395
|
-
continue;
|
|
2396
|
-
}
|
|
2397
|
-
if (PROTOTYPE_KEYS.has(ns)) {
|
|
2398
|
-
skipped.push({ name, reason: "prototype-key" });
|
|
2399
|
-
continue;
|
|
2400
|
-
}
|
|
2401
|
-
if (RESERVED_NAMESPACES.has(ns)) {
|
|
2402
|
-
skipped.push({ name, reason: "reserved-namespace" });
|
|
2403
|
-
continue;
|
|
2404
|
-
}
|
|
2405
|
-
const bucket = namespaces[ns] ?? (namespaces[ns] = /* @__PURE__ */ Object.create(null));
|
|
2406
|
-
if (Object.prototype.hasOwnProperty.call(bucket, method)) {
|
|
2407
|
-
skipped.push({ name, reason: "duplicate-method" });
|
|
2408
|
-
continue;
|
|
2409
|
-
}
|
|
2410
|
-
bucket[method] = (input, options) => callTool(name, input, options);
|
|
2411
|
-
}
|
|
2412
|
-
return { namespaces, skipped };
|
|
2413
|
-
}
|
|
2414
|
-
|
|
2415
2604
|
// plugins/plugin-codecall/src/utils/describe.utils.ts
|
|
2416
2605
|
var INTENT_PATTERNS = {
|
|
2417
2606
|
create: /^(create|add|new|insert|make|append|register|generate|produce|build|construct|provision|instantiate|define|compose|draft)/i,
|
|
@@ -2773,12 +2962,13 @@ var DescribeTool = class extends ToolContext4 {
|
|
|
2773
2962
|
const tools = [];
|
|
2774
2963
|
const notFound = [];
|
|
2775
2964
|
const config = this.get(CodeCallConfig);
|
|
2965
|
+
const surface = getCallSurface2();
|
|
2776
2966
|
for (const toolName of toolNames) {
|
|
2777
2967
|
if (isBlockedSelfReference(toolName)) {
|
|
2778
2968
|
notFound.push(toolName);
|
|
2779
2969
|
continue;
|
|
2780
2970
|
}
|
|
2781
|
-
const access = checkCodeCallToolAccess(this.scope, config, toolName);
|
|
2971
|
+
const access = checkCodeCallToolAccess(this.scope, config, toolName, { surface });
|
|
2782
2972
|
if (!access.allowed) {
|
|
2783
2973
|
audit?.logSecurityAccessDenied(executionId, toolName, access.reason);
|
|
2784
2974
|
notFound.push(toolName);
|
|
@@ -2936,7 +3126,7 @@ DescribeTool = __decorateClass([
|
|
|
2936
3126
|
], DescribeTool);
|
|
2937
3127
|
|
|
2938
3128
|
// plugins/plugin-codecall/src/tools/execute.tool.ts
|
|
2939
|
-
import { Tool as Tool5, ToolContext as ToolContext5 } from "@frontmcp/sdk";
|
|
3129
|
+
import { getCallSurface as getCallSurface3, Tool as Tool5, ToolContext as ToolContext5 } from "@frontmcp/sdk";
|
|
2940
3130
|
|
|
2941
3131
|
// plugins/plugin-codecall/src/tools/execute.schema.ts
|
|
2942
3132
|
import { z as z7 } from "@frontmcp/lazy-zod";
|
|
@@ -2990,6 +3180,7 @@ var runtimeErrorPayloadSchema = z7.object({
|
|
|
2990
3180
|
source: z7.literal("script"),
|
|
2991
3181
|
message: z7.string(),
|
|
2992
3182
|
name: z7.string().optional(),
|
|
3183
|
+
/** @deprecated Never set: stack traces name server files, so results don't carry them. */
|
|
2993
3184
|
stack: z7.string().optional()
|
|
2994
3185
|
});
|
|
2995
3186
|
var toolErrorPayloadSchema = z7.object({
|
|
@@ -2998,6 +3189,7 @@ var toolErrorPayloadSchema = z7.object({
|
|
|
2998
3189
|
toolInput: z7.unknown(),
|
|
2999
3190
|
message: z7.string(),
|
|
3000
3191
|
code: z7.string().optional(),
|
|
3192
|
+
/** @deprecated Never set: the enclave's error data is not sanitized for clients. */
|
|
3001
3193
|
details: z7.unknown().optional()
|
|
3002
3194
|
});
|
|
3003
3195
|
var timeoutErrorPayloadSchema = z7.object({
|
|
@@ -3062,11 +3254,12 @@ var ExecuteTool = class extends ToolContext5 {
|
|
|
3062
3254
|
* otherwise it would skip every metadata-driven check and reach `tools:call-tool`
|
|
3063
3255
|
* unexamined.
|
|
3064
3256
|
*/
|
|
3065
|
-
checkToolPolicy(name) {
|
|
3066
|
-
return checkCodeCallToolAccess(this.scope, this.get(CodeCallConfig), name);
|
|
3257
|
+
checkToolPolicy(name, surface) {
|
|
3258
|
+
return checkCodeCallToolAccess(this.scope, this.get(CodeCallConfig), name, { surface });
|
|
3067
3259
|
}
|
|
3068
3260
|
async execute(input) {
|
|
3069
3261
|
const { script, allowedTools } = input;
|
|
3262
|
+
const callerSurface = getCallSurface3();
|
|
3070
3263
|
const audit = this.tryGet(AuditLoggerService);
|
|
3071
3264
|
const executionId = audit ? audit.generateExecutionId() : "";
|
|
3072
3265
|
const callDepth = 1;
|
|
@@ -3079,7 +3272,7 @@ var ExecuteTool = class extends ToolContext5 {
|
|
|
3079
3272
|
audit?.logSecuritySelfReference(executionId, name);
|
|
3080
3273
|
}
|
|
3081
3274
|
assertNotSelfReference(name);
|
|
3082
|
-
const decision = this.checkToolPolicy(name);
|
|
3275
|
+
const decision = this.checkToolPolicy(name, callerSurface);
|
|
3083
3276
|
if (!decision.allowed) {
|
|
3084
3277
|
audit?.logSecurityAccessDenied(executionId, name, decision.reason);
|
|
3085
3278
|
const error = createToolCallError(TOOL_CALL_ERROR_CODES.ACCESS_DENIED, name, decision.reason);
|
|
@@ -3108,7 +3301,8 @@ var ExecuteTool = class extends ToolContext5 {
|
|
|
3108
3301
|
}
|
|
3109
3302
|
};
|
|
3110
3303
|
const ctx = {
|
|
3111
|
-
authInfo: this.authInfo
|
|
3304
|
+
authInfo: this.authInfo,
|
|
3305
|
+
surface: callerSurface
|
|
3112
3306
|
};
|
|
3113
3307
|
const mcpResult = await this.scope.runFlow("tools:call-tool", { request, ctx });
|
|
3114
3308
|
if (!mcpResult) {
|
|
@@ -3148,7 +3342,7 @@ var ExecuteTool = class extends ToolContext5 {
|
|
|
3148
3342
|
audit?.logSecuritySelfReference(executionId, name);
|
|
3149
3343
|
return void 0;
|
|
3150
3344
|
}
|
|
3151
|
-
const introspectionAccess = this.checkToolPolicy(name);
|
|
3345
|
+
const introspectionAccess = this.checkToolPolicy(name, callerSurface);
|
|
3152
3346
|
if (!introspectionAccess.allowed) {
|
|
3153
3347
|
audit?.logSecurityAccessDenied(executionId, name, introspectionAccess.reason);
|
|
3154
3348
|
return void 0;
|
|
@@ -3178,8 +3372,8 @@ var ExecuteTool = class extends ToolContext5 {
|
|
|
3178
3372
|
const callableTools = this.scope.tools.getTools(true).filter(
|
|
3179
3373
|
(tool) => checkCodeCallToolPolicy(toCodeCallPolicyTool(tool, void 0, this.scope), policyConfig).allowed
|
|
3180
3374
|
);
|
|
3181
|
-
const { namespaces, skipped } = buildToolNamespaces(callableTools
|
|
3182
|
-
environment.
|
|
3375
|
+
const { namespaces, skipped } = buildToolNamespaces(callableTools);
|
|
3376
|
+
environment.toolNamespaces = namespaces;
|
|
3183
3377
|
if (skipped.length > 0) {
|
|
3184
3378
|
this.logger?.debug?.("codecall: tools skipped during namespace generation", {
|
|
3185
3379
|
count: skipped.length,
|
|
@@ -3211,6 +3405,16 @@ var ExecuteTool = class extends ToolContext5 {
|
|
|
3211
3405
|
}
|
|
3212
3406
|
if (!executionResult.success) {
|
|
3213
3407
|
const error = executionResult.error;
|
|
3408
|
+
if (error.code === "SYNTAX_ERROR") {
|
|
3409
|
+
audit?.logExecutionFailure(executionId, script, durationMs, error.message);
|
|
3410
|
+
return {
|
|
3411
|
+
status: "syntax_error",
|
|
3412
|
+
error: {
|
|
3413
|
+
message: toClientErrorMessage(error.message) || "Syntax error in script",
|
|
3414
|
+
...error.location ? { location: error.location } : {}
|
|
3415
|
+
}
|
|
3416
|
+
};
|
|
3417
|
+
}
|
|
3214
3418
|
if (error.code === "VALIDATION_ERROR" || error.name === "ValidationError") {
|
|
3215
3419
|
audit?.logSecurityAstBlocked(executionId, error.blockedPatterns?.join(", ") ?? "UNKNOWN", error.message);
|
|
3216
3420
|
audit?.logExecutionFailure(executionId, script, durationMs, error.message);
|
|
@@ -3230,9 +3434,9 @@ var ExecuteTool = class extends ToolContext5 {
|
|
|
3230
3434
|
source: "tool",
|
|
3231
3435
|
toolName: error.toolName,
|
|
3232
3436
|
toolInput: error.toolInput,
|
|
3233
|
-
message: error.message,
|
|
3234
|
-
code: error.code
|
|
3235
|
-
details
|
|
3437
|
+
message: toClientErrorMessage(error.message),
|
|
3438
|
+
code: error.code
|
|
3439
|
+
// No `details`: the enclave's error data is not sanitized for clients.
|
|
3236
3440
|
}
|
|
3237
3441
|
};
|
|
3238
3442
|
}
|
|
@@ -3241,9 +3445,8 @@ var ExecuteTool = class extends ToolContext5 {
|
|
|
3241
3445
|
status: "runtime_error",
|
|
3242
3446
|
error: {
|
|
3243
3447
|
source: "script",
|
|
3244
|
-
message: error.message,
|
|
3245
|
-
name: error.name
|
|
3246
|
-
stack: error.stack
|
|
3448
|
+
message: toClientErrorMessage(error.message),
|
|
3449
|
+
name: error.name
|
|
3247
3450
|
}
|
|
3248
3451
|
};
|
|
3249
3452
|
}
|
|
@@ -3257,13 +3460,12 @@ var ExecuteTool = class extends ToolContext5 {
|
|
|
3257
3460
|
const errorName = error instanceof Error ? error.name : "Error";
|
|
3258
3461
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3259
3462
|
audit?.logExecutionFailure(executionId, script, elapsed(), errorMessage);
|
|
3260
|
-
const errorStack = error instanceof Error ? error.stack : void 0;
|
|
3261
3463
|
const errorLoc = error.loc;
|
|
3262
3464
|
if (errorName === "SyntaxError" || errorMessage?.includes("syntax")) {
|
|
3263
3465
|
return {
|
|
3264
3466
|
status: "syntax_error",
|
|
3265
3467
|
error: {
|
|
3266
|
-
message: errorMessage || "Syntax error in script",
|
|
3468
|
+
message: toClientErrorMessage(errorMessage) || "Syntax error in script",
|
|
3267
3469
|
location: errorLoc ? { line: errorLoc.line, column: errorLoc.column } : void 0
|
|
3268
3470
|
}
|
|
3269
3471
|
};
|
|
@@ -3272,9 +3474,8 @@ var ExecuteTool = class extends ToolContext5 {
|
|
|
3272
3474
|
status: "runtime_error",
|
|
3273
3475
|
error: {
|
|
3274
3476
|
source: "script",
|
|
3275
|
-
message: errorMessage || "An unexpected error occurred during script execution",
|
|
3276
|
-
name: errorName
|
|
3277
|
-
stack: errorStack
|
|
3477
|
+
message: toClientErrorMessage(errorMessage) || "An unexpected error occurred during script execution",
|
|
3478
|
+
name: errorName
|
|
3278
3479
|
}
|
|
3279
3480
|
};
|
|
3280
3481
|
}
|
|
@@ -3299,7 +3500,7 @@ ExecuteTool = __decorateClass([
|
|
|
3299
3500
|
], ExecuteTool);
|
|
3300
3501
|
|
|
3301
3502
|
// plugins/plugin-codecall/src/tools/invoke.tool.ts
|
|
3302
|
-
import { Tool as Tool6, ToolContext as ToolContext6 } from "@frontmcp/sdk";
|
|
3503
|
+
import { getCallSurface as getCallSurface4, Tool as Tool6, ToolContext as ToolContext6 } from "@frontmcp/sdk";
|
|
3303
3504
|
|
|
3304
3505
|
// plugins/plugin-codecall/src/tools/invoke.schema.ts
|
|
3305
3506
|
import { z as z8 } from "@frontmcp/lazy-zod";
|
|
@@ -3343,7 +3544,11 @@ var InvokeTool = class extends ToolContext6 {
|
|
|
3343
3544
|
`Tool "${toolName}" cannot be invoked directly. CodeCall tools are internal and not accessible via codecall:invoke.`
|
|
3344
3545
|
);
|
|
3345
3546
|
}
|
|
3346
|
-
const
|
|
3547
|
+
const surface = getCallSurface4();
|
|
3548
|
+
const decision = checkCodeCallToolAccess(this.scope, this.get(CodeCallConfig), toolName, {
|
|
3549
|
+
directCall: true,
|
|
3550
|
+
surface
|
|
3551
|
+
});
|
|
3347
3552
|
if (!decision.allowed) {
|
|
3348
3553
|
audit?.logSecurityAccessDenied(executionId, toolName, decision.reason);
|
|
3349
3554
|
return buildErrorResult(`Tool "${toolName}" is not available. Use codecall:search to discover available tools.`);
|
|
@@ -3356,7 +3561,8 @@ var InvokeTool = class extends ToolContext6 {
|
|
|
3356
3561
|
}
|
|
3357
3562
|
};
|
|
3358
3563
|
const ctx = {
|
|
3359
|
-
authInfo: this.authInfo
|
|
3564
|
+
authInfo: this.authInfo,
|
|
3565
|
+
surface
|
|
3360
3566
|
};
|
|
3361
3567
|
const result = await this.scope.runFlow("tools:call-tool", { request, ctx });
|
|
3362
3568
|
if (!result) {
|