@botbotgo/kit 1.0.106
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +65 -0
- package/config/build/build.sh +182 -0
- package/config/build/tsconfig.dts.json +34 -0
- package/config/build/tsup.config.ts +19 -0
- package/config/build/vitest.config.ts +29 -0
- package/config/tool.yaml +11 -0
- package/dist/agent-context.d.ts +3 -0
- package/dist/agent-context.d.ts.map +1 -0
- package/dist/api/adapters/LangChainToolsHub.d.ts +35 -0
- package/dist/api/adapters/LangChainToolsHub.d.ts.map +1 -0
- package/dist/api/createAgentTools.d.ts +52 -0
- package/dist/api/createAgentTools.d.ts.map +1 -0
- package/dist/api/expose/extension-init/index.d.ts +3 -0
- package/dist/api/expose/extension-init/index.d.ts.map +1 -0
- package/dist/api/expose/extension-init/initExtension.d.ts +21 -0
- package/dist/api/expose/extension-init/initExtension.d.ts.map +1 -0
- package/dist/api/expose/index.d.ts +16 -0
- package/dist/api/expose/index.d.ts.map +1 -0
- package/dist/api/expose/mcp-build/build.d.ts +21 -0
- package/dist/api/expose/mcp-build/build.d.ts.map +1 -0
- package/dist/api/expose/mcp-build/generator.d.ts +15 -0
- package/dist/api/expose/mcp-build/generator.d.ts.map +1 -0
- package/dist/api/expose/mcp-build/index.d.ts +8 -0
- package/dist/api/expose/mcp-build/index.d.ts.map +1 -0
- package/dist/api/expose/mcp-build/init.d.ts +17 -0
- package/dist/api/expose/mcp-build/init.d.ts.map +1 -0
- package/dist/api/expose/mcp-build/run.d.ts +17 -0
- package/dist/api/expose/mcp-build/run.d.ts.map +1 -0
- package/dist/api/expose/mcp-build/types.d.ts +25 -0
- package/dist/api/expose/mcp-build/types.d.ts.map +1 -0
- package/dist/api/expose/mcpServer.d.ts +74 -0
- package/dist/api/expose/mcpServer.d.ts.map +1 -0
- package/dist/api/expose/openapi.d.ts +23 -0
- package/dist/api/expose/openapi.d.ts.map +1 -0
- package/dist/api/expose/openapiHttp.d.ts +51 -0
- package/dist/api/expose/openapiHttp.d.ts.map +1 -0
- package/dist/api/extension/contextRunner.d.ts +10 -0
- package/dist/api/extension/contextRunner.d.ts.map +1 -0
- package/dist/api/extension/createExtension.d.ts +38 -0
- package/dist/api/extension/createExtension.d.ts.map +1 -0
- package/dist/api/extension/dynamicImportAdapter.d.ts +25 -0
- package/dist/api/extension/dynamicImportAdapter.d.ts.map +1 -0
- package/dist/api/extension/generateExtensionManifest.d.ts +29 -0
- package/dist/api/extension/generateExtensionManifest.d.ts.map +1 -0
- package/dist/api/extension/index.d.ts +23 -0
- package/dist/api/extension/index.d.ts.map +1 -0
- package/dist/api/extension/loadToolYaml.d.ts +7 -0
- package/dist/api/extension/loadToolYaml.d.ts.map +1 -0
- package/dist/api/extension/overrideWithConfig.d.ts +2 -0
- package/dist/api/extension/overrideWithConfig.d.ts.map +1 -0
- package/dist/api/extension/registerExtension.d.ts +32 -0
- package/dist/api/extension/registerExtension.d.ts.map +1 -0
- package/dist/api/extension/registerFromManifest.d.ts +43 -0
- package/dist/api/extension/registerFromManifest.d.ts.map +1 -0
- package/dist/api/extension/resolvePackageRoot.d.ts +2 -0
- package/dist/api/extension/resolvePackageRoot.d.ts.map +1 -0
- package/dist/api/extension/support/groupPrefix.d.ts +21 -0
- package/dist/api/extension/support/groupPrefix.d.ts.map +1 -0
- package/dist/api/extension/support/types.d.ts +15 -0
- package/dist/api/extension/support/types.d.ts.map +1 -0
- package/dist/api/register-tools.d.ts +17 -0
- package/dist/api/register-tools.d.ts.map +1 -0
- package/dist/api/resolveAgentSkillRoots.d.ts +7 -0
- package/dist/api/resolveAgentSkillRoots.d.ts.map +1 -0
- package/dist/api/runtimeFromConfig.d.ts +20 -0
- package/dist/api/runtimeFromConfig.d.ts.map +1 -0
- package/dist/api/runtimeFromConfig.helpers.d.ts +12 -0
- package/dist/api/runtimeFromConfig.helpers.d.ts.map +1 -0
- package/dist/api/runtimeFromConfig.types.d.ts +37 -0
- package/dist/api/runtimeFromConfig.types.d.ts.map +1 -0
- package/dist/build.cjs +30 -0
- package/dist/build.cjs.map +1 -0
- package/dist/build.d.ts +13 -0
- package/dist/build.d.ts.map +1 -0
- package/dist/build.js +5 -0
- package/dist/build.js.map +1 -0
- package/dist/canonicalCoreSchemas-PHGTNPN5.js +3 -0
- package/dist/canonicalCoreSchemas-PHGTNPN5.js.map +1 -0
- package/dist/canonicalCoreSchemas-TY7NCWCC.cjs +16 -0
- package/dist/canonicalCoreSchemas-TY7NCWCC.cjs.map +1 -0
- package/dist/chunk-4OOTCNR7.js +324 -0
- package/dist/chunk-4OOTCNR7.js.map +1 -0
- package/dist/chunk-4VKCWJHF.cjs +3043 -0
- package/dist/chunk-4VKCWJHF.cjs.map +1 -0
- package/dist/chunk-AGLGFQUW.cjs +259 -0
- package/dist/chunk-AGLGFQUW.cjs.map +1 -0
- package/dist/chunk-AZUXVVGV.cjs +1073 -0
- package/dist/chunk-AZUXVVGV.cjs.map +1 -0
- package/dist/chunk-BDUSB6GT.js +520 -0
- package/dist/chunk-BDUSB6GT.js.map +1 -0
- package/dist/chunk-BNIE2IKZ.cjs +100 -0
- package/dist/chunk-BNIE2IKZ.cjs.map +1 -0
- package/dist/chunk-BTHDNP3C.cjs +350 -0
- package/dist/chunk-BTHDNP3C.cjs.map +1 -0
- package/dist/chunk-GGFAGLDC.js +1049 -0
- package/dist/chunk-GGFAGLDC.js.map +1 -0
- package/dist/chunk-ITX6A2BT.js +92 -0
- package/dist/chunk-ITX6A2BT.js.map +1 -0
- package/dist/chunk-IVL4TBFB.js +248 -0
- package/dist/chunk-IVL4TBFB.js.map +1 -0
- package/dist/chunk-JH4ZF3FN.js +3013 -0
- package/dist/chunk-JH4ZF3FN.js.map +1 -0
- package/dist/chunk-JW4EMVTE.cjs +553 -0
- package/dist/chunk-JW4EMVTE.cjs.map +1 -0
- package/dist/chunk-NTWOVFEY.js +16 -0
- package/dist/chunk-NTWOVFEY.js.map +1 -0
- package/dist/chunk-UUNG3GL3.cjs +19 -0
- package/dist/chunk-UUNG3GL3.cjs.map +1 -0
- package/dist/core/registry/ToolRegistry.d.ts +68 -0
- package/dist/core/registry/ToolRegistry.d.ts.map +1 -0
- package/dist/core/runtime/Budget.d.ts +63 -0
- package/dist/core/runtime/Budget.d.ts.map +1 -0
- package/dist/core/runtime/Evidence.d.ts +19 -0
- package/dist/core/runtime/Evidence.d.ts.map +1 -0
- package/dist/core/runtime/PTCRuntime.d.ts +124 -0
- package/dist/core/runtime/PTCRuntime.d.ts.map +1 -0
- package/dist/core/runtime/PTCRuntimeObservability.d.ts +26 -0
- package/dist/core/runtime/PTCRuntimeObservability.d.ts.map +1 -0
- package/dist/core/runtime/PTCRuntimePipeline.d.ts +69 -0
- package/dist/core/runtime/PTCRuntimePipeline.d.ts.map +1 -0
- package/dist/core/runtime/PolicyEngine.d.ts +67 -0
- package/dist/core/runtime/PolicyEngine.d.ts.map +1 -0
- package/dist/core/runtime/Retry.d.ts +33 -0
- package/dist/core/runtime/Retry.d.ts.map +1 -0
- package/dist/core/runtime/SchemaValidator.d.ts +42 -0
- package/dist/core/runtime/SchemaValidator.d.ts.map +1 -0
- package/dist/core/runtime/toolObservation.d.ts +7 -0
- package/dist/core/runtime/toolObservation.d.ts.map +1 -0
- package/dist/core/types/Events.d.ts +99 -0
- package/dist/core/types/Events.d.ts.map +1 -0
- package/dist/core/types/ToolIntent.d.ts +40 -0
- package/dist/core/types/ToolIntent.d.ts.map +1 -0
- package/dist/core/types/ToolResult.d.ts +44 -0
- package/dist/core/types/ToolResult.d.ts.map +1 -0
- package/dist/core/types/ToolSpec.d.ts +116 -0
- package/dist/core/types/ToolSpec.d.ts.map +1 -0
- package/dist/core/types/ToolTypeHandler.d.ts +88 -0
- package/dist/core/types/ToolTypeHandler.d.ts.map +1 -0
- package/dist/core/types/index.d.ts +7 -0
- package/dist/core/types/index.d.ts.map +1 -0
- package/dist/index.cjs +399 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +394 -0
- package/dist/index.js.map +1 -0
- package/dist/observability/EventLog.d.ts +60 -0
- package/dist/observability/EventLog.d.ts.map +1 -0
- package/dist/observability/Logger.d.ts +33 -0
- package/dist/observability/Logger.d.ts.map +1 -0
- package/dist/observability/Metrics.d.ts +70 -0
- package/dist/observability/Metrics.d.ts.map +1 -0
- package/dist/observability/Tracing.d.ts +69 -0
- package/dist/observability/Tracing.d.ts.map +1 -0
- package/dist/sdk.cjs +493 -0
- package/dist/sdk.cjs.map +1 -0
- package/dist/sdk.d.ts +17 -0
- package/dist/sdk.d.ts.map +1 -0
- package/dist/sdk.js +443 -0
- package/dist/sdk.js.map +1 -0
- package/dist/security/sandbox.d.ts +10 -0
- package/dist/security/sandbox.d.ts.map +1 -0
- package/dist/security/ssrf.d.ts +24 -0
- package/dist/security/ssrf.d.ts.map +1 -0
- package/dist/templates/mcp-server.js +48 -0
- package/dist/templates/n8n-invoker.js +11 -0
- package/dist/templates/skill-invoker.js +11 -0
- package/dist/templates/tool-index.js +9 -0
- package/dist/tools/discoveryFactory.d.ts +117 -0
- package/dist/tools/discoveryFactory.d.ts.map +1 -0
- package/dist/tools/function/index.d.ts +10 -0
- package/dist/tools/function/index.d.ts.map +1 -0
- package/dist/tools/function/scanner.d.ts +29 -0
- package/dist/tools/function/scanner.d.ts.map +1 -0
- package/dist/tools/function/schemaFromTs.d.ts +16 -0
- package/dist/tools/function/schemaFromTs.d.ts.map +1 -0
- package/dist/tools/function/types.d.ts +20 -0
- package/dist/tools/function/types.d.ts.map +1 -0
- package/dist/tools/index.d.ts +13 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/langchain/LangChainLoader.d.ts +7 -0
- package/dist/tools/langchain/LangChainLoader.d.ts.map +1 -0
- package/dist/tools/langchain/directoryApply.d.ts +5 -0
- package/dist/tools/langchain/directoryApply.d.ts.map +1 -0
- package/dist/tools/langchain/directoryLoad.d.ts +13 -0
- package/dist/tools/langchain/directoryLoad.d.ts.map +1 -0
- package/dist/tools/langchain/index.d.ts +3 -0
- package/dist/tools/langchain/index.d.ts.map +1 -0
- package/dist/tools/langchain/scanner.d.ts +8 -0
- package/dist/tools/langchain/scanner.d.ts.map +1 -0
- package/dist/tools/langchain/types.d.ts +5 -0
- package/dist/tools/langchain/types.d.ts.map +1 -0
- package/dist/tools/mcp/MCPClientAdapter.d.ts +34 -0
- package/dist/tools/mcp/MCPClientAdapter.d.ts.map +1 -0
- package/dist/tools/mcp/MCPLoader.d.ts +8 -0
- package/dist/tools/mcp/MCPLoader.d.ts.map +1 -0
- package/dist/tools/mcp/MCPProcessManager.d.ts +29 -0
- package/dist/tools/mcp/MCPProcessManager.d.ts.map +1 -0
- package/dist/tools/mcp/connectMCP.d.ts +47 -0
- package/dist/tools/mcp/connectMCP.d.ts.map +1 -0
- package/dist/tools/mcp/directoryApply.d.ts +10 -0
- package/dist/tools/mcp/directoryApply.d.ts.map +1 -0
- package/dist/tools/mcp/index.d.ts +16 -0
- package/dist/tools/mcp/index.d.ts.map +1 -0
- package/dist/tools/mcp/mcpSpecToToolSpec.d.ts +8 -0
- package/dist/tools/mcp/mcpSpecToToolSpec.d.ts.map +1 -0
- package/dist/tools/mcp/registerMCPTools.d.ts +24 -0
- package/dist/tools/mcp/registerMCPTools.d.ts.map +1 -0
- package/dist/tools/mcp/scanner.d.ts +8 -0
- package/dist/tools/mcp/scanner.d.ts.map +1 -0
- package/dist/tools/mcp/support/types.d.ts +3 -0
- package/dist/tools/mcp/support/types.d.ts.map +1 -0
- package/dist/tools/n8n/N8nLoader.d.ts +25 -0
- package/dist/tools/n8n/N8nLoader.d.ts.map +1 -0
- package/dist/tools/n8n/directoryApply.d.ts +10 -0
- package/dist/tools/n8n/directoryApply.d.ts.map +1 -0
- package/dist/tools/n8n/index.d.ts +6 -0
- package/dist/tools/n8n/index.d.ts.map +1 -0
- package/dist/tools/n8n/scanN8n.d.ts +20 -0
- package/dist/tools/n8n/scanN8n.d.ts.map +1 -0
- package/dist/tools/n8n/types.d.ts +18 -0
- package/dist/tools/n8n/types.d.ts.map +1 -0
- package/dist/tools/scanPackage.d.ts +42 -0
- package/dist/tools/scanPackage.d.ts.map +1 -0
- package/dist/tools/skill/SkillLoader.d.ts +20 -0
- package/dist/tools/skill/SkillLoader.d.ts.map +1 -0
- package/dist/tools/skill/SkillManifest.d.ts +79 -0
- package/dist/tools/skill/SkillManifest.d.ts.map +1 -0
- package/dist/tools/skill/SkillMdParser.d.ts +31 -0
- package/dist/tools/skill/SkillMdParser.d.ts.map +1 -0
- package/dist/tools/skill/directoryApply.d.ts +10 -0
- package/dist/tools/skill/directoryApply.d.ts.map +1 -0
- package/dist/tools/skill/index.d.ts +8 -0
- package/dist/tools/skill/index.d.ts.map +1 -0
- package/dist/tools/skill/scanSkill.d.ts +20 -0
- package/dist/tools/skill/scanSkill.d.ts.map +1 -0
- package/dist/tools/skill/types.d.ts +19 -0
- package/dist/tools/skill/types.d.ts.map +1 -0
- package/dist/tools/util/canonicalCoreSchemas.d.ts +15 -0
- package/dist/tools/util/canonicalCoreSchemas.d.ts.map +1 -0
- package/dist/tools/util/index.d.ts +13 -0
- package/dist/tools/util/index.d.ts.map +1 -0
- package/dist/tools/util/resolveEntry.d.ts +6 -0
- package/dist/tools/util/resolveEntry.d.ts.map +1 -0
- package/dist/tools/util/scanUtil.d.ts +9 -0
- package/dist/tools/util/scanUtil.d.ts.map +1 -0
- package/dist/tools/util/toolConfig.d.ts +38 -0
- package/dist/tools/util/toolConfig.d.ts.map +1 -0
- package/dist/tools/util/toolDescriptor.d.ts +117 -0
- package/dist/tools/util/toolDescriptor.d.ts.map +1 -0
- package/dist/utils/cli/help.d.ts +2 -0
- package/dist/utils/cli/help.d.ts.map +1 -0
- package/dist/utils/cli/index.cjs +700 -0
- package/dist/utils/cli/index.cjs.map +1 -0
- package/dist/utils/cli/index.d.ts +9 -0
- package/dist/utils/cli/index.d.ts.map +1 -0
- package/dist/utils/cli/index.js +677 -0
- package/dist/utils/cli/index.js.map +1 -0
- package/dist/utils/cli/toolRuntime.d.ts +19 -0
- package/dist/utils/cli/toolRuntime.d.ts.map +1 -0
- package/dist/utils/log.d.ts +2 -0
- package/dist/utils/log.d.ts.map +1 -0
- package/dist/utils/npmCache.d.ts +11 -0
- package/dist/utils/npmCache.d.ts.map +1 -0
- package/dist/utils/npmVersion.d.ts +10 -0
- package/dist/utils/npmVersion.d.ts.map +1 -0
- package/dist/utils/overrideWithConfig.d.ts +2 -0
- package/dist/utils/overrideWithConfig.d.ts.map +1 -0
- package/package.json +125 -0
|
@@ -0,0 +1,3043 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkAZUXVVGV_cjs = require('./chunk-AZUXVVGV.cjs');
|
|
4
|
+
var chunkAGLGFQUW_cjs = require('./chunk-AGLGFQUW.cjs');
|
|
5
|
+
var chunkJW4EMVTE_cjs = require('./chunk-JW4EMVTE.cjs');
|
|
6
|
+
var chunkUUNG3GL3_cjs = require('./chunk-UUNG3GL3.cjs');
|
|
7
|
+
var fs = require('fs');
|
|
8
|
+
var path = require('path');
|
|
9
|
+
var config = require('@botbotgo/common/config');
|
|
10
|
+
var module$1 = require('module');
|
|
11
|
+
var url = require('url');
|
|
12
|
+
var Ajv = require('ajv');
|
|
13
|
+
var addFormats = require('ajv-formats');
|
|
14
|
+
var cockatiel = require('cockatiel');
|
|
15
|
+
var eventemitter3 = require('eventemitter3');
|
|
16
|
+
var uuid = require('uuid');
|
|
17
|
+
var pTimeout = require('p-timeout');
|
|
18
|
+
var child_process = require('child_process');
|
|
19
|
+
var os = require('os');
|
|
20
|
+
var express = require('express');
|
|
21
|
+
|
|
22
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
23
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
24
|
+
|
|
25
|
+
var Ajv__default = /*#__PURE__*/_interopDefault(Ajv);
|
|
26
|
+
var addFormats__default = /*#__PURE__*/_interopDefault(addFormats);
|
|
27
|
+
var pTimeout__default = /*#__PURE__*/_interopDefault(pTimeout);
|
|
28
|
+
var express__default = /*#__PURE__*/_interopDefault(express);
|
|
29
|
+
|
|
30
|
+
function normalizeMcpConfig(raw) {
|
|
31
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
|
|
32
|
+
const source = raw;
|
|
33
|
+
const out = {};
|
|
34
|
+
if (typeof source.name === "string" && source.name.trim()) out.name = source.name.trim();
|
|
35
|
+
if (typeof source.version === "string" && source.version.trim()) out.version = source.version.trim();
|
|
36
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
37
|
+
}
|
|
38
|
+
function normalizeOpenApiConfig(raw) {
|
|
39
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
|
|
40
|
+
const source = raw;
|
|
41
|
+
const out = {};
|
|
42
|
+
if (typeof source.host === "string" && source.host.trim()) out.host = source.host.trim();
|
|
43
|
+
if (typeof source.basePath === "string") out.basePath = source.basePath;
|
|
44
|
+
if (typeof source.title === "string" && source.title.trim()) out.title = source.title.trim();
|
|
45
|
+
if (typeof source.version === "string" && source.version.trim()) out.version = source.version.trim();
|
|
46
|
+
if (typeof source.port === "number" && Number.isFinite(source.port)) out.port = source.port;
|
|
47
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
48
|
+
}
|
|
49
|
+
function normalizeToolSources(raw) {
|
|
50
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
|
|
51
|
+
const source = raw;
|
|
52
|
+
const out = {};
|
|
53
|
+
const customized = source.customized;
|
|
54
|
+
if (customized && typeof customized === "object" && !Array.isArray(customized)) {
|
|
55
|
+
const customizedSource = customized;
|
|
56
|
+
const descriptorGrouped = Object.keys(customizedSource).some((key) => /^(npm|file):/.test(key));
|
|
57
|
+
if (descriptorGrouped) {
|
|
58
|
+
for (const [sourceKey, sourceValue] of Object.entries(customizedSource)) {
|
|
59
|
+
if (!sourceValue || typeof sourceValue !== "object" || Array.isArray(sourceValue)) continue;
|
|
60
|
+
const toolMap = {};
|
|
61
|
+
for (const [toolName, toolValue] of Object.entries(sourceValue)) {
|
|
62
|
+
if (!toolValue || typeof toolValue !== "object" || Array.isArray(toolValue)) continue;
|
|
63
|
+
toolMap[toolName] = toolValue;
|
|
64
|
+
}
|
|
65
|
+
out[sourceKey] = toolMap;
|
|
66
|
+
}
|
|
67
|
+
} else {
|
|
68
|
+
const toolMap = {};
|
|
69
|
+
for (const [toolName, toolValue] of Object.entries(customizedSource)) {
|
|
70
|
+
if (!toolValue || typeof toolValue !== "object" || Array.isArray(toolValue)) continue;
|
|
71
|
+
toolMap[toolName] = toolValue;
|
|
72
|
+
}
|
|
73
|
+
if (Object.keys(toolMap).length > 0) out.self = toolMap;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
for (const [sourceKey, sourceValue] of Object.entries(source)) {
|
|
77
|
+
if (sourceKey === "customized" || sourceKey === "deepagents") continue;
|
|
78
|
+
if (!sourceValue || typeof sourceValue !== "object" || Array.isArray(sourceValue)) continue;
|
|
79
|
+
const toolMap = {};
|
|
80
|
+
for (const [toolName, toolValue] of Object.entries(sourceValue)) {
|
|
81
|
+
if (!toolValue || typeof toolValue !== "object" || Array.isArray(toolValue)) continue;
|
|
82
|
+
toolMap[toolName] = toolValue;
|
|
83
|
+
}
|
|
84
|
+
out[sourceKey] = toolMap;
|
|
85
|
+
}
|
|
86
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
87
|
+
}
|
|
88
|
+
function normalizePathSources(raw) {
|
|
89
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
|
|
90
|
+
const source = raw;
|
|
91
|
+
const out = {};
|
|
92
|
+
for (const [descriptor, value] of Object.entries(source)) {
|
|
93
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
94
|
+
out[descriptor] = {};
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
out[descriptor] = value;
|
|
98
|
+
}
|
|
99
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
100
|
+
}
|
|
101
|
+
function loadToolConfig(toolYamlPath) {
|
|
102
|
+
const abs = path.resolve(toolYamlPath);
|
|
103
|
+
const raw = fs.readFileSync(abs, "utf8");
|
|
104
|
+
const parsed = config.parseYamlContent(raw, {
|
|
105
|
+
substituteEnv: false
|
|
106
|
+
});
|
|
107
|
+
if (!parsed || typeof parsed !== "object") return {};
|
|
108
|
+
const source = parsed.spec && typeof parsed.spec === "object" && !Array.isArray(parsed.spec) ? parsed.spec : parsed;
|
|
109
|
+
return {
|
|
110
|
+
sandboxedPath: typeof source.sandboxedPath === "string" ? source.sandboxedPath : void 0,
|
|
111
|
+
cacheDir: typeof source.cacheDir === "string" ? source.cacheDir : void 0,
|
|
112
|
+
toolPath: typeof source.toolPath === "string" ? source.toolPath : void 0,
|
|
113
|
+
skillPath: typeof source.skillPath === "string" ? source.skillPath : void 0,
|
|
114
|
+
paths: normalizePathSources(source.paths),
|
|
115
|
+
enableSandboxValidation: typeof source.enableSandboxValidation === "boolean" ? source.enableSandboxValidation : void 0,
|
|
116
|
+
allowedHosts: Array.isArray(source.allowedHosts) ? source.allowedHosts : void 0,
|
|
117
|
+
blockedHosts: Array.isArray(source.blockedHosts) ? source.blockedHosts : void 0,
|
|
118
|
+
blockedCidrs: Array.isArray(source.blockedCidrs) ? source.blockedCidrs : void 0,
|
|
119
|
+
tools: normalizeToolSources(source.tools),
|
|
120
|
+
mcp: normalizeMcpConfig(source.expose?.mcp ?? source.mcp),
|
|
121
|
+
openapi: normalizeOpenApiConfig(source.expose?.openapi ?? source.openapi)
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function getToolSourceDescriptors(config, options) {
|
|
125
|
+
const includeSelf = options?.includeSelf ?? false;
|
|
126
|
+
return Object.keys(config.tools ?? {}).filter((key) => includeSelf || key !== "self");
|
|
127
|
+
}
|
|
128
|
+
function getPathSourceDescriptors(config) {
|
|
129
|
+
const fromPaths = Object.keys(config.paths ?? {});
|
|
130
|
+
if (fromPaths.length > 0) return fromPaths;
|
|
131
|
+
return getToolSourceDescriptors(config);
|
|
132
|
+
}
|
|
133
|
+
function resolveSandboxedPath(toolYamlPath, sandboxedPath) {
|
|
134
|
+
const configDir = path.dirname(path.resolve(toolYamlPath));
|
|
135
|
+
return config.resolveConfigPath(sandboxedPath, configDir, {
|
|
136
|
+
expandHome: true
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
function resolveCacheDir(toolYamlPath, cacheDir) {
|
|
140
|
+
const configDir = path.dirname(path.resolve(toolYamlPath));
|
|
141
|
+
return config.resolveConfigPath(cacheDir, configDir, {
|
|
142
|
+
expandHome: true
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
var CACHE_SUBDIR = ".agent/cache";
|
|
146
|
+
function getCacheBaseFromToolConfig(toolYamlPath) {
|
|
147
|
+
const config = loadToolConfig(toolYamlPath);
|
|
148
|
+
if (config.cacheDir && typeof config.cacheDir === "string") {
|
|
149
|
+
return resolveCacheDir(toolYamlPath, config.cacheDir);
|
|
150
|
+
}
|
|
151
|
+
if (!config.sandboxedPath || typeof config.sandboxedPath !== "string") return void 0;
|
|
152
|
+
const sandboxRoot = resolveSandboxedPath(toolYamlPath, config.sandboxedPath);
|
|
153
|
+
return path.join(sandboxRoot, CACHE_SUBDIR);
|
|
154
|
+
}
|
|
155
|
+
function findAndLoadToolConfig(dir) {
|
|
156
|
+
const resolvedDir = path.resolve(dir);
|
|
157
|
+
const candidates = [path.join(resolvedDir, "tool.yaml"), path.join(resolvedDir, ".tool.yaml")];
|
|
158
|
+
for (const p of candidates) {
|
|
159
|
+
if (fs.existsSync(p)) {
|
|
160
|
+
const config = loadToolConfig(p);
|
|
161
|
+
return { ...config, configPath: p };
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return {};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// src/tools/util/toolDescriptor.ts
|
|
168
|
+
var TOOL_PATH_REGEX = /^([a-z][a-z0-9-]*):([^/]+)\/([^#]+)(#(.+))?$/;
|
|
169
|
+
function isToolPath(descriptor) {
|
|
170
|
+
return TOOL_PATH_REGEX.test(descriptor.trim());
|
|
171
|
+
}
|
|
172
|
+
function isBarePackageDescriptor(descriptor) {
|
|
173
|
+
const parsed = parseToolPath(descriptor.trim());
|
|
174
|
+
return parsed !== null && parsed.toolName === "";
|
|
175
|
+
}
|
|
176
|
+
function parseToolPath(descriptor) {
|
|
177
|
+
const s = descriptor.trim();
|
|
178
|
+
const m = s.match(TOOL_PATH_REGEX);
|
|
179
|
+
if (!m || m[1] === void 0 || m[2] === void 0 || m[3] === void 0) return null;
|
|
180
|
+
return {
|
|
181
|
+
protocol: m[1],
|
|
182
|
+
scope: m[2],
|
|
183
|
+
packageWithVersion: m[3],
|
|
184
|
+
toolName: m[5] ?? ""
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
function npmDescriptorToRegistryPrefix(descriptor, resolvedVersion) {
|
|
188
|
+
const s = descriptor.trim();
|
|
189
|
+
if (typeof s !== "string" || !s.startsWith("npm:")) return "";
|
|
190
|
+
const rest = s.slice(4).trim();
|
|
191
|
+
const hashIdx = rest.indexOf("#");
|
|
192
|
+
const beforeHash = hashIdx < 0 ? rest : rest.slice(0, hashIdx);
|
|
193
|
+
const lastAt = beforeHash.lastIndexOf("@");
|
|
194
|
+
const scopeAndPackage = lastAt <= 0 ? beforeHash : beforeHash.slice(0, lastAt);
|
|
195
|
+
let version = lastAt <= 0 ? "latest" : beforeHash.slice(lastAt + 1).trim() || "latest";
|
|
196
|
+
if (version === "latest" || !version) {
|
|
197
|
+
const resolved = (resolvedVersion ?? "").trim();
|
|
198
|
+
if (resolved !== "" && resolved.toLowerCase() !== "latest") {
|
|
199
|
+
version = resolved;
|
|
200
|
+
} else {
|
|
201
|
+
throw new Error(
|
|
202
|
+
`Registry prefix requires a concrete version when descriptor uses latest (${descriptor}). Resolve version from registry (e.g. resolveLatestVersionFromRegistry) and pass as resolvedVersion.`
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
if (!version || version.toLowerCase() === "latest") {
|
|
207
|
+
throw new Error(
|
|
208
|
+
`Registry never uses "latest"; pass resolved concrete version for npm descriptor: ${descriptor}`
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
const slashIdx = scopeAndPackage.indexOf("/");
|
|
212
|
+
const scope = slashIdx < 0 ? scopeAndPackage : scopeAndPackage.slice(0, slashIdx).replace(/^@/, "");
|
|
213
|
+
const pkg = slashIdx < 0 ? "" : scopeAndPackage.slice(slashIdx + 1);
|
|
214
|
+
const segment = [scope, pkg, version].filter(Boolean).join(".");
|
|
215
|
+
const normalized = chunkJW4EMVTE_cjs.normalizeToolName(segment);
|
|
216
|
+
if (!normalized) return "";
|
|
217
|
+
return "npm." + normalized + ".";
|
|
218
|
+
}
|
|
219
|
+
function npmDescriptorToPackagePrefix(descriptor) {
|
|
220
|
+
const s = descriptor.trim();
|
|
221
|
+
if (typeof s !== "string" || !s.startsWith("npm:")) return "";
|
|
222
|
+
const rest = s.slice(4).trim();
|
|
223
|
+
const hashIdx = rest.indexOf("#");
|
|
224
|
+
const beforeHash = hashIdx < 0 ? rest : rest.slice(0, hashIdx);
|
|
225
|
+
const lastAt = beforeHash.lastIndexOf("@");
|
|
226
|
+
const scopeAndPackage = lastAt <= 0 ? beforeHash : beforeHash.slice(0, lastAt);
|
|
227
|
+
const slashIdx = scopeAndPackage.indexOf("/");
|
|
228
|
+
const scope = slashIdx < 0 ? scopeAndPackage : scopeAndPackage.slice(0, slashIdx).replace(/^@/, "");
|
|
229
|
+
const pkg = slashIdx < 0 ? "" : scopeAndPackage.slice(slashIdx + 1);
|
|
230
|
+
const segment = [scope, pkg].filter(Boolean).join(".");
|
|
231
|
+
const normalized = chunkJW4EMVTE_cjs.normalizeToolName(segment);
|
|
232
|
+
if (!normalized) return "";
|
|
233
|
+
return "npm." + normalized;
|
|
234
|
+
}
|
|
235
|
+
function getDisplayScope(registryName, _kind, _toolVersion) {
|
|
236
|
+
const i = registryName.indexOf(".");
|
|
237
|
+
return i < 0 ? registryName : registryName.slice(0, i);
|
|
238
|
+
}
|
|
239
|
+
function expandToolDescriptorsToRegistryNames(descriptors, registryNames) {
|
|
240
|
+
const out = [];
|
|
241
|
+
const seen = /* @__PURE__ */ new Set();
|
|
242
|
+
function add(name) {
|
|
243
|
+
const key = chunkJW4EMVTE_cjs.normalizeToolName(name);
|
|
244
|
+
if (registryNames.includes(key) && !seen.has(key)) {
|
|
245
|
+
seen.add(key);
|
|
246
|
+
out.push(key);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
const matched = registryNames.filter((r) => r === key || r.endsWith("." + key));
|
|
250
|
+
for (const m of matched) {
|
|
251
|
+
if (!seen.has(m)) {
|
|
252
|
+
seen.add(m);
|
|
253
|
+
out.push(m);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
for (const d of descriptors) {
|
|
258
|
+
const s = d.trim();
|
|
259
|
+
if (!s) continue;
|
|
260
|
+
if (isToolPath(s)) {
|
|
261
|
+
if (registryNames.includes(s) && !seen.has(s)) {
|
|
262
|
+
seen.add(s);
|
|
263
|
+
out.push(s);
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
const path2 = parseToolPath(s);
|
|
267
|
+
if (path2) {
|
|
268
|
+
const packagePrefix = path2.protocol === "npm" ? npmDescriptorToPackagePrefix(s) : path2.protocol === "file" ? fileDescriptorToPackagePrefix(s) : "";
|
|
269
|
+
const prefixWithDot = packagePrefix ? packagePrefix + "." : "";
|
|
270
|
+
if (prefixWithDot) {
|
|
271
|
+
if (path2.toolName) {
|
|
272
|
+
const suffix = "." + path2.toolName;
|
|
273
|
+
for (const r of registryNames) {
|
|
274
|
+
if (r.startsWith(prefixWithDot) && r.endsWith(suffix) && !seen.has(r)) {
|
|
275
|
+
seen.add(r);
|
|
276
|
+
out.push(r);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
} else {
|
|
280
|
+
for (const r of registryNames) {
|
|
281
|
+
if (r.startsWith(prefixWithDot) && !seen.has(r)) {
|
|
282
|
+
seen.add(r);
|
|
283
|
+
out.push(r);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
const name = chunkJW4EMVTE_cjs.normalizeToolName(s);
|
|
292
|
+
add(name);
|
|
293
|
+
}
|
|
294
|
+
return out;
|
|
295
|
+
}
|
|
296
|
+
function resolveToolDescriptor(descriptor) {
|
|
297
|
+
const s = descriptor.trim();
|
|
298
|
+
return s;
|
|
299
|
+
}
|
|
300
|
+
function fileDescriptorToPackagePrefix(descriptor) {
|
|
301
|
+
const path2 = parseToolPath(descriptor.trim());
|
|
302
|
+
if (!path2 || path2.protocol !== "file") return "";
|
|
303
|
+
const pathPart = `${path2.scope}/${path2.packageWithVersion}`;
|
|
304
|
+
const normalized = chunkJW4EMVTE_cjs.normalizeToolName(pathPart);
|
|
305
|
+
if (!normalized) return "";
|
|
306
|
+
return chunkJW4EMVTE_cjs.normalizeToolName("file." + normalized);
|
|
307
|
+
}
|
|
308
|
+
function fileDescriptorToRegistryPrefix(descriptor) {
|
|
309
|
+
const prefix = fileDescriptorToPackagePrefix(descriptor);
|
|
310
|
+
return prefix ? prefix + "." : "";
|
|
311
|
+
}
|
|
312
|
+
var SchemaValidator = class {
|
|
313
|
+
ajv;
|
|
314
|
+
cache = /* @__PURE__ */ new Map();
|
|
315
|
+
constructor() {
|
|
316
|
+
this.ajv = new Ajv__default.default({
|
|
317
|
+
allErrors: true,
|
|
318
|
+
coerceTypes: true,
|
|
319
|
+
useDefaults: true,
|
|
320
|
+
removeAdditional: "failing",
|
|
321
|
+
strict: false
|
|
322
|
+
});
|
|
323
|
+
addFormats__default.default(this.ajv);
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Validate data against a JSON Schema.
|
|
327
|
+
* Coerces types and applies defaults in-place.
|
|
328
|
+
*/
|
|
329
|
+
validate(schema, data) {
|
|
330
|
+
const validate = this.getOrCompile(schema);
|
|
331
|
+
const cloned = structuredClone(data);
|
|
332
|
+
const valid = validate(cloned);
|
|
333
|
+
if (valid) {
|
|
334
|
+
return { valid: true, data: cloned };
|
|
335
|
+
}
|
|
336
|
+
return {
|
|
337
|
+
valid: false,
|
|
338
|
+
errors: validate.errors ?? void 0
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Validate and return coerced data, or throw a descriptive error.
|
|
343
|
+
*/
|
|
344
|
+
validateOrThrow(schema, data, context) {
|
|
345
|
+
const result = this.validate(schema, data);
|
|
346
|
+
if (!result.valid) {
|
|
347
|
+
const messages = (result.errors ?? []).map((e) => `${e.instancePath || "/"} ${e.message}`).join("; ");
|
|
348
|
+
throw new SchemaValidationError(
|
|
349
|
+
`${context}: ${messages}`,
|
|
350
|
+
result.errors ?? []
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
return result.data;
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Apply default values from schema to data without full validation.
|
|
357
|
+
*/
|
|
358
|
+
enrichDefaults(schema, data) {
|
|
359
|
+
const validate = this.getOrCompile(schema);
|
|
360
|
+
const cloned = structuredClone(data);
|
|
361
|
+
validate(cloned);
|
|
362
|
+
return cloned;
|
|
363
|
+
}
|
|
364
|
+
getOrCompile(schema) {
|
|
365
|
+
const normalized = this.normalizeSchema(schema);
|
|
366
|
+
const key = JSON.stringify(normalized);
|
|
367
|
+
let cached = this.cache.get(key);
|
|
368
|
+
if (!cached) {
|
|
369
|
+
cached = this.ajv.compile(normalized);
|
|
370
|
+
this.cache.set(key, cached);
|
|
371
|
+
}
|
|
372
|
+
return cached;
|
|
373
|
+
}
|
|
374
|
+
/** Ensure schema is AJV-compatible (required = string[], nullable handled via type). */
|
|
375
|
+
normalizeSchema(schema) {
|
|
376
|
+
return this.normalizeSchemaRec(schema);
|
|
377
|
+
}
|
|
378
|
+
normalizeSchemaRec(s) {
|
|
379
|
+
const out = {};
|
|
380
|
+
for (const [key, value] of Object.entries(s)) {
|
|
381
|
+
if (key === "required") {
|
|
382
|
+
const raw = value;
|
|
383
|
+
out.required = Array.isArray(raw) ? raw.filter((x) => typeof x === "string") : typeof raw === "string" ? [raw] : [];
|
|
384
|
+
continue;
|
|
385
|
+
}
|
|
386
|
+
if (key === "nullable") {
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
if (key === "properties" && value !== null && typeof value === "object") {
|
|
390
|
+
const props = {};
|
|
391
|
+
for (const [pk, pv] of Object.entries(value)) {
|
|
392
|
+
if (pv !== null && typeof pv === "object" && !Array.isArray(pv)) {
|
|
393
|
+
props[pk] = this.normalizeSchemaRec(pv);
|
|
394
|
+
} else {
|
|
395
|
+
props[pk] = pv;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
out.properties = props;
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
401
|
+
if ((key === "items" || key === "additionalProperties") && value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
402
|
+
out[key] = this.normalizeSchemaRec(value);
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
if ((key === "oneOf" || key === "anyOf" || key === "allOf") && Array.isArray(value)) {
|
|
406
|
+
out[key] = value.map(
|
|
407
|
+
(item) => item !== null && typeof item === "object" && !Array.isArray(item) ? this.normalizeSchemaRec(item) : item
|
|
408
|
+
);
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
out[key] = value;
|
|
412
|
+
}
|
|
413
|
+
if (s.nullable === true) {
|
|
414
|
+
const existingType = out.type;
|
|
415
|
+
if (existingType === void 0) {
|
|
416
|
+
out.type = "object";
|
|
417
|
+
} else if (Array.isArray(existingType)) {
|
|
418
|
+
if (!existingType.includes("null")) out.type = [...existingType, "null"];
|
|
419
|
+
} else {
|
|
420
|
+
out.type = [existingType, "null"];
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
return out;
|
|
424
|
+
}
|
|
425
|
+
};
|
|
426
|
+
var SchemaValidationError = class extends Error {
|
|
427
|
+
constructor(message, errors) {
|
|
428
|
+
super(message);
|
|
429
|
+
this.errors = errors;
|
|
430
|
+
this.name = "SchemaValidationError";
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
|
|
434
|
+
// src/core/runtime/PolicyEngine.ts
|
|
435
|
+
var PolicyEngine = class {
|
|
436
|
+
config;
|
|
437
|
+
constructor(config = {}) {
|
|
438
|
+
this.config = {
|
|
439
|
+
requireExplicitDangerPermission: true,
|
|
440
|
+
deniedSqlPatterns: ["DROP\\s", "TRUNCATE\\s", "DELETE\\s+FROM\\s+\\w+\\s*$"],
|
|
441
|
+
...config
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Enforce all policy checks. Throws PolicyDeniedError if denied.
|
|
446
|
+
*/
|
|
447
|
+
enforce(spec, args, ctx) {
|
|
448
|
+
const result = this.check(spec, args, ctx);
|
|
449
|
+
if (!result.allowed) {
|
|
450
|
+
throw new PolicyDeniedError(
|
|
451
|
+
result.reason ?? "Policy denied",
|
|
452
|
+
result.missingCapabilities
|
|
453
|
+
);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Check all policies without throwing.
|
|
458
|
+
*/
|
|
459
|
+
check(spec, args, ctx) {
|
|
460
|
+
const capResult = this.checkCapabilities(spec, ctx);
|
|
461
|
+
if (!capResult.allowed) return capResult;
|
|
462
|
+
const paramResult = this.checkParameters(spec, args);
|
|
463
|
+
if (!paramResult.allowed) return paramResult;
|
|
464
|
+
return { allowed: true };
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Check that context permissions cover tool capabilities.
|
|
468
|
+
*/
|
|
469
|
+
checkCapabilities(spec, ctx) {
|
|
470
|
+
const missing = [];
|
|
471
|
+
for (const cap of spec.capabilities) {
|
|
472
|
+
if (cap === "danger:destructive") {
|
|
473
|
+
if (this.config.requireExplicitDangerPermission && !ctx.permissions.includes("danger:destructive")) {
|
|
474
|
+
missing.push(cap);
|
|
475
|
+
}
|
|
476
|
+
} else if (!ctx.permissions.includes(cap)) {
|
|
477
|
+
missing.push(cap);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
if (missing.length > 0) {
|
|
481
|
+
return {
|
|
482
|
+
allowed: false,
|
|
483
|
+
reason: `Missing capabilities: ${missing.join(", ")}`,
|
|
484
|
+
missingCapabilities: missing
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
return { allowed: true };
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Check parameter-level security constraints.
|
|
491
|
+
*/
|
|
492
|
+
checkParameters(spec, args) {
|
|
493
|
+
if (!args || typeof args !== "object") return { allowed: true };
|
|
494
|
+
const argsObj = args;
|
|
495
|
+
if (spec.capabilities.includes("write:fs") && this.config.sandboxPaths) {
|
|
496
|
+
const pathResult = this.checkFilePaths(argsObj);
|
|
497
|
+
if (!pathResult.allowed) return pathResult;
|
|
498
|
+
}
|
|
499
|
+
if (spec.capabilities.includes("network") || spec.capabilities.includes("read:web")) {
|
|
500
|
+
const urlResult = this.checkUrls(argsObj);
|
|
501
|
+
if (!urlResult.allowed) return urlResult;
|
|
502
|
+
}
|
|
503
|
+
if (spec.capabilities.includes("write:db") || spec.capabilities.includes("read:db")) {
|
|
504
|
+
const sqlResult = this.checkSql(argsObj);
|
|
505
|
+
if (!sqlResult.allowed) return sqlResult;
|
|
506
|
+
}
|
|
507
|
+
if (spec.capabilities.includes("network") && this.config.allowedDomains) {
|
|
508
|
+
const domainResult = this.checkDomains(argsObj);
|
|
509
|
+
if (!domainResult.allowed) return domainResult;
|
|
510
|
+
}
|
|
511
|
+
return { allowed: true };
|
|
512
|
+
}
|
|
513
|
+
checkFilePaths(args) {
|
|
514
|
+
const paths = this.extractStringValues(args, ["path", "file", "filepath", "filename", "dir", "directory"]);
|
|
515
|
+
for (const p of paths) {
|
|
516
|
+
const normalized = p.replace(/\.\./g, "");
|
|
517
|
+
if (p.includes("..")) {
|
|
518
|
+
return {
|
|
519
|
+
allowed: false,
|
|
520
|
+
reason: `Path traversal detected: ${p}`
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
if (this.config.sandboxPaths && this.config.sandboxPaths.length > 0) {
|
|
524
|
+
const inSandbox = this.config.sandboxPaths.some(
|
|
525
|
+
(sp) => normalized.startsWith(sp)
|
|
526
|
+
);
|
|
527
|
+
if (!inSandbox) {
|
|
528
|
+
return {
|
|
529
|
+
allowed: false,
|
|
530
|
+
reason: `Path outside sandbox: ${p}. Allowed: ${this.config.sandboxPaths.join(", ")}`
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
return { allowed: true };
|
|
536
|
+
}
|
|
537
|
+
checkUrls(args) {
|
|
538
|
+
const urls = this.extractStringValues(args, ["url", "endpoint", "href", "uri"]);
|
|
539
|
+
for (const url of urls) {
|
|
540
|
+
if (this.config.urlDenylist) {
|
|
541
|
+
for (const pattern of this.config.urlDenylist) {
|
|
542
|
+
if (new RegExp(pattern, "i").test(url)) {
|
|
543
|
+
return {
|
|
544
|
+
allowed: false,
|
|
545
|
+
reason: `URL denied by policy: ${url}`
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
if (this.config.urlAllowlist && this.config.urlAllowlist.length > 0) {
|
|
551
|
+
const allowed = this.config.urlAllowlist.some(
|
|
552
|
+
(pattern) => new RegExp(pattern, "i").test(url)
|
|
553
|
+
);
|
|
554
|
+
if (!allowed) {
|
|
555
|
+
return {
|
|
556
|
+
allowed: false,
|
|
557
|
+
reason: `URL not in allowlist: ${url}`
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
return { allowed: true };
|
|
563
|
+
}
|
|
564
|
+
checkSql(args) {
|
|
565
|
+
const sqls = this.extractStringValues(args, ["sql", "query", "statement"]);
|
|
566
|
+
for (const sql of sqls) {
|
|
567
|
+
if (this.config.deniedSqlPatterns) {
|
|
568
|
+
for (const pattern of this.config.deniedSqlPatterns) {
|
|
569
|
+
if (new RegExp(pattern, "i").test(sql)) {
|
|
570
|
+
return {
|
|
571
|
+
allowed: false,
|
|
572
|
+
reason: `SQL pattern denied: ${sql.slice(0, 50)}...`
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
return { allowed: true };
|
|
579
|
+
}
|
|
580
|
+
checkDomains(args) {
|
|
581
|
+
const urls = this.extractStringValues(args, ["url", "endpoint", "href", "host", "domain"]);
|
|
582
|
+
for (const url of urls) {
|
|
583
|
+
try {
|
|
584
|
+
const hostname = url.includes("://") ? new URL(url).hostname : url;
|
|
585
|
+
if (this.config.allowedDomains && !this.config.allowedDomains.some(
|
|
586
|
+
(d) => hostname === d || hostname.endsWith(`.${d}`)
|
|
587
|
+
)) {
|
|
588
|
+
return {
|
|
589
|
+
allowed: false,
|
|
590
|
+
reason: `Domain not allowed: ${hostname}`
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
} catch {
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
return { allowed: true };
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Extract string values from args matching given key patterns.
|
|
600
|
+
*/
|
|
601
|
+
extractStringValues(args, keyPatterns) {
|
|
602
|
+
const results = [];
|
|
603
|
+
const walk = (obj) => {
|
|
604
|
+
for (const [key, val] of Object.entries(obj)) {
|
|
605
|
+
const lowerKey = key.toLowerCase();
|
|
606
|
+
if (typeof val === "string" && keyPatterns.some((p) => lowerKey.includes(p))) {
|
|
607
|
+
results.push(val);
|
|
608
|
+
} else if (val && typeof val === "object" && !Array.isArray(val)) {
|
|
609
|
+
walk(val);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
};
|
|
613
|
+
walk(args);
|
|
614
|
+
return results;
|
|
615
|
+
}
|
|
616
|
+
};
|
|
617
|
+
var PolicyDeniedError = class extends Error {
|
|
618
|
+
constructor(message, missingCapabilities) {
|
|
619
|
+
super(message);
|
|
620
|
+
this.missingCapabilities = missingCapabilities;
|
|
621
|
+
this.name = "PolicyDeniedError";
|
|
622
|
+
}
|
|
623
|
+
kind = "POLICY_DENIED";
|
|
624
|
+
};
|
|
625
|
+
var RateLimiter = class {
|
|
626
|
+
constructor(maxCalls, windowMs) {
|
|
627
|
+
this.maxCalls = maxCalls;
|
|
628
|
+
this.windowMs = windowMs;
|
|
629
|
+
}
|
|
630
|
+
timestamps = [];
|
|
631
|
+
tryAcquire() {
|
|
632
|
+
const now = Date.now();
|
|
633
|
+
while (this.timestamps.length > 0 && this.timestamps[0] <= now - this.windowMs) {
|
|
634
|
+
this.timestamps.shift();
|
|
635
|
+
}
|
|
636
|
+
if (this.timestamps.length >= this.maxCalls) {
|
|
637
|
+
return false;
|
|
638
|
+
}
|
|
639
|
+
this.timestamps.push(now);
|
|
640
|
+
return true;
|
|
641
|
+
}
|
|
642
|
+
get remaining() {
|
|
643
|
+
const now = Date.now();
|
|
644
|
+
const active = this.timestamps.filter((t) => t > now - this.windowMs);
|
|
645
|
+
return Math.max(0, this.maxCalls - active.length);
|
|
646
|
+
}
|
|
647
|
+
};
|
|
648
|
+
var BudgetManager = class {
|
|
649
|
+
defaultTimeoutMs;
|
|
650
|
+
bulkheads = /* @__PURE__ */ new Map();
|
|
651
|
+
circuitBreakers = /* @__PURE__ */ new Map();
|
|
652
|
+
rateLimiters = /* @__PURE__ */ new Map();
|
|
653
|
+
options;
|
|
654
|
+
constructor(options = {}) {
|
|
655
|
+
this.options = options;
|
|
656
|
+
this.defaultTimeoutMs = options.defaultTimeoutMs ?? 3e4;
|
|
657
|
+
}
|
|
658
|
+
/**
|
|
659
|
+
* Get effective timeout for a tool invocation.
|
|
660
|
+
*/
|
|
661
|
+
getTimeout(_toolName, contextTimeoutMs) {
|
|
662
|
+
return contextTimeoutMs ?? this.defaultTimeoutMs;
|
|
663
|
+
}
|
|
664
|
+
/**
|
|
665
|
+
* Check rate limit for a tool. Returns true if allowed.
|
|
666
|
+
*/
|
|
667
|
+
checkRateLimit(toolName) {
|
|
668
|
+
if (!this.options.rateLimit) return true;
|
|
669
|
+
let limiter = this.rateLimiters.get(toolName);
|
|
670
|
+
if (!limiter) {
|
|
671
|
+
limiter = new RateLimiter(
|
|
672
|
+
this.options.rateLimit.maxCalls,
|
|
673
|
+
this.options.rateLimit.windowMs
|
|
674
|
+
);
|
|
675
|
+
this.rateLimiters.set(toolName, limiter);
|
|
676
|
+
}
|
|
677
|
+
return limiter.tryAcquire();
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* Get or create a bulkhead (concurrency limiter) for a tool.
|
|
681
|
+
*/
|
|
682
|
+
getBulkhead(toolName) {
|
|
683
|
+
if (!this.options.maxConcurrency) return void 0;
|
|
684
|
+
let bh = this.bulkheads.get(toolName);
|
|
685
|
+
if (!bh) {
|
|
686
|
+
bh = cockatiel.bulkhead(this.options.maxConcurrency, 0);
|
|
687
|
+
this.bulkheads.set(toolName, bh);
|
|
688
|
+
}
|
|
689
|
+
return bh;
|
|
690
|
+
}
|
|
691
|
+
/**
|
|
692
|
+
* Get or create a circuit breaker for a tool.
|
|
693
|
+
*/
|
|
694
|
+
getCircuitBreaker(toolName) {
|
|
695
|
+
if (!this.options.circuitBreaker) return void 0;
|
|
696
|
+
let breaker = this.circuitBreakers.get(toolName);
|
|
697
|
+
if (!breaker) {
|
|
698
|
+
breaker = cockatiel.circuitBreaker(cockatiel.handleAll, {
|
|
699
|
+
breaker: new cockatiel.ConsecutiveBreaker(this.options.circuitBreaker.threshold),
|
|
700
|
+
halfOpenAfter: this.options.circuitBreaker.halfOpenAfterMs
|
|
701
|
+
});
|
|
702
|
+
this.circuitBreakers.set(toolName, breaker);
|
|
703
|
+
}
|
|
704
|
+
return breaker;
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* Execute a function within budget constraints (bulkhead + circuit breaker).
|
|
708
|
+
*/
|
|
709
|
+
async execute(toolName, fn) {
|
|
710
|
+
const bh = this.getBulkhead(toolName);
|
|
711
|
+
const breaker = this.getCircuitBreaker(toolName);
|
|
712
|
+
let wrapped = fn;
|
|
713
|
+
if (breaker) {
|
|
714
|
+
const prevWrapped = wrapped;
|
|
715
|
+
wrapped = () => breaker.execute(() => prevWrapped());
|
|
716
|
+
}
|
|
717
|
+
if (bh) {
|
|
718
|
+
const prevWrapped = wrapped;
|
|
719
|
+
wrapped = () => bh.execute(() => prevWrapped());
|
|
720
|
+
}
|
|
721
|
+
return wrapped();
|
|
722
|
+
}
|
|
723
|
+
/**
|
|
724
|
+
* Reset all policies for a tool (useful for testing).
|
|
725
|
+
*/
|
|
726
|
+
reset(toolName) {
|
|
727
|
+
this.bulkheads.delete(toolName);
|
|
728
|
+
this.circuitBreakers.delete(toolName);
|
|
729
|
+
this.rateLimiters.delete(toolName);
|
|
730
|
+
}
|
|
731
|
+
/**
|
|
732
|
+
* Reset all policies globally.
|
|
733
|
+
*/
|
|
734
|
+
resetAll() {
|
|
735
|
+
this.bulkheads.clear();
|
|
736
|
+
this.circuitBreakers.clear();
|
|
737
|
+
this.rateLimiters.clear();
|
|
738
|
+
}
|
|
739
|
+
};
|
|
740
|
+
|
|
741
|
+
// src/core/runtime/Evidence.ts
|
|
742
|
+
function buildEvidence(options) {
|
|
743
|
+
const { spec, args, result, ctx, durationMs } = options;
|
|
744
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
745
|
+
const evidence = [];
|
|
746
|
+
evidence.push({
|
|
747
|
+
type: "tool",
|
|
748
|
+
ref: `${spec.name}@${spec.version}`,
|
|
749
|
+
summary: summarizeToolCall(spec, args, result, durationMs),
|
|
750
|
+
createdAt: now
|
|
751
|
+
});
|
|
752
|
+
if (result && typeof result === "object") {
|
|
753
|
+
const urls = extractUrls(result);
|
|
754
|
+
for (const url of urls) {
|
|
755
|
+
evidence.push({
|
|
756
|
+
type: "url",
|
|
757
|
+
ref: url,
|
|
758
|
+
summary: `Output URL from ${spec.name}`,
|
|
759
|
+
createdAt: now
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
const files = extractFilePaths(result);
|
|
763
|
+
for (const file of files) {
|
|
764
|
+
evidence.push({
|
|
765
|
+
type: "file",
|
|
766
|
+
ref: file,
|
|
767
|
+
summary: `Output file from ${spec.name}`,
|
|
768
|
+
createdAt: now
|
|
769
|
+
});
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
if (durationMs !== void 0 && durationMs > 0) {
|
|
773
|
+
evidence.push({
|
|
774
|
+
type: "metric",
|
|
775
|
+
ref: `latency:${spec.name}`,
|
|
776
|
+
summary: `Completed in ${durationMs}ms (request: ${ctx.requestId})`,
|
|
777
|
+
createdAt: now
|
|
778
|
+
});
|
|
779
|
+
}
|
|
780
|
+
return evidence;
|
|
781
|
+
}
|
|
782
|
+
function summarizeToolCall(spec, args, result, durationMs) {
|
|
783
|
+
const argKeys = args && typeof args === "object" ? Object.keys(args).join(", ") : "none";
|
|
784
|
+
const duration = durationMs ? ` in ${durationMs}ms` : "";
|
|
785
|
+
const resultPreview = summarizeValue(result, 100);
|
|
786
|
+
return `${spec.kind}:${spec.name} called with [${argKeys}]${duration} \u2192 ${resultPreview}`;
|
|
787
|
+
}
|
|
788
|
+
function summarizeValue(value, maxLen) {
|
|
789
|
+
if (value === null || value === void 0) return "null";
|
|
790
|
+
if (typeof value === "string") {
|
|
791
|
+
return value.length > maxLen ? value.slice(0, maxLen) + "..." : value;
|
|
792
|
+
}
|
|
793
|
+
const str = JSON.stringify(value);
|
|
794
|
+
return str.length > maxLen ? str.slice(0, maxLen) + "..." : str;
|
|
795
|
+
}
|
|
796
|
+
function extractUrls(obj) {
|
|
797
|
+
const urls = [];
|
|
798
|
+
const walk = (val) => {
|
|
799
|
+
if (typeof val === "string" && /^https?:\/\//i.test(val)) {
|
|
800
|
+
urls.push(val);
|
|
801
|
+
} else if (val && typeof val === "object") {
|
|
802
|
+
for (const v of Object.values(val)) {
|
|
803
|
+
walk(v);
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
};
|
|
807
|
+
walk(obj);
|
|
808
|
+
return urls.slice(0, 10);
|
|
809
|
+
}
|
|
810
|
+
function extractFilePaths(obj) {
|
|
811
|
+
const paths = [];
|
|
812
|
+
const walk = (val) => {
|
|
813
|
+
if (typeof val === "string" && (val.startsWith("/") || val.startsWith("./")) && val.includes(".")) {
|
|
814
|
+
paths.push(val);
|
|
815
|
+
} else if (val && typeof val === "object") {
|
|
816
|
+
for (const v of Object.values(val)) {
|
|
817
|
+
walk(v);
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
};
|
|
821
|
+
walk(obj);
|
|
822
|
+
return paths.slice(0, 10);
|
|
823
|
+
}
|
|
824
|
+
var EventLog = class {
|
|
825
|
+
entries = [];
|
|
826
|
+
seq = 0;
|
|
827
|
+
maxEntries;
|
|
828
|
+
emitter = new eventemitter3.EventEmitter();
|
|
829
|
+
constructor(options = {}) {
|
|
830
|
+
this.maxEntries = options.maxEntries ?? 1e4;
|
|
831
|
+
}
|
|
832
|
+
/**
|
|
833
|
+
* Append an event to the log.
|
|
834
|
+
*/
|
|
835
|
+
append(event) {
|
|
836
|
+
const entry = { seq: ++this.seq, event };
|
|
837
|
+
this.entries.push(entry);
|
|
838
|
+
if (this.entries.length > this.maxEntries) {
|
|
839
|
+
this.entries.shift();
|
|
840
|
+
}
|
|
841
|
+
this.emitter.emit("event", entry);
|
|
842
|
+
this.emitter.emit(event.type, entry);
|
|
843
|
+
return entry;
|
|
844
|
+
}
|
|
845
|
+
/**
|
|
846
|
+
* Subscribe to all events.
|
|
847
|
+
*/
|
|
848
|
+
on(listener) {
|
|
849
|
+
this.emitter.on("event", listener);
|
|
850
|
+
return () => this.emitter.off("event", listener);
|
|
851
|
+
}
|
|
852
|
+
/**
|
|
853
|
+
* Subscribe to events of a specific type.
|
|
854
|
+
*/
|
|
855
|
+
onType(type, listener) {
|
|
856
|
+
this.emitter.on(type, listener);
|
|
857
|
+
return () => this.emitter.off(type, listener);
|
|
858
|
+
}
|
|
859
|
+
/**
|
|
860
|
+
* Query events by filter.
|
|
861
|
+
*/
|
|
862
|
+
query(filter) {
|
|
863
|
+
let results = this.entries;
|
|
864
|
+
if (filter.since !== void 0) {
|
|
865
|
+
results = results.filter((e) => e.seq > filter.since);
|
|
866
|
+
}
|
|
867
|
+
if (filter.type) {
|
|
868
|
+
results = results.filter((e) => e.event.type === filter.type);
|
|
869
|
+
}
|
|
870
|
+
if (filter.toolName) {
|
|
871
|
+
results = results.filter((e) => e.event.toolName === filter.toolName);
|
|
872
|
+
}
|
|
873
|
+
if (filter.requestId) {
|
|
874
|
+
results = results.filter((e) => e.event.requestId === filter.requestId);
|
|
875
|
+
}
|
|
876
|
+
if (filter.limit) {
|
|
877
|
+
results = results.slice(-filter.limit);
|
|
878
|
+
}
|
|
879
|
+
return results;
|
|
880
|
+
}
|
|
881
|
+
/**
|
|
882
|
+
* Get all entries.
|
|
883
|
+
*/
|
|
884
|
+
getAll() {
|
|
885
|
+
return this.entries;
|
|
886
|
+
}
|
|
887
|
+
/**
|
|
888
|
+
* Get entry count.
|
|
889
|
+
*/
|
|
890
|
+
get size() {
|
|
891
|
+
return this.entries.length;
|
|
892
|
+
}
|
|
893
|
+
/**
|
|
894
|
+
* Clear all entries (for testing).
|
|
895
|
+
*/
|
|
896
|
+
clear() {
|
|
897
|
+
this.entries.length = 0;
|
|
898
|
+
this.seq = 0;
|
|
899
|
+
}
|
|
900
|
+
};
|
|
901
|
+
|
|
902
|
+
// src/utils/log.ts
|
|
903
|
+
function summarizeForLog(value, maxLen = 220) {
|
|
904
|
+
const raw = typeof value === "string" ? value : value == null ? "" : (() => {
|
|
905
|
+
try {
|
|
906
|
+
return JSON.stringify(value);
|
|
907
|
+
} catch {
|
|
908
|
+
return String(value);
|
|
909
|
+
}
|
|
910
|
+
})();
|
|
911
|
+
const compact = raw.replace(/\s+/g, " ").trim();
|
|
912
|
+
if (!compact) return "(empty)";
|
|
913
|
+
return compact.length > maxLen ? `${compact.slice(0, maxLen)}...` : compact;
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
// src/observability/Logger.ts
|
|
917
|
+
var LEVEL_ORDER = {
|
|
918
|
+
silent: 0,
|
|
919
|
+
error: 1,
|
|
920
|
+
warn: 2,
|
|
921
|
+
info: 3,
|
|
922
|
+
debug: 4,
|
|
923
|
+
trace: 5
|
|
924
|
+
};
|
|
925
|
+
function createLogger(options = {}) {
|
|
926
|
+
const resolved = resolveDebugOptions(options);
|
|
927
|
+
const log = (level, message, meta) => {
|
|
928
|
+
if (!resolved.enabled) return;
|
|
929
|
+
if (LEVEL_ORDER[level] > LEVEL_ORDER[resolved.level]) return;
|
|
930
|
+
const prefix = `[${resolved.prefix}]`;
|
|
931
|
+
const levelTag = `[${level.toUpperCase()}]`;
|
|
932
|
+
const metaText = meta ? ` ${safeStringify(meta, 1e3)}` : "";
|
|
933
|
+
switch (level) {
|
|
934
|
+
case "error":
|
|
935
|
+
console.error(`${prefix} ${levelTag} ${message}${metaText}`);
|
|
936
|
+
break;
|
|
937
|
+
case "warn":
|
|
938
|
+
console.warn(`${prefix} ${levelTag} ${message}${metaText}`);
|
|
939
|
+
break;
|
|
940
|
+
case "info":
|
|
941
|
+
console.info(`${prefix} ${levelTag} ${message}${metaText}`);
|
|
942
|
+
break;
|
|
943
|
+
default:
|
|
944
|
+
console.log(`${prefix} ${levelTag} ${message}${metaText}`);
|
|
945
|
+
break;
|
|
946
|
+
}
|
|
947
|
+
};
|
|
948
|
+
return {
|
|
949
|
+
options: resolved,
|
|
950
|
+
isEnabled: (level) => resolved.enabled && LEVEL_ORDER[level] <= LEVEL_ORDER[resolved.level],
|
|
951
|
+
error: (message, meta) => log("error", message, meta),
|
|
952
|
+
warn: (message, meta) => log("warn", message, meta),
|
|
953
|
+
info: (message, meta) => log("info", message, meta),
|
|
954
|
+
debug: (message, meta) => log("debug", message, meta),
|
|
955
|
+
trace: (message, meta) => log("trace", message, meta)
|
|
956
|
+
};
|
|
957
|
+
}
|
|
958
|
+
function resolveDebugOptions(options = {}) {
|
|
959
|
+
const envLevel = parseEnvLogLevel();
|
|
960
|
+
const enabledFromEnv = envLevel !== void 0 && envLevel !== "silent";
|
|
961
|
+
const enabled = options.enabled ?? enabledFromEnv ?? false;
|
|
962
|
+
const level = options.level ?? envLevel ?? (enabled ? "debug" : "silent");
|
|
963
|
+
return {
|
|
964
|
+
enabled,
|
|
965
|
+
level,
|
|
966
|
+
includeArgs: options.includeArgs ?? false,
|
|
967
|
+
includeResults: options.includeResults ?? false,
|
|
968
|
+
includeRaw: options.includeRaw ?? false,
|
|
969
|
+
logEvents: options.logEvents ?? false,
|
|
970
|
+
prefix: options.prefix ?? "agent-tool"
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
function sanitizeForLog(value, maxLen = 500) {
|
|
974
|
+
const str = safeStringify(value, maxLen);
|
|
975
|
+
return str.replace(
|
|
976
|
+
/"(password|token|secret|key|auth)":\s*"[^"]*"/gi,
|
|
977
|
+
'"$1":"[REDACTED]"'
|
|
978
|
+
);
|
|
979
|
+
}
|
|
980
|
+
function safeStringify(value, maxLen) {
|
|
981
|
+
try {
|
|
982
|
+
const json = JSON.stringify(value);
|
|
983
|
+
if (!json) return String(value);
|
|
984
|
+
return json.length > maxLen ? `${json.slice(0, maxLen)}...` : json;
|
|
985
|
+
} catch {
|
|
986
|
+
const fallback = String(value);
|
|
987
|
+
return fallback.length > maxLen ? `${fallback.slice(0, maxLen)}...` : fallback;
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
function parseEnvLogLevel() {
|
|
991
|
+
const raw = process.env.TOOLHUB_LOG_LEVEL ?? process.env.TOOLHUB_DEBUG ?? process.env.DEBUG;
|
|
992
|
+
if (!raw) return void 0;
|
|
993
|
+
const value = raw.trim().toLowerCase();
|
|
994
|
+
if (!value || value === "0" || value === "false" || value === "off") {
|
|
995
|
+
return "silent";
|
|
996
|
+
}
|
|
997
|
+
if (value.includes("trace")) return "trace";
|
|
998
|
+
if (value.includes("debug") || value === "1" || value === "true" || value === "yes") {
|
|
999
|
+
return "debug";
|
|
1000
|
+
}
|
|
1001
|
+
if (value.includes("info")) return "info";
|
|
1002
|
+
if (value.includes("warn")) return "warn";
|
|
1003
|
+
if (value.includes("error")) return "error";
|
|
1004
|
+
if (value.includes("silent")) return "silent";
|
|
1005
|
+
return "debug";
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
// src/observability/Metrics.ts
|
|
1009
|
+
var Metrics = class {
|
|
1010
|
+
counters = /* @__PURE__ */ new Map();
|
|
1011
|
+
histograms = /* @__PURE__ */ new Map();
|
|
1012
|
+
defaultBuckets = [
|
|
1013
|
+
5,
|
|
1014
|
+
10,
|
|
1015
|
+
25,
|
|
1016
|
+
50,
|
|
1017
|
+
100,
|
|
1018
|
+
250,
|
|
1019
|
+
500,
|
|
1020
|
+
1e3,
|
|
1021
|
+
2500,
|
|
1022
|
+
5e3,
|
|
1023
|
+
1e4
|
|
1024
|
+
];
|
|
1025
|
+
/**
|
|
1026
|
+
* Increment a counter.
|
|
1027
|
+
*/
|
|
1028
|
+
increment(name, labels = {}, value = 1) {
|
|
1029
|
+
const key = this.makeKey(name, labels);
|
|
1030
|
+
this.counters.set(key, (this.counters.get(key) ?? 0) + value);
|
|
1031
|
+
}
|
|
1032
|
+
/**
|
|
1033
|
+
* Record a value in a histogram.
|
|
1034
|
+
*/
|
|
1035
|
+
observe(name, labels, value) {
|
|
1036
|
+
const key = this.makeKey(name, labels);
|
|
1037
|
+
let hist = this.histograms.get(key);
|
|
1038
|
+
if (!hist) {
|
|
1039
|
+
hist = { count: 0, sum: 0, values: [] };
|
|
1040
|
+
this.histograms.set(key, hist);
|
|
1041
|
+
}
|
|
1042
|
+
hist.count++;
|
|
1043
|
+
hist.sum += value;
|
|
1044
|
+
hist.values.push(value);
|
|
1045
|
+
}
|
|
1046
|
+
/**
|
|
1047
|
+
* Get a counter value.
|
|
1048
|
+
*/
|
|
1049
|
+
getCounter(name, labels = {}) {
|
|
1050
|
+
return this.counters.get(this.makeKey(name, labels)) ?? 0;
|
|
1051
|
+
}
|
|
1052
|
+
/**
|
|
1053
|
+
* Get histogram stats.
|
|
1054
|
+
*/
|
|
1055
|
+
getHistogram(name, labels) {
|
|
1056
|
+
const key = this.makeKey(name, labels);
|
|
1057
|
+
const hist = this.histograms.get(key);
|
|
1058
|
+
if (!hist) return void 0;
|
|
1059
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
1060
|
+
for (const bound of this.defaultBuckets) {
|
|
1061
|
+
buckets.set(bound, hist.values.filter((v) => v <= bound).length);
|
|
1062
|
+
}
|
|
1063
|
+
return { name, labels, count: hist.count, sum: hist.sum, buckets };
|
|
1064
|
+
}
|
|
1065
|
+
/**
|
|
1066
|
+
* Get all counter values.
|
|
1067
|
+
*/
|
|
1068
|
+
getAllCounters() {
|
|
1069
|
+
const results = [];
|
|
1070
|
+
for (const [key, value] of this.counters) {
|
|
1071
|
+
const { name, labels } = this.parseKey(key);
|
|
1072
|
+
results.push({ name, labels, value });
|
|
1073
|
+
}
|
|
1074
|
+
return results;
|
|
1075
|
+
}
|
|
1076
|
+
/**
|
|
1077
|
+
* Get all histogram values.
|
|
1078
|
+
*/
|
|
1079
|
+
getAllHistograms() {
|
|
1080
|
+
const results = [];
|
|
1081
|
+
for (const [key, hist] of this.histograms) {
|
|
1082
|
+
const { name, labels } = this.parseKey(key);
|
|
1083
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
1084
|
+
for (const bound of this.defaultBuckets) {
|
|
1085
|
+
buckets.set(bound, hist.values.filter((v) => v <= bound).length);
|
|
1086
|
+
}
|
|
1087
|
+
results.push({ name, labels, count: hist.count, sum: hist.sum, buckets });
|
|
1088
|
+
}
|
|
1089
|
+
return results;
|
|
1090
|
+
}
|
|
1091
|
+
/**
|
|
1092
|
+
* Record standard tool invocation metrics.
|
|
1093
|
+
*/
|
|
1094
|
+
recordInvocation(toolName, ok, durationMs) {
|
|
1095
|
+
this.increment("tool_invocations_total", {
|
|
1096
|
+
toolName,
|
|
1097
|
+
ok: String(ok)
|
|
1098
|
+
});
|
|
1099
|
+
this.observe("tool_latency_ms", { toolName }, durationMs);
|
|
1100
|
+
}
|
|
1101
|
+
/**
|
|
1102
|
+
* Record a retry event.
|
|
1103
|
+
*/
|
|
1104
|
+
recordRetry(toolName) {
|
|
1105
|
+
this.increment("tool_retries_total", { toolName });
|
|
1106
|
+
}
|
|
1107
|
+
/**
|
|
1108
|
+
* Record a policy denial.
|
|
1109
|
+
*/
|
|
1110
|
+
recordPolicyDenied(toolName, reason) {
|
|
1111
|
+
this.increment("policy_denied_total", { toolName, reason });
|
|
1112
|
+
}
|
|
1113
|
+
/**
|
|
1114
|
+
* Reset all metrics (for testing).
|
|
1115
|
+
*/
|
|
1116
|
+
reset() {
|
|
1117
|
+
this.counters.clear();
|
|
1118
|
+
this.histograms.clear();
|
|
1119
|
+
}
|
|
1120
|
+
makeKey(name, labels) {
|
|
1121
|
+
const sortedLabels = Object.entries(labels).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => `${k}=${v}`).join(",");
|
|
1122
|
+
return `${name}{${sortedLabels}}`;
|
|
1123
|
+
}
|
|
1124
|
+
parseKey(key) {
|
|
1125
|
+
const match = key.match(/^(.+?)\{(.*)\}$/);
|
|
1126
|
+
if (!match) return { name: key, labels: {} };
|
|
1127
|
+
const labels = {};
|
|
1128
|
+
if (match[2]) {
|
|
1129
|
+
for (const part of match[2].split(",")) {
|
|
1130
|
+
const [k, v] = part.split("=");
|
|
1131
|
+
if (k && v !== void 0) labels[k] = v;
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
return { name: match[1], labels };
|
|
1135
|
+
}
|
|
1136
|
+
};
|
|
1137
|
+
var Tracing = class {
|
|
1138
|
+
spans = /* @__PURE__ */ new Map();
|
|
1139
|
+
traceSpans = /* @__PURE__ */ new Map();
|
|
1140
|
+
// traceId → spanIds
|
|
1141
|
+
/**
|
|
1142
|
+
* Start a new span.
|
|
1143
|
+
*/
|
|
1144
|
+
startSpan(options) {
|
|
1145
|
+
const span = {
|
|
1146
|
+
spanId: uuid.v4(),
|
|
1147
|
+
traceId: options.traceId ?? uuid.v4(),
|
|
1148
|
+
parentSpanId: options.parentSpanId,
|
|
1149
|
+
name: options.name,
|
|
1150
|
+
startTime: Date.now(),
|
|
1151
|
+
status: "in_progress",
|
|
1152
|
+
attributes: options.attributes ?? {},
|
|
1153
|
+
events: []
|
|
1154
|
+
};
|
|
1155
|
+
this.spans.set(span.spanId, span);
|
|
1156
|
+
const traceList = this.traceSpans.get(span.traceId) ?? [];
|
|
1157
|
+
traceList.push(span.spanId);
|
|
1158
|
+
this.traceSpans.set(span.traceId, traceList);
|
|
1159
|
+
return span;
|
|
1160
|
+
}
|
|
1161
|
+
/**
|
|
1162
|
+
* End a span and calculate duration.
|
|
1163
|
+
*/
|
|
1164
|
+
endSpan(spanId, status = "ok") {
|
|
1165
|
+
const span = this.spans.get(spanId);
|
|
1166
|
+
if (!span) return void 0;
|
|
1167
|
+
span.endTime = Date.now();
|
|
1168
|
+
span.durationMs = span.endTime - span.startTime;
|
|
1169
|
+
span.status = status;
|
|
1170
|
+
return span;
|
|
1171
|
+
}
|
|
1172
|
+
/**
|
|
1173
|
+
* Add an event to a span.
|
|
1174
|
+
*/
|
|
1175
|
+
addEvent(spanId, name, attributes) {
|
|
1176
|
+
const span = this.spans.get(spanId);
|
|
1177
|
+
if (!span) return;
|
|
1178
|
+
span.events.push({ name, timestamp: Date.now(), attributes });
|
|
1179
|
+
}
|
|
1180
|
+
/**
|
|
1181
|
+
* Set attributes on a span.
|
|
1182
|
+
*/
|
|
1183
|
+
setAttributes(spanId, attributes) {
|
|
1184
|
+
const span = this.spans.get(spanId);
|
|
1185
|
+
if (!span) return;
|
|
1186
|
+
Object.assign(span.attributes, attributes);
|
|
1187
|
+
}
|
|
1188
|
+
/**
|
|
1189
|
+
* Get a span by ID.
|
|
1190
|
+
*/
|
|
1191
|
+
getSpan(spanId) {
|
|
1192
|
+
return this.spans.get(spanId);
|
|
1193
|
+
}
|
|
1194
|
+
/**
|
|
1195
|
+
* Get all spans for a trace.
|
|
1196
|
+
*/
|
|
1197
|
+
getTrace(traceId) {
|
|
1198
|
+
const spanIds = this.traceSpans.get(traceId) ?? [];
|
|
1199
|
+
return spanIds.map((id) => this.spans.get(id)).filter((s) => s !== void 0);
|
|
1200
|
+
}
|
|
1201
|
+
/**
|
|
1202
|
+
* Create a child span from a parent.
|
|
1203
|
+
*/
|
|
1204
|
+
createChildSpan(parentSpanId, name, attributes) {
|
|
1205
|
+
const parent = this.spans.get(parentSpanId);
|
|
1206
|
+
if (!parent) return void 0;
|
|
1207
|
+
return this.startSpan({
|
|
1208
|
+
name,
|
|
1209
|
+
traceId: parent.traceId,
|
|
1210
|
+
parentSpanId: parent.spanId,
|
|
1211
|
+
attributes
|
|
1212
|
+
});
|
|
1213
|
+
}
|
|
1214
|
+
/**
|
|
1215
|
+
* Clear all traces (for testing).
|
|
1216
|
+
*/
|
|
1217
|
+
clear() {
|
|
1218
|
+
this.spans.clear();
|
|
1219
|
+
this.traceSpans.clear();
|
|
1220
|
+
}
|
|
1221
|
+
};
|
|
1222
|
+
function resolveTool(toolName, registry) {
|
|
1223
|
+
const key = chunkJW4EMVTE_cjs.normalizeToolName(toolName);
|
|
1224
|
+
const spec = registry.get(key);
|
|
1225
|
+
if (spec) {
|
|
1226
|
+
return spec;
|
|
1227
|
+
}
|
|
1228
|
+
const suffixMatches = registry.snapshot().filter((candidate) => candidate.name.endsWith(`.${key}`));
|
|
1229
|
+
const uniqueSuffixMatch = suffixMatches[0];
|
|
1230
|
+
if (suffixMatches.length === 1 && uniqueSuffixMatch !== void 0) {
|
|
1231
|
+
return uniqueSuffixMatch;
|
|
1232
|
+
}
|
|
1233
|
+
throw chunkAGLGFQUW_cjs.createTaggedError(
|
|
1234
|
+
"TOOL_NOT_FOUND",
|
|
1235
|
+
`Tool not found: ${toolName}`,
|
|
1236
|
+
{ availableTools: registry.snapshot().slice(0, 20).map((s) => s.name) }
|
|
1237
|
+
);
|
|
1238
|
+
}
|
|
1239
|
+
var INPUT_ALIASES = {
|
|
1240
|
+
q: "query"
|
|
1241
|
+
};
|
|
1242
|
+
function normalizeInputAliases(spec, args) {
|
|
1243
|
+
if (args == null || typeof args !== "object" || Array.isArray(args)) {
|
|
1244
|
+
return args;
|
|
1245
|
+
}
|
|
1246
|
+
const required = getRequiredKeys(spec.inputSchema);
|
|
1247
|
+
const obj = args;
|
|
1248
|
+
let changed = false;
|
|
1249
|
+
const out = { ...obj };
|
|
1250
|
+
for (const [aliasKey, canonicalKey] of Object.entries(INPUT_ALIASES)) {
|
|
1251
|
+
if (required.includes(canonicalKey) && (out[canonicalKey] === void 0 || out[canonicalKey] === "") && out[aliasKey] !== void 0 && out[aliasKey] !== "") {
|
|
1252
|
+
out[canonicalKey] = out[aliasKey];
|
|
1253
|
+
delete out[aliasKey];
|
|
1254
|
+
changed = true;
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
return changed ? out : args;
|
|
1258
|
+
}
|
|
1259
|
+
function validateInput(spec, args, validator) {
|
|
1260
|
+
try {
|
|
1261
|
+
return validator.validateOrThrow(
|
|
1262
|
+
spec.inputSchema,
|
|
1263
|
+
args,
|
|
1264
|
+
`Input validation failed for ${spec.name}`
|
|
1265
|
+
);
|
|
1266
|
+
} catch (error) {
|
|
1267
|
+
if (error instanceof SchemaValidationError) {
|
|
1268
|
+
const requiredKeys = getRequiredKeys(spec.inputSchema);
|
|
1269
|
+
const passedKeys = args != null && typeof args === "object" && !Array.isArray(args) ? Object.keys(args) : [];
|
|
1270
|
+
throw chunkAGLGFQUW_cjs.createTaggedError("INPUT_SCHEMA_INVALID", error.message, {
|
|
1271
|
+
errors: error.errors,
|
|
1272
|
+
schema: spec.inputSchema,
|
|
1273
|
+
requiredKeys: requiredKeys.length ? requiredKeys : void 0,
|
|
1274
|
+
passedKeys: passedKeys.length ? passedKeys : void 0,
|
|
1275
|
+
hint: requiredKeys.length > 0 ? `Expected input property ${requiredKeys.length === 1 ? `'${requiredKeys[0]}'` : `[${requiredKeys.map((k) => `'${k}'`).join(", ")}]`}. You passed: ${passedKeys.length ? passedKeys.map((k) => `'${k}'`).join(", ") : "none"}. Use the exact property names from the tool schema.` : void 0
|
|
1276
|
+
});
|
|
1277
|
+
}
|
|
1278
|
+
throw error;
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
function getRequiredKeys(schema) {
|
|
1282
|
+
const s = schema;
|
|
1283
|
+
const raw = s.required;
|
|
1284
|
+
if (!Array.isArray(raw)) return [];
|
|
1285
|
+
return raw.filter((k) => typeof k === "string");
|
|
1286
|
+
}
|
|
1287
|
+
function enrichDefaults(spec, args, validator) {
|
|
1288
|
+
return validator.enrichDefaults(spec.inputSchema, args);
|
|
1289
|
+
}
|
|
1290
|
+
function enforcePolicy(spec, args, ctx, deps) {
|
|
1291
|
+
try {
|
|
1292
|
+
deps.policy.enforce(spec, args, ctx);
|
|
1293
|
+
} catch (error) {
|
|
1294
|
+
if (error instanceof PolicyDeniedError) {
|
|
1295
|
+
const event = {
|
|
1296
|
+
type: "POLICY_DENIED",
|
|
1297
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1298
|
+
requestId: ctx.requestId,
|
|
1299
|
+
taskId: ctx.taskId,
|
|
1300
|
+
toolName: spec.name,
|
|
1301
|
+
traceId: ctx.traceId,
|
|
1302
|
+
userId: ctx.userId,
|
|
1303
|
+
reason: error.message,
|
|
1304
|
+
missingCapabilities: error.missingCapabilities?.map(String)
|
|
1305
|
+
};
|
|
1306
|
+
deps.eventLog.append(event);
|
|
1307
|
+
deps.metrics.recordPolicyDenied(spec.name, error.message);
|
|
1308
|
+
}
|
|
1309
|
+
throw error;
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
var HITL_GATED_SIDE_EFFECTS = ["external_write", "destructive"];
|
|
1313
|
+
async function requireHumanApproval(spec, args, ctx, deps) {
|
|
1314
|
+
const sideEffect = spec._meta?.hitl?.sideEffect ?? "none";
|
|
1315
|
+
if (!HITL_GATED_SIDE_EFFECTS.includes(sideEffect)) return;
|
|
1316
|
+
const onApproval = deps.onApprovalRequired;
|
|
1317
|
+
if (!onApproval) return;
|
|
1318
|
+
const baseEvent = {
|
|
1319
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1320
|
+
requestId: ctx.requestId,
|
|
1321
|
+
taskId: ctx.taskId,
|
|
1322
|
+
toolName: spec.name,
|
|
1323
|
+
traceId: ctx.traceId,
|
|
1324
|
+
userId: ctx.userId
|
|
1325
|
+
};
|
|
1326
|
+
const requested = {
|
|
1327
|
+
...baseEvent,
|
|
1328
|
+
type: "HITL_APPROVAL_REQUESTED",
|
|
1329
|
+
sideEffect
|
|
1330
|
+
};
|
|
1331
|
+
deps.eventLog.append(requested);
|
|
1332
|
+
deps.logger.trace("hitl.requested", { tool: spec.name, sideEffect, requestId: ctx.requestId });
|
|
1333
|
+
let approved;
|
|
1334
|
+
try {
|
|
1335
|
+
approved = await onApproval(spec, args, ctx);
|
|
1336
|
+
} catch (err) {
|
|
1337
|
+
deps.eventLog.append({
|
|
1338
|
+
...baseEvent,
|
|
1339
|
+
type: "HITL_APPROVAL_DENIED",
|
|
1340
|
+
sideEffect,
|
|
1341
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
1342
|
+
});
|
|
1343
|
+
throw chunkAGLGFQUW_cjs.createTaggedError(
|
|
1344
|
+
"HITL_DENIED",
|
|
1345
|
+
`Human denied approval for ${spec.name} (${sideEffect})`,
|
|
1346
|
+
{ reason: err instanceof Error ? err.message : String(err) }
|
|
1347
|
+
);
|
|
1348
|
+
}
|
|
1349
|
+
if (approved === false) {
|
|
1350
|
+
deps.eventLog.append({
|
|
1351
|
+
...baseEvent,
|
|
1352
|
+
type: "HITL_APPROVAL_DENIED",
|
|
1353
|
+
sideEffect,
|
|
1354
|
+
reason: "User rejected"
|
|
1355
|
+
});
|
|
1356
|
+
throw chunkAGLGFQUW_cjs.createTaggedError("HITL_DENIED", `Human denied approval for ${spec.name} (${sideEffect})`);
|
|
1357
|
+
}
|
|
1358
|
+
deps.eventLog.append({
|
|
1359
|
+
...baseEvent,
|
|
1360
|
+
type: "HITL_APPROVAL_GRANTED",
|
|
1361
|
+
sideEffect
|
|
1362
|
+
});
|
|
1363
|
+
deps.logger.trace("hitl.granted", { tool: spec.name, sideEffect, requestId: ctx.requestId });
|
|
1364
|
+
}
|
|
1365
|
+
async function executeWithBudget(spec, args, ctx, spanId, deps) {
|
|
1366
|
+
const adapter = deps.adaptersByToolName.get(spec.name) ?? deps.adapters.get(spec.kind);
|
|
1367
|
+
if (!adapter) {
|
|
1368
|
+
throw chunkAGLGFQUW_cjs.createTaggedError(
|
|
1369
|
+
"TOOL_NOT_FOUND",
|
|
1370
|
+
`No adapter registered for kind: ${spec.kind}`
|
|
1371
|
+
);
|
|
1372
|
+
}
|
|
1373
|
+
const timeoutMs = deps.budget.getTimeout(
|
|
1374
|
+
spec.name,
|
|
1375
|
+
ctx.budget?.timeoutMs
|
|
1376
|
+
);
|
|
1377
|
+
const maxRetries = ctx.budget?.maxRetries ?? deps.defaultMaxRetries ?? 2;
|
|
1378
|
+
const executeFn = async () => {
|
|
1379
|
+
return deps.budget.execute(spec.name, async () => {
|
|
1380
|
+
deps.tracing.addEvent(spanId, "execute_start");
|
|
1381
|
+
deps.logger.trace("execute.start", {
|
|
1382
|
+
tool: spec.name,
|
|
1383
|
+
requestId: ctx.requestId,
|
|
1384
|
+
timeoutMs,
|
|
1385
|
+
maxRetries
|
|
1386
|
+
});
|
|
1387
|
+
const result = await adapter.invoke(spec, args, ctx);
|
|
1388
|
+
deps.tracing.addEvent(spanId, "execute_end");
|
|
1389
|
+
deps.logger.trace("execute.end", {
|
|
1390
|
+
tool: spec.name,
|
|
1391
|
+
requestId: ctx.requestId
|
|
1392
|
+
});
|
|
1393
|
+
return result;
|
|
1394
|
+
});
|
|
1395
|
+
};
|
|
1396
|
+
const retryFn = () => chunkAGLGFQUW_cjs.withRetry(executeFn, {
|
|
1397
|
+
maxRetries,
|
|
1398
|
+
onRetry: (error, attempt) => {
|
|
1399
|
+
deps.metrics.recordRetry(spec.name);
|
|
1400
|
+
const event = {
|
|
1401
|
+
type: "RETRY",
|
|
1402
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1403
|
+
requestId: ctx.requestId,
|
|
1404
|
+
taskId: ctx.taskId,
|
|
1405
|
+
toolName: spec.name,
|
|
1406
|
+
traceId: ctx.traceId,
|
|
1407
|
+
userId: ctx.userId,
|
|
1408
|
+
attempt,
|
|
1409
|
+
maxRetries,
|
|
1410
|
+
reason: error.message
|
|
1411
|
+
};
|
|
1412
|
+
deps.eventLog.append(event);
|
|
1413
|
+
deps.tracing.addEvent(spanId, "retry", { attempt, reason: error.message });
|
|
1414
|
+
}
|
|
1415
|
+
});
|
|
1416
|
+
try {
|
|
1417
|
+
return await pTimeout__default.default(retryFn(), {
|
|
1418
|
+
milliseconds: timeoutMs,
|
|
1419
|
+
message: `Tool ${spec.name} timed out after ${timeoutMs}ms`
|
|
1420
|
+
});
|
|
1421
|
+
} catch (error) {
|
|
1422
|
+
if (error instanceof Error && error.message.includes("timed out")) {
|
|
1423
|
+
throw chunkAGLGFQUW_cjs.createTaggedError("TIMEOUT", error.message);
|
|
1424
|
+
}
|
|
1425
|
+
throw error;
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
function validateOutput(spec, result, validator) {
|
|
1429
|
+
try {
|
|
1430
|
+
return validator.validateOrThrow(
|
|
1431
|
+
spec.outputSchema,
|
|
1432
|
+
result,
|
|
1433
|
+
`Output validation failed for ${spec.name}`
|
|
1434
|
+
);
|
|
1435
|
+
} catch (error) {
|
|
1436
|
+
if (error instanceof SchemaValidationError) {
|
|
1437
|
+
throw chunkAGLGFQUW_cjs.createTaggedError("OUTPUT_SCHEMA_INVALID", error.message, {
|
|
1438
|
+
errors: error.errors
|
|
1439
|
+
});
|
|
1440
|
+
}
|
|
1441
|
+
throw error;
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
// src/core/runtime/PTCRuntimeObservability.ts
|
|
1446
|
+
function emitToolCalled(intent, ctx, deps) {
|
|
1447
|
+
const event = {
|
|
1448
|
+
type: "TOOL_CALLED",
|
|
1449
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1450
|
+
requestId: ctx.requestId,
|
|
1451
|
+
taskId: ctx.taskId,
|
|
1452
|
+
toolName: intent.tool,
|
|
1453
|
+
traceId: ctx.traceId,
|
|
1454
|
+
userId: ctx.userId,
|
|
1455
|
+
argsSummary: sanitizeArgs(intent.args),
|
|
1456
|
+
purpose: intent.purpose,
|
|
1457
|
+
idempotencyKey: intent.idempotencyKey
|
|
1458
|
+
};
|
|
1459
|
+
deps.eventLog.append(event);
|
|
1460
|
+
}
|
|
1461
|
+
function recordSuccess(spec, durationMs, _evidence, spanId, deps) {
|
|
1462
|
+
deps.metrics.recordInvocation(spec.name, true, durationMs);
|
|
1463
|
+
deps.tracing.setAttributes(spanId, {
|
|
1464
|
+
"tool.duration_ms": durationMs,
|
|
1465
|
+
"tool.ok": true
|
|
1466
|
+
});
|
|
1467
|
+
deps.tracing.endSpan(spanId, "ok");
|
|
1468
|
+
}
|
|
1469
|
+
function handleError(error, intent, ctx, durationMs, spanId, deps) {
|
|
1470
|
+
const kind = error?.kind ?? "UPSTREAM_ERROR";
|
|
1471
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1472
|
+
const details = error?.details;
|
|
1473
|
+
deps.metrics.recordInvocation(intent.tool, false, durationMs);
|
|
1474
|
+
deps.tracing.setAttributes(spanId, {
|
|
1475
|
+
"tool.duration_ms": durationMs,
|
|
1476
|
+
"tool.ok": false,
|
|
1477
|
+
"tool.error_kind": kind
|
|
1478
|
+
});
|
|
1479
|
+
deps.tracing.endSpan(spanId, "error");
|
|
1480
|
+
const event = {
|
|
1481
|
+
type: "TOOL_RESULT",
|
|
1482
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1483
|
+
requestId: ctx.requestId,
|
|
1484
|
+
taskId: ctx.taskId,
|
|
1485
|
+
toolName: intent.tool,
|
|
1486
|
+
traceId: ctx.traceId,
|
|
1487
|
+
userId: ctx.userId,
|
|
1488
|
+
ok: false,
|
|
1489
|
+
durationMs,
|
|
1490
|
+
resultSummary: message,
|
|
1491
|
+
evidence: [],
|
|
1492
|
+
error: { kind, message, details }
|
|
1493
|
+
};
|
|
1494
|
+
deps.eventLog.append(event);
|
|
1495
|
+
deps.logger.warn("invoke.error", {
|
|
1496
|
+
tool: intent.tool,
|
|
1497
|
+
requestId: ctx.requestId,
|
|
1498
|
+
taskId: ctx.taskId,
|
|
1499
|
+
traceId: ctx.traceId,
|
|
1500
|
+
kind,
|
|
1501
|
+
message,
|
|
1502
|
+
durationMs,
|
|
1503
|
+
details: deps.logger.options.includeResults ? summarizeForLog(details) : void 0
|
|
1504
|
+
});
|
|
1505
|
+
return {
|
|
1506
|
+
ok: false,
|
|
1507
|
+
evidence: [],
|
|
1508
|
+
error: { kind, message, details }
|
|
1509
|
+
};
|
|
1510
|
+
}
|
|
1511
|
+
function sanitizeArgs(args) {
|
|
1512
|
+
if (!args) return "{}";
|
|
1513
|
+
return sanitizeForLog(args);
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
// src/core/runtime/PTCRuntime.ts
|
|
1517
|
+
var PTCRuntime = class {
|
|
1518
|
+
registry;
|
|
1519
|
+
adapters = /* @__PURE__ */ new Map();
|
|
1520
|
+
adaptersByToolName = /* @__PURE__ */ new Map();
|
|
1521
|
+
validator;
|
|
1522
|
+
policy;
|
|
1523
|
+
budget;
|
|
1524
|
+
eventLog;
|
|
1525
|
+
metrics;
|
|
1526
|
+
tracing;
|
|
1527
|
+
config;
|
|
1528
|
+
logger;
|
|
1529
|
+
constructor(options = {}) {
|
|
1530
|
+
this.config = options.config ?? {};
|
|
1531
|
+
this.registry = options.registry ?? new chunkAGLGFQUW_cjs.ToolRegistry();
|
|
1532
|
+
this.validator = options.validator ?? new SchemaValidator();
|
|
1533
|
+
this.policy = options.policy ?? new PolicyEngine(this.config.policy);
|
|
1534
|
+
this.budget = options.budget ?? new BudgetManager(this.config.budget);
|
|
1535
|
+
this.eventLog = options.eventLog ?? new EventLog();
|
|
1536
|
+
this.metrics = options.metrics ?? new Metrics();
|
|
1537
|
+
this.tracing = options.tracing ?? new Tracing();
|
|
1538
|
+
this.logger = createLogger({ ...this.config.debug, prefix: "PTCRuntime" });
|
|
1539
|
+
if (this.logger.options.logEvents) {
|
|
1540
|
+
this.eventLog.on((entry) => {
|
|
1541
|
+
const event = entry.event;
|
|
1542
|
+
this.logger.debug("event", {
|
|
1543
|
+
seq: entry.seq,
|
|
1544
|
+
type: event.type,
|
|
1545
|
+
toolName: event.toolName,
|
|
1546
|
+
requestId: event.requestId,
|
|
1547
|
+
taskId: event.taskId,
|
|
1548
|
+
ok: "ok" in event ? event.ok : void 0
|
|
1549
|
+
});
|
|
1550
|
+
});
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
/**
|
|
1554
|
+
* Register an adapter for a tool kind.
|
|
1555
|
+
*/
|
|
1556
|
+
registerAdapter(adapter) {
|
|
1557
|
+
this.adapters.set(adapter.kind, adapter);
|
|
1558
|
+
}
|
|
1559
|
+
/**
|
|
1560
|
+
* Bind an adapter to exact tool keys (full package path + tool path).
|
|
1561
|
+
* This avoids collisions when multiple extensions share the same kind.
|
|
1562
|
+
*/
|
|
1563
|
+
registerAdapterForTools(toolNames, adapter) {
|
|
1564
|
+
for (const name of toolNames) {
|
|
1565
|
+
this.adaptersByToolName.set(name, adapter);
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
/**
|
|
1569
|
+
* Get an adapter by kind (e.g. "mcp"). Use to set MCP client via adapter.setClient().
|
|
1570
|
+
*/
|
|
1571
|
+
getAdapter(kind) {
|
|
1572
|
+
return this.adapters.get(kind);
|
|
1573
|
+
}
|
|
1574
|
+
/**
|
|
1575
|
+
* Get the tool registry.
|
|
1576
|
+
*/
|
|
1577
|
+
getRegistry() {
|
|
1578
|
+
return this.registry;
|
|
1579
|
+
}
|
|
1580
|
+
/**
|
|
1581
|
+
* Get the event log.
|
|
1582
|
+
*/
|
|
1583
|
+
getEventLog() {
|
|
1584
|
+
return this.eventLog;
|
|
1585
|
+
}
|
|
1586
|
+
/**
|
|
1587
|
+
* Get the metrics collector.
|
|
1588
|
+
*/
|
|
1589
|
+
getMetrics() {
|
|
1590
|
+
return this.metrics;
|
|
1591
|
+
}
|
|
1592
|
+
/**
|
|
1593
|
+
* Get the tracing system.
|
|
1594
|
+
*/
|
|
1595
|
+
getTracing() {
|
|
1596
|
+
return this.tracing;
|
|
1597
|
+
}
|
|
1598
|
+
/**
|
|
1599
|
+
* Invoke a tool through the PTC pipeline.
|
|
1600
|
+
* Never throws - always returns a structured ToolResult.
|
|
1601
|
+
*/
|
|
1602
|
+
async invoke(intent, ctx) {
|
|
1603
|
+
const startTime = Date.now();
|
|
1604
|
+
const span = this.beginInvokeSpan(intent, ctx);
|
|
1605
|
+
const observability = this.getObservabilityDeps();
|
|
1606
|
+
emitToolCalled(intent, ctx, observability);
|
|
1607
|
+
try {
|
|
1608
|
+
const pipeline = await this.runInvokePipeline(intent, ctx, span.spanId);
|
|
1609
|
+
if (pipeline.dryRun) {
|
|
1610
|
+
return this.buildDryRunResult(pipeline.spec, pipeline.enrichedArgs, ctx, startTime, span.spanId);
|
|
1611
|
+
}
|
|
1612
|
+
return this.buildInvokeSuccessResult(pipeline, ctx, startTime, span.spanId, observability);
|
|
1613
|
+
} catch (error) {
|
|
1614
|
+
const durationMs = Date.now() - startTime;
|
|
1615
|
+
return handleError(error, intent, ctx, durationMs, span.spanId, observability);
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
/**
|
|
1619
|
+
* Search for tools in the registry.
|
|
1620
|
+
*/
|
|
1621
|
+
searchTools(query, filters) {
|
|
1622
|
+
return this.registry.search({
|
|
1623
|
+
text: query,
|
|
1624
|
+
kind: filters?.kind,
|
|
1625
|
+
capabilities: filters?.capabilities,
|
|
1626
|
+
tags: filters?.tags
|
|
1627
|
+
});
|
|
1628
|
+
}
|
|
1629
|
+
/**
|
|
1630
|
+
* Get the schema for a tool.
|
|
1631
|
+
*/
|
|
1632
|
+
getToolSchema(toolName) {
|
|
1633
|
+
const spec = this.registry.get(toolName);
|
|
1634
|
+
if (!spec) return void 0;
|
|
1635
|
+
return { input: spec.inputSchema, output: spec.outputSchema };
|
|
1636
|
+
}
|
|
1637
|
+
// --- Helper Methods ---
|
|
1638
|
+
getPipelineDeps() {
|
|
1639
|
+
return {
|
|
1640
|
+
registry: this.registry,
|
|
1641
|
+
adapters: this.adapters,
|
|
1642
|
+
adaptersByToolName: this.adaptersByToolName,
|
|
1643
|
+
validator: this.validator,
|
|
1644
|
+
policy: this.policy,
|
|
1645
|
+
budget: this.budget,
|
|
1646
|
+
eventLog: this.eventLog,
|
|
1647
|
+
metrics: this.metrics,
|
|
1648
|
+
tracing: this.tracing,
|
|
1649
|
+
logger: this.logger,
|
|
1650
|
+
defaultMaxRetries: this.config.defaultMaxRetries,
|
|
1651
|
+
onApprovalRequired: this.config.onApprovalRequired
|
|
1652
|
+
};
|
|
1653
|
+
}
|
|
1654
|
+
getObservabilityDeps() {
|
|
1655
|
+
return {
|
|
1656
|
+
eventLog: this.eventLog,
|
|
1657
|
+
metrics: this.metrics,
|
|
1658
|
+
tracing: this.tracing,
|
|
1659
|
+
logger: this.logger
|
|
1660
|
+
};
|
|
1661
|
+
}
|
|
1662
|
+
beginInvokeSpan(intent, ctx) {
|
|
1663
|
+
if (this.logger.isEnabled("debug")) {
|
|
1664
|
+
this.logger.debug("invoke.start", {
|
|
1665
|
+
tool: intent.tool,
|
|
1666
|
+
requestId: ctx.requestId,
|
|
1667
|
+
taskId: ctx.taskId,
|
|
1668
|
+
traceId: ctx.traceId,
|
|
1669
|
+
purpose: intent.purpose,
|
|
1670
|
+
args: this.logger.options.includeArgs ? sanitizeForLog(intent.args) : void 0
|
|
1671
|
+
});
|
|
1672
|
+
}
|
|
1673
|
+
return this.tracing.startSpan({
|
|
1674
|
+
name: `tool:${intent.tool}`,
|
|
1675
|
+
traceId: ctx.traceId,
|
|
1676
|
+
attributes: {
|
|
1677
|
+
"tool.name": intent.tool,
|
|
1678
|
+
"tool.purpose": intent.purpose,
|
|
1679
|
+
requestId: ctx.requestId,
|
|
1680
|
+
taskId: ctx.taskId
|
|
1681
|
+
}
|
|
1682
|
+
});
|
|
1683
|
+
}
|
|
1684
|
+
async runInvokePipeline(intent, ctx, spanId) {
|
|
1685
|
+
const spec = resolveTool(intent.tool, this.registry);
|
|
1686
|
+
this.tracing.addEvent(spanId, "resolved", { kind: spec.kind, version: spec.version });
|
|
1687
|
+
const normalizedArgs = normalizeInputAliases(spec, intent.args);
|
|
1688
|
+
const validatedArgs = validateInput(spec, normalizedArgs, this.validator);
|
|
1689
|
+
const enrichedArgs = enrichDefaults(spec, validatedArgs, this.validator);
|
|
1690
|
+
enforcePolicy(spec, enrichedArgs, ctx, this.getPipelineDeps());
|
|
1691
|
+
if (!this.budget.checkRateLimit(spec.name)) {
|
|
1692
|
+
throw chunkAGLGFQUW_cjs.createTaggedError("BUDGET_EXCEEDED", `Rate limit exceeded for tool: ${spec.name}`);
|
|
1693
|
+
}
|
|
1694
|
+
await requireHumanApproval(spec, enrichedArgs, ctx, {
|
|
1695
|
+
onApprovalRequired: this.config.onApprovalRequired,
|
|
1696
|
+
eventLog: this.eventLog,
|
|
1697
|
+
logger: this.logger
|
|
1698
|
+
});
|
|
1699
|
+
if (ctx.dryRun) return { spec, enrichedArgs, dryRun: true };
|
|
1700
|
+
const execution = await executeWithBudget(spec, enrichedArgs, ctx, spanId, this.getPipelineDeps());
|
|
1701
|
+
return { spec, enrichedArgs, dryRun: false, result: execution.result, raw: execution.raw };
|
|
1702
|
+
}
|
|
1703
|
+
buildInvokeSuccessResult(pipeline, ctx, startTime, spanId, observability) {
|
|
1704
|
+
const toolError = asToolReturnedError(pipeline.result);
|
|
1705
|
+
if (toolError) {
|
|
1706
|
+
const hint = buildInputSchemaHint(pipeline.spec.inputSchema);
|
|
1707
|
+
throw chunkAGLGFQUW_cjs.createTaggedError("UPSTREAM_ERROR", toolError.message, {
|
|
1708
|
+
...toolError.details && typeof toolError.details === "object" && !Array.isArray(toolError.details) ? toolError.details : {},
|
|
1709
|
+
hint: hint ?? "Check the tool's input schema for required property names."
|
|
1710
|
+
});
|
|
1711
|
+
}
|
|
1712
|
+
const validatedOutput = validateOutput(pipeline.spec, pipeline.result, this.validator);
|
|
1713
|
+
const toolFeedback = asToolReturnedFeedback(validatedOutput);
|
|
1714
|
+
const durationMs = Date.now() - startTime;
|
|
1715
|
+
const builtEvidence = buildEvidence({
|
|
1716
|
+
spec: pipeline.spec,
|
|
1717
|
+
args: pipeline.enrichedArgs,
|
|
1718
|
+
result: validatedOutput,
|
|
1719
|
+
raw: pipeline.raw,
|
|
1720
|
+
ctx,
|
|
1721
|
+
durationMs
|
|
1722
|
+
});
|
|
1723
|
+
const adapterEvidence = getAdapterEvidence(pipeline.raw);
|
|
1724
|
+
const evidence = [...adapterEvidence, ...builtEvidence];
|
|
1725
|
+
recordSuccess(pipeline.spec, durationMs, evidence, spanId, observability);
|
|
1726
|
+
if (this.logger.isEnabled("debug")) {
|
|
1727
|
+
this.logger.debug("invoke.ok", {
|
|
1728
|
+
tool: pipeline.spec.name,
|
|
1729
|
+
durationMs,
|
|
1730
|
+
result: this.logger.options.includeResults ? summarizeForLog(validatedOutput) : void 0,
|
|
1731
|
+
raw: this.logger.options.includeRaw ? summarizeForLog(pipeline.raw) : void 0
|
|
1732
|
+
});
|
|
1733
|
+
}
|
|
1734
|
+
return {
|
|
1735
|
+
ok: true,
|
|
1736
|
+
result: validatedOutput,
|
|
1737
|
+
feedback: toolFeedback ?? void 0,
|
|
1738
|
+
evidence,
|
|
1739
|
+
raw: this.config.includeRaw !== false ? pipeline.raw : void 0
|
|
1740
|
+
};
|
|
1741
|
+
}
|
|
1742
|
+
buildDryRunResult(spec, args, _ctx, startTime, spanId) {
|
|
1743
|
+
this.tracing.endSpan(spanId, "ok");
|
|
1744
|
+
return {
|
|
1745
|
+
ok: true,
|
|
1746
|
+
result: {
|
|
1747
|
+
dryRun: true,
|
|
1748
|
+
tool: spec.name,
|
|
1749
|
+
kind: spec.kind,
|
|
1750
|
+
args,
|
|
1751
|
+
capabilities: spec.capabilities
|
|
1752
|
+
},
|
|
1753
|
+
evidence: [
|
|
1754
|
+
{
|
|
1755
|
+
type: "tool",
|
|
1756
|
+
ref: `${spec.name}@${spec.version}`,
|
|
1757
|
+
summary: `Dry-run: would execute ${spec.kind}:${spec.name}`,
|
|
1758
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1759
|
+
}
|
|
1760
|
+
]
|
|
1761
|
+
};
|
|
1762
|
+
}
|
|
1763
|
+
};
|
|
1764
|
+
function getAdapterEvidence(raw) {
|
|
1765
|
+
if (!raw || typeof raw !== "object") return [];
|
|
1766
|
+
const value = raw.evidence;
|
|
1767
|
+
return Array.isArray(value) ? value : [];
|
|
1768
|
+
}
|
|
1769
|
+
function asToolReturnedError(result) {
|
|
1770
|
+
if (result == null || typeof result !== "object" || Array.isArray(result)) {
|
|
1771
|
+
return null;
|
|
1772
|
+
}
|
|
1773
|
+
const r = result;
|
|
1774
|
+
const msg = r.error;
|
|
1775
|
+
if (typeof msg !== "string" || !msg.trim()) {
|
|
1776
|
+
return null;
|
|
1777
|
+
}
|
|
1778
|
+
return { message: msg.trim(), details: r.details };
|
|
1779
|
+
}
|
|
1780
|
+
function asToolReturnedFeedback(result) {
|
|
1781
|
+
if (result == null || typeof result !== "object" || Array.isArray(result)) return null;
|
|
1782
|
+
const rec = result;
|
|
1783
|
+
const feedbackRaw = rec.feedback;
|
|
1784
|
+
if (!feedbackRaw || typeof feedbackRaw !== "object" || Array.isArray(feedbackRaw)) return null;
|
|
1785
|
+
const feedback = feedbackRaw;
|
|
1786
|
+
const status = typeof feedback.status === "string" ? feedback.status.trim() : "";
|
|
1787
|
+
const allowed = /* @__PURE__ */ new Set(["resolved", "needs_retry", "needs_input", "blocked"]);
|
|
1788
|
+
if (!allowed.has(status)) return null;
|
|
1789
|
+
const message = typeof feedback.message === "string" ? feedback.message.trim() : "";
|
|
1790
|
+
if (!message) return null;
|
|
1791
|
+
return {
|
|
1792
|
+
status,
|
|
1793
|
+
message,
|
|
1794
|
+
hint: typeof feedback.hint === "string" ? feedback.hint : void 0,
|
|
1795
|
+
suggested_intent_patch: feedback.suggested_intent_patch && typeof feedback.suggested_intent_patch === "object" && !Array.isArray(feedback.suggested_intent_patch) ? feedback.suggested_intent_patch : void 0,
|
|
1796
|
+
suggested_tool_args: feedback.suggested_tool_args && typeof feedback.suggested_tool_args === "object" && !Array.isArray(feedback.suggested_tool_args) ? feedback.suggested_tool_args : void 0
|
|
1797
|
+
};
|
|
1798
|
+
}
|
|
1799
|
+
function buildInputSchemaHint(inputSchema) {
|
|
1800
|
+
const schema = inputSchema;
|
|
1801
|
+
const required = schema.required;
|
|
1802
|
+
if (!Array.isArray(required) || required.length === 0) {
|
|
1803
|
+
return null;
|
|
1804
|
+
}
|
|
1805
|
+
const names = required.filter((k) => typeof k === "string");
|
|
1806
|
+
if (names.length === 0) return null;
|
|
1807
|
+
return `This tool expects input property ${names.length === 1 ? `'${names[0]}'` : `one of [${names.map((n) => `'${n}'`).join(", ")}]`}. Use the exact property names from the tool schema.`;
|
|
1808
|
+
}
|
|
1809
|
+
var versionCache = /* @__PURE__ */ new Map();
|
|
1810
|
+
var CACHE_TTL = 5 * 60 * 1e3;
|
|
1811
|
+
function resolveNpmPackageVersion(packageName, tag, options = {}) {
|
|
1812
|
+
const cacheKey = packageName;
|
|
1813
|
+
const cached = versionCache.get(cacheKey);
|
|
1814
|
+
if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
|
|
1815
|
+
return cached.version;
|
|
1816
|
+
}
|
|
1817
|
+
try {
|
|
1818
|
+
const spec = tag ? `${packageName}@${tag}` : packageName;
|
|
1819
|
+
const out = child_process.execFileSync("npm", ["view", spec, "version"], {
|
|
1820
|
+
cwd: options.cwd ?? process.cwd(),
|
|
1821
|
+
encoding: "utf-8",
|
|
1822
|
+
timeout: options.timeoutMs ?? 8e3,
|
|
1823
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
1824
|
+
});
|
|
1825
|
+
const version = out?.trim() ?? null;
|
|
1826
|
+
if (version) {
|
|
1827
|
+
versionCache.set(cacheKey, { version, timestamp: Date.now() });
|
|
1828
|
+
}
|
|
1829
|
+
return version;
|
|
1830
|
+
} catch {
|
|
1831
|
+
return null;
|
|
1832
|
+
}
|
|
1833
|
+
}
|
|
1834
|
+
function resolveLatestVersionFromRegistry(packageName, options = {}) {
|
|
1835
|
+
const version = resolveNpmPackageVersion(packageName, void 0, options);
|
|
1836
|
+
if (!version) {
|
|
1837
|
+
throw new Error(`Failed to resolve latest version for ${packageName}`);
|
|
1838
|
+
}
|
|
1839
|
+
return version;
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
// src/utils/npmCache.ts
|
|
1843
|
+
var DEFAULT_CACHE_BASE = path.join(os.homedir(), ".agent", "cache");
|
|
1844
|
+
function isLatestRequest(version) {
|
|
1845
|
+
const normalized = (version ?? "").trim().toLowerCase();
|
|
1846
|
+
return normalized === "" || normalized === "latest";
|
|
1847
|
+
}
|
|
1848
|
+
function getCachedPackageVersion(cacheDir) {
|
|
1849
|
+
const pkgPath = path.join(cacheDir, "package.json");
|
|
1850
|
+
if (!fs.existsSync(pkgPath)) return void 0;
|
|
1851
|
+
try {
|
|
1852
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
1853
|
+
return typeof pkg.version === "string" ? pkg.version : void 0;
|
|
1854
|
+
} catch {
|
|
1855
|
+
return void 0;
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
function packagePathSegments(name) {
|
|
1859
|
+
const withoutScope = name.replace(/^@/, "");
|
|
1860
|
+
return withoutScope.split("/").filter(Boolean);
|
|
1861
|
+
}
|
|
1862
|
+
function resolveCacheDir2(cacheBase, packageName, version) {
|
|
1863
|
+
const segments = packagePathSegments(packageName);
|
|
1864
|
+
return path.join(cacheBase, ...segments, version);
|
|
1865
|
+
}
|
|
1866
|
+
function ensurePackageInCache(packageName, version = "latest", options = {}) {
|
|
1867
|
+
const cacheBase = options.cacheBase ?? DEFAULT_CACHE_BASE;
|
|
1868
|
+
const cwd = options.cwd ?? process.cwd();
|
|
1869
|
+
const resolvedVersion = isLatestRequest(version) ? resolveLatestVersionFromRegistry(packageName, { cwd }) : version;
|
|
1870
|
+
const cacheDir = resolveCacheDir2(cacheBase, packageName, resolvedVersion);
|
|
1871
|
+
const packageJsonPath = path.join(cacheDir, "package.json");
|
|
1872
|
+
const nodeModulesPath = path.join(cacheDir, "node_modules");
|
|
1873
|
+
if (fs.existsSync(packageJsonPath) && fs.existsSync(nodeModulesPath)) {
|
|
1874
|
+
const cachedVersion = getCachedPackageVersion(cacheDir);
|
|
1875
|
+
if (cachedVersion === resolvedVersion) {
|
|
1876
|
+
options.afterInstall?.(cacheDir, packageName);
|
|
1877
|
+
return cacheDir;
|
|
1878
|
+
}
|
|
1879
|
+
fs.rmSync(cacheDir, { recursive: true, force: true });
|
|
1880
|
+
}
|
|
1881
|
+
const packDest = path.join(cacheBase, ".pack-tmp", packageName.replace(/@/g, "").replace(/\//g, "_"));
|
|
1882
|
+
fs.mkdirSync(packDest, { recursive: true });
|
|
1883
|
+
try {
|
|
1884
|
+
child_process.execSync(`npm pack ${packageName}@${resolvedVersion} --pack-destination "${packDest}"`, {
|
|
1885
|
+
cwd,
|
|
1886
|
+
stdio: "pipe",
|
|
1887
|
+
encoding: "utf-8"
|
|
1888
|
+
});
|
|
1889
|
+
const files = fs.readdirSync(packDest);
|
|
1890
|
+
const tgz = files.find((file) => file.endsWith(".tgz"));
|
|
1891
|
+
if (!tgz) throw new Error(`npm pack did not produce a .tgz in ${packDest}`);
|
|
1892
|
+
const extractDir = path.join(packDest, "extract");
|
|
1893
|
+
fs.mkdirSync(extractDir, { recursive: true });
|
|
1894
|
+
child_process.execSync(`tar -xzf "${path.join(packDest, tgz)}" -C "${extractDir}"`, {
|
|
1895
|
+
stdio: "pipe",
|
|
1896
|
+
encoding: "utf-8"
|
|
1897
|
+
});
|
|
1898
|
+
const extractedPackage = path.join(extractDir, "package");
|
|
1899
|
+
if (!fs.existsSync(extractedPackage)) {
|
|
1900
|
+
throw new Error(`Extracted tarball did not contain "package" dir in ${extractDir}`);
|
|
1901
|
+
}
|
|
1902
|
+
fs.mkdirSync(path.join(cacheDir, ".."), { recursive: true });
|
|
1903
|
+
if (fs.existsSync(cacheDir)) fs.rmSync(cacheDir, { recursive: true, force: true });
|
|
1904
|
+
fs.renameSync(extractedPackage, cacheDir);
|
|
1905
|
+
const npmInstallTimeout = 12e4;
|
|
1906
|
+
const maxAttempts = 3;
|
|
1907
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
1908
|
+
try {
|
|
1909
|
+
child_process.execSync("npm install --prefer-offline --no-audit --no-fund", {
|
|
1910
|
+
cwd: cacheDir,
|
|
1911
|
+
stdio: "pipe",
|
|
1912
|
+
encoding: "utf-8",
|
|
1913
|
+
timeout: npmInstallTimeout
|
|
1914
|
+
});
|
|
1915
|
+
break;
|
|
1916
|
+
} catch (error) {
|
|
1917
|
+
if (attempt >= maxAttempts) {
|
|
1918
|
+
const lastError = error instanceof Error ? error : new Error(String(error));
|
|
1919
|
+
throw new Error(`npm install in cache failed after ${maxAttempts} attempts: ${lastError.message}`);
|
|
1920
|
+
}
|
|
1921
|
+
const delayMs = 5e3 * attempt;
|
|
1922
|
+
const deadline = Date.now() + delayMs;
|
|
1923
|
+
while (Date.now() < deadline) {
|
|
1924
|
+
}
|
|
1925
|
+
}
|
|
1926
|
+
}
|
|
1927
|
+
options.afterInstall?.(cacheDir, packageName);
|
|
1928
|
+
return cacheDir;
|
|
1929
|
+
} finally {
|
|
1930
|
+
if (fs.existsSync(packDest)) fs.rmSync(packDest, { recursive: true, force: true });
|
|
1931
|
+
}
|
|
1932
|
+
}
|
|
1933
|
+
function getPackageEntryPath(packageRoot) {
|
|
1934
|
+
const pkgPath = path.join(packageRoot, "package.json");
|
|
1935
|
+
if (!fs.existsSync(pkgPath)) throw new Error(`No package.json in ${packageRoot}`);
|
|
1936
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
1937
|
+
const main = pkg.main ?? "dist/index.js";
|
|
1938
|
+
const entryPath = path.join(packageRoot, main);
|
|
1939
|
+
if (!fs.existsSync(entryPath)) throw new Error(`Entry not found: ${entryPath}`);
|
|
1940
|
+
return entryPath;
|
|
1941
|
+
}
|
|
1942
|
+
async function importFromCache(packageRoot) {
|
|
1943
|
+
const entryPath = getPackageEntryPath(packageRoot);
|
|
1944
|
+
const fileUrl = url.pathToFileURL(entryPath).href;
|
|
1945
|
+
return import(
|
|
1946
|
+
/* @vite-ignore */
|
|
1947
|
+
fileUrl
|
|
1948
|
+
);
|
|
1949
|
+
}
|
|
1950
|
+
var requireFromPackage = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-4VKCWJHF.cjs', document.baseURI).href)));
|
|
1951
|
+
function getProjectRequire() {
|
|
1952
|
+
const cwd = process.cwd();
|
|
1953
|
+
if (fs.existsSync(path.join(cwd, "package.json"))) return module$1.createRequire(path.join(cwd, "package.json"));
|
|
1954
|
+
if (fs.existsSync(path.join(cwd, "tool.yaml"))) return module$1.createRequire(path.join(cwd, "tool.yaml"));
|
|
1955
|
+
return null;
|
|
1956
|
+
}
|
|
1957
|
+
function findNearestPackageJson(startDir) {
|
|
1958
|
+
let dir = path.resolve(startDir);
|
|
1959
|
+
while (true) {
|
|
1960
|
+
const pkg = path.join(dir, "package.json");
|
|
1961
|
+
if (fs.existsSync(pkg)) return pkg;
|
|
1962
|
+
const parent = path.dirname(dir);
|
|
1963
|
+
if (parent === dir) return null;
|
|
1964
|
+
dir = parent;
|
|
1965
|
+
}
|
|
1966
|
+
}
|
|
1967
|
+
function getInstalledPackageVersion(packageName) {
|
|
1968
|
+
const projectRequire = getProjectRequire();
|
|
1969
|
+
const requirers = [requireFromPackage];
|
|
1970
|
+
if (projectRequire) requirers.push(projectRequire);
|
|
1971
|
+
for (const req of requirers) {
|
|
1972
|
+
try {
|
|
1973
|
+
const pkgJsonPath = req.resolve(`${packageName}/package.json`);
|
|
1974
|
+
const json = fs.readFileSync(pkgJsonPath, "utf-8");
|
|
1975
|
+
const pkg = JSON.parse(json);
|
|
1976
|
+
return pkg.version ?? null;
|
|
1977
|
+
} catch {
|
|
1978
|
+
continue;
|
|
1979
|
+
}
|
|
1980
|
+
}
|
|
1981
|
+
return null;
|
|
1982
|
+
}
|
|
1983
|
+
function hasInvokeFunction(value) {
|
|
1984
|
+
return value != null && typeof value === "object" && "invoke" in value && typeof value.invoke === "function";
|
|
1985
|
+
}
|
|
1986
|
+
function normalizeToolOutput(output) {
|
|
1987
|
+
if (output != null && typeof output === "object" && "result" in output) {
|
|
1988
|
+
const o = output;
|
|
1989
|
+
const evidence = Array.isArray(o.evidence) ? o.evidence : void 0;
|
|
1990
|
+
return evidence ? { result: o.result, raw: { evidence } } : { result: o.result };
|
|
1991
|
+
}
|
|
1992
|
+
return { result: output };
|
|
1993
|
+
}
|
|
1994
|
+
function createLocalDirectoryAdapter(kind) {
|
|
1995
|
+
return {
|
|
1996
|
+
kind,
|
|
1997
|
+
async invoke(spec, args, ctx) {
|
|
1998
|
+
if (spec.kind === "skill") {
|
|
1999
|
+
const impl = spec.impl;
|
|
2000
|
+
if (hasInvokeFunction(impl)) {
|
|
2001
|
+
const out2 = await impl.invoke(args);
|
|
2002
|
+
return normalizeToolOutput(out2);
|
|
2003
|
+
}
|
|
2004
|
+
const handler = typeof impl?.handler === "function" ? impl.handler : typeof spec.impl === "function" ? spec.impl : void 0;
|
|
2005
|
+
if (typeof handler !== "function") {
|
|
2006
|
+
throw new Error(`Local skill ${spec.name} has no executable handler`);
|
|
2007
|
+
}
|
|
2008
|
+
const out = await handler(args, {
|
|
2009
|
+
requestId: ctx.requestId,
|
|
2010
|
+
taskId: ctx.taskId,
|
|
2011
|
+
skill: {
|
|
2012
|
+
name: impl?.frontmatter?.name ?? spec.name,
|
|
2013
|
+
description: impl?.frontmatter?.description ?? spec.description ?? "",
|
|
2014
|
+
instructions: impl?.instructions ?? "",
|
|
2015
|
+
resources: [],
|
|
2016
|
+
readResource: async () => "",
|
|
2017
|
+
getResourcesByType: () => [],
|
|
2018
|
+
dirPath: impl?.dirPath ?? ""
|
|
2019
|
+
}
|
|
2020
|
+
});
|
|
2021
|
+
return normalizeToolOutput(out);
|
|
2022
|
+
}
|
|
2023
|
+
if (spec.kind === "langchain") {
|
|
2024
|
+
if (!hasInvokeFunction(spec.impl)) {
|
|
2025
|
+
throw new Error(`Local langchain tool ${spec.name} missing invoke()`);
|
|
2026
|
+
}
|
|
2027
|
+
const out = await spec.impl.invoke(args);
|
|
2028
|
+
return normalizeToolOutput(out);
|
|
2029
|
+
}
|
|
2030
|
+
if (spec.kind === "n8n") {
|
|
2031
|
+
if (!spec.endpoint) {
|
|
2032
|
+
throw new Error(`Local n8n tool ${spec.name} missing endpoint/webhook URL`);
|
|
2033
|
+
}
|
|
2034
|
+
const res = await fetch(spec.endpoint, {
|
|
2035
|
+
method: "POST",
|
|
2036
|
+
headers: { "content-type": "application/json" },
|
|
2037
|
+
body: JSON.stringify(args ?? {})
|
|
2038
|
+
});
|
|
2039
|
+
if (!res.ok) {
|
|
2040
|
+
throw new Error(`n8n request failed (${res.status})`);
|
|
2041
|
+
}
|
|
2042
|
+
const text = await res.text();
|
|
2043
|
+
if (!text.trim()) return { result: {} };
|
|
2044
|
+
try {
|
|
2045
|
+
return { result: JSON.parse(text) };
|
|
2046
|
+
} catch {
|
|
2047
|
+
return { result: text };
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
if (spec.kind === "function") {
|
|
2051
|
+
const meta = spec._meta;
|
|
2052
|
+
if (!meta?.sourcePath || !meta?.exportName || !meta?.projectPath) {
|
|
2053
|
+
throw new Error(`Local function ${spec.name} missing sourcePath/exportName/projectPath`);
|
|
2054
|
+
}
|
|
2055
|
+
const source = path.resolve(meta.projectPath, meta.sourcePath);
|
|
2056
|
+
const mod = await import(url.pathToFileURL(source).href);
|
|
2057
|
+
const fn = mod[meta.exportName];
|
|
2058
|
+
if (typeof fn !== "function") {
|
|
2059
|
+
throw new Error(`Local function ${spec.name} export "${meta.exportName}" is not a function`);
|
|
2060
|
+
}
|
|
2061
|
+
const out = await fn(args);
|
|
2062
|
+
return normalizeToolOutput(out);
|
|
2063
|
+
}
|
|
2064
|
+
throw new Error(`Local directory tool kind not supported for invoke: ${spec.kind}`);
|
|
2065
|
+
}
|
|
2066
|
+
};
|
|
2067
|
+
}
|
|
2068
|
+
function createPrefixingRegistry(registry, prefix) {
|
|
2069
|
+
return {
|
|
2070
|
+
register(spec) {
|
|
2071
|
+
registry.register({
|
|
2072
|
+
...spec,
|
|
2073
|
+
name: prefix + chunkJW4EMVTE_cjs.normalizeToolName(spec.name)
|
|
2074
|
+
});
|
|
2075
|
+
},
|
|
2076
|
+
bulkRegister(specs) {
|
|
2077
|
+
specs.forEach((s) => this.register(s));
|
|
2078
|
+
},
|
|
2079
|
+
unregister(name) {
|
|
2080
|
+
return registry.unregister(name);
|
|
2081
|
+
},
|
|
2082
|
+
get(name) {
|
|
2083
|
+
return registry.get(name);
|
|
2084
|
+
},
|
|
2085
|
+
has(name) {
|
|
2086
|
+
return registry.has(name);
|
|
2087
|
+
},
|
|
2088
|
+
search(query) {
|
|
2089
|
+
return registry.search(query);
|
|
2090
|
+
},
|
|
2091
|
+
list() {
|
|
2092
|
+
return registry.list();
|
|
2093
|
+
},
|
|
2094
|
+
get size() {
|
|
2095
|
+
return registry.size;
|
|
2096
|
+
},
|
|
2097
|
+
snapshot() {
|
|
2098
|
+
return registry.snapshot();
|
|
2099
|
+
},
|
|
2100
|
+
clear() {
|
|
2101
|
+
return registry.clear();
|
|
2102
|
+
}
|
|
2103
|
+
};
|
|
2104
|
+
}
|
|
2105
|
+
function parseNpmDescriptor(entry) {
|
|
2106
|
+
if (typeof entry !== "string" || !entry.startsWith("npm:")) return null;
|
|
2107
|
+
const rest = entry.slice(4).trim();
|
|
2108
|
+
const at = rest.indexOf("@", 1);
|
|
2109
|
+
if (at < 0) return { packageName: rest, version: "latest" };
|
|
2110
|
+
const packageName = rest.slice(0, at);
|
|
2111
|
+
const version = rest.slice(at + 1).split("#")[0]?.trim() || "latest";
|
|
2112
|
+
return { packageName, version };
|
|
2113
|
+
}
|
|
2114
|
+
|
|
2115
|
+
// src/api/runtimeFromConfig.types.ts
|
|
2116
|
+
var DEFAULT_EXTENSION_PACKAGES = [];
|
|
2117
|
+
|
|
2118
|
+
// src/api/runtimeFromConfig.ts
|
|
2119
|
+
var requireFromPackage2 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-4VKCWJHF.cjs', document.baseURI).href)));
|
|
2120
|
+
function resolveEffectiveCoreTools(options) {
|
|
2121
|
+
if (options.coreTools) return options.coreTools;
|
|
2122
|
+
if (options.configFilePath) return {};
|
|
2123
|
+
return void 0;
|
|
2124
|
+
}
|
|
2125
|
+
function resolveFileDescriptorPath(descriptor, configFilePath) {
|
|
2126
|
+
const parsed = parseToolPath(descriptor.trim());
|
|
2127
|
+
if (!parsed || parsed.protocol !== "file") return null;
|
|
2128
|
+
const localPath = path.isAbsolute(configFilePath) ? configFilePath : path.resolve(process.cwd(), configFilePath);
|
|
2129
|
+
const configDir = path.dirname(localPath);
|
|
2130
|
+
return path.resolve(configDir, `${parsed.scope}/${parsed.packageWithVersion}`);
|
|
2131
|
+
}
|
|
2132
|
+
function getRegisterFn(mod) {
|
|
2133
|
+
return mod?.register ?? mod?.registerCoreTools;
|
|
2134
|
+
}
|
|
2135
|
+
function loadExtensionFromNodeModules() {
|
|
2136
|
+
const projectRequire = getProjectRequire();
|
|
2137
|
+
const requirers = [requireFromPackage2];
|
|
2138
|
+
if (projectRequire) requirers.push(projectRequire);
|
|
2139
|
+
for (const req of requirers) {
|
|
2140
|
+
for (const pkg of DEFAULT_EXTENSION_PACKAGES) {
|
|
2141
|
+
try {
|
|
2142
|
+
const mod = req(pkg);
|
|
2143
|
+
const fn = getRegisterFn(mod);
|
|
2144
|
+
if (typeof fn === "function") return { register: fn, packageName: pkg };
|
|
2145
|
+
} catch {
|
|
2146
|
+
continue;
|
|
2147
|
+
}
|
|
2148
|
+
}
|
|
2149
|
+
}
|
|
2150
|
+
return null;
|
|
2151
|
+
}
|
|
2152
|
+
function loadExtensionFromFileDescriptorSync(descriptor, configFilePath, stepLog) {
|
|
2153
|
+
const entryStr = descriptor.trim();
|
|
2154
|
+
const path2 = parseToolPath(entryStr);
|
|
2155
|
+
if (!path2 || path2.protocol !== "file") return null;
|
|
2156
|
+
const localPath = path.isAbsolute(configFilePath) ? configFilePath : path.resolve(process.cwd(), configFilePath);
|
|
2157
|
+
const configDir = path.dirname(localPath);
|
|
2158
|
+
const pathPart = `${path2.scope}/${path2.packageWithVersion}`;
|
|
2159
|
+
const resolvedPath = path.resolve(configDir, pathPart);
|
|
2160
|
+
if (!fs.existsSync(resolvedPath) || !fs.statSync(resolvedPath).isDirectory()) return null;
|
|
2161
|
+
try {
|
|
2162
|
+
const entryPath = getPackageEntryPath(resolvedPath);
|
|
2163
|
+
const req = module$1.createRequire(path.join(resolvedPath, "package.json"));
|
|
2164
|
+
const mod = req(entryPath);
|
|
2165
|
+
const fn = getRegisterFn(mod);
|
|
2166
|
+
if (typeof fn === "function") {
|
|
2167
|
+
if (stepLog) stepLog(`Loaded local extension from ${resolvedPath}`);
|
|
2168
|
+
return { register: fn, descriptor: entryStr, resolvedVersion: "local", packageRoot: resolvedPath };
|
|
2169
|
+
}
|
|
2170
|
+
} catch (error) {
|
|
2171
|
+
if (stepLog) {
|
|
2172
|
+
stepLog(`Failed to load local extension from ${resolvedPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
2173
|
+
}
|
|
2174
|
+
}
|
|
2175
|
+
return null;
|
|
2176
|
+
}
|
|
2177
|
+
async function loadExtensionFromFileDescriptorAsync(descriptor, configFilePath, stepLog) {
|
|
2178
|
+
const entryStr = descriptor.trim();
|
|
2179
|
+
const path2 = parseToolPath(entryStr);
|
|
2180
|
+
if (!path2 || path2.protocol !== "file") return null;
|
|
2181
|
+
const localPath = path.isAbsolute(configFilePath) ? configFilePath : path.resolve(process.cwd(), configFilePath);
|
|
2182
|
+
const configDir = path.dirname(localPath);
|
|
2183
|
+
const pathPart = `${path2.scope}/${path2.packageWithVersion}`;
|
|
2184
|
+
const resolvedPath = path.resolve(configDir, pathPart);
|
|
2185
|
+
if (!fs.existsSync(resolvedPath) || !fs.statSync(resolvedPath).isDirectory()) return null;
|
|
2186
|
+
try {
|
|
2187
|
+
const entryPath = getPackageEntryPath(resolvedPath);
|
|
2188
|
+
const mod = await import(url.pathToFileURL(entryPath).href);
|
|
2189
|
+
const fn = getRegisterFn(mod);
|
|
2190
|
+
if (typeof fn === "function") {
|
|
2191
|
+
if (stepLog) stepLog(`Loaded local extension from ${resolvedPath} (async import)`);
|
|
2192
|
+
return { register: fn, descriptor: entryStr, resolvedVersion: "local", packageRoot: resolvedPath };
|
|
2193
|
+
}
|
|
2194
|
+
} catch (error) {
|
|
2195
|
+
if (stepLog) {
|
|
2196
|
+
stepLog(`Failed to load local extension from ${resolvedPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
2199
|
+
return null;
|
|
2200
|
+
}
|
|
2201
|
+
function loadExtensionForDescriptorSync(descriptor, configFilePath, stepLog) {
|
|
2202
|
+
const entryStr = descriptor.trim();
|
|
2203
|
+
const parsed = parseNpmDescriptor(entryStr);
|
|
2204
|
+
if (!parsed) return null;
|
|
2205
|
+
const localPath = path.isAbsolute(configFilePath) ? configFilePath : path.resolve(process.cwd(), configFilePath);
|
|
2206
|
+
const configDir = path.dirname(localPath);
|
|
2207
|
+
const packageJsonPath = findNearestPackageJson(configDir);
|
|
2208
|
+
const configRequire = packageJsonPath ? module$1.createRequire(packageJsonPath) : null;
|
|
2209
|
+
const npmCwd = packageJsonPath ? path.dirname(packageJsonPath) : configDir;
|
|
2210
|
+
if (configRequire) {
|
|
2211
|
+
try {
|
|
2212
|
+
const mod = configRequire(parsed.packageName);
|
|
2213
|
+
const fn = getRegisterFn(mod);
|
|
2214
|
+
if (typeof fn === "function") {
|
|
2215
|
+
const installed = getInstalledPackageVersionFromRequire(parsed.packageName, configRequire);
|
|
2216
|
+
const requested = parsed.version === "latest" || !parsed.version?.trim() ? null : parsed.version;
|
|
2217
|
+
const resolvedVersion = requested ?? installed ?? resolveLatestVersionFromRegistry(parsed.packageName, { cwd: npmCwd });
|
|
2218
|
+
if (installed === resolvedVersion) {
|
|
2219
|
+
if (stepLog) stepLog(`Loaded ${parsed.packageName}@${resolvedVersion} from node_modules`);
|
|
2220
|
+
const pkgRoot = path.dirname(configRequire.resolve(`${parsed.packageName}/package.json`));
|
|
2221
|
+
return { register: fn, descriptor: entryStr, resolvedVersion, packageRoot: pkgRoot };
|
|
2222
|
+
}
|
|
2223
|
+
}
|
|
2224
|
+
} catch {
|
|
2225
|
+
}
|
|
2226
|
+
}
|
|
2227
|
+
const cacheBase = getCacheBaseFromToolConfig(localPath);
|
|
2228
|
+
const cacheOptions = cacheBase ? [{ cacheBase, cwd: npmCwd }, { cwd: npmCwd }] : [{ cwd: npmCwd }];
|
|
2229
|
+
for (const opts of cacheOptions) {
|
|
2230
|
+
try {
|
|
2231
|
+
const cacheDir = ensurePackageInCache(parsed.packageName, parsed.version, opts);
|
|
2232
|
+
if (stepLog) stepLog(`Loaded ${parsed.packageName} from cache: ${cacheDir}`);
|
|
2233
|
+
const entryPath = getPackageEntryPath(cacheDir);
|
|
2234
|
+
const req = module$1.createRequire(path.join(cacheDir, "package.json"));
|
|
2235
|
+
const mod = req(entryPath);
|
|
2236
|
+
const fn = getRegisterFn(mod);
|
|
2237
|
+
if (typeof fn === "function") {
|
|
2238
|
+
const resolvedVersion = path.basename(cacheDir);
|
|
2239
|
+
return { register: fn, descriptor: entryStr, resolvedVersion, packageRoot: cacheDir };
|
|
2240
|
+
}
|
|
2241
|
+
break;
|
|
2242
|
+
} catch {
|
|
2243
|
+
if (cacheBase && "cacheBase" in opts) continue;
|
|
2244
|
+
break;
|
|
2245
|
+
}
|
|
2246
|
+
}
|
|
2247
|
+
return null;
|
|
2248
|
+
}
|
|
2249
|
+
function loadAllExtensionsFromToolYamlSync(configFilePath, stepLog) {
|
|
2250
|
+
const localPath = path.isAbsolute(configFilePath) ? configFilePath : path.resolve(process.cwd(), configFilePath);
|
|
2251
|
+
if (!fs.existsSync(localPath)) return [];
|
|
2252
|
+
const config = loadToolConfig(localPath);
|
|
2253
|
+
const tools = getPathSourceDescriptors(config);
|
|
2254
|
+
if (!Array.isArray(tools) || tools.length === 0) return [];
|
|
2255
|
+
if (stepLog) stepLog("Loading extensions from tool.yaml (npm + file)");
|
|
2256
|
+
const loaded = [];
|
|
2257
|
+
for (const entry of tools) {
|
|
2258
|
+
const entryStr = String(entry).trim();
|
|
2259
|
+
if (entryStr.startsWith("npm:")) {
|
|
2260
|
+
const result = loadExtensionForDescriptorSync(entryStr, configFilePath, stepLog);
|
|
2261
|
+
if (result) loaded.push(result);
|
|
2262
|
+
} else if (entryStr.startsWith("file:")) {
|
|
2263
|
+
const result = loadExtensionFromFileDescriptorSync(entryStr, configFilePath, stepLog);
|
|
2264
|
+
if (result) loaded.push(result);
|
|
2265
|
+
}
|
|
2266
|
+
}
|
|
2267
|
+
return loaded;
|
|
2268
|
+
}
|
|
2269
|
+
function getInstalledPackageVersionFromRequire(packageName, req) {
|
|
2270
|
+
try {
|
|
2271
|
+
const pkgJsonPath = req.resolve(`${packageName}/package.json`);
|
|
2272
|
+
const json = fs.readFileSync(pkgJsonPath, "utf-8");
|
|
2273
|
+
const pkg = JSON.parse(json);
|
|
2274
|
+
return pkg.version ?? null;
|
|
2275
|
+
} catch {
|
|
2276
|
+
return null;
|
|
2277
|
+
}
|
|
2278
|
+
}
|
|
2279
|
+
async function loadExtensionForDescriptorAsync(descriptor, configFilePath, stepLog) {
|
|
2280
|
+
const syncResult = loadExtensionForDescriptorSync(descriptor, configFilePath, stepLog);
|
|
2281
|
+
if (syncResult) return syncResult;
|
|
2282
|
+
const entryStr = descriptor.trim();
|
|
2283
|
+
const parsed = parseNpmDescriptor(entryStr);
|
|
2284
|
+
if (!parsed) return null;
|
|
2285
|
+
const localPath = path.isAbsolute(configFilePath) ? configFilePath : path.resolve(process.cwd(), configFilePath);
|
|
2286
|
+
const configDir = path.dirname(localPath);
|
|
2287
|
+
const packageJsonPath = findNearestPackageJson(configDir);
|
|
2288
|
+
const configRequire = packageJsonPath ? module$1.createRequire(packageJsonPath) : null;
|
|
2289
|
+
const npmCwd = packageJsonPath ? path.dirname(packageJsonPath) : configDir;
|
|
2290
|
+
if (configRequire) {
|
|
2291
|
+
try {
|
|
2292
|
+
const installed = getInstalledPackageVersionFromRequire(parsed.packageName, configRequire);
|
|
2293
|
+
const requested = parsed.version === "latest" || !parsed.version?.trim() ? null : parsed.version;
|
|
2294
|
+
const resolvedVersion = requested ?? installed ?? resolveLatestVersionFromRegistry(parsed.packageName, { cwd: npmCwd });
|
|
2295
|
+
if (installed === resolvedVersion) {
|
|
2296
|
+
const pkgJsonResolved = configRequire.resolve(`${parsed.packageName}/package.json`);
|
|
2297
|
+
const packageRoot = path.dirname(pkgJsonResolved);
|
|
2298
|
+
const entryPath = getPackageEntryPath(packageRoot);
|
|
2299
|
+
const mod = await import(url.pathToFileURL(entryPath).href);
|
|
2300
|
+
const fn = getRegisterFn(mod);
|
|
2301
|
+
if (typeof fn === "function") {
|
|
2302
|
+
if (stepLog) stepLog(`Loaded ${parsed.packageName}@${resolvedVersion} from node_modules (async import)`);
|
|
2303
|
+
return { register: fn, descriptor: entryStr, resolvedVersion, packageRoot };
|
|
2304
|
+
}
|
|
2305
|
+
}
|
|
2306
|
+
} catch {
|
|
2307
|
+
}
|
|
2308
|
+
}
|
|
2309
|
+
const cacheBase = getCacheBaseFromToolConfig(localPath);
|
|
2310
|
+
const cacheOptions = cacheBase ? [{ cacheBase, cwd: npmCwd }, { cwd: npmCwd }] : [{ cwd: npmCwd }];
|
|
2311
|
+
for (const opts of cacheOptions) {
|
|
2312
|
+
try {
|
|
2313
|
+
const cacheDir = ensurePackageInCache(parsed.packageName, parsed.version, opts);
|
|
2314
|
+
if (stepLog) stepLog(`Loaded ${parsed.packageName} from cache (async): ${cacheDir}`);
|
|
2315
|
+
const mod = await importFromCache(cacheDir);
|
|
2316
|
+
const fn = getRegisterFn(mod);
|
|
2317
|
+
if (typeof fn === "function") {
|
|
2318
|
+
const resolvedVersion = path.basename(cacheDir);
|
|
2319
|
+
return { register: fn, descriptor: entryStr, resolvedVersion, packageRoot: cacheDir };
|
|
2320
|
+
}
|
|
2321
|
+
break;
|
|
2322
|
+
} catch {
|
|
2323
|
+
if (cacheBase && "cacheBase" in opts) continue;
|
|
2324
|
+
break;
|
|
2325
|
+
}
|
|
2326
|
+
}
|
|
2327
|
+
return null;
|
|
2328
|
+
}
|
|
2329
|
+
async function loadLocalDirectoryForFileDescriptor(descriptor, configFilePath, stepLog) {
|
|
2330
|
+
const resolvedPath = resolveFileDescriptorPath(descriptor, configFilePath);
|
|
2331
|
+
if (!resolvedPath || !fs.existsSync(resolvedPath) || !fs.statSync(resolvedPath).isDirectory()) return null;
|
|
2332
|
+
if (fs.existsSync(path.join(resolvedPath, "package.json"))) return null;
|
|
2333
|
+
const scanErrors = [];
|
|
2334
|
+
const scanner = new chunkAZUXVVGV_cjs.DirectoryScanner({
|
|
2335
|
+
roots: [{ path: resolvedPath, namespace: "local" }],
|
|
2336
|
+
onError: (toolDir, error) => scanErrors.push(`${toolDir}: ${error.message}`)
|
|
2337
|
+
});
|
|
2338
|
+
const specs = await scanner.scan();
|
|
2339
|
+
if (scanErrors.length > 0 && stepLog) {
|
|
2340
|
+
stepLog(`Local directory scan (${descriptor}) reported ${scanErrors.length} error(s)`);
|
|
2341
|
+
}
|
|
2342
|
+
if (specs.length === 0) return null;
|
|
2343
|
+
if (stepLog) {
|
|
2344
|
+
stepLog(`Loaded ${specs.length} local tool(s) from ${descriptor}`);
|
|
2345
|
+
}
|
|
2346
|
+
return {
|
|
2347
|
+
specs,
|
|
2348
|
+
descriptor: descriptor.trim(),
|
|
2349
|
+
resolvedVersion: "local"
|
|
2350
|
+
};
|
|
2351
|
+
}
|
|
2352
|
+
async function loadAllExtensionsFromToolYamlAsync(configFilePath, stepLog) {
|
|
2353
|
+
const localPath = path.isAbsolute(configFilePath) ? configFilePath : path.resolve(process.cwd(), configFilePath);
|
|
2354
|
+
if (!fs.existsSync(localPath)) return [];
|
|
2355
|
+
const config = loadToolConfig(localPath);
|
|
2356
|
+
const tools = getPathSourceDescriptors(config);
|
|
2357
|
+
if (!Array.isArray(tools) || tools.length === 0) return [];
|
|
2358
|
+
if (stepLog) stepLog("Loading extensions from tool.yaml (async)");
|
|
2359
|
+
const loaded = [];
|
|
2360
|
+
for (const entry of tools) {
|
|
2361
|
+
const entryStr = String(entry).trim();
|
|
2362
|
+
if (entryStr.startsWith("npm:")) {
|
|
2363
|
+
const result = await loadExtensionForDescriptorAsync(entryStr, configFilePath, stepLog);
|
|
2364
|
+
if (result) loaded.push(result);
|
|
2365
|
+
} else if (entryStr.startsWith("file:")) {
|
|
2366
|
+
const result = await loadExtensionFromFileDescriptorAsync(entryStr, configFilePath, stepLog);
|
|
2367
|
+
if (result) {
|
|
2368
|
+
loaded.push(result);
|
|
2369
|
+
} else {
|
|
2370
|
+
const local = await loadLocalDirectoryForFileDescriptor(entryStr, configFilePath, stepLog);
|
|
2371
|
+
if (local) loaded.push(local);
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
return loaded;
|
|
2376
|
+
}
|
|
2377
|
+
function createRuntimeFromConfigSync(options = {}) {
|
|
2378
|
+
const registry = new chunkAGLGFQUW_cjs.ToolRegistry();
|
|
2379
|
+
const stepLog = options.stepLog;
|
|
2380
|
+
const effectiveCoreTools = resolveEffectiveCoreTools(options);
|
|
2381
|
+
chunkAGLGFQUW_cjs.setSandboxValidationEnabled(effectiveCoreTools?.enableSandboxValidation === true);
|
|
2382
|
+
if (effectiveCoreTools !== void 0) {
|
|
2383
|
+
if (options.configFilePath) {
|
|
2384
|
+
const all = loadAllExtensionsFromToolYamlSync(options.configFilePath, stepLog);
|
|
2385
|
+
if (all.length > 0) {
|
|
2386
|
+
if (stepLog) stepLog(`Registered ${all.length} extension(s) from tool.yaml`);
|
|
2387
|
+
const runtime3 = new PTCRuntime({ registry });
|
|
2388
|
+
for (const ext of all) {
|
|
2389
|
+
const before = new Set(registry.snapshot().map((s) => s.name));
|
|
2390
|
+
const prefix = ext.descriptor.startsWith("file:") ? fileDescriptorToRegistryPrefix(ext.descriptor) : npmDescriptorToRegistryPrefix(ext.descriptor, ext.resolvedVersion);
|
|
2391
|
+
const reg = createPrefixingRegistry(registry, prefix ?? "");
|
|
2392
|
+
const adapter = ext.register(reg, effectiveCoreTools);
|
|
2393
|
+
runtime3.registerAdapter(adapter);
|
|
2394
|
+
const registeredNow = registry.snapshot().map((s) => s.name).filter((name) => !before.has(name));
|
|
2395
|
+
runtime3.registerAdapterForTools(registeredNow, adapter);
|
|
2396
|
+
}
|
|
2397
|
+
return { runtime: runtime3, registry };
|
|
2398
|
+
}
|
|
2399
|
+
}
|
|
2400
|
+
if (stepLog) stepLog("Trying extension from node_modules");
|
|
2401
|
+
const extensionNode = loadExtensionFromNodeModules();
|
|
2402
|
+
if (extensionNode) {
|
|
2403
|
+
if (stepLog) stepLog("Registered extension from node_modules");
|
|
2404
|
+
const descriptor = `npm:${extensionNode.packageName}`;
|
|
2405
|
+
const resolvedVersion = getInstalledPackageVersion(extensionNode.packageName) ?? resolveLatestVersionFromRegistry(extensionNode.packageName);
|
|
2406
|
+
const before = new Set(registry.snapshot().map((s) => s.name));
|
|
2407
|
+
const prefix = npmDescriptorToRegistryPrefix(descriptor, resolvedVersion);
|
|
2408
|
+
const reg = createPrefixingRegistry(registry, prefix ?? "");
|
|
2409
|
+
const coreAdapter = extensionNode.register(reg, effectiveCoreTools);
|
|
2410
|
+
const runtime3 = new PTCRuntime({ registry });
|
|
2411
|
+
runtime3.registerAdapter(coreAdapter);
|
|
2412
|
+
const registeredNow = registry.snapshot().map((s) => s.name).filter((name) => !before.has(name));
|
|
2413
|
+
runtime3.registerAdapterForTools(registeredNow, coreAdapter);
|
|
2414
|
+
return { runtime: runtime3, registry };
|
|
2415
|
+
}
|
|
2416
|
+
const runtime2 = new PTCRuntime({ registry });
|
|
2417
|
+
return { runtime: runtime2, registry };
|
|
2418
|
+
}
|
|
2419
|
+
const runtime = new PTCRuntime({ registry });
|
|
2420
|
+
return { runtime, registry };
|
|
2421
|
+
}
|
|
2422
|
+
async function createRuntimeFromConfig(options = {}) {
|
|
2423
|
+
const effectiveCoreTools = resolveEffectiveCoreTools(options);
|
|
2424
|
+
chunkAGLGFQUW_cjs.setSandboxValidationEnabled(effectiveCoreTools?.enableSandboxValidation === true);
|
|
2425
|
+
if (effectiveCoreTools !== void 0 && options.configFilePath) {
|
|
2426
|
+
const all = await loadAllExtensionsFromToolYamlAsync(options.configFilePath, options.stepLog);
|
|
2427
|
+
if (all.length > 0) {
|
|
2428
|
+
if (options.stepLog) options.stepLog(`Registered ${all.length} extension(s) from tool.yaml`);
|
|
2429
|
+
const registry = new chunkAGLGFQUW_cjs.ToolRegistry();
|
|
2430
|
+
const runtime = new PTCRuntime({ registry });
|
|
2431
|
+
for (const ext of all) {
|
|
2432
|
+
const before = new Set(registry.snapshot().map((s) => s.name));
|
|
2433
|
+
const prefix = ext.descriptor.startsWith("file:") ? fileDescriptorToRegistryPrefix(ext.descriptor) : npmDescriptorToRegistryPrefix(ext.descriptor, ext.resolvedVersion);
|
|
2434
|
+
const reg = createPrefixingRegistry(registry, prefix ?? "");
|
|
2435
|
+
if ("register" in ext) {
|
|
2436
|
+
const adapter = ext.register(reg, effectiveCoreTools);
|
|
2437
|
+
runtime.registerAdapter(adapter);
|
|
2438
|
+
const registeredNow = registry.snapshot().map((s) => s.name).filter((name) => !before.has(name));
|
|
2439
|
+
runtime.registerAdapterForTools(registeredNow, adapter);
|
|
2440
|
+
} else {
|
|
2441
|
+
reg.bulkRegister(ext.specs);
|
|
2442
|
+
const registeredNow = registry.snapshot().map((s) => s.name).filter((name) => !before.has(name));
|
|
2443
|
+
const byKind = /* @__PURE__ */ new Map();
|
|
2444
|
+
for (const toolName of registeredNow) {
|
|
2445
|
+
const spec = registry.get(toolName);
|
|
2446
|
+
if (!spec) continue;
|
|
2447
|
+
const list = byKind.get(spec.kind) ?? [];
|
|
2448
|
+
list.push(toolName);
|
|
2449
|
+
byKind.set(spec.kind, list);
|
|
2450
|
+
}
|
|
2451
|
+
for (const [kind, names] of byKind.entries()) {
|
|
2452
|
+
const adapter = createLocalDirectoryAdapter(kind);
|
|
2453
|
+
runtime.registerAdapter(adapter);
|
|
2454
|
+
runtime.registerAdapterForTools(names, adapter);
|
|
2455
|
+
}
|
|
2456
|
+
}
|
|
2457
|
+
}
|
|
2458
|
+
return { runtime, registry };
|
|
2459
|
+
}
|
|
2460
|
+
}
|
|
2461
|
+
return createRuntimeFromConfigSync(options);
|
|
2462
|
+
}
|
|
2463
|
+
|
|
2464
|
+
// src/core/runtime/toolObservation.ts
|
|
2465
|
+
var PTC_FEEDBACK_MARKER = "__PTC_FEEDBACK__:";
|
|
2466
|
+
function tryStringify(value) {
|
|
2467
|
+
if (typeof value === "string") return value;
|
|
2468
|
+
try {
|
|
2469
|
+
return JSON.stringify(value);
|
|
2470
|
+
} catch {
|
|
2471
|
+
return String(value);
|
|
2472
|
+
}
|
|
2473
|
+
}
|
|
2474
|
+
function extractObservationText(value) {
|
|
2475
|
+
if (!value || typeof value !== "object") return null;
|
|
2476
|
+
const record = value;
|
|
2477
|
+
const nested = record.result;
|
|
2478
|
+
if (nested && typeof nested === "object" && typeof nested.output === "string") {
|
|
2479
|
+
return nested.output;
|
|
2480
|
+
}
|
|
2481
|
+
if (typeof record.output === "string") return record.output;
|
|
2482
|
+
return null;
|
|
2483
|
+
}
|
|
2484
|
+
function encodeFeedback(feedback, includeFeedbackMarker) {
|
|
2485
|
+
if (!includeFeedbackMarker || !feedback) return "";
|
|
2486
|
+
return `${PTC_FEEDBACK_MARKER}${tryStringify(feedback)}
|
|
2487
|
+
`;
|
|
2488
|
+
}
|
|
2489
|
+
function toToolObservationText(result, opts = {}) {
|
|
2490
|
+
const includeFeedbackMarker = opts.includeFeedbackMarker === true;
|
|
2491
|
+
if (result.ok) {
|
|
2492
|
+
const prefix = encodeFeedback(result.feedback, includeFeedbackMarker);
|
|
2493
|
+
if (typeof result.result === "string") return `${prefix}${result.result}`;
|
|
2494
|
+
const observation = extractObservationText(result.result);
|
|
2495
|
+
if (observation != null) return `${prefix}${observation}`;
|
|
2496
|
+
return `${prefix}${tryStringify(result.result)}`;
|
|
2497
|
+
}
|
|
2498
|
+
const err = result.error;
|
|
2499
|
+
const message = err?.message ?? "Tool failed";
|
|
2500
|
+
const details = err?.details;
|
|
2501
|
+
return tryStringify(details != null ? { error: message, kind: err?.kind, details } : { error: message, kind: err?.kind });
|
|
2502
|
+
}
|
|
2503
|
+
|
|
2504
|
+
// src/api/expose/mcpServer.ts
|
|
2505
|
+
var DEFAULT_CTX = {
|
|
2506
|
+
requestId: `mcp-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
|
|
2507
|
+
taskId: `task-${Date.now()}`,
|
|
2508
|
+
permissions: [
|
|
2509
|
+
"read:web",
|
|
2510
|
+
"read:fs",
|
|
2511
|
+
"write:fs",
|
|
2512
|
+
"read:db",
|
|
2513
|
+
"write:db",
|
|
2514
|
+
"network",
|
|
2515
|
+
"workflow",
|
|
2516
|
+
"danger:destructive"
|
|
2517
|
+
]
|
|
2518
|
+
};
|
|
2519
|
+
function toMcpToolName(registryName) {
|
|
2520
|
+
return chunkJW4EMVTE_cjs.normalizeToolName(registryName);
|
|
2521
|
+
}
|
|
2522
|
+
async function createMcpServerWithTools(runtime, options) {
|
|
2523
|
+
const { McpServer } = await import('@modelcontextprotocol/sdk/server/mcp.js');
|
|
2524
|
+
const name = options.name ?? "agent-tool";
|
|
2525
|
+
const version = options.version ?? "1.0.0";
|
|
2526
|
+
const ctxFactory = options.execContextFactory ?? (() => ({ ...DEFAULT_CTX }));
|
|
2527
|
+
const server = new McpServer({ name, version });
|
|
2528
|
+
const registry = runtime.getRegistry();
|
|
2529
|
+
const specs = registry.snapshot();
|
|
2530
|
+
for (const spec of specs) {
|
|
2531
|
+
const mcpName = toMcpToolName(spec.name);
|
|
2532
|
+
server.registerTool(
|
|
2533
|
+
mcpName,
|
|
2534
|
+
{
|
|
2535
|
+
description: spec.description ?? `Tool: ${spec.name}`,
|
|
2536
|
+
inputSchema: spec.inputSchema,
|
|
2537
|
+
_meta: spec._meta
|
|
2538
|
+
},
|
|
2539
|
+
async (args) => {
|
|
2540
|
+
const ctx = ctxFactory();
|
|
2541
|
+
const result = await runtime.invoke(
|
|
2542
|
+
{ tool: spec.name, args: args ?? {}, purpose: chunkAZUXVVGV_cjs.MCP_KIND },
|
|
2543
|
+
ctx
|
|
2544
|
+
);
|
|
2545
|
+
if (result.ok) {
|
|
2546
|
+
return { content: [{ type: "text", text: toToolObservationText(result) }] };
|
|
2547
|
+
}
|
|
2548
|
+
return {
|
|
2549
|
+
content: [
|
|
2550
|
+
{
|
|
2551
|
+
type: "text",
|
|
2552
|
+
text: toToolObservationText(result)
|
|
2553
|
+
}
|
|
2554
|
+
],
|
|
2555
|
+
isError: true
|
|
2556
|
+
};
|
|
2557
|
+
}
|
|
2558
|
+
);
|
|
2559
|
+
}
|
|
2560
|
+
return { server };
|
|
2561
|
+
}
|
|
2562
|
+
async function createMCPServer(runtimeOrConfig, options = {}) {
|
|
2563
|
+
const runtime = "invoke" in runtimeOrConfig && typeof runtimeOrConfig.invoke === "function" ? runtimeOrConfig : (await createRuntimeFromConfig(runtimeOrConfig)).runtime;
|
|
2564
|
+
const { StdioServerTransport } = await import('@modelcontextprotocol/sdk/server/stdio.js');
|
|
2565
|
+
const { server } = await createMcpServerWithTools(runtime, options);
|
|
2566
|
+
return {
|
|
2567
|
+
server,
|
|
2568
|
+
async connectStdio() {
|
|
2569
|
+
const transport = new StdioServerTransport();
|
|
2570
|
+
await server.connect(transport);
|
|
2571
|
+
}
|
|
2572
|
+
};
|
|
2573
|
+
}
|
|
2574
|
+
function createMCPStreamableHttpHandler(runtimeOrConfig, options = {}) {
|
|
2575
|
+
if ("invoke" in runtimeOrConfig && typeof runtimeOrConfig.invoke === "function") {
|
|
2576
|
+
const runtime = runtimeOrConfig;
|
|
2577
|
+
return async function streamableHttpHandler(req, res, parsedBody) {
|
|
2578
|
+
const { StreamableHTTPServerTransport } = await import('@modelcontextprotocol/sdk/server/streamableHttp.js');
|
|
2579
|
+
const { server } = await createMcpServerWithTools(runtime, options);
|
|
2580
|
+
const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: void 0 });
|
|
2581
|
+
await server.connect(transport);
|
|
2582
|
+
const onClose = () => {
|
|
2583
|
+
transport.close().catch(() => {
|
|
2584
|
+
});
|
|
2585
|
+
server.close().catch(() => {
|
|
2586
|
+
});
|
|
2587
|
+
res.removeListener("close", onClose);
|
|
2588
|
+
res.removeListener("finish", onClose);
|
|
2589
|
+
};
|
|
2590
|
+
res.once("close", onClose);
|
|
2591
|
+
res.once("finish", onClose);
|
|
2592
|
+
await transport.handleRequest(
|
|
2593
|
+
req,
|
|
2594
|
+
res,
|
|
2595
|
+
parsedBody
|
|
2596
|
+
);
|
|
2597
|
+
};
|
|
2598
|
+
}
|
|
2599
|
+
return (async () => {
|
|
2600
|
+
const { runtime } = await createRuntimeFromConfig(runtimeOrConfig);
|
|
2601
|
+
return createMCPStreamableHttpHandler(runtime, options);
|
|
2602
|
+
})();
|
|
2603
|
+
}
|
|
2604
|
+
async function createMCPServerStreamableHttp(runtimeOrConfig, options = {}) {
|
|
2605
|
+
const path2 = options.path ?? "/mcp";
|
|
2606
|
+
const host = options.host ?? "127.0.0.1";
|
|
2607
|
+
const port = options.port ?? 3e3;
|
|
2608
|
+
const { createMcpExpressApp } = await import('@modelcontextprotocol/sdk/server/express.js');
|
|
2609
|
+
const handler = "invoke" in runtimeOrConfig && typeof runtimeOrConfig.invoke === "function" ? createMCPStreamableHttpHandler(runtimeOrConfig, options) : await createMCPStreamableHttpHandler(runtimeOrConfig, options);
|
|
2610
|
+
const app = createMcpExpressApp({ host });
|
|
2611
|
+
app.post(path2, handler);
|
|
2612
|
+
return {
|
|
2613
|
+
app,
|
|
2614
|
+
path: path2,
|
|
2615
|
+
async listen(listenPort, listenHost) {
|
|
2616
|
+
const p = listenPort ?? port;
|
|
2617
|
+
const h = listenHost ?? host;
|
|
2618
|
+
return new Promise((resolve4) => {
|
|
2619
|
+
const server = app.listen(p, h, () => {
|
|
2620
|
+
const addr = server.address();
|
|
2621
|
+
const actualPort = typeof addr === "object" && addr !== null && "port" in addr ? addr.port : p;
|
|
2622
|
+
resolve4({ url: `http://${h}:${actualPort}${path2}`, port: actualPort });
|
|
2623
|
+
});
|
|
2624
|
+
});
|
|
2625
|
+
}
|
|
2626
|
+
};
|
|
2627
|
+
}
|
|
2628
|
+
async function runMCPServerOverStdio(runtime, options = {}) {
|
|
2629
|
+
const result = await createMCPServer(runtime, options);
|
|
2630
|
+
await result.connectStdio();
|
|
2631
|
+
return result;
|
|
2632
|
+
}
|
|
2633
|
+
|
|
2634
|
+
// src/api/expose/openapi.ts
|
|
2635
|
+
function toolNameToSlug(name) {
|
|
2636
|
+
return name.replace(/\./g, "~");
|
|
2637
|
+
}
|
|
2638
|
+
function slugToToolName(slug) {
|
|
2639
|
+
return slug.replace(/~/g, ".");
|
|
2640
|
+
}
|
|
2641
|
+
function toolSchemaKey(name) {
|
|
2642
|
+
return `Tool_${name.replace(/[^a-zA-Z0-9_]/g, "_")}`;
|
|
2643
|
+
}
|
|
2644
|
+
var resultSchema = {
|
|
2645
|
+
type: "object",
|
|
2646
|
+
properties: {
|
|
2647
|
+
result: { description: "Tool return value", additionalProperties: true }
|
|
2648
|
+
}
|
|
2649
|
+
};
|
|
2650
|
+
var errorSchema = {
|
|
2651
|
+
type: "object",
|
|
2652
|
+
properties: {
|
|
2653
|
+
error: { type: "string" },
|
|
2654
|
+
kind: { type: "string" },
|
|
2655
|
+
details: { type: "object", additionalProperties: true }
|
|
2656
|
+
}
|
|
2657
|
+
};
|
|
2658
|
+
function toolsToOpenAPISpec(registry, options = {}) {
|
|
2659
|
+
const title = options.title ?? "Tool API";
|
|
2660
|
+
const version = options.version ?? "1.0.0";
|
|
2661
|
+
const basePath = (options.basePath ?? "").replace(/\/$/, "");
|
|
2662
|
+
const specs = registry.snapshot().map(chunkUUNG3GL3_cjs.enrichSpecWithCanonicalSchema);
|
|
2663
|
+
const prefix = basePath ? `${basePath}/` : "/";
|
|
2664
|
+
const paths = createBasePaths(prefix);
|
|
2665
|
+
const schemaEntries = addPerToolPaths(specs, prefix, paths);
|
|
2666
|
+
return {
|
|
2667
|
+
openapi: "3.0.3",
|
|
2668
|
+
info: { title, version },
|
|
2669
|
+
paths,
|
|
2670
|
+
components: {
|
|
2671
|
+
schemas: Object.fromEntries(schemaEntries)
|
|
2672
|
+
}
|
|
2673
|
+
};
|
|
2674
|
+
}
|
|
2675
|
+
function createToolNamesSchema() {
|
|
2676
|
+
return {
|
|
2677
|
+
type: "object",
|
|
2678
|
+
required: ["tools"],
|
|
2679
|
+
properties: {
|
|
2680
|
+
tools: {
|
|
2681
|
+
type: "array",
|
|
2682
|
+
items: {
|
|
2683
|
+
type: "object",
|
|
2684
|
+
properties: {
|
|
2685
|
+
name: { type: "string" },
|
|
2686
|
+
description: { type: "string" },
|
|
2687
|
+
kind: { type: "string" }
|
|
2688
|
+
}
|
|
2689
|
+
}
|
|
2690
|
+
}
|
|
2691
|
+
}
|
|
2692
|
+
};
|
|
2693
|
+
}
|
|
2694
|
+
function createInvokeRequestBodySchema() {
|
|
2695
|
+
return {
|
|
2696
|
+
type: "object",
|
|
2697
|
+
required: ["tool", "args"],
|
|
2698
|
+
properties: {
|
|
2699
|
+
tool: { type: "string", description: "Tool name (e.g. from GET /tools)" },
|
|
2700
|
+
args: {
|
|
2701
|
+
type: "object",
|
|
2702
|
+
description: "Tool arguments (schema per tool; use per-tool paths for typed schema)",
|
|
2703
|
+
additionalProperties: true
|
|
2704
|
+
}
|
|
2705
|
+
}
|
|
2706
|
+
};
|
|
2707
|
+
}
|
|
2708
|
+
function createBasePaths(prefix) {
|
|
2709
|
+
return {
|
|
2710
|
+
[`${prefix}tools`]: {
|
|
2711
|
+
get: {
|
|
2712
|
+
summary: "List tools",
|
|
2713
|
+
description: "Returns all registered tool names and descriptions.",
|
|
2714
|
+
operationId: "listTools",
|
|
2715
|
+
responses: {
|
|
2716
|
+
"200": {
|
|
2717
|
+
description: "List of tools",
|
|
2718
|
+
content: { "application/json": { schema: createToolNamesSchema() } }
|
|
2719
|
+
}
|
|
2720
|
+
}
|
|
2721
|
+
}
|
|
2722
|
+
},
|
|
2723
|
+
[`${prefix}invoke`]: {
|
|
2724
|
+
post: {
|
|
2725
|
+
summary: "Invoke a tool (generic)",
|
|
2726
|
+
description: "Call any tool by name with body { tool, args }. For typed schemas use POST /invoke/{toolSlug}.",
|
|
2727
|
+
operationId: "invokeTool",
|
|
2728
|
+
requestBody: {
|
|
2729
|
+
required: true,
|
|
2730
|
+
content: { "application/json": { schema: createInvokeRequestBodySchema() } }
|
|
2731
|
+
},
|
|
2732
|
+
responses: {
|
|
2733
|
+
"200": { description: "Tool result", content: { "application/json": { schema: resultSchema } } },
|
|
2734
|
+
"400": { description: "Bad request", content: { "application/json": { schema: errorSchema } } }
|
|
2735
|
+
}
|
|
2736
|
+
}
|
|
2737
|
+
}
|
|
2738
|
+
};
|
|
2739
|
+
}
|
|
2740
|
+
function addPerToolPaths(specs, prefix, paths) {
|
|
2741
|
+
const schemaEntries = [];
|
|
2742
|
+
for (const spec of specs) {
|
|
2743
|
+
const key = toolSchemaKey(spec.name);
|
|
2744
|
+
schemaEntries.push([key, spec.inputSchema]);
|
|
2745
|
+
paths[`${prefix}invoke/${toolNameToSlug(spec.name)}`] = createPerToolPathSpec(spec, key);
|
|
2746
|
+
}
|
|
2747
|
+
return schemaEntries;
|
|
2748
|
+
}
|
|
2749
|
+
function createPerToolPathSpec(spec, key) {
|
|
2750
|
+
return {
|
|
2751
|
+
post: {
|
|
2752
|
+
summary: spec.description ?? spec.name,
|
|
2753
|
+
description: `Invoke tool \`${spec.name}\`. Request body is the tool's arguments (JSON Schema below).`,
|
|
2754
|
+
operationId: `invoke_${key}`,
|
|
2755
|
+
requestBody: {
|
|
2756
|
+
required: true,
|
|
2757
|
+
content: { "application/json": { schema: { $ref: `#/components/schemas/${key}` } } }
|
|
2758
|
+
},
|
|
2759
|
+
responses: {
|
|
2760
|
+
"200": { description: "Tool result", content: { "application/json": { schema: resultSchema } } },
|
|
2761
|
+
"400": {
|
|
2762
|
+
description: "Bad request (invalid args or tool error)",
|
|
2763
|
+
content: { "application/json": { schema: errorSchema } }
|
|
2764
|
+
}
|
|
2765
|
+
}
|
|
2766
|
+
}
|
|
2767
|
+
};
|
|
2768
|
+
}
|
|
2769
|
+
|
|
2770
|
+
// src/api/expose/openapiHttp.ts
|
|
2771
|
+
var DEFAULT_CTX2 = {
|
|
2772
|
+
requestId: `http-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
|
|
2773
|
+
taskId: `task-${Date.now()}`,
|
|
2774
|
+
permissions: [
|
|
2775
|
+
"read:web",
|
|
2776
|
+
"read:fs",
|
|
2777
|
+
"write:fs",
|
|
2778
|
+
"read:db",
|
|
2779
|
+
"write:db",
|
|
2780
|
+
"network",
|
|
2781
|
+
"workflow",
|
|
2782
|
+
"danger:destructive"
|
|
2783
|
+
]
|
|
2784
|
+
};
|
|
2785
|
+
var BodyParseError = class extends Error {
|
|
2786
|
+
hint;
|
|
2787
|
+
constructor(message, hint) {
|
|
2788
|
+
super(message);
|
|
2789
|
+
this.name = "BodyParseError";
|
|
2790
|
+
this.hint = hint;
|
|
2791
|
+
}
|
|
2792
|
+
};
|
|
2793
|
+
function safeParseToolArgs(raw) {
|
|
2794
|
+
const text = String(raw ?? "").trim();
|
|
2795
|
+
if (!text) return { ok: true, value: {} };
|
|
2796
|
+
const firstBrace = text.indexOf("{");
|
|
2797
|
+
if (firstBrace === -1) {
|
|
2798
|
+
return {
|
|
2799
|
+
ok: false,
|
|
2800
|
+
hint: 'Tool arguments must be a single JSON object. Do not prepend explanations. Example: itermRunCommandInSession({"command":"df -h"})'
|
|
2801
|
+
};
|
|
2802
|
+
}
|
|
2803
|
+
let jsonText = text.slice(firstBrace);
|
|
2804
|
+
const lastBrace = jsonText.lastIndexOf("}");
|
|
2805
|
+
if (lastBrace !== -1) jsonText = jsonText.slice(0, lastBrace + 1);
|
|
2806
|
+
try {
|
|
2807
|
+
return { ok: true, value: JSON.parse(jsonText) };
|
|
2808
|
+
} catch {
|
|
2809
|
+
return {
|
|
2810
|
+
ok: false,
|
|
2811
|
+
hint: "Tool arguments must be valid JSON: double-quoted keys/strings, no comments or trailing commas."
|
|
2812
|
+
};
|
|
2813
|
+
}
|
|
2814
|
+
}
|
|
2815
|
+
function sendJson(res, status, data) {
|
|
2816
|
+
res.status(status).json(data);
|
|
2817
|
+
}
|
|
2818
|
+
function swaggerUiHtml(specUrl) {
|
|
2819
|
+
const specUrlEscaped = specUrl.replace(/"/g, """);
|
|
2820
|
+
return `<!DOCTYPE html>
|
|
2821
|
+
<html lang="en">
|
|
2822
|
+
<head>
|
|
2823
|
+
<meta charset="UTF-8">
|
|
2824
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
2825
|
+
<title>Tool API \u2013 Swagger UI</title>
|
|
2826
|
+
<link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@5/swagger-ui.css">
|
|
2827
|
+
</head>
|
|
2828
|
+
<body>
|
|
2829
|
+
<div id="swagger-ui"></div>
|
|
2830
|
+
<script src="https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js" crossorigin></script>
|
|
2831
|
+
<script src="https://unpkg.com/swagger-ui-dist@5/swagger-ui-standalone-preset.js" crossorigin></script>
|
|
2832
|
+
<script>
|
|
2833
|
+
window.onload = function() {
|
|
2834
|
+
window.ui = SwaggerUIBundle({
|
|
2835
|
+
url: "${specUrlEscaped}",
|
|
2836
|
+
dom_id: "#swagger-ui",
|
|
2837
|
+
deepLinking: true,
|
|
2838
|
+
presets: [
|
|
2839
|
+
SwaggerUIBundle.presets.apis,
|
|
2840
|
+
SwaggerUIStandalonePreset
|
|
2841
|
+
],
|
|
2842
|
+
layout: "StandaloneLayout"
|
|
2843
|
+
});
|
|
2844
|
+
};
|
|
2845
|
+
</script>
|
|
2846
|
+
</body>
|
|
2847
|
+
</html>`;
|
|
2848
|
+
}
|
|
2849
|
+
function parseBodyFromExpress(raw) {
|
|
2850
|
+
if (raw == null) return {};
|
|
2851
|
+
if (typeof raw === "object") return raw;
|
|
2852
|
+
const text = Buffer.isBuffer(raw) ? raw.toString("utf-8") : String(raw);
|
|
2853
|
+
const parsed = safeParseToolArgs(text);
|
|
2854
|
+
if (parsed.ok) return parsed.value;
|
|
2855
|
+
throw new BodyParseError("Invalid JSON body", parsed.hint);
|
|
2856
|
+
}
|
|
2857
|
+
function sendBadJsonBody(res, err) {
|
|
2858
|
+
const hint = err instanceof BodyParseError ? err.hint : void 0;
|
|
2859
|
+
sendJson(res, 400, {
|
|
2860
|
+
ok: false,
|
|
2861
|
+
error: "Invalid JSON body",
|
|
2862
|
+
kind: "BAD_REQUEST",
|
|
2863
|
+
...hint ? { hint } : {}
|
|
2864
|
+
});
|
|
2865
|
+
}
|
|
2866
|
+
async function invokeAndSend(runtime, ctx, res, tool, args) {
|
|
2867
|
+
const result = await runtime.invoke({ tool, args, purpose: "openapi" }, ctx);
|
|
2868
|
+
if (result.ok) {
|
|
2869
|
+
sendJson(res, 200, { result: result.result });
|
|
2870
|
+
return;
|
|
2871
|
+
}
|
|
2872
|
+
sendJson(res, 400, {
|
|
2873
|
+
error: result.error?.message ?? "Tool failed",
|
|
2874
|
+
kind: result.error?.kind,
|
|
2875
|
+
details: result.error?.details
|
|
2876
|
+
});
|
|
2877
|
+
}
|
|
2878
|
+
function buildSpec(runtime, basePath) {
|
|
2879
|
+
return toolsToOpenAPISpec(runtime.getRegistry(), {
|
|
2880
|
+
title: "Tool API",
|
|
2881
|
+
version: "1.0.0",
|
|
2882
|
+
basePath: basePath || void 0
|
|
2883
|
+
});
|
|
2884
|
+
}
|
|
2885
|
+
function registerSpecRoutes(router, runtime, basePath) {
|
|
2886
|
+
const sendSpec = (_req, res) => {
|
|
2887
|
+
sendJson(res, 200, buildSpec(runtime, basePath));
|
|
2888
|
+
};
|
|
2889
|
+
const sendSwagger = (_req, res) => {
|
|
2890
|
+
const specPath = basePath ? `${basePath}/openapi.json` : "/openapi.json";
|
|
2891
|
+
res.type("text/html; charset=utf-8").send(swaggerUiHtml(specPath));
|
|
2892
|
+
};
|
|
2893
|
+
router.get("/", sendSwagger);
|
|
2894
|
+
router.get("/swagger", sendSwagger);
|
|
2895
|
+
router.get("/openapi.json", sendSpec);
|
|
2896
|
+
router.get("/spec", sendSpec);
|
|
2897
|
+
}
|
|
2898
|
+
function registerToolRoutes(router, runtime, ctxFactory) {
|
|
2899
|
+
router.get("/tools", async (_req, res, next) => {
|
|
2900
|
+
try {
|
|
2901
|
+
const { enrichSpecWithCanonicalSchema: enrichSpecWithCanonicalSchema2 } = await import('./canonicalCoreSchemas-TY7NCWCC.cjs');
|
|
2902
|
+
const tools = runtime.getRegistry().snapshot().map(enrichSpecWithCanonicalSchema2).map((s) => ({
|
|
2903
|
+
name: s.name,
|
|
2904
|
+
description: s.description,
|
|
2905
|
+
kind: s.kind,
|
|
2906
|
+
inputSchema: s.inputSchema
|
|
2907
|
+
}));
|
|
2908
|
+
sendJson(res, 200, { tools });
|
|
2909
|
+
} catch (error) {
|
|
2910
|
+
next(error);
|
|
2911
|
+
}
|
|
2912
|
+
});
|
|
2913
|
+
router.post("/invoke", async (req, res) => {
|
|
2914
|
+
let body = null;
|
|
2915
|
+
try {
|
|
2916
|
+
body = parseBodyFromExpress(req.body);
|
|
2917
|
+
} catch (err) {
|
|
2918
|
+
sendBadJsonBody(res, err);
|
|
2919
|
+
return;
|
|
2920
|
+
}
|
|
2921
|
+
const tool = body.tool;
|
|
2922
|
+
if (typeof tool !== "string" || !tool.trim()) {
|
|
2923
|
+
sendJson(res, 400, { error: "Missing or invalid 'tool' in body", kind: "BAD_REQUEST" });
|
|
2924
|
+
return;
|
|
2925
|
+
}
|
|
2926
|
+
await invokeAndSend(runtime, ctxFactory(req), res, tool.trim(), body.args ?? {});
|
|
2927
|
+
});
|
|
2928
|
+
router.post("/invoke/:slug", async (req, res) => {
|
|
2929
|
+
let args;
|
|
2930
|
+
try {
|
|
2931
|
+
args = parseBodyFromExpress(req.body);
|
|
2932
|
+
} catch (err) {
|
|
2933
|
+
sendBadJsonBody(res, err);
|
|
2934
|
+
return;
|
|
2935
|
+
}
|
|
2936
|
+
await invokeAndSend(runtime, ctxFactory(req), res, slugToToolName(req.params?.slug ?? ""), args);
|
|
2937
|
+
});
|
|
2938
|
+
}
|
|
2939
|
+
function mountRouter(app, router, basePath) {
|
|
2940
|
+
if (basePath) {
|
|
2941
|
+
app.use(basePath, router);
|
|
2942
|
+
return;
|
|
2943
|
+
}
|
|
2944
|
+
app.use(router);
|
|
2945
|
+
}
|
|
2946
|
+
function registerErrorHandlers(app) {
|
|
2947
|
+
app.use((req, res) => {
|
|
2948
|
+
sendJson(res, 404, { error: "Not found", path: req.url ?? "/" });
|
|
2949
|
+
});
|
|
2950
|
+
app.use((err, _req, res, _next) => {
|
|
2951
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2952
|
+
sendJson(res, 500, { error: message, kind: "INTERNAL_ERROR" });
|
|
2953
|
+
});
|
|
2954
|
+
}
|
|
2955
|
+
function patchListenDefaults(app, options) {
|
|
2956
|
+
const originalListen = app.listen.bind(app);
|
|
2957
|
+
const defaultPort = options.port;
|
|
2958
|
+
const defaultHost = options.host;
|
|
2959
|
+
app.listen = ((...args) => {
|
|
2960
|
+
if (args.length === 0) {
|
|
2961
|
+
return originalListen(defaultPort ?? 0, defaultHost ?? "localhost");
|
|
2962
|
+
}
|
|
2963
|
+
if (args.length === 1 && typeof args[0] === "function") {
|
|
2964
|
+
return originalListen(defaultPort ?? 0, defaultHost ?? "localhost", args[0]);
|
|
2965
|
+
}
|
|
2966
|
+
return originalListen(...args);
|
|
2967
|
+
});
|
|
2968
|
+
}
|
|
2969
|
+
function createOpenAPIHttpServer(runtime, options = {}) {
|
|
2970
|
+
const app = express__default.default();
|
|
2971
|
+
const router = express__default.default.Router();
|
|
2972
|
+
const basePath = (options.basePath ?? "").replace(/\/$/, "");
|
|
2973
|
+
const ctxFactory = options.execContextFactory ?? (() => ({ ...DEFAULT_CTX2 }));
|
|
2974
|
+
app.use(express__default.default.text({ type: "*/*" }));
|
|
2975
|
+
registerSpecRoutes(router, runtime, basePath);
|
|
2976
|
+
registerToolRoutes(router, runtime, ctxFactory);
|
|
2977
|
+
mountRouter(app, router, basePath);
|
|
2978
|
+
registerErrorHandlers(app);
|
|
2979
|
+
patchListenDefaults(app, options);
|
|
2980
|
+
return app;
|
|
2981
|
+
}
|
|
2982
|
+
function listenOpenAPIHttpServer(app, options = {}) {
|
|
2983
|
+
return new Promise((resolve4, reject) => {
|
|
2984
|
+
const port = options.port ?? 0;
|
|
2985
|
+
const host = options.host ?? "localhost";
|
|
2986
|
+
const httpServer = app.listen(port, host, () => {
|
|
2987
|
+
const addr = httpServer.address();
|
|
2988
|
+
const actualPort = typeof addr === "object" && addr?.port != null ? addr.port : port;
|
|
2989
|
+
resolve4({ port: actualPort, host, httpServer });
|
|
2990
|
+
});
|
|
2991
|
+
httpServer.on("error", reject);
|
|
2992
|
+
});
|
|
2993
|
+
}
|
|
2994
|
+
async function createHttpService(runtimeOrConfig, options = {}) {
|
|
2995
|
+
const runtime = "invoke" in runtimeOrConfig && typeof runtimeOrConfig.invoke === "function" ? runtimeOrConfig : (await createRuntimeFromConfig(runtimeOrConfig)).runtime;
|
|
2996
|
+
const server = createOpenAPIHttpServer(runtime, options);
|
|
2997
|
+
const openApiSpec = toolsToOpenAPISpec(runtime.getRegistry(), {
|
|
2998
|
+
title: options.title ?? "Tool API",
|
|
2999
|
+
version: options.version ?? "1.0.0",
|
|
3000
|
+
basePath: options.basePath
|
|
3001
|
+
});
|
|
3002
|
+
let activeHttpServer = null;
|
|
3003
|
+
return {
|
|
3004
|
+
server,
|
|
3005
|
+
openApiSpec,
|
|
3006
|
+
listen: async (listenOpts) => {
|
|
3007
|
+
const { port, host, httpServer } = await listenOpenAPIHttpServer(server, listenOpts);
|
|
3008
|
+
activeHttpServer = httpServer;
|
|
3009
|
+
return { port, host };
|
|
3010
|
+
},
|
|
3011
|
+
close: async () => {
|
|
3012
|
+
if (!activeHttpServer) return;
|
|
3013
|
+
await new Promise((resolve4, reject) => {
|
|
3014
|
+
activeHttpServer.close((err) => err ? reject(err) : resolve4());
|
|
3015
|
+
});
|
|
3016
|
+
activeHttpServer = null;
|
|
3017
|
+
}
|
|
3018
|
+
};
|
|
3019
|
+
}
|
|
3020
|
+
|
|
3021
|
+
exports.createHttpService = createHttpService;
|
|
3022
|
+
exports.createMCPServerStreamableHttp = createMCPServerStreamableHttp;
|
|
3023
|
+
exports.createRuntimeFromConfig = createRuntimeFromConfig;
|
|
3024
|
+
exports.ensurePackageInCache = ensurePackageInCache;
|
|
3025
|
+
exports.expandToolDescriptorsToRegistryNames = expandToolDescriptorsToRegistryNames;
|
|
3026
|
+
exports.fileDescriptorToPackagePrefix = fileDescriptorToPackagePrefix;
|
|
3027
|
+
exports.findAndLoadToolConfig = findAndLoadToolConfig;
|
|
3028
|
+
exports.getCacheBaseFromToolConfig = getCacheBaseFromToolConfig;
|
|
3029
|
+
exports.getDisplayScope = getDisplayScope;
|
|
3030
|
+
exports.getPathSourceDescriptors = getPathSourceDescriptors;
|
|
3031
|
+
exports.getToolSourceDescriptors = getToolSourceDescriptors;
|
|
3032
|
+
exports.isBarePackageDescriptor = isBarePackageDescriptor;
|
|
3033
|
+
exports.loadToolConfig = loadToolConfig;
|
|
3034
|
+
exports.npmDescriptorToPackagePrefix = npmDescriptorToPackagePrefix;
|
|
3035
|
+
exports.parseNpmDescriptor = parseNpmDescriptor;
|
|
3036
|
+
exports.parseToolPath = parseToolPath;
|
|
3037
|
+
exports.resolveLatestVersionFromRegistry = resolveLatestVersionFromRegistry;
|
|
3038
|
+
exports.resolveSandboxedPath = resolveSandboxedPath;
|
|
3039
|
+
exports.resolveToolDescriptor = resolveToolDescriptor;
|
|
3040
|
+
exports.runMCPServerOverStdio = runMCPServerOverStdio;
|
|
3041
|
+
exports.toToolObservationText = toToolObservationText;
|
|
3042
|
+
//# sourceMappingURL=chunk-4VKCWJHF.cjs.map
|
|
3043
|
+
//# sourceMappingURL=chunk-4VKCWJHF.cjs.map
|