@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/index.js
CHANGED
|
@@ -413,6 +413,46 @@ function presetDefaults(preset) {
|
|
|
413
413
|
|
|
414
414
|
// plugins/plugin-codecall/src/services/audit-logger.service.ts
|
|
415
415
|
var import_sdk2 = require("@frontmcp/sdk");
|
|
416
|
+
|
|
417
|
+
// plugins/plugin-codecall/src/utils/client-error-message.ts
|
|
418
|
+
var EMBEDDED_STACK_FRAME_RE = /\n[ \t]*at\s[^\n]*/g;
|
|
419
|
+
var QUOTED_PATH_RE = /(['"`])((?:~?\/|[A-Za-z]:[\\/]|\\\\)[^\s'"`\\/][^'"`\n]*)\1/g;
|
|
420
|
+
var URL_RE = /\b[A-Za-z][A-Za-z0-9+.-]{1,31}:\/\/(?:[^\s'"`<>,;]|[,;](?!~?\/|[A-Za-z]:[\\/]|\\\\))*/g;
|
|
421
|
+
var QUERY_PATH_VALUE_RE = /([?&][^=&#]*=)(?:~?\/|[A-Za-z]:[\\/]|\\\\)[^&#]*/g;
|
|
422
|
+
var POSIX_SEGMENT = String.raw`[^\s/\\'"\x60<>|,;:()\[\]{}]+`;
|
|
423
|
+
var WINDOWS_SEGMENT = String.raw`[^\s/\\'"\x60<>|,;:*?]+`;
|
|
424
|
+
function segments(segment, separator) {
|
|
425
|
+
const spaced = `${segment}(?: ${segment}){0,2}`;
|
|
426
|
+
return `(?:(?:${spaced}${separator})+(?:${segment})?|${segment})`;
|
|
427
|
+
}
|
|
428
|
+
var UNQUOTED_PATH_RE = new RegExp(
|
|
429
|
+
[
|
|
430
|
+
String.raw`(?<![\w.~/\\)\]-])~?/+${segments(POSIX_SEGMENT, "/+")}`,
|
|
431
|
+
String.raw`(?<![\w\\/])[A-Za-z]:[\\/]+${segments(WINDOWS_SEGMENT, String.raw`[\\/]+`)}?`,
|
|
432
|
+
String.raw`(?<![\w\\])\\\\${segments(WINDOWS_SEGMENT, String.raw`[\\/]+`)}`
|
|
433
|
+
].join("|"),
|
|
434
|
+
"g"
|
|
435
|
+
);
|
|
436
|
+
function redactPaths(text) {
|
|
437
|
+
return text.replace(QUOTED_PATH_RE, "$1[path]$1").replace(UNQUOTED_PATH_RE, "[path]");
|
|
438
|
+
}
|
|
439
|
+
function toClientErrorMessage(message) {
|
|
440
|
+
if (!message) return "";
|
|
441
|
+
return redactAbsolutePaths(message.replace(EMBEDDED_STACK_FRAME_RE, ""));
|
|
442
|
+
}
|
|
443
|
+
function redactAbsolutePaths(text) {
|
|
444
|
+
let result = "";
|
|
445
|
+
let last = 0;
|
|
446
|
+
for (const match of text.matchAll(URL_RE)) {
|
|
447
|
+
const start = match.index ?? 0;
|
|
448
|
+
result += redactPaths(text.slice(last, start));
|
|
449
|
+
result += /^file:/i.test(match[0]) ? "[path]" : match[0].replace(QUERY_PATH_VALUE_RE, "$1[path]");
|
|
450
|
+
last = start + match[0].length;
|
|
451
|
+
}
|
|
452
|
+
return result + redactPaths(text.slice(last));
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// plugins/plugin-codecall/src/services/audit-logger.service.ts
|
|
416
456
|
var AUDIT_EVENT_TYPES = {
|
|
417
457
|
/** Script execution started */
|
|
418
458
|
EXECUTION_START: "codecall:execution:start",
|
|
@@ -689,9 +729,8 @@ var AuditLoggerService = class {
|
|
|
689
729
|
*/
|
|
690
730
|
sanitizeError(error) {
|
|
691
731
|
if (!error) return "Unknown error";
|
|
692
|
-
let sanitized = error
|
|
732
|
+
let sanitized = toClientErrorMessage(error);
|
|
693
733
|
sanitized = sanitized.replace(/:\d+:\d+/g, "");
|
|
694
|
-
sanitized = sanitized.replace(/\n\s*at .*/g, "");
|
|
695
734
|
if (sanitized.length > 200) {
|
|
696
735
|
sanitized = sanitized.substring(0, 200) + "...";
|
|
697
736
|
}
|
|
@@ -710,6 +749,10 @@ var import_vectoriadb = require("vectoriadb");
|
|
|
710
749
|
|
|
711
750
|
// plugins/plugin-codecall/src/security/codecall-tool-policy.ts
|
|
712
751
|
var BLOCKED_NAMESPACE_PATTERNS = Object.freeze([/^system:/, /^internal:/, /^__/]);
|
|
752
|
+
function isOfferedToCaller(availableWhen, surface) {
|
|
753
|
+
const offered = availableWhen?.surface;
|
|
754
|
+
return offered === void 0 || surface === void 0 || offered.includes(surface);
|
|
755
|
+
}
|
|
713
756
|
var ALLOWED = { allowed: true };
|
|
714
757
|
function deny(reason) {
|
|
715
758
|
return { allowed: false, reason };
|
|
@@ -730,16 +773,46 @@ function toCodeCallPolicyTool(entry, requestedName, scope) {
|
|
|
730
773
|
tags: metadata?.tags,
|
|
731
774
|
// `internal` tools refuse every external tools/call, CodeCall's included, so no surface may offer them.
|
|
732
775
|
hidden: metadata?.hideFromDiscovery === true || metadata?.visibility === "hidden" || metadata?.visibility === "internal",
|
|
733
|
-
codecall: metadata?.codecall
|
|
776
|
+
codecall: metadata?.codecall,
|
|
777
|
+
annotations: metadata?.annotations,
|
|
778
|
+
metadata
|
|
734
779
|
};
|
|
735
780
|
}
|
|
781
|
+
function isPlainData(value) {
|
|
782
|
+
if (Array.isArray(value)) return true;
|
|
783
|
+
const proto = Object.getPrototypeOf(value);
|
|
784
|
+
return proto === Object.prototype || proto === null;
|
|
785
|
+
}
|
|
786
|
+
function readOnlyCopy(value, copies) {
|
|
787
|
+
if (typeof value !== "object" || value === null || !isPlainData(value)) return value;
|
|
788
|
+
const existing = copies.get(value);
|
|
789
|
+
if (existing !== void 0) return existing;
|
|
790
|
+
const copy = Array.isArray(value) ? [] : Object.create(Object.getPrototypeOf(value));
|
|
791
|
+
copies.set(value, copy);
|
|
792
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
793
|
+
if (!Object.prototype.propertyIsEnumerable.call(value, key)) continue;
|
|
794
|
+
Object.defineProperty(copy, key, {
|
|
795
|
+
value: readOnlyCopy(Reflect.get(value, key), copies),
|
|
796
|
+
enumerable: true,
|
|
797
|
+
writable: true,
|
|
798
|
+
configurable: true
|
|
799
|
+
});
|
|
800
|
+
}
|
|
801
|
+
return Object.freeze(copy);
|
|
802
|
+
}
|
|
736
803
|
function toToolFilterInfo(tool) {
|
|
804
|
+
const copies = /* @__PURE__ */ new WeakMap();
|
|
805
|
+
const annotations = readOnlyCopy(tool.annotations, copies);
|
|
806
|
+
const metadata = tool.metadata ? readOnlyCopy({ ...tool.metadata, ...annotations ? { annotations: tool.annotations } : {} }, copies) : void 0;
|
|
737
807
|
return {
|
|
738
808
|
name: tool.name,
|
|
809
|
+
fullName: tool.fullName,
|
|
739
810
|
appId: tool.appId,
|
|
740
811
|
source: tool.codecall?.source,
|
|
741
812
|
description: tool.description,
|
|
742
|
-
tags: tool.codecall?.tags ?? tool.tags
|
|
813
|
+
tags: readOnlyCopy(tool.codecall?.tags ?? tool.tags, copies),
|
|
814
|
+
annotations,
|
|
815
|
+
metadata
|
|
743
816
|
};
|
|
744
817
|
}
|
|
745
818
|
function ownNamesOf(tool) {
|
|
@@ -826,6 +899,9 @@ function readCodeCallPolicyConfig(config) {
|
|
|
826
899
|
function checkCodeCallToolAccess(scope, config, name, options = {}) {
|
|
827
900
|
const entry = resolveCodeCallTool(scope, name);
|
|
828
901
|
if (!entry) return denyUnknownTool(name);
|
|
902
|
+
if (!isOfferedToCaller(entry.metadata?.availableWhen, options.surface)) {
|
|
903
|
+
return deny(`Tool "${name}" is not offered on the caller's surface "${options.surface}"`);
|
|
904
|
+
}
|
|
829
905
|
const policyTool = toCodeCallPolicyTool(entry, name, scope);
|
|
830
906
|
const baseDecision = checkCodeCallToolPolicy(policyTool, readCodeCallPolicyConfig(config));
|
|
831
907
|
if (!baseDecision.allowed) return baseDecision;
|
|
@@ -1359,6 +1435,8 @@ var ToolSearchService = class _ToolSearchService {
|
|
|
1359
1435
|
subscriptionReject = null;
|
|
1360
1436
|
retryTimeoutId = null;
|
|
1361
1437
|
disposed = false;
|
|
1438
|
+
/** `availableWhen` of each indexed tool, by indexed name, for per-caller surface filtering. */
|
|
1439
|
+
availabilityByTool = /* @__PURE__ */ new Map();
|
|
1362
1440
|
constructor(config = {}, scope) {
|
|
1363
1441
|
this.scope = scope;
|
|
1364
1442
|
const embeddingOptions = config.embeddingOptions || {
|
|
@@ -1468,6 +1546,7 @@ var ToolSearchService = class _ToolSearchService {
|
|
|
1468
1546
|
*/
|
|
1469
1547
|
async handleToolChange(tools) {
|
|
1470
1548
|
this.vectorDB.clear();
|
|
1549
|
+
this.availabilityByTool = /* @__PURE__ */ new Map();
|
|
1471
1550
|
if (tools.length === 0) {
|
|
1472
1551
|
this.initialized = true;
|
|
1473
1552
|
return;
|
|
@@ -1482,6 +1561,7 @@ var ToolSearchService = class _ToolSearchService {
|
|
|
1482
1561
|
return;
|
|
1483
1562
|
}
|
|
1484
1563
|
const documents = filteredTools.map((tool) => {
|
|
1564
|
+
this.availabilityByTool.set(tool.name, tool.metadata.availableWhen);
|
|
1485
1565
|
const searchableText = this.extractSearchableText(tool);
|
|
1486
1566
|
const appId = this.extractAppId(tool);
|
|
1487
1567
|
const toolName = tool.name;
|
|
@@ -1610,12 +1690,15 @@ var ToolSearchService = class _ToolSearchService {
|
|
|
1610
1690
|
*/
|
|
1611
1691
|
async search(query, options = {}) {
|
|
1612
1692
|
await this.ensureSubscribed();
|
|
1613
|
-
const { topK = this.config.defaultTopK, appIds, excludeToolNames = [] } = options;
|
|
1693
|
+
const { topK = this.config.defaultTopK, appIds, excludeToolNames = [], surface } = options;
|
|
1614
1694
|
const minScore = this.config.defaultSimilarityThreshold;
|
|
1615
1695
|
const filter = (metadata) => {
|
|
1616
1696
|
if (excludeToolNames.includes(metadata.toolName)) {
|
|
1617
1697
|
return false;
|
|
1618
1698
|
}
|
|
1699
|
+
if (!isOfferedToCaller(metadata.toolInstance.metadata.availableWhen, surface)) {
|
|
1700
|
+
return false;
|
|
1701
|
+
}
|
|
1619
1702
|
if (appIds && appIds.length > 0) {
|
|
1620
1703
|
if (!metadata.appId || !appIds.includes(metadata.appId)) {
|
|
1621
1704
|
return false;
|
|
@@ -1647,9 +1730,12 @@ var ToolSearchService = class _ToolSearchService {
|
|
|
1647
1730
|
}
|
|
1648
1731
|
}
|
|
1649
1732
|
/**
|
|
1650
|
-
* Gets the total number of indexed tools
|
|
1733
|
+
* Gets the total number of indexed tools, or of those a caller on `surface` may reach
|
|
1651
1734
|
*/
|
|
1652
|
-
getTotalCount() {
|
|
1735
|
+
getTotalCount(surface) {
|
|
1736
|
+
if (surface !== void 0) {
|
|
1737
|
+
return this.getAllToolNames().filter((toolName) => this.hasTool(toolName, surface)).length;
|
|
1738
|
+
}
|
|
1653
1739
|
if (this.vectorDB instanceof import_vectoriadb.VectoriaDB) {
|
|
1654
1740
|
return this.vectorDB.size();
|
|
1655
1741
|
} else {
|
|
@@ -1657,20 +1743,18 @@ var ToolSearchService = class _ToolSearchService {
|
|
|
1657
1743
|
}
|
|
1658
1744
|
}
|
|
1659
1745
|
/**
|
|
1660
|
-
* Checks if a tool exists in the index
|
|
1746
|
+
* Checks if a tool exists in the index, for a caller on `surface` when given
|
|
1661
1747
|
*/
|
|
1662
|
-
hasTool(toolName) {
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
} else {
|
|
1666
|
-
return this.vectorDB.hasDocument(toolName);
|
|
1667
|
-
}
|
|
1748
|
+
hasTool(toolName, surface) {
|
|
1749
|
+
const indexed = this.vectorDB instanceof import_vectoriadb.VectoriaDB ? this.vectorDB.has(toolName) : this.vectorDB.hasDocument(toolName);
|
|
1750
|
+
return indexed && isOfferedToCaller(this.availabilityByTool.get(toolName), surface);
|
|
1668
1751
|
}
|
|
1669
1752
|
/**
|
|
1670
1753
|
* Clears the entire index
|
|
1671
1754
|
*/
|
|
1672
1755
|
clear() {
|
|
1673
1756
|
this.vectorDB.clear();
|
|
1757
|
+
this.availabilityByTool = /* @__PURE__ */ new Map();
|
|
1674
1758
|
this.initialized = false;
|
|
1675
1759
|
}
|
|
1676
1760
|
/**
|
|
@@ -1690,6 +1774,159 @@ var ToolSearchService = class _ToolSearchService {
|
|
|
1690
1774
|
// plugins/plugin-codecall/src/services/enclave.service.ts
|
|
1691
1775
|
var import_core = require("@enclave-vm/core");
|
|
1692
1776
|
var import_sdk3 = require("@frontmcp/sdk");
|
|
1777
|
+
|
|
1778
|
+
// plugins/plugin-codecall/src/utils/build-tool-namespaces.ts
|
|
1779
|
+
var IDENT_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
1780
|
+
var PROTOTYPE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
1781
|
+
var RESERVED_NAMESPACES = /* @__PURE__ */ new Set([
|
|
1782
|
+
"console",
|
|
1783
|
+
"Math",
|
|
1784
|
+
"JSON",
|
|
1785
|
+
"Object",
|
|
1786
|
+
"Array",
|
|
1787
|
+
"String",
|
|
1788
|
+
"Number",
|
|
1789
|
+
"Boolean",
|
|
1790
|
+
"Promise",
|
|
1791
|
+
"Symbol",
|
|
1792
|
+
"Map",
|
|
1793
|
+
"Set",
|
|
1794
|
+
"WeakMap",
|
|
1795
|
+
"WeakSet",
|
|
1796
|
+
"Date",
|
|
1797
|
+
"Error",
|
|
1798
|
+
"RegExp",
|
|
1799
|
+
"globalThis",
|
|
1800
|
+
"global",
|
|
1801
|
+
"window",
|
|
1802
|
+
"self",
|
|
1803
|
+
"undefined",
|
|
1804
|
+
"null",
|
|
1805
|
+
"true",
|
|
1806
|
+
"false",
|
|
1807
|
+
"callTool",
|
|
1808
|
+
"getTool",
|
|
1809
|
+
"mcpLog",
|
|
1810
|
+
"mcpNotify"
|
|
1811
|
+
]);
|
|
1812
|
+
var UNBINDABLE_NAMESPACES = new Set(
|
|
1813
|
+
[
|
|
1814
|
+
// Reserved words and strict-mode restricted bindings
|
|
1815
|
+
"break case catch class const continue debugger default delete do else enum export extends finally for",
|
|
1816
|
+
"function if import in instanceof new return super switch this throw try typeof var void while with yield",
|
|
1817
|
+
"let static implements interface package private protected public await eval arguments NaN Infinity",
|
|
1818
|
+
// AgentScript globals
|
|
1819
|
+
"parallel isNaN isFinite parseInt parseFloat encodeURI encodeURIComponent decodeURI decodeURIComponent",
|
|
1820
|
+
// Identifiers the AgentScript validator refuses
|
|
1821
|
+
"process require module exports Buffer Function AsyncFunction GeneratorFunction Reflect Proxy TypeError",
|
|
1822
|
+
"ReferenceError SyntaxError RangeError URIError EvalError AggregateError fetch XMLHttpRequest WebSocket",
|
|
1823
|
+
"localStorage sessionStorage indexedDB crypto performance structuredClone AbortController AbortSignal",
|
|
1824
|
+
"MessageChannel MessagePort BroadcastChannel TextEncoder TextDecoder Intl setTimeout setInterval",
|
|
1825
|
+
"setImmediate clearTimeout clearInterval clearImmediate queueMicrotask WebAssembly Worker SharedWorker",
|
|
1826
|
+
"ServiceWorker WeakRef FinalizationRegistry BigInt Atomics SharedArrayBuffer ArrayBuffer DataView",
|
|
1827
|
+
"importScripts ShadowRealm Iterator AsyncIterator"
|
|
1828
|
+
].join(" ").split(" ")
|
|
1829
|
+
);
|
|
1830
|
+
var UNCALLABLE_METHODS = new Set(
|
|
1831
|
+
[
|
|
1832
|
+
"process require module exports Buffer eval Function AsyncFunction GeneratorFunction arguments RegExp",
|
|
1833
|
+
"Promise Symbol Proxy Reflect Error TypeError ReferenceError SyntaxError RangeError URIError EvalError",
|
|
1834
|
+
"AggregateError fetch XMLHttpRequest WebSocket localStorage sessionStorage indexedDB crypto performance",
|
|
1835
|
+
"structuredClone AbortController AbortSignal MessageChannel MessagePort BroadcastChannel TextEncoder",
|
|
1836
|
+
"TextDecoder Intl setTimeout setInterval setImmediate clearTimeout clearInterval clearImmediate",
|
|
1837
|
+
"queueMicrotask WebAssembly Worker SharedWorker ServiceWorker WeakMap WeakSet WeakRef FinalizationRegistry",
|
|
1838
|
+
"Map Set Atomics SharedArrayBuffer importScripts ShadowRealm Iterator AsyncIterator"
|
|
1839
|
+
].join(" ").split(" ")
|
|
1840
|
+
);
|
|
1841
|
+
var SANDBOX_TOOL_NAME_RE = /^[a-zA-Z][a-zA-Z0-9:._-]*$/;
|
|
1842
|
+
var MAX_SANDBOX_TOOL_NAME_LENGTH = 256;
|
|
1843
|
+
function isBindableNamespace(ns, reservedGlobals) {
|
|
1844
|
+
return IDENT_RE.test(ns) && !PROTOTYPE_KEYS.has(ns) && !ns.startsWith("__") && !RESERVED_NAMESPACES.has(ns) && !UNBINDABLE_NAMESPACES.has(ns) && !reservedGlobals.has(ns);
|
|
1845
|
+
}
|
|
1846
|
+
function isBindableMethod(ns, method, toolName) {
|
|
1847
|
+
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);
|
|
1848
|
+
}
|
|
1849
|
+
function buildToolNamespaces(tools) {
|
|
1850
|
+
const namespaces = /* @__PURE__ */ Object.create(null);
|
|
1851
|
+
const skipped = [];
|
|
1852
|
+
for (const tool of tools) {
|
|
1853
|
+
const name = tool?.name;
|
|
1854
|
+
if (typeof name !== "string" || name.length === 0) continue;
|
|
1855
|
+
const dot = name.indexOf(".");
|
|
1856
|
+
if (dot <= 0 || dot === name.length - 1) {
|
|
1857
|
+
skipped.push({ name, reason: "no-namespace-prefix" });
|
|
1858
|
+
continue;
|
|
1859
|
+
}
|
|
1860
|
+
const ns = name.slice(0, dot);
|
|
1861
|
+
const method = name.slice(dot + 1);
|
|
1862
|
+
if (!IDENT_RE.test(ns) || !IDENT_RE.test(method)) {
|
|
1863
|
+
skipped.push({ name, reason: "invalid-identifier" });
|
|
1864
|
+
continue;
|
|
1865
|
+
}
|
|
1866
|
+
if (PROTOTYPE_KEYS.has(ns) || PROTOTYPE_KEYS.has(method)) {
|
|
1867
|
+
skipped.push({ name, reason: "prototype-key" });
|
|
1868
|
+
continue;
|
|
1869
|
+
}
|
|
1870
|
+
if (RESERVED_NAMESPACES.has(ns) || UNBINDABLE_NAMESPACES.has(ns) || ns.startsWith("__")) {
|
|
1871
|
+
skipped.push({ name, reason: "reserved-namespace" });
|
|
1872
|
+
continue;
|
|
1873
|
+
}
|
|
1874
|
+
if (!isBindableMethod(ns, method, name)) {
|
|
1875
|
+
skipped.push({ name, reason: "unsupported-name" });
|
|
1876
|
+
continue;
|
|
1877
|
+
}
|
|
1878
|
+
const bucket = namespaces[ns] ?? (namespaces[ns] = /* @__PURE__ */ Object.create(null));
|
|
1879
|
+
if (Object.prototype.hasOwnProperty.call(bucket, method)) {
|
|
1880
|
+
skipped.push({ name, reason: "duplicate-method" });
|
|
1881
|
+
continue;
|
|
1882
|
+
}
|
|
1883
|
+
bucket[method] = name;
|
|
1884
|
+
}
|
|
1885
|
+
return { namespaces, skipped };
|
|
1886
|
+
}
|
|
1887
|
+
function toSandboxToolNamespaces(namespaces, reservedGlobals = []) {
|
|
1888
|
+
if (!namespaces) return void 0;
|
|
1889
|
+
const reserved = new Set(reservedGlobals);
|
|
1890
|
+
const bindable = /* @__PURE__ */ Object.create(null);
|
|
1891
|
+
let count = 0;
|
|
1892
|
+
for (const ns of Object.keys(namespaces)) {
|
|
1893
|
+
if (!isBindableNamespace(ns, reserved)) continue;
|
|
1894
|
+
const methods = namespaces[ns];
|
|
1895
|
+
const bucket = /* @__PURE__ */ Object.create(null);
|
|
1896
|
+
let methodCount = 0;
|
|
1897
|
+
for (const method of Object.keys(methods)) {
|
|
1898
|
+
const toolName = methods[method];
|
|
1899
|
+
if (typeof toolName !== "string" || !isBindableMethod(ns, method, toolName)) continue;
|
|
1900
|
+
bucket[method] = toolName;
|
|
1901
|
+
methodCount += 1;
|
|
1902
|
+
}
|
|
1903
|
+
if (methodCount > 0) {
|
|
1904
|
+
bindable[ns] = bucket;
|
|
1905
|
+
count += 1;
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
return count > 0 ? bindable : void 0;
|
|
1909
|
+
}
|
|
1910
|
+
|
|
1911
|
+
// plugins/plugin-codecall/src/services/enclave.service.ts
|
|
1912
|
+
function toolFailureMessage(error, toolName) {
|
|
1913
|
+
if (typeof error === "string" && error) return error;
|
|
1914
|
+
const message = error?.message;
|
|
1915
|
+
return typeof message === "string" && message ? message : `Tool call failed: ${toolName}`;
|
|
1916
|
+
}
|
|
1917
|
+
function toolFailureName(error) {
|
|
1918
|
+
const name = error && typeof error === "object" ? error.name : void 0;
|
|
1919
|
+
return typeof name === "string" && name ? name.slice(0, 128) : "ToolError";
|
|
1920
|
+
}
|
|
1921
|
+
var PARSE_FAILURE_PREFIX = "Failed to parse AgentScript code: ";
|
|
1922
|
+
var PARSE_POSITION_RE = /\((\d+):(\d+)\)$/;
|
|
1923
|
+
function parseFailureOf(message) {
|
|
1924
|
+
const match = PARSE_POSITION_RE.exec(message);
|
|
1925
|
+
const line = match ? Number(match[1]) - 1 : 0;
|
|
1926
|
+
if (!match || line < 1) return { message };
|
|
1927
|
+
const column = Number(match[2]);
|
|
1928
|
+
return { message: `${message.slice(0, match.index)}(${line}:${column})`, location: { line, column } };
|
|
1929
|
+
}
|
|
1693
1930
|
var ScriptTooLargeError = class extends Error {
|
|
1694
1931
|
code = "SCRIPT_TOO_LARGE";
|
|
1695
1932
|
scriptLength;
|
|
@@ -1727,8 +1964,20 @@ var EnclaveService = class {
|
|
|
1727
1964
|
throw new ScriptTooLargeError(code.length, maxLength);
|
|
1728
1965
|
}
|
|
1729
1966
|
}
|
|
1967
|
+
const toolFailures = [];
|
|
1730
1968
|
const toolHandler = async (toolName, args) => {
|
|
1731
|
-
|
|
1969
|
+
try {
|
|
1970
|
+
return await environment.callTool(toolName, args);
|
|
1971
|
+
} catch (error) {
|
|
1972
|
+
const code2 = error?.code;
|
|
1973
|
+
toolFailures.push({
|
|
1974
|
+
toolName,
|
|
1975
|
+
name: toolFailureName(error),
|
|
1976
|
+
message: toolFailureMessage(error, toolName),
|
|
1977
|
+
...typeof code2 === "string" ? { code: code2 } : {}
|
|
1978
|
+
});
|
|
1979
|
+
throw error;
|
|
1980
|
+
}
|
|
1732
1981
|
};
|
|
1733
1982
|
const sidecar = this.sidecarOptions.enabled ? {
|
|
1734
1983
|
enabled: true,
|
|
@@ -1738,11 +1987,29 @@ var EnclaveService = class {
|
|
|
1738
1987
|
maxResolvedSize: this.sidecarOptions.maxResolvedSize,
|
|
1739
1988
|
allowComposites: this.sidecarOptions.allowComposites
|
|
1740
1989
|
} : void 0;
|
|
1741
|
-
const
|
|
1742
|
-
const
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1990
|
+
const { mcpLog, mcpNotify } = environment;
|
|
1991
|
+
const globals = {
|
|
1992
|
+
// Provide getTool as a custom global
|
|
1993
|
+
getTool: environment.getTool,
|
|
1994
|
+
// Provide logging functions if available
|
|
1995
|
+
...mcpLog ? {
|
|
1996
|
+
mcpLog: (level, message, metadata) => {
|
|
1997
|
+
mcpLog(level, message, metadata);
|
|
1998
|
+
logs.push(`[mcp:${level}] ${message}`);
|
|
1999
|
+
}
|
|
2000
|
+
} : {},
|
|
2001
|
+
...mcpNotify ? {
|
|
2002
|
+
mcpNotify: (event, payload) => {
|
|
2003
|
+
mcpNotify(event, payload);
|
|
2004
|
+
logs.push(`[notify] ${event}`);
|
|
2005
|
+
}
|
|
2006
|
+
} : {}
|
|
2007
|
+
// Note: enclave-vm v2.0.0+ provides its own __safe_console internally with rate limiting
|
|
2008
|
+
// and output size limits. Passing console in globals causes "Cannot redefine property"
|
|
2009
|
+
// errors due to Double VM architecture. Console output from user scripts goes to stdout
|
|
2010
|
+
// via enclave's internal console, not to this logs array. Only mcpLog/mcpNotify are captured.
|
|
2011
|
+
};
|
|
2012
|
+
const options = {
|
|
1746
2013
|
timeout: this.vmOptions.timeoutMs,
|
|
1747
2014
|
maxToolCalls: this.vmOptions.maxSteps || 100,
|
|
1748
2015
|
maxIterations: 1e4,
|
|
@@ -1752,38 +2019,20 @@ var EnclaveService = class {
|
|
|
1752
2019
|
validate: true,
|
|
1753
2020
|
transform: true,
|
|
1754
2021
|
sidecar,
|
|
2022
|
+
// Error stacks name no host file, whatever stage raised them.
|
|
2023
|
+
sanitizeStackTraces: true,
|
|
1755
2024
|
// Allow functions in globals since we intentionally provide getTool, mcpLog, mcpNotify, and console
|
|
1756
2025
|
allowFunctionsInGlobals: true,
|
|
1757
|
-
globals
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
getTool: environment.getTool,
|
|
1765
|
-
// Provide logging functions if available
|
|
1766
|
-
...environment.mcpLog ? {
|
|
1767
|
-
mcpLog: (level, message, metadata) => {
|
|
1768
|
-
environment.mcpLog(level, message, metadata);
|
|
1769
|
-
logs.push(`[mcp:${level}] ${message}`);
|
|
1770
|
-
}
|
|
1771
|
-
} : {},
|
|
1772
|
-
...environment.mcpNotify ? {
|
|
1773
|
-
mcpNotify: (event, payload) => {
|
|
1774
|
-
environment.mcpNotify(event, payload);
|
|
1775
|
-
logs.push(`[notify] ${event}`);
|
|
1776
|
-
}
|
|
1777
|
-
} : {}
|
|
1778
|
-
// Note: enclave-vm v2.0.0+ provides its own __safe_console internally with rate limiting
|
|
1779
|
-
// and output size limits. Passing console in globals causes "Cannot redefine property"
|
|
1780
|
-
// errors due to Double VM architecture. Console output from user scripts goes to stdout
|
|
1781
|
-
// via enclave's internal console, not to this logs array. Only mcpLog/mcpNotify are captured.
|
|
1782
|
-
}
|
|
1783
|
-
});
|
|
2026
|
+
globals,
|
|
2027
|
+
// Tool namespaces (`acme.getUser()` for a tool named `acme.getUser`) are built by the sandbox
|
|
2028
|
+
// itself: a method call is exactly `callTool('acme.getUser', args, options)`, with the
|
|
2029
|
+
// sandbox's tool-call cap, rate limit, suspicious-sequence checks and `throwOnError`.
|
|
2030
|
+
toolNamespaces: toSandboxToolNamespaces(environment.toolNamespaces, Object.keys(globals))
|
|
2031
|
+
};
|
|
2032
|
+
const enclave = createEnclave(options);
|
|
1784
2033
|
try {
|
|
1785
2034
|
const result = await enclave.run(code);
|
|
1786
|
-
return this.mapEnclaveResult(result, logs);
|
|
2035
|
+
return this.mapEnclaveResult(result, logs, toolFailures);
|
|
1787
2036
|
} finally {
|
|
1788
2037
|
enclave.dispose();
|
|
1789
2038
|
}
|
|
@@ -1791,58 +2040,56 @@ var EnclaveService = class {
|
|
|
1791
2040
|
/**
|
|
1792
2041
|
* Map Enclave ExecutionResult to EnclaveExecutionResult
|
|
1793
2042
|
*/
|
|
1794
|
-
mapEnclaveResult(result, logs) {
|
|
2043
|
+
mapEnclaveResult(result, logs, toolFailures = []) {
|
|
2044
|
+
const stats = {
|
|
2045
|
+
duration: result.stats.duration,
|
|
2046
|
+
toolCallCount: result.stats.toolCallCount,
|
|
2047
|
+
iterationCount: result.stats.iterationCount
|
|
2048
|
+
};
|
|
1795
2049
|
if (result.success) {
|
|
2050
|
+
return { success: true, result: result.value, logs, timedOut: false, stats };
|
|
2051
|
+
}
|
|
2052
|
+
const error = result.error ?? { name: "Error", message: "Script execution failed" };
|
|
2053
|
+
if (error.code === "ENCLAVE_ERROR" && error.message?.startsWith(PARSE_FAILURE_PREFIX)) {
|
|
2054
|
+
const { message, location } = parseFailureOf(error.message);
|
|
1796
2055
|
return {
|
|
1797
|
-
success:
|
|
1798
|
-
|
|
2056
|
+
success: false,
|
|
2057
|
+
error: { message, name: "SyntaxError", code: "SYNTAX_ERROR", ...location ? { location } : {} },
|
|
1799
2058
|
logs,
|
|
1800
2059
|
timedOut: false,
|
|
1801
|
-
stats
|
|
1802
|
-
duration: result.stats.duration,
|
|
1803
|
-
toolCallCount: result.stats.toolCallCount,
|
|
1804
|
-
iterationCount: result.stats.iterationCount
|
|
1805
|
-
}
|
|
2060
|
+
stats
|
|
1806
2061
|
};
|
|
1807
2062
|
}
|
|
1808
|
-
const
|
|
1809
|
-
|
|
1810
|
-
if (error.code === "VALIDATION_ERROR") {
|
|
1811
|
-
const issues = error.data?.issues ?? [];
|
|
1812
|
-
const blockedPatterns = [...new Set(issues.map((issue) => issue.code).filter((code) => !!code))];
|
|
2063
|
+
const toolFailure = [...toolFailures].reverse().find((failure) => failure.message === error.message && failure.name === error.name);
|
|
2064
|
+
if (toolFailure) {
|
|
1813
2065
|
return {
|
|
1814
2066
|
success: false,
|
|
1815
2067
|
error: {
|
|
1816
2068
|
message: error.message,
|
|
1817
|
-
name:
|
|
1818
|
-
code:
|
|
1819
|
-
|
|
2069
|
+
name: error.name,
|
|
2070
|
+
...toolFailure.code ? { code: toolFailure.code } : {},
|
|
2071
|
+
toolName: toolFailure.toolName
|
|
1820
2072
|
},
|
|
1821
2073
|
logs,
|
|
1822
2074
|
timedOut: false,
|
|
1823
|
-
stats
|
|
1824
|
-
duration: result.stats.duration,
|
|
1825
|
-
toolCallCount: result.stats.toolCallCount,
|
|
1826
|
-
iterationCount: result.stats.iterationCount
|
|
1827
|
-
}
|
|
2075
|
+
stats
|
|
1828
2076
|
};
|
|
1829
2077
|
}
|
|
1830
|
-
const
|
|
1831
|
-
|
|
1832
|
-
|
|
2078
|
+
const timedOut = error.message?.includes("timed out") || error.code === "TIMEOUT";
|
|
2079
|
+
if (error.code === "VALIDATION_ERROR") {
|
|
2080
|
+
const issues = error.data?.issues ?? [];
|
|
2081
|
+
const blockedPatterns = [...new Set(issues.map((issue) => issue.code).filter((code) => !!code))];
|
|
1833
2082
|
return {
|
|
1834
2083
|
success: false,
|
|
1835
2084
|
error: {
|
|
1836
2085
|
message: error.message,
|
|
1837
|
-
name:
|
|
1838
|
-
stack: error.stack,
|
|
2086
|
+
name: "ValidationError",
|
|
1839
2087
|
code: error.code,
|
|
1840
|
-
|
|
1841
|
-
toolInput: errorData?.["toolInput"],
|
|
1842
|
-
details: errorData?.["details"]
|
|
2088
|
+
...blockedPatterns.length > 0 ? { blockedPatterns } : {}
|
|
1843
2089
|
},
|
|
1844
2090
|
logs,
|
|
1845
|
-
timedOut
|
|
2091
|
+
timedOut: false,
|
|
2092
|
+
stats
|
|
1846
2093
|
};
|
|
1847
2094
|
}
|
|
1848
2095
|
return {
|
|
@@ -1855,11 +2102,7 @@ var EnclaveService = class {
|
|
|
1855
2102
|
},
|
|
1856
2103
|
logs,
|
|
1857
2104
|
timedOut,
|
|
1858
|
-
stats
|
|
1859
|
-
duration: result.stats.duration,
|
|
1860
|
-
toolCallCount: result.stats.toolCallCount,
|
|
1861
|
-
iterationCount: result.stats.iterationCount
|
|
1862
|
-
}
|
|
2105
|
+
stats
|
|
1863
2106
|
};
|
|
1864
2107
|
}
|
|
1865
2108
|
};
|
|
@@ -1870,6 +2113,16 @@ EnclaveService = __decorateClass([
|
|
|
1870
2113
|
scope: import_sdk3.ProviderScope.GLOBAL
|
|
1871
2114
|
})
|
|
1872
2115
|
], EnclaveService);
|
|
2116
|
+
function createEnclave(options) {
|
|
2117
|
+
try {
|
|
2118
|
+
return new import_core.Enclave(options);
|
|
2119
|
+
} catch (error) {
|
|
2120
|
+
if (!options.toolNamespaces || !(error instanceof TypeError) || !error.message.startsWith("Invalid toolNamespaces")) {
|
|
2121
|
+
throw error;
|
|
2122
|
+
}
|
|
2123
|
+
return new import_core.Enclave({ ...options, toolNamespaces: void 0 });
|
|
2124
|
+
}
|
|
2125
|
+
}
|
|
1873
2126
|
|
|
1874
2127
|
// plugins/plugin-codecall/src/tools/search.tool.ts
|
|
1875
2128
|
var import_sdk4 = require("@frontmcp/sdk");
|
|
@@ -1930,7 +2183,10 @@ var SearchTool = class extends import_sdk4.ToolContext {
|
|
|
1930
2183
|
const audit = this.tryGet(AuditLoggerService);
|
|
1931
2184
|
const executionId = audit ? audit.generateExecutionId() : "";
|
|
1932
2185
|
const startedAt = Date.now();
|
|
1933
|
-
const
|
|
2186
|
+
const surface = (0, import_sdk4.getCallSurface)();
|
|
2187
|
+
const nonExistentExcludedTools = excludeToolNames.filter(
|
|
2188
|
+
(toolName) => !searchService.hasTool(toolName, surface)
|
|
2189
|
+
);
|
|
1934
2190
|
if (nonExistentExcludedTools.length > 0) {
|
|
1935
2191
|
warnings.push({
|
|
1936
2192
|
type: "excluded_tool_not_found",
|
|
@@ -1944,7 +2200,8 @@ var SearchTool = class extends import_sdk4.ToolContext {
|
|
|
1944
2200
|
const searchResults = await searchService.search(query, {
|
|
1945
2201
|
topK,
|
|
1946
2202
|
appIds,
|
|
1947
|
-
excludeToolNames
|
|
2203
|
+
excludeToolNames,
|
|
2204
|
+
surface
|
|
1948
2205
|
});
|
|
1949
2206
|
for (const result of searchResults) {
|
|
1950
2207
|
if (result.relevanceScore < minRelevanceScore) {
|
|
@@ -1989,7 +2246,7 @@ var SearchTool = class extends import_sdk4.ToolContext {
|
|
|
1989
2246
|
return {
|
|
1990
2247
|
tools,
|
|
1991
2248
|
warnings,
|
|
1992
|
-
totalAvailableTools: searchService.getTotalCount()
|
|
2249
|
+
totalAvailableTools: searchService.getTotalCount(surface)
|
|
1993
2250
|
};
|
|
1994
2251
|
}
|
|
1995
2252
|
};
|
|
@@ -2340,11 +2597,10 @@ function getSanitizedMessage(code, toolName, rawMessage) {
|
|
|
2340
2597
|
}
|
|
2341
2598
|
}
|
|
2342
2599
|
function sanitizeValidationMessage(message) {
|
|
2343
|
-
let sanitized = message
|
|
2600
|
+
let sanitized = toClientErrorMessage(message);
|
|
2344
2601
|
sanitized = sanitized.replace(/\bat line \d+/gi, "");
|
|
2345
2602
|
sanitized = sanitized.replace(/\bline \d+/gi, "");
|
|
2346
2603
|
sanitized = sanitized.replace(/:\d+:\d+/g, "");
|
|
2347
|
-
sanitized = sanitized.replace(/\n\s*at .*/g, "");
|
|
2348
2604
|
if (sanitized.length > 200) {
|
|
2349
2605
|
sanitized = sanitized.substring(0, 200) + "...";
|
|
2350
2606
|
}
|
|
@@ -2382,75 +2638,6 @@ function assertNotSelfReference(toolName) {
|
|
|
2382
2638
|
}
|
|
2383
2639
|
}
|
|
2384
2640
|
|
|
2385
|
-
// plugins/plugin-codecall/src/utils/build-tool-namespaces.ts
|
|
2386
|
-
var IDENT_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
2387
|
-
var PROTOTYPE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
2388
|
-
var RESERVED_NAMESPACES = /* @__PURE__ */ new Set([
|
|
2389
|
-
"console",
|
|
2390
|
-
"Math",
|
|
2391
|
-
"JSON",
|
|
2392
|
-
"Object",
|
|
2393
|
-
"Array",
|
|
2394
|
-
"String",
|
|
2395
|
-
"Number",
|
|
2396
|
-
"Boolean",
|
|
2397
|
-
"Promise",
|
|
2398
|
-
"Symbol",
|
|
2399
|
-
"Map",
|
|
2400
|
-
"Set",
|
|
2401
|
-
"WeakMap",
|
|
2402
|
-
"WeakSet",
|
|
2403
|
-
"Date",
|
|
2404
|
-
"Error",
|
|
2405
|
-
"RegExp",
|
|
2406
|
-
"globalThis",
|
|
2407
|
-
"global",
|
|
2408
|
-
"window",
|
|
2409
|
-
"self",
|
|
2410
|
-
"undefined",
|
|
2411
|
-
"null",
|
|
2412
|
-
"true",
|
|
2413
|
-
"false",
|
|
2414
|
-
"callTool",
|
|
2415
|
-
"getTool",
|
|
2416
|
-
"mcpLog",
|
|
2417
|
-
"mcpNotify"
|
|
2418
|
-
]);
|
|
2419
|
-
function buildToolNamespaces(tools, callTool) {
|
|
2420
|
-
const namespaces = /* @__PURE__ */ Object.create(null);
|
|
2421
|
-
const skipped = [];
|
|
2422
|
-
for (const tool of tools) {
|
|
2423
|
-
const name = tool?.name;
|
|
2424
|
-
if (typeof name !== "string" || name.length === 0) continue;
|
|
2425
|
-
const dot = name.indexOf(".");
|
|
2426
|
-
if (dot <= 0 || dot === name.length - 1) {
|
|
2427
|
-
skipped.push({ name, reason: "no-namespace-prefix" });
|
|
2428
|
-
continue;
|
|
2429
|
-
}
|
|
2430
|
-
const ns = name.slice(0, dot);
|
|
2431
|
-
const method = name.slice(dot + 1);
|
|
2432
|
-
if (!IDENT_RE.test(ns) || !IDENT_RE.test(method)) {
|
|
2433
|
-
skipped.push({ name, reason: "invalid-identifier" });
|
|
2434
|
-
continue;
|
|
2435
|
-
}
|
|
2436
|
-
if (PROTOTYPE_KEYS.has(ns)) {
|
|
2437
|
-
skipped.push({ name, reason: "prototype-key" });
|
|
2438
|
-
continue;
|
|
2439
|
-
}
|
|
2440
|
-
if (RESERVED_NAMESPACES.has(ns)) {
|
|
2441
|
-
skipped.push({ name, reason: "reserved-namespace" });
|
|
2442
|
-
continue;
|
|
2443
|
-
}
|
|
2444
|
-
const bucket = namespaces[ns] ?? (namespaces[ns] = /* @__PURE__ */ Object.create(null));
|
|
2445
|
-
if (Object.prototype.hasOwnProperty.call(bucket, method)) {
|
|
2446
|
-
skipped.push({ name, reason: "duplicate-method" });
|
|
2447
|
-
continue;
|
|
2448
|
-
}
|
|
2449
|
-
bucket[method] = (input, options) => callTool(name, input, options);
|
|
2450
|
-
}
|
|
2451
|
-
return { namespaces, skipped };
|
|
2452
|
-
}
|
|
2453
|
-
|
|
2454
2641
|
// plugins/plugin-codecall/src/utils/describe.utils.ts
|
|
2455
2642
|
var INTENT_PATTERNS = {
|
|
2456
2643
|
create: /^(create|add|new|insert|make|append|register|generate|produce|build|construct|provision|instantiate|define|compose|draft)/i,
|
|
@@ -2812,12 +2999,13 @@ var DescribeTool = class extends import_sdk7.ToolContext {
|
|
|
2812
2999
|
const tools = [];
|
|
2813
3000
|
const notFound = [];
|
|
2814
3001
|
const config = this.get(CodeCallConfig);
|
|
3002
|
+
const surface = (0, import_sdk7.getCallSurface)();
|
|
2815
3003
|
for (const toolName of toolNames) {
|
|
2816
3004
|
if (isBlockedSelfReference(toolName)) {
|
|
2817
3005
|
notFound.push(toolName);
|
|
2818
3006
|
continue;
|
|
2819
3007
|
}
|
|
2820
|
-
const access = checkCodeCallToolAccess(this.scope, config, toolName);
|
|
3008
|
+
const access = checkCodeCallToolAccess(this.scope, config, toolName, { surface });
|
|
2821
3009
|
if (!access.allowed) {
|
|
2822
3010
|
audit?.logSecurityAccessDenied(executionId, toolName, access.reason);
|
|
2823
3011
|
notFound.push(toolName);
|
|
@@ -3029,6 +3217,7 @@ var runtimeErrorPayloadSchema = import_lazy_zod7.z.object({
|
|
|
3029
3217
|
source: import_lazy_zod7.z.literal("script"),
|
|
3030
3218
|
message: import_lazy_zod7.z.string(),
|
|
3031
3219
|
name: import_lazy_zod7.z.string().optional(),
|
|
3220
|
+
/** @deprecated Never set: stack traces name server files, so results don't carry them. */
|
|
3032
3221
|
stack: import_lazy_zod7.z.string().optional()
|
|
3033
3222
|
});
|
|
3034
3223
|
var toolErrorPayloadSchema = import_lazy_zod7.z.object({
|
|
@@ -3037,6 +3226,7 @@ var toolErrorPayloadSchema = import_lazy_zod7.z.object({
|
|
|
3037
3226
|
toolInput: import_lazy_zod7.z.unknown(),
|
|
3038
3227
|
message: import_lazy_zod7.z.string(),
|
|
3039
3228
|
code: import_lazy_zod7.z.string().optional(),
|
|
3229
|
+
/** @deprecated Never set: the enclave's error data is not sanitized for clients. */
|
|
3040
3230
|
details: import_lazy_zod7.z.unknown().optional()
|
|
3041
3231
|
});
|
|
3042
3232
|
var timeoutErrorPayloadSchema = import_lazy_zod7.z.object({
|
|
@@ -3101,11 +3291,12 @@ var ExecuteTool = class extends import_sdk8.ToolContext {
|
|
|
3101
3291
|
* otherwise it would skip every metadata-driven check and reach `tools:call-tool`
|
|
3102
3292
|
* unexamined.
|
|
3103
3293
|
*/
|
|
3104
|
-
checkToolPolicy(name) {
|
|
3105
|
-
return checkCodeCallToolAccess(this.scope, this.get(CodeCallConfig), name);
|
|
3294
|
+
checkToolPolicy(name, surface) {
|
|
3295
|
+
return checkCodeCallToolAccess(this.scope, this.get(CodeCallConfig), name, { surface });
|
|
3106
3296
|
}
|
|
3107
3297
|
async execute(input) {
|
|
3108
3298
|
const { script, allowedTools } = input;
|
|
3299
|
+
const callerSurface = (0, import_sdk8.getCallSurface)();
|
|
3109
3300
|
const audit = this.tryGet(AuditLoggerService);
|
|
3110
3301
|
const executionId = audit ? audit.generateExecutionId() : "";
|
|
3111
3302
|
const callDepth = 1;
|
|
@@ -3118,7 +3309,7 @@ var ExecuteTool = class extends import_sdk8.ToolContext {
|
|
|
3118
3309
|
audit?.logSecuritySelfReference(executionId, name);
|
|
3119
3310
|
}
|
|
3120
3311
|
assertNotSelfReference(name);
|
|
3121
|
-
const decision = this.checkToolPolicy(name);
|
|
3312
|
+
const decision = this.checkToolPolicy(name, callerSurface);
|
|
3122
3313
|
if (!decision.allowed) {
|
|
3123
3314
|
audit?.logSecurityAccessDenied(executionId, name, decision.reason);
|
|
3124
3315
|
const error = createToolCallError(TOOL_CALL_ERROR_CODES.ACCESS_DENIED, name, decision.reason);
|
|
@@ -3147,7 +3338,8 @@ var ExecuteTool = class extends import_sdk8.ToolContext {
|
|
|
3147
3338
|
}
|
|
3148
3339
|
};
|
|
3149
3340
|
const ctx = {
|
|
3150
|
-
authInfo: this.authInfo
|
|
3341
|
+
authInfo: this.authInfo,
|
|
3342
|
+
surface: callerSurface
|
|
3151
3343
|
};
|
|
3152
3344
|
const mcpResult = await this.scope.runFlow("tools:call-tool", { request, ctx });
|
|
3153
3345
|
if (!mcpResult) {
|
|
@@ -3187,7 +3379,7 @@ var ExecuteTool = class extends import_sdk8.ToolContext {
|
|
|
3187
3379
|
audit?.logSecuritySelfReference(executionId, name);
|
|
3188
3380
|
return void 0;
|
|
3189
3381
|
}
|
|
3190
|
-
const introspectionAccess = this.checkToolPolicy(name);
|
|
3382
|
+
const introspectionAccess = this.checkToolPolicy(name, callerSurface);
|
|
3191
3383
|
if (!introspectionAccess.allowed) {
|
|
3192
3384
|
audit?.logSecurityAccessDenied(executionId, name, introspectionAccess.reason);
|
|
3193
3385
|
return void 0;
|
|
@@ -3217,8 +3409,8 @@ var ExecuteTool = class extends import_sdk8.ToolContext {
|
|
|
3217
3409
|
const callableTools = this.scope.tools.getTools(true).filter(
|
|
3218
3410
|
(tool) => checkCodeCallToolPolicy(toCodeCallPolicyTool(tool, void 0, this.scope), policyConfig).allowed
|
|
3219
3411
|
);
|
|
3220
|
-
const { namespaces, skipped } = buildToolNamespaces(callableTools
|
|
3221
|
-
environment.
|
|
3412
|
+
const { namespaces, skipped } = buildToolNamespaces(callableTools);
|
|
3413
|
+
environment.toolNamespaces = namespaces;
|
|
3222
3414
|
if (skipped.length > 0) {
|
|
3223
3415
|
this.logger?.debug?.("codecall: tools skipped during namespace generation", {
|
|
3224
3416
|
count: skipped.length,
|
|
@@ -3250,6 +3442,16 @@ var ExecuteTool = class extends import_sdk8.ToolContext {
|
|
|
3250
3442
|
}
|
|
3251
3443
|
if (!executionResult.success) {
|
|
3252
3444
|
const error = executionResult.error;
|
|
3445
|
+
if (error.code === "SYNTAX_ERROR") {
|
|
3446
|
+
audit?.logExecutionFailure(executionId, script, durationMs, error.message);
|
|
3447
|
+
return {
|
|
3448
|
+
status: "syntax_error",
|
|
3449
|
+
error: {
|
|
3450
|
+
message: toClientErrorMessage(error.message) || "Syntax error in script",
|
|
3451
|
+
...error.location ? { location: error.location } : {}
|
|
3452
|
+
}
|
|
3453
|
+
};
|
|
3454
|
+
}
|
|
3253
3455
|
if (error.code === "VALIDATION_ERROR" || error.name === "ValidationError") {
|
|
3254
3456
|
audit?.logSecurityAstBlocked(executionId, error.blockedPatterns?.join(", ") ?? "UNKNOWN", error.message);
|
|
3255
3457
|
audit?.logExecutionFailure(executionId, script, durationMs, error.message);
|
|
@@ -3269,9 +3471,9 @@ var ExecuteTool = class extends import_sdk8.ToolContext {
|
|
|
3269
3471
|
source: "tool",
|
|
3270
3472
|
toolName: error.toolName,
|
|
3271
3473
|
toolInput: error.toolInput,
|
|
3272
|
-
message: error.message,
|
|
3273
|
-
code: error.code
|
|
3274
|
-
details
|
|
3474
|
+
message: toClientErrorMessage(error.message),
|
|
3475
|
+
code: error.code
|
|
3476
|
+
// No `details`: the enclave's error data is not sanitized for clients.
|
|
3275
3477
|
}
|
|
3276
3478
|
};
|
|
3277
3479
|
}
|
|
@@ -3280,9 +3482,8 @@ var ExecuteTool = class extends import_sdk8.ToolContext {
|
|
|
3280
3482
|
status: "runtime_error",
|
|
3281
3483
|
error: {
|
|
3282
3484
|
source: "script",
|
|
3283
|
-
message: error.message,
|
|
3284
|
-
name: error.name
|
|
3285
|
-
stack: error.stack
|
|
3485
|
+
message: toClientErrorMessage(error.message),
|
|
3486
|
+
name: error.name
|
|
3286
3487
|
}
|
|
3287
3488
|
};
|
|
3288
3489
|
}
|
|
@@ -3296,13 +3497,12 @@ var ExecuteTool = class extends import_sdk8.ToolContext {
|
|
|
3296
3497
|
const errorName = error instanceof Error ? error.name : "Error";
|
|
3297
3498
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3298
3499
|
audit?.logExecutionFailure(executionId, script, elapsed(), errorMessage);
|
|
3299
|
-
const errorStack = error instanceof Error ? error.stack : void 0;
|
|
3300
3500
|
const errorLoc = error.loc;
|
|
3301
3501
|
if (errorName === "SyntaxError" || errorMessage?.includes("syntax")) {
|
|
3302
3502
|
return {
|
|
3303
3503
|
status: "syntax_error",
|
|
3304
3504
|
error: {
|
|
3305
|
-
message: errorMessage || "Syntax error in script",
|
|
3505
|
+
message: toClientErrorMessage(errorMessage) || "Syntax error in script",
|
|
3306
3506
|
location: errorLoc ? { line: errorLoc.line, column: errorLoc.column } : void 0
|
|
3307
3507
|
}
|
|
3308
3508
|
};
|
|
@@ -3311,9 +3511,8 @@ var ExecuteTool = class extends import_sdk8.ToolContext {
|
|
|
3311
3511
|
status: "runtime_error",
|
|
3312
3512
|
error: {
|
|
3313
3513
|
source: "script",
|
|
3314
|
-
message: errorMessage || "An unexpected error occurred during script execution",
|
|
3315
|
-
name: errorName
|
|
3316
|
-
stack: errorStack
|
|
3514
|
+
message: toClientErrorMessage(errorMessage) || "An unexpected error occurred during script execution",
|
|
3515
|
+
name: errorName
|
|
3317
3516
|
}
|
|
3318
3517
|
};
|
|
3319
3518
|
}
|
|
@@ -3382,7 +3581,11 @@ var InvokeTool = class extends import_sdk9.ToolContext {
|
|
|
3382
3581
|
`Tool "${toolName}" cannot be invoked directly. CodeCall tools are internal and not accessible via codecall:invoke.`
|
|
3383
3582
|
);
|
|
3384
3583
|
}
|
|
3385
|
-
const
|
|
3584
|
+
const surface = (0, import_sdk9.getCallSurface)();
|
|
3585
|
+
const decision = checkCodeCallToolAccess(this.scope, this.get(CodeCallConfig), toolName, {
|
|
3586
|
+
directCall: true,
|
|
3587
|
+
surface
|
|
3588
|
+
});
|
|
3386
3589
|
if (!decision.allowed) {
|
|
3387
3590
|
audit?.logSecurityAccessDenied(executionId, toolName, decision.reason);
|
|
3388
3591
|
return buildErrorResult(`Tool "${toolName}" is not available. Use codecall:search to discover available tools.`);
|
|
@@ -3395,7 +3598,8 @@ var InvokeTool = class extends import_sdk9.ToolContext {
|
|
|
3395
3598
|
}
|
|
3396
3599
|
};
|
|
3397
3600
|
const ctx = {
|
|
3398
|
-
authInfo: this.authInfo
|
|
3601
|
+
authInfo: this.authInfo,
|
|
3602
|
+
surface
|
|
3399
3603
|
};
|
|
3400
3604
|
const result = await this.scope.runFlow("tools:call-tool", { request, ctx });
|
|
3401
3605
|
if (!result) {
|