@easynet/agent-tool 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +92 -50
- package/dist/api/adapters/LangChainToolsHub.d.ts +34 -0
- package/dist/api/adapters/LangChainToolsHub.d.ts.map +1 -0
- package/dist/api/createAgentTools.d.ts +24 -0
- package/dist/api/createAgentTools.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.map +1 -0
- package/dist/{codegen → api/expose/mcp-build}/generator.d.ts +3 -3
- 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.map +1 -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 +75 -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 +67 -0
- package/dist/api/expose/openapiHttp.d.ts.map +1 -0
- package/dist/api/main.cjs +56 -0
- package/dist/api/main.cjs.map +1 -0
- package/dist/api/main.d.ts +23 -0
- package/dist/api/main.d.ts.map +1 -0
- package/dist/api/main.js +7 -0
- package/dist/api/main.js.map +1 -0
- package/dist/api/runtimeFromConfig.d.ts +34 -0
- package/dist/api/runtimeFromConfig.d.ts.map +1 -0
- package/dist/canonicalCoreSchemas-CTW6CCFY.cjs +20 -0
- package/dist/canonicalCoreSchemas-CTW6CCFY.cjs.map +1 -0
- package/dist/canonicalCoreSchemas-YLHVHYJZ.js +3 -0
- package/dist/canonicalCoreSchemas-YLHVHYJZ.js.map +1 -0
- package/dist/{chunk-AXUNV4MK.js → chunk-5SWSNVMI.js} +3 -3
- package/dist/chunk-5SWSNVMI.js.map +1 -0
- package/dist/chunk-6F5JHLZ7.cjs +243 -0
- package/dist/chunk-6F5JHLZ7.cjs.map +1 -0
- package/dist/chunk-AE6FSNGY.js +201 -0
- package/dist/chunk-AE6FSNGY.js.map +1 -0
- package/dist/chunk-BZOKPJMP.cjs +120 -0
- package/dist/chunk-BZOKPJMP.cjs.map +1 -0
- package/dist/chunk-FA2ZEICE.cjs +1620 -0
- package/dist/chunk-FA2ZEICE.cjs.map +1 -0
- package/dist/chunk-FR2CXERF.js +239 -0
- package/dist/chunk-FR2CXERF.js.map +1 -0
- package/dist/chunk-MGEQPAHV.cjs +475 -0
- package/dist/chunk-MGEQPAHV.cjs.map +1 -0
- package/dist/{chunk-BM4EVYI5.js → chunk-PJ4RUBZL.js} +836 -122
- package/dist/chunk-PJ4RUBZL.js.map +1 -0
- package/dist/chunk-Q7KPGWC6.js +1584 -0
- package/dist/chunk-Q7KPGWC6.js.map +1 -0
- package/dist/chunk-QVH6IQKQ.js +469 -0
- package/dist/chunk-QVH6IQKQ.js.map +1 -0
- package/dist/{chunk-3YLVPZRJ.cjs → chunk-SOFUWEZ6.cjs} +3 -3
- package/dist/chunk-SOFUWEZ6.cjs.map +1 -0
- package/dist/chunk-TBMWJWQ2.js +116 -0
- package/dist/chunk-TBMWJWQ2.js.map +1 -0
- package/dist/{chunk-Z7TGIG77.cjs → chunk-ZBNRHRGM.cjs} +843 -127
- package/dist/chunk-ZBNRHRGM.cjs.map +1 -0
- package/dist/chunk-ZNJBRLKN.cjs +210 -0
- package/dist/chunk-ZNJBRLKN.cjs.map +1 -0
- package/dist/core/index.cjs +20 -0
- package/dist/core/index.cjs.map +1 -0
- package/dist/{core.d.ts → core/index.d.ts} +2 -3
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +3 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/registry/ToolRegistry.d.ts.map +1 -0
- package/dist/core/runtime/Budget.d.ts.map +1 -0
- package/dist/core/runtime/Evidence.d.ts.map +1 -0
- package/dist/{runtime → core/runtime}/PTCRuntime.d.ts +4 -4
- package/dist/core/runtime/PTCRuntime.d.ts.map +1 -0
- package/dist/{runtime → core/runtime}/PTCRuntimeObservability.d.ts +4 -4
- package/dist/core/runtime/PTCRuntimeObservability.d.ts.map +1 -0
- package/dist/{runtime → core/runtime}/PTCRuntimePipeline.d.ts +4 -4
- package/dist/core/runtime/PTCRuntimePipeline.d.ts.map +1 -0
- package/dist/core/runtime/PolicyEngine.d.ts.map +1 -0
- package/dist/core/runtime/Retry.d.ts.map +1 -0
- package/dist/core/runtime/SchemaValidator.d.ts.map +1 -0
- package/dist/core/runtime.cjs +24 -0
- package/dist/core/runtime.cjs.map +1 -0
- package/dist/core/runtime.d.ts +12 -0
- package/dist/core/runtime.d.ts.map +1 -0
- package/dist/core/runtime.js +3 -0
- package/dist/core/runtime.js.map +1 -0
- package/dist/core/types/Events.d.ts.map +1 -0
- package/dist/core/types/ToolIntent.d.ts.map +1 -0
- package/dist/{types → core/types}/ToolResult.d.ts +6 -1
- package/dist/core/types/ToolResult.d.ts.map +1 -0
- package/dist/{types → core/types}/ToolSpec.d.ts +15 -5
- 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/{types → core/types}/index.d.ts +2 -1
- package/dist/core/types/index.d.ts.map +1 -0
- package/dist/index.cjs +249 -2749
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +61 -55
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +126 -2688
- package/dist/index.js.map +1 -1
- package/dist/observability/EventLog.d.ts +1 -1
- package/dist/observability/EventLog.d.ts.map +1 -1
- 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/{codegen/scan → tools/function}/scanner.d.ts +5 -2
- package/dist/{codegen/scan → tools/function}/scanner.d.ts.map +1 -1
- package/dist/{codegen/scan → tools/function}/schemaFromTs.d.ts +1 -1
- 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/{discovery/load → tools/langchain}/LangChainLoader.d.ts +1 -1
- 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/{mcp → tools/mcp}/MCPClientAdapter.d.ts +3 -3
- package/dist/tools/mcp/MCPClientAdapter.d.ts.map +1 -0
- package/dist/{discovery/load → tools/mcp}/MCPLoader.d.ts +1 -1
- 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/{mcp → tools/mcp}/connectMCP.d.ts +3 -3
- 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/{mcp → tools/mcp}/index.d.ts +6 -1
- 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/{mcp → tools/mcp}/registerMCPTools.d.ts +2 -2
- 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/types.d.ts +3 -0
- package/dist/tools/mcp/types.d.ts.map +1 -0
- package/dist/{discovery/load → tools/n8n}/N8nLoader.d.ts +3 -3
- 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/{discovery/load → tools/skill}/SkillLoader.d.ts +1 -1
- package/dist/tools/skill/SkillLoader.d.ts.map +1 -0
- package/dist/tools/skill/SkillManifest.d.ts.map +1 -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 +19 -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 +32 -0
- package/dist/tools/util/toolConfig.d.ts.map +1 -0
- package/dist/tools/util/toolDescriptor.d.ts +92 -0
- package/dist/tools/util/toolDescriptor.d.ts.map +1 -0
- package/dist/utils/cli/index.cjs +419 -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 +412 -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/npmCache.d.ts +28 -0
- package/dist/utils/npmCache.d.ts.map +1 -0
- package/package.json +20 -11
- package/dist/chunk-3YLVPZRJ.cjs.map +0 -1
- package/dist/chunk-AXUNV4MK.js.map +0 -1
- package/dist/chunk-BM4EVYI5.js.map +0 -1
- package/dist/chunk-P3UEAZHK.cjs +0 -171
- package/dist/chunk-P3UEAZHK.cjs.map +0 -1
- package/dist/chunk-RPAMQCFH.js +0 -167
- package/dist/chunk-RPAMQCFH.js.map +0 -1
- package/dist/chunk-Z7TGIG77.cjs.map +0 -1
- package/dist/cli.cjs +0 -154
- package/dist/cli.cjs.map +0 -1
- package/dist/cli.d.ts +0 -10
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -147
- package/dist/cli.js.map +0 -1
- package/dist/codegen/build.d.ts.map +0 -1
- package/dist/codegen/generator.d.ts.map +0 -1
- package/dist/codegen/index.d.ts +0 -21
- package/dist/codegen/index.d.ts.map +0 -1
- package/dist/codegen/init.d.ts.map +0 -1
- package/dist/codegen/run.d.ts.map +0 -1
- package/dist/codegen/scan/scanN8n.d.ts +0 -17
- package/dist/codegen/scan/scanN8n.d.ts.map +0 -1
- package/dist/codegen/scan/scanSkill.d.ts +0 -17
- package/dist/codegen/scan/scanSkill.d.ts.map +0 -1
- package/dist/codegen/scan/scanTools.d.ts +0 -31
- package/dist/codegen/scan/scanTools.d.ts.map +0 -1
- package/dist/codegen/scan/schemaFromTs.d.ts.map +0 -1
- package/dist/codegen/types.d.ts +0 -81
- package/dist/codegen/types.d.ts.map +0 -1
- package/dist/core.cjs +0 -20
- package/dist/core.cjs.map +0 -1
- package/dist/core.d.ts.map +0 -1
- package/dist/core.js +0 -3
- package/dist/core.js.map +0 -1
- package/dist/discovery/MCPProcessManager.d.ts +0 -57
- package/dist/discovery/MCPProcessManager.d.ts.map +0 -1
- package/dist/discovery/errors.d.ts +0 -13
- package/dist/discovery/errors.d.ts.map +0 -1
- package/dist/discovery/load/LangChainLoader.d.ts.map +0 -1
- package/dist/discovery/load/MCPLoader.d.ts.map +0 -1
- package/dist/discovery/load/N8nLoader.d.ts.map +0 -1
- package/dist/discovery/load/SkillLoader.d.ts.map +0 -1
- package/dist/discovery/load/SkillManifest.d.ts.map +0 -1
- package/dist/discovery/load/SkillMdParser.d.ts.map +0 -1
- package/dist/discovery/load/index.d.ts +0 -6
- package/dist/discovery/load/index.d.ts.map +0 -1
- package/dist/discovery/load/resolveEntry.d.ts +0 -7
- package/dist/discovery/load/resolveEntry.d.ts.map +0 -1
- package/dist/discovery/scan/DirectoryScanner.d.ts +0 -37
- package/dist/discovery/scan/DirectoryScanner.d.ts.map +0 -1
- package/dist/discovery/scan/scanUtil.d.ts +0 -16
- package/dist/discovery/scan/scanUtil.d.ts.map +0 -1
- package/dist/discovery/types.d.ts +0 -99
- package/dist/discovery/types.d.ts.map +0 -1
- package/dist/llm/AgentLLMAdapter.d.ts +0 -27
- package/dist/llm/AgentLLMAdapter.d.ts.map +0 -1
- package/dist/llm/LangChainToolsHub.d.ts +0 -31
- package/dist/llm/LangChainToolsHub.d.ts.map +0 -1
- package/dist/llm/OpenAICompatibleClient.d.ts +0 -64
- package/dist/llm/OpenAICompatibleClient.d.ts.map +0 -1
- package/dist/llm/ReActAgent.d.ts +0 -35
- package/dist/llm/ReActAgent.d.ts.map +0 -1
- package/dist/llm-export.cjs +0 -20
- package/dist/llm-export.cjs.map +0 -1
- package/dist/llm-export.d.ts +0 -9
- package/dist/llm-export.d.ts.map +0 -1
- package/dist/llm-export.js +0 -3
- package/dist/llm-export.js.map +0 -1
- package/dist/mcp/MCPClientAdapter.d.ts.map +0 -1
- package/dist/mcp/connectMCP.d.ts.map +0 -1
- package/dist/mcp/index.d.ts.map +0 -1
- package/dist/mcp/registerMCPTools.d.ts.map +0 -1
- package/dist/registry/ToolRegistry.d.ts.map +0 -1
- package/dist/report/AgentReportGenerator.d.ts +0 -53
- package/dist/report/AgentReportGenerator.d.ts.map +0 -1
- package/dist/report/agent-report-template.html +0 -362
- package/dist/report/index.d.ts +0 -3
- package/dist/report/index.d.ts.map +0 -1
- package/dist/report/types.d.ts +0 -101
- package/dist/report/types.d.ts.map +0 -1
- package/dist/runAgent.d.ts +0 -37
- package/dist/runAgent.d.ts.map +0 -1
- package/dist/runtime/Budget.d.ts.map +0 -1
- package/dist/runtime/Evidence.d.ts.map +0 -1
- package/dist/runtime/PTCRuntime.d.ts.map +0 -1
- package/dist/runtime/PTCRuntimeObservability.d.ts.map +0 -1
- package/dist/runtime/PTCRuntimePipeline.d.ts.map +0 -1
- package/dist/runtime/PolicyEngine.d.ts.map +0 -1
- package/dist/runtime/Retry.d.ts.map +0 -1
- package/dist/runtime/SchemaValidator.d.ts.map +0 -1
- package/dist/toolDescriptor.d.ts +0 -38
- package/dist/toolDescriptor.d.ts.map +0 -1
- package/dist/types/Events.d.ts.map +0 -1
- package/dist/types/ToolIntent.d.ts.map +0 -1
- package/dist/types/ToolResult.d.ts.map +0 -1
- package/dist/types/ToolSpec.d.ts.map +0 -1
- package/dist/types/index.d.ts.map +0 -1
- package/extensions/examples/README.md +0 -40
- package/extensions/examples/scripts/agent-tool-react-stock.mjs +0 -30
- package/extensions/examples/tools/instruction-only/skill/SKILL.md +0 -26
- package/extensions/examples/tools/web-search/mcp/mcp.json +0 -8
- /package/dist/{codegen → api/expose/mcp-build}/build.d.ts +0 -0
- /package/dist/{codegen → api/expose/mcp-build}/init.d.ts +0 -0
- /package/dist/{codegen → api/expose/mcp-build}/run.d.ts +0 -0
- /package/dist/{registry → core/registry}/ToolRegistry.d.ts +0 -0
- /package/dist/{runtime → core/runtime}/Budget.d.ts +0 -0
- /package/dist/{runtime → core/runtime}/Evidence.d.ts +0 -0
- /package/dist/{runtime → core/runtime}/PolicyEngine.d.ts +0 -0
- /package/dist/{runtime → core/runtime}/Retry.d.ts +0 -0
- /package/dist/{runtime → core/runtime}/SchemaValidator.d.ts +0 -0
- /package/dist/{types → core/types}/Events.d.ts +0 -0
- /package/dist/{types → core/types}/ToolIntent.d.ts +0 -0
- /package/dist/{discovery/load → tools/skill}/SkillManifest.d.ts +0 -0
- /package/dist/{discovery/load → tools/skill}/SkillMdParser.d.ts +0 -0
package/dist/index.cjs
CHANGED
|
@@ -1,2306 +1,20 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
var
|
|
6
|
-
var
|
|
7
|
-
var
|
|
8
|
-
|
|
9
|
-
var eventemitter3 = require('eventemitter3');
|
|
10
|
-
var uuid = require('uuid');
|
|
11
|
-
var pRetry = require('p-retry');
|
|
12
|
-
var pTimeout = require('p-timeout');
|
|
3
|
+
var chunkBZOKPJMP_cjs = require('./chunk-BZOKPJMP.cjs');
|
|
4
|
+
var chunkZBNRHRGM_cjs = require('./chunk-ZBNRHRGM.cjs');
|
|
5
|
+
var chunkSOFUWEZ6_cjs = require('./chunk-SOFUWEZ6.cjs');
|
|
6
|
+
var chunkFA2ZEICE_cjs = require('./chunk-FA2ZEICE.cjs');
|
|
7
|
+
var chunkZNJBRLKN_cjs = require('./chunk-ZNJBRLKN.cjs');
|
|
8
|
+
require('./chunk-6F5JHLZ7.cjs');
|
|
13
9
|
var agentToolBuiltinTools = require('@easynet/agent-tool-builtin-tools');
|
|
14
10
|
var agentToolExampleTools = require('@easynet/agent-tool-example-tools');
|
|
15
|
-
var promises = require('fs/promises');
|
|
16
11
|
var path = require('path');
|
|
17
|
-
var
|
|
18
|
-
var
|
|
19
|
-
var
|
|
20
|
-
var
|
|
21
|
-
var agentLlm = require('@easynet/agent-llm');
|
|
22
|
-
|
|
23
|
-
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
24
|
-
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
25
|
-
|
|
26
|
-
var Ajv__default = /*#__PURE__*/_interopDefault(Ajv);
|
|
27
|
-
var addFormats__default = /*#__PURE__*/_interopDefault(addFormats);
|
|
28
|
-
var pRetry__default = /*#__PURE__*/_interopDefault(pRetry);
|
|
29
|
-
var pTimeout__default = /*#__PURE__*/_interopDefault(pTimeout);
|
|
30
|
-
var yaml__default = /*#__PURE__*/_interopDefault(yaml);
|
|
31
|
-
|
|
32
|
-
// src/registry/ToolRegistry.ts
|
|
33
|
-
var ToolRegistry = class {
|
|
34
|
-
tools = /* @__PURE__ */ new Map();
|
|
35
|
-
tagIndex = /* @__PURE__ */ new Map();
|
|
36
|
-
// tag → tool names
|
|
37
|
-
kindIndex = /* @__PURE__ */ new Map();
|
|
38
|
-
// kind → tool names
|
|
39
|
-
/**
|
|
40
|
-
* Register a single tool spec.
|
|
41
|
-
* Overwrites if same name already exists.
|
|
42
|
-
*/
|
|
43
|
-
register(spec) {
|
|
44
|
-
this.validateSpec(spec);
|
|
45
|
-
this.tools.set(spec.name, spec);
|
|
46
|
-
this.indexTool(spec);
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Register multiple tool specs at once.
|
|
50
|
-
*/
|
|
51
|
-
bulkRegister(specs) {
|
|
52
|
-
for (const spec of specs) {
|
|
53
|
-
this.register(spec);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Unregister a tool by name.
|
|
58
|
-
*/
|
|
59
|
-
unregister(name) {
|
|
60
|
-
const spec = this.tools.get(name);
|
|
61
|
-
if (!spec) return false;
|
|
62
|
-
this.tools.delete(name);
|
|
63
|
-
this.deindexTool(spec);
|
|
64
|
-
return true;
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Get a tool spec by name.
|
|
68
|
-
*/
|
|
69
|
-
get(name) {
|
|
70
|
-
return this.tools.get(name);
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Check if a tool exists.
|
|
74
|
-
*/
|
|
75
|
-
has(name) {
|
|
76
|
-
return this.tools.has(name);
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Search tools by query.
|
|
80
|
-
*/
|
|
81
|
-
search(query) {
|
|
82
|
-
let candidates;
|
|
83
|
-
if (query.kind) {
|
|
84
|
-
const names = this.kindIndex.get(query.kind);
|
|
85
|
-
if (!names || names.size === 0) return [];
|
|
86
|
-
candidates = [...names].map((n) => this.tools.get(n)).filter((s) => s !== void 0);
|
|
87
|
-
} else {
|
|
88
|
-
candidates = [...this.tools.values()];
|
|
89
|
-
}
|
|
90
|
-
if (query.tags && query.tags.length > 0) {
|
|
91
|
-
candidates = candidates.filter(
|
|
92
|
-
(spec) => query.tags.some((tag) => spec.tags?.includes(tag))
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
if (query.capabilities && query.capabilities.length > 0) {
|
|
96
|
-
candidates = candidates.filter(
|
|
97
|
-
(spec) => query.capabilities.every((cap) => spec.capabilities.includes(cap))
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
if (query.text) {
|
|
101
|
-
const lower = query.text.toLowerCase();
|
|
102
|
-
candidates = candidates.filter(
|
|
103
|
-
(spec) => spec.name.toLowerCase().includes(lower) || spec.description?.toLowerCase().includes(lower) || spec.tags?.some((t) => t.toLowerCase().includes(lower))
|
|
104
|
-
);
|
|
105
|
-
}
|
|
106
|
-
return candidates;
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* List all registered tool names.
|
|
110
|
-
*/
|
|
111
|
-
list() {
|
|
112
|
-
return [...this.tools.keys()];
|
|
113
|
-
}
|
|
114
|
-
/**
|
|
115
|
-
* Get count of registered tools.
|
|
116
|
-
*/
|
|
117
|
-
get size() {
|
|
118
|
-
return this.tools.size;
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* Export a snapshot of all registered tools (for debugging/routing).
|
|
122
|
-
*/
|
|
123
|
-
snapshot() {
|
|
124
|
-
return [...this.tools.values()];
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* Clear all registered tools.
|
|
128
|
-
*/
|
|
129
|
-
clear() {
|
|
130
|
-
this.tools.clear();
|
|
131
|
-
this.tagIndex.clear();
|
|
132
|
-
this.kindIndex.clear();
|
|
133
|
-
}
|
|
134
|
-
validateSpec(spec) {
|
|
135
|
-
if (!spec.name) throw new Error("ToolSpec.name is required");
|
|
136
|
-
if (!spec.version) throw new Error("ToolSpec.version is required");
|
|
137
|
-
if (!spec.kind) throw new Error("ToolSpec.kind is required");
|
|
138
|
-
if (!spec.inputSchema) throw new Error("ToolSpec.inputSchema is required");
|
|
139
|
-
if (!spec.outputSchema) throw new Error("ToolSpec.outputSchema is required");
|
|
140
|
-
if (!spec.capabilities) throw new Error("ToolSpec.capabilities is required");
|
|
141
|
-
}
|
|
142
|
-
indexTool(spec) {
|
|
143
|
-
let kindSet = this.kindIndex.get(spec.kind);
|
|
144
|
-
if (!kindSet) {
|
|
145
|
-
kindSet = /* @__PURE__ */ new Set();
|
|
146
|
-
this.kindIndex.set(spec.kind, kindSet);
|
|
147
|
-
}
|
|
148
|
-
kindSet.add(spec.name);
|
|
149
|
-
if (spec.tags) {
|
|
150
|
-
for (const tag of spec.tags) {
|
|
151
|
-
let tagSet = this.tagIndex.get(tag);
|
|
152
|
-
if (!tagSet) {
|
|
153
|
-
tagSet = /* @__PURE__ */ new Set();
|
|
154
|
-
this.tagIndex.set(tag, tagSet);
|
|
155
|
-
}
|
|
156
|
-
tagSet.add(spec.name);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
deindexTool(spec) {
|
|
161
|
-
this.kindIndex.get(spec.kind)?.delete(spec.name);
|
|
162
|
-
if (spec.tags) {
|
|
163
|
-
for (const tag of spec.tags) {
|
|
164
|
-
this.tagIndex.get(tag)?.delete(spec.name);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
};
|
|
169
|
-
var SchemaValidator = class {
|
|
170
|
-
ajv;
|
|
171
|
-
cache = /* @__PURE__ */ new Map();
|
|
172
|
-
constructor() {
|
|
173
|
-
this.ajv = new Ajv__default.default({
|
|
174
|
-
allErrors: true,
|
|
175
|
-
coerceTypes: true,
|
|
176
|
-
useDefaults: true,
|
|
177
|
-
removeAdditional: "failing",
|
|
178
|
-
strict: false
|
|
179
|
-
});
|
|
180
|
-
addFormats__default.default(this.ajv);
|
|
181
|
-
}
|
|
182
|
-
/**
|
|
183
|
-
* Validate data against a JSON Schema.
|
|
184
|
-
* Coerces types and applies defaults in-place.
|
|
185
|
-
*/
|
|
186
|
-
validate(schema, data) {
|
|
187
|
-
const validate = this.getOrCompile(schema);
|
|
188
|
-
const cloned = structuredClone(data);
|
|
189
|
-
const valid = validate(cloned);
|
|
190
|
-
if (valid) {
|
|
191
|
-
return { valid: true, data: cloned };
|
|
192
|
-
}
|
|
193
|
-
return {
|
|
194
|
-
valid: false,
|
|
195
|
-
errors: validate.errors ?? void 0
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* Validate and return coerced data, or throw a descriptive error.
|
|
200
|
-
*/
|
|
201
|
-
validateOrThrow(schema, data, context) {
|
|
202
|
-
const result = this.validate(schema, data);
|
|
203
|
-
if (!result.valid) {
|
|
204
|
-
const messages = (result.errors ?? []).map((e) => `${e.instancePath || "/"} ${e.message}`).join("; ");
|
|
205
|
-
throw new SchemaValidationError(
|
|
206
|
-
`${context}: ${messages}`,
|
|
207
|
-
result.errors ?? []
|
|
208
|
-
);
|
|
209
|
-
}
|
|
210
|
-
return result.data;
|
|
211
|
-
}
|
|
212
|
-
/**
|
|
213
|
-
* Apply default values from schema to data without full validation.
|
|
214
|
-
*/
|
|
215
|
-
enrichDefaults(schema, data) {
|
|
216
|
-
const validate = this.getOrCompile(schema);
|
|
217
|
-
const cloned = structuredClone(data);
|
|
218
|
-
validate(cloned);
|
|
219
|
-
return cloned;
|
|
220
|
-
}
|
|
221
|
-
getOrCompile(schema) {
|
|
222
|
-
const normalized = this.normalizeSchema(schema);
|
|
223
|
-
const key = JSON.stringify(normalized);
|
|
224
|
-
let cached = this.cache.get(key);
|
|
225
|
-
if (!cached) {
|
|
226
|
-
cached = this.ajv.compile(normalized);
|
|
227
|
-
this.cache.set(key, cached);
|
|
228
|
-
}
|
|
229
|
-
return cached;
|
|
230
|
-
}
|
|
231
|
-
/** Ensure schema is AJV-compatible (required = string[], nullable handled via type). */
|
|
232
|
-
normalizeSchema(schema) {
|
|
233
|
-
return this.normalizeSchemaRec(schema);
|
|
234
|
-
}
|
|
235
|
-
normalizeSchemaRec(s) {
|
|
236
|
-
const out = {};
|
|
237
|
-
for (const [key, value] of Object.entries(s)) {
|
|
238
|
-
if (key === "required") {
|
|
239
|
-
const raw = value;
|
|
240
|
-
out.required = Array.isArray(raw) ? raw.filter((x) => typeof x === "string") : typeof raw === "string" ? [raw] : [];
|
|
241
|
-
continue;
|
|
242
|
-
}
|
|
243
|
-
if (key === "nullable") {
|
|
244
|
-
continue;
|
|
245
|
-
}
|
|
246
|
-
if (key === "properties" && value !== null && typeof value === "object") {
|
|
247
|
-
const props = {};
|
|
248
|
-
for (const [pk, pv] of Object.entries(value)) {
|
|
249
|
-
if (pv !== null && typeof pv === "object" && !Array.isArray(pv)) {
|
|
250
|
-
props[pk] = this.normalizeSchemaRec(pv);
|
|
251
|
-
} else {
|
|
252
|
-
props[pk] = pv;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
out.properties = props;
|
|
256
|
-
continue;
|
|
257
|
-
}
|
|
258
|
-
if ((key === "items" || key === "additionalProperties") && value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
259
|
-
out[key] = this.normalizeSchemaRec(value);
|
|
260
|
-
continue;
|
|
261
|
-
}
|
|
262
|
-
if ((key === "oneOf" || key === "anyOf" || key === "allOf") && Array.isArray(value)) {
|
|
263
|
-
out[key] = value.map(
|
|
264
|
-
(item) => item !== null && typeof item === "object" && !Array.isArray(item) ? this.normalizeSchemaRec(item) : item
|
|
265
|
-
);
|
|
266
|
-
continue;
|
|
267
|
-
}
|
|
268
|
-
out[key] = value;
|
|
269
|
-
}
|
|
270
|
-
if (s.nullable === true) {
|
|
271
|
-
const existingType = out.type;
|
|
272
|
-
if (existingType === void 0) {
|
|
273
|
-
out.type = "object";
|
|
274
|
-
} else if (Array.isArray(existingType)) {
|
|
275
|
-
if (!existingType.includes("null")) out.type = [...existingType, "null"];
|
|
276
|
-
} else {
|
|
277
|
-
out.type = [existingType, "null"];
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
return out;
|
|
281
|
-
}
|
|
282
|
-
};
|
|
283
|
-
var SchemaValidationError = class extends Error {
|
|
284
|
-
constructor(message, errors) {
|
|
285
|
-
super(message);
|
|
286
|
-
this.errors = errors;
|
|
287
|
-
this.name = "SchemaValidationError";
|
|
288
|
-
}
|
|
289
|
-
};
|
|
290
|
-
|
|
291
|
-
// src/runtime/PolicyEngine.ts
|
|
292
|
-
var PolicyEngine = class {
|
|
293
|
-
config;
|
|
294
|
-
constructor(config = {}) {
|
|
295
|
-
this.config = {
|
|
296
|
-
requireExplicitDangerPermission: true,
|
|
297
|
-
deniedSqlPatterns: ["DROP\\s", "TRUNCATE\\s", "DELETE\\s+FROM\\s+\\w+\\s*$"],
|
|
298
|
-
...config
|
|
299
|
-
};
|
|
300
|
-
}
|
|
301
|
-
/**
|
|
302
|
-
* Enforce all policy checks. Throws PolicyDeniedError if denied.
|
|
303
|
-
*/
|
|
304
|
-
enforce(spec, args, ctx) {
|
|
305
|
-
const result = this.check(spec, args, ctx);
|
|
306
|
-
if (!result.allowed) {
|
|
307
|
-
throw new PolicyDeniedError(
|
|
308
|
-
result.reason ?? "Policy denied",
|
|
309
|
-
result.missingCapabilities
|
|
310
|
-
);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
/**
|
|
314
|
-
* Check all policies without throwing.
|
|
315
|
-
*/
|
|
316
|
-
check(spec, args, ctx) {
|
|
317
|
-
const capResult = this.checkCapabilities(spec, ctx);
|
|
318
|
-
if (!capResult.allowed) return capResult;
|
|
319
|
-
const paramResult = this.checkParameters(spec, args);
|
|
320
|
-
if (!paramResult.allowed) return paramResult;
|
|
321
|
-
return { allowed: true };
|
|
322
|
-
}
|
|
323
|
-
/**
|
|
324
|
-
* Check that context permissions cover tool capabilities.
|
|
325
|
-
*/
|
|
326
|
-
checkCapabilities(spec, ctx) {
|
|
327
|
-
const missing = [];
|
|
328
|
-
for (const cap of spec.capabilities) {
|
|
329
|
-
if (cap === "danger:destructive") {
|
|
330
|
-
if (this.config.requireExplicitDangerPermission && !ctx.permissions.includes("danger:destructive")) {
|
|
331
|
-
missing.push(cap);
|
|
332
|
-
}
|
|
333
|
-
} else if (!ctx.permissions.includes(cap)) {
|
|
334
|
-
missing.push(cap);
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
if (missing.length > 0) {
|
|
338
|
-
return {
|
|
339
|
-
allowed: false,
|
|
340
|
-
reason: `Missing capabilities: ${missing.join(", ")}`,
|
|
341
|
-
missingCapabilities: missing
|
|
342
|
-
};
|
|
343
|
-
}
|
|
344
|
-
return { allowed: true };
|
|
345
|
-
}
|
|
346
|
-
/**
|
|
347
|
-
* Check parameter-level security constraints.
|
|
348
|
-
*/
|
|
349
|
-
checkParameters(spec, args) {
|
|
350
|
-
if (!args || typeof args !== "object") return { allowed: true };
|
|
351
|
-
const argsObj = args;
|
|
352
|
-
if (spec.capabilities.includes("write:fs") && this.config.sandboxPaths) {
|
|
353
|
-
const pathResult = this.checkFilePaths(argsObj);
|
|
354
|
-
if (!pathResult.allowed) return pathResult;
|
|
355
|
-
}
|
|
356
|
-
if (spec.capabilities.includes("network") || spec.capabilities.includes("read:web")) {
|
|
357
|
-
const urlResult = this.checkUrls(argsObj);
|
|
358
|
-
if (!urlResult.allowed) return urlResult;
|
|
359
|
-
}
|
|
360
|
-
if (spec.capabilities.includes("write:db") || spec.capabilities.includes("read:db")) {
|
|
361
|
-
const sqlResult = this.checkSql(argsObj);
|
|
362
|
-
if (!sqlResult.allowed) return sqlResult;
|
|
363
|
-
}
|
|
364
|
-
if (spec.capabilities.includes("network") && this.config.allowedDomains) {
|
|
365
|
-
const domainResult = this.checkDomains(argsObj);
|
|
366
|
-
if (!domainResult.allowed) return domainResult;
|
|
367
|
-
}
|
|
368
|
-
return { allowed: true };
|
|
369
|
-
}
|
|
370
|
-
checkFilePaths(args) {
|
|
371
|
-
const paths = this.extractStringValues(args, ["path", "file", "filepath", "filename", "dir", "directory"]);
|
|
372
|
-
for (const p of paths) {
|
|
373
|
-
const normalized = p.replace(/\.\./g, "");
|
|
374
|
-
if (p.includes("..")) {
|
|
375
|
-
return {
|
|
376
|
-
allowed: false,
|
|
377
|
-
reason: `Path traversal detected: ${p}`
|
|
378
|
-
};
|
|
379
|
-
}
|
|
380
|
-
if (this.config.sandboxPaths && this.config.sandboxPaths.length > 0) {
|
|
381
|
-
const inSandbox = this.config.sandboxPaths.some(
|
|
382
|
-
(sp) => normalized.startsWith(sp)
|
|
383
|
-
);
|
|
384
|
-
if (!inSandbox) {
|
|
385
|
-
return {
|
|
386
|
-
allowed: false,
|
|
387
|
-
reason: `Path outside sandbox: ${p}. Allowed: ${this.config.sandboxPaths.join(", ")}`
|
|
388
|
-
};
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
return { allowed: true };
|
|
393
|
-
}
|
|
394
|
-
checkUrls(args) {
|
|
395
|
-
const urls = this.extractStringValues(args, ["url", "endpoint", "href", "uri"]);
|
|
396
|
-
for (const url of urls) {
|
|
397
|
-
if (this.config.urlDenylist) {
|
|
398
|
-
for (const pattern of this.config.urlDenylist) {
|
|
399
|
-
if (new RegExp(pattern, "i").test(url)) {
|
|
400
|
-
return {
|
|
401
|
-
allowed: false,
|
|
402
|
-
reason: `URL denied by policy: ${url}`
|
|
403
|
-
};
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
if (this.config.urlAllowlist && this.config.urlAllowlist.length > 0) {
|
|
408
|
-
const allowed = this.config.urlAllowlist.some(
|
|
409
|
-
(pattern) => new RegExp(pattern, "i").test(url)
|
|
410
|
-
);
|
|
411
|
-
if (!allowed) {
|
|
412
|
-
return {
|
|
413
|
-
allowed: false,
|
|
414
|
-
reason: `URL not in allowlist: ${url}`
|
|
415
|
-
};
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
return { allowed: true };
|
|
420
|
-
}
|
|
421
|
-
checkSql(args) {
|
|
422
|
-
const sqls = this.extractStringValues(args, ["sql", "query", "statement"]);
|
|
423
|
-
for (const sql of sqls) {
|
|
424
|
-
if (this.config.deniedSqlPatterns) {
|
|
425
|
-
for (const pattern of this.config.deniedSqlPatterns) {
|
|
426
|
-
if (new RegExp(pattern, "i").test(sql)) {
|
|
427
|
-
return {
|
|
428
|
-
allowed: false,
|
|
429
|
-
reason: `SQL pattern denied: ${sql.slice(0, 50)}...`
|
|
430
|
-
};
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
return { allowed: true };
|
|
436
|
-
}
|
|
437
|
-
checkDomains(args) {
|
|
438
|
-
const urls = this.extractStringValues(args, ["url", "endpoint", "href", "host", "domain"]);
|
|
439
|
-
for (const url of urls) {
|
|
440
|
-
try {
|
|
441
|
-
const hostname = url.includes("://") ? new URL(url).hostname : url;
|
|
442
|
-
if (this.config.allowedDomains && !this.config.allowedDomains.some(
|
|
443
|
-
(d) => hostname === d || hostname.endsWith(`.${d}`)
|
|
444
|
-
)) {
|
|
445
|
-
return {
|
|
446
|
-
allowed: false,
|
|
447
|
-
reason: `Domain not allowed: ${hostname}`
|
|
448
|
-
};
|
|
449
|
-
}
|
|
450
|
-
} catch {
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
return { allowed: true };
|
|
454
|
-
}
|
|
455
|
-
/**
|
|
456
|
-
* Extract string values from args matching given key patterns.
|
|
457
|
-
*/
|
|
458
|
-
extractStringValues(args, keyPatterns) {
|
|
459
|
-
const results = [];
|
|
460
|
-
const walk = (obj) => {
|
|
461
|
-
for (const [key, val] of Object.entries(obj)) {
|
|
462
|
-
const lowerKey = key.toLowerCase();
|
|
463
|
-
if (typeof val === "string" && keyPatterns.some((p) => lowerKey.includes(p))) {
|
|
464
|
-
results.push(val);
|
|
465
|
-
} else if (val && typeof val === "object" && !Array.isArray(val)) {
|
|
466
|
-
walk(val);
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
};
|
|
470
|
-
walk(args);
|
|
471
|
-
return results;
|
|
472
|
-
}
|
|
473
|
-
};
|
|
474
|
-
var PolicyDeniedError = class extends Error {
|
|
475
|
-
constructor(message, missingCapabilities) {
|
|
476
|
-
super(message);
|
|
477
|
-
this.missingCapabilities = missingCapabilities;
|
|
478
|
-
this.name = "PolicyDeniedError";
|
|
479
|
-
}
|
|
480
|
-
kind = "POLICY_DENIED";
|
|
481
|
-
};
|
|
482
|
-
var RateLimiter = class {
|
|
483
|
-
constructor(maxCalls, windowMs) {
|
|
484
|
-
this.maxCalls = maxCalls;
|
|
485
|
-
this.windowMs = windowMs;
|
|
486
|
-
}
|
|
487
|
-
timestamps = [];
|
|
488
|
-
tryAcquire() {
|
|
489
|
-
const now = Date.now();
|
|
490
|
-
while (this.timestamps.length > 0 && this.timestamps[0] <= now - this.windowMs) {
|
|
491
|
-
this.timestamps.shift();
|
|
492
|
-
}
|
|
493
|
-
if (this.timestamps.length >= this.maxCalls) {
|
|
494
|
-
return false;
|
|
495
|
-
}
|
|
496
|
-
this.timestamps.push(now);
|
|
497
|
-
return true;
|
|
498
|
-
}
|
|
499
|
-
get remaining() {
|
|
500
|
-
const now = Date.now();
|
|
501
|
-
const active = this.timestamps.filter((t) => t > now - this.windowMs);
|
|
502
|
-
return Math.max(0, this.maxCalls - active.length);
|
|
503
|
-
}
|
|
504
|
-
};
|
|
505
|
-
var BudgetManager = class {
|
|
506
|
-
defaultTimeoutMs;
|
|
507
|
-
bulkheads = /* @__PURE__ */ new Map();
|
|
508
|
-
circuitBreakers = /* @__PURE__ */ new Map();
|
|
509
|
-
rateLimiters = /* @__PURE__ */ new Map();
|
|
510
|
-
options;
|
|
511
|
-
constructor(options = {}) {
|
|
512
|
-
this.options = options;
|
|
513
|
-
this.defaultTimeoutMs = options.defaultTimeoutMs ?? 3e4;
|
|
514
|
-
}
|
|
515
|
-
/**
|
|
516
|
-
* Get effective timeout for a tool invocation.
|
|
517
|
-
*/
|
|
518
|
-
getTimeout(_toolName, contextTimeoutMs) {
|
|
519
|
-
return contextTimeoutMs ?? this.defaultTimeoutMs;
|
|
520
|
-
}
|
|
521
|
-
/**
|
|
522
|
-
* Check rate limit for a tool. Returns true if allowed.
|
|
523
|
-
*/
|
|
524
|
-
checkRateLimit(toolName) {
|
|
525
|
-
if (!this.options.rateLimit) return true;
|
|
526
|
-
let limiter = this.rateLimiters.get(toolName);
|
|
527
|
-
if (!limiter) {
|
|
528
|
-
limiter = new RateLimiter(
|
|
529
|
-
this.options.rateLimit.maxCalls,
|
|
530
|
-
this.options.rateLimit.windowMs
|
|
531
|
-
);
|
|
532
|
-
this.rateLimiters.set(toolName, limiter);
|
|
533
|
-
}
|
|
534
|
-
return limiter.tryAcquire();
|
|
535
|
-
}
|
|
536
|
-
/**
|
|
537
|
-
* Get or create a bulkhead (concurrency limiter) for a tool.
|
|
538
|
-
*/
|
|
539
|
-
getBulkhead(toolName) {
|
|
540
|
-
if (!this.options.maxConcurrency) return void 0;
|
|
541
|
-
let bh = this.bulkheads.get(toolName);
|
|
542
|
-
if (!bh) {
|
|
543
|
-
bh = cockatiel.bulkhead(this.options.maxConcurrency, 0);
|
|
544
|
-
this.bulkheads.set(toolName, bh);
|
|
545
|
-
}
|
|
546
|
-
return bh;
|
|
547
|
-
}
|
|
548
|
-
/**
|
|
549
|
-
* Get or create a circuit breaker for a tool.
|
|
550
|
-
*/
|
|
551
|
-
getCircuitBreaker(toolName) {
|
|
552
|
-
if (!this.options.circuitBreaker) return void 0;
|
|
553
|
-
let breaker = this.circuitBreakers.get(toolName);
|
|
554
|
-
if (!breaker) {
|
|
555
|
-
breaker = cockatiel.circuitBreaker(cockatiel.handleAll, {
|
|
556
|
-
breaker: new cockatiel.ConsecutiveBreaker(this.options.circuitBreaker.threshold),
|
|
557
|
-
halfOpenAfter: this.options.circuitBreaker.halfOpenAfterMs
|
|
558
|
-
});
|
|
559
|
-
this.circuitBreakers.set(toolName, breaker);
|
|
560
|
-
}
|
|
561
|
-
return breaker;
|
|
562
|
-
}
|
|
563
|
-
/**
|
|
564
|
-
* Execute a function within budget constraints (bulkhead + circuit breaker).
|
|
565
|
-
*/
|
|
566
|
-
async execute(toolName, fn) {
|
|
567
|
-
const bh = this.getBulkhead(toolName);
|
|
568
|
-
const breaker = this.getCircuitBreaker(toolName);
|
|
569
|
-
let wrapped = fn;
|
|
570
|
-
if (breaker) {
|
|
571
|
-
const prevWrapped = wrapped;
|
|
572
|
-
wrapped = () => breaker.execute(() => prevWrapped());
|
|
573
|
-
}
|
|
574
|
-
if (bh) {
|
|
575
|
-
const prevWrapped = wrapped;
|
|
576
|
-
wrapped = () => bh.execute(() => prevWrapped());
|
|
577
|
-
}
|
|
578
|
-
return wrapped();
|
|
579
|
-
}
|
|
580
|
-
/**
|
|
581
|
-
* Reset all policies for a tool (useful for testing).
|
|
582
|
-
*/
|
|
583
|
-
reset(toolName) {
|
|
584
|
-
this.bulkheads.delete(toolName);
|
|
585
|
-
this.circuitBreakers.delete(toolName);
|
|
586
|
-
this.rateLimiters.delete(toolName);
|
|
587
|
-
}
|
|
588
|
-
/**
|
|
589
|
-
* Reset all policies globally.
|
|
590
|
-
*/
|
|
591
|
-
resetAll() {
|
|
592
|
-
this.bulkheads.clear();
|
|
593
|
-
this.circuitBreakers.clear();
|
|
594
|
-
this.rateLimiters.clear();
|
|
595
|
-
}
|
|
596
|
-
};
|
|
597
|
-
|
|
598
|
-
// src/runtime/Evidence.ts
|
|
599
|
-
function buildEvidence(options) {
|
|
600
|
-
const { spec, args, result, ctx, durationMs } = options;
|
|
601
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
602
|
-
const evidence = [];
|
|
603
|
-
evidence.push({
|
|
604
|
-
type: "tool",
|
|
605
|
-
ref: `${spec.name}@${spec.version}`,
|
|
606
|
-
summary: summarizeToolCall(spec, args, result, durationMs),
|
|
607
|
-
createdAt: now
|
|
608
|
-
});
|
|
609
|
-
if (result && typeof result === "object") {
|
|
610
|
-
const urls = extractUrls(result);
|
|
611
|
-
for (const url of urls) {
|
|
612
|
-
evidence.push({
|
|
613
|
-
type: "url",
|
|
614
|
-
ref: url,
|
|
615
|
-
summary: `Output URL from ${spec.name}`,
|
|
616
|
-
createdAt: now
|
|
617
|
-
});
|
|
618
|
-
}
|
|
619
|
-
const files = extractFilePaths(result);
|
|
620
|
-
for (const file of files) {
|
|
621
|
-
evidence.push({
|
|
622
|
-
type: "file",
|
|
623
|
-
ref: file,
|
|
624
|
-
summary: `Output file from ${spec.name}`,
|
|
625
|
-
createdAt: now
|
|
626
|
-
});
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
if (durationMs !== void 0 && durationMs > 0) {
|
|
630
|
-
evidence.push({
|
|
631
|
-
type: "metric",
|
|
632
|
-
ref: `latency:${spec.name}`,
|
|
633
|
-
summary: `Completed in ${durationMs}ms (request: ${ctx.requestId})`,
|
|
634
|
-
createdAt: now
|
|
635
|
-
});
|
|
636
|
-
}
|
|
637
|
-
return evidence;
|
|
638
|
-
}
|
|
639
|
-
function summarizeToolCall(spec, args, result, durationMs) {
|
|
640
|
-
const argKeys = args && typeof args === "object" ? Object.keys(args).join(", ") : "none";
|
|
641
|
-
const duration = durationMs ? ` in ${durationMs}ms` : "";
|
|
642
|
-
const resultPreview = summarizeValue(result, 100);
|
|
643
|
-
return `${spec.kind}:${spec.name} called with [${argKeys}]${duration} \u2192 ${resultPreview}`;
|
|
644
|
-
}
|
|
645
|
-
function summarizeValue(value, maxLen) {
|
|
646
|
-
if (value === null || value === void 0) return "null";
|
|
647
|
-
if (typeof value === "string") {
|
|
648
|
-
return value.length > maxLen ? value.slice(0, maxLen) + "..." : value;
|
|
649
|
-
}
|
|
650
|
-
const str = JSON.stringify(value);
|
|
651
|
-
return str.length > maxLen ? str.slice(0, maxLen) + "..." : str;
|
|
652
|
-
}
|
|
653
|
-
function extractUrls(obj) {
|
|
654
|
-
const urls = [];
|
|
655
|
-
const walk = (val) => {
|
|
656
|
-
if (typeof val === "string" && /^https?:\/\//i.test(val)) {
|
|
657
|
-
urls.push(val);
|
|
658
|
-
} else if (val && typeof val === "object") {
|
|
659
|
-
for (const v of Object.values(val)) {
|
|
660
|
-
walk(v);
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
};
|
|
664
|
-
walk(obj);
|
|
665
|
-
return urls.slice(0, 10);
|
|
666
|
-
}
|
|
667
|
-
function extractFilePaths(obj) {
|
|
668
|
-
const paths = [];
|
|
669
|
-
const walk = (val) => {
|
|
670
|
-
if (typeof val === "string" && (val.startsWith("/") || val.startsWith("./")) && val.includes(".")) {
|
|
671
|
-
paths.push(val);
|
|
672
|
-
} else if (val && typeof val === "object") {
|
|
673
|
-
for (const v of Object.values(val)) {
|
|
674
|
-
walk(v);
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
};
|
|
678
|
-
walk(obj);
|
|
679
|
-
return paths.slice(0, 10);
|
|
680
|
-
}
|
|
681
|
-
var EventLog = class {
|
|
682
|
-
entries = [];
|
|
683
|
-
seq = 0;
|
|
684
|
-
maxEntries;
|
|
685
|
-
emitter = new eventemitter3.EventEmitter();
|
|
686
|
-
constructor(options = {}) {
|
|
687
|
-
this.maxEntries = options.maxEntries ?? 1e4;
|
|
688
|
-
}
|
|
689
|
-
/**
|
|
690
|
-
* Append an event to the log.
|
|
691
|
-
*/
|
|
692
|
-
append(event) {
|
|
693
|
-
const entry = { seq: ++this.seq, event };
|
|
694
|
-
this.entries.push(entry);
|
|
695
|
-
if (this.entries.length > this.maxEntries) {
|
|
696
|
-
this.entries.shift();
|
|
697
|
-
}
|
|
698
|
-
this.emitter.emit("event", entry);
|
|
699
|
-
this.emitter.emit(event.type, entry);
|
|
700
|
-
return entry;
|
|
701
|
-
}
|
|
702
|
-
/**
|
|
703
|
-
* Subscribe to all events.
|
|
704
|
-
*/
|
|
705
|
-
on(listener) {
|
|
706
|
-
this.emitter.on("event", listener);
|
|
707
|
-
return () => this.emitter.off("event", listener);
|
|
708
|
-
}
|
|
709
|
-
/**
|
|
710
|
-
* Subscribe to events of a specific type.
|
|
711
|
-
*/
|
|
712
|
-
onType(type, listener) {
|
|
713
|
-
this.emitter.on(type, listener);
|
|
714
|
-
return () => this.emitter.off(type, listener);
|
|
715
|
-
}
|
|
716
|
-
/**
|
|
717
|
-
* Query events by filter.
|
|
718
|
-
*/
|
|
719
|
-
query(filter) {
|
|
720
|
-
let results = this.entries;
|
|
721
|
-
if (filter.since !== void 0) {
|
|
722
|
-
results = results.filter((e) => e.seq > filter.since);
|
|
723
|
-
}
|
|
724
|
-
if (filter.type) {
|
|
725
|
-
results = results.filter((e) => e.event.type === filter.type);
|
|
726
|
-
}
|
|
727
|
-
if (filter.toolName) {
|
|
728
|
-
results = results.filter((e) => e.event.toolName === filter.toolName);
|
|
729
|
-
}
|
|
730
|
-
if (filter.requestId) {
|
|
731
|
-
results = results.filter((e) => e.event.requestId === filter.requestId);
|
|
732
|
-
}
|
|
733
|
-
if (filter.limit) {
|
|
734
|
-
results = results.slice(-filter.limit);
|
|
735
|
-
}
|
|
736
|
-
return results;
|
|
737
|
-
}
|
|
738
|
-
/**
|
|
739
|
-
* Get all entries.
|
|
740
|
-
*/
|
|
741
|
-
getAll() {
|
|
742
|
-
return this.entries;
|
|
743
|
-
}
|
|
744
|
-
/**
|
|
745
|
-
* Get entry count.
|
|
746
|
-
*/
|
|
747
|
-
get size() {
|
|
748
|
-
return this.entries.length;
|
|
749
|
-
}
|
|
750
|
-
/**
|
|
751
|
-
* Clear all entries (for testing).
|
|
752
|
-
*/
|
|
753
|
-
clear() {
|
|
754
|
-
this.entries.length = 0;
|
|
755
|
-
this.seq = 0;
|
|
756
|
-
}
|
|
757
|
-
};
|
|
758
|
-
|
|
759
|
-
// src/observability/Logger.ts
|
|
760
|
-
var LEVEL_ORDER = {
|
|
761
|
-
silent: 0,
|
|
762
|
-
error: 1,
|
|
763
|
-
warn: 2,
|
|
764
|
-
info: 3,
|
|
765
|
-
debug: 4,
|
|
766
|
-
trace: 5
|
|
767
|
-
};
|
|
768
|
-
function createLogger(options = {}) {
|
|
769
|
-
const resolved = resolveDebugOptions(options);
|
|
770
|
-
const log = (level, message, meta) => {
|
|
771
|
-
if (!resolved.enabled) return;
|
|
772
|
-
if (LEVEL_ORDER[level] > LEVEL_ORDER[resolved.level]) return;
|
|
773
|
-
const prefix = `[${resolved.prefix}]`;
|
|
774
|
-
const levelTag = `[${level.toUpperCase()}]`;
|
|
775
|
-
const metaText = meta ? ` ${safeStringify(meta, 1e3)}` : "";
|
|
776
|
-
switch (level) {
|
|
777
|
-
case "error":
|
|
778
|
-
console.error(`${prefix} ${levelTag} ${message}${metaText}`);
|
|
779
|
-
break;
|
|
780
|
-
case "warn":
|
|
781
|
-
console.warn(`${prefix} ${levelTag} ${message}${metaText}`);
|
|
782
|
-
break;
|
|
783
|
-
case "info":
|
|
784
|
-
console.info(`${prefix} ${levelTag} ${message}${metaText}`);
|
|
785
|
-
break;
|
|
786
|
-
default:
|
|
787
|
-
console.log(`${prefix} ${levelTag} ${message}${metaText}`);
|
|
788
|
-
break;
|
|
789
|
-
}
|
|
790
|
-
};
|
|
791
|
-
return {
|
|
792
|
-
options: resolved,
|
|
793
|
-
isEnabled: (level) => resolved.enabled && LEVEL_ORDER[level] <= LEVEL_ORDER[resolved.level],
|
|
794
|
-
error: (message, meta) => log("error", message, meta),
|
|
795
|
-
warn: (message, meta) => log("warn", message, meta),
|
|
796
|
-
info: (message, meta) => log("info", message, meta),
|
|
797
|
-
debug: (message, meta) => log("debug", message, meta),
|
|
798
|
-
trace: (message, meta) => log("trace", message, meta)
|
|
799
|
-
};
|
|
800
|
-
}
|
|
801
|
-
function resolveDebugOptions(options = {}) {
|
|
802
|
-
const envLevel = parseEnvLogLevel();
|
|
803
|
-
const enabledFromEnv = envLevel !== void 0 && envLevel !== "silent";
|
|
804
|
-
const enabled = options.enabled ?? enabledFromEnv ?? false;
|
|
805
|
-
const level = options.level ?? envLevel ?? (enabled ? "debug" : "silent");
|
|
806
|
-
return {
|
|
807
|
-
enabled,
|
|
808
|
-
level,
|
|
809
|
-
includeArgs: options.includeArgs ?? false,
|
|
810
|
-
includeResults: options.includeResults ?? false,
|
|
811
|
-
includeRaw: options.includeRaw ?? false,
|
|
812
|
-
logEvents: options.logEvents ?? false,
|
|
813
|
-
prefix: options.prefix ?? "agent-tool"
|
|
814
|
-
};
|
|
815
|
-
}
|
|
816
|
-
function sanitizeForLog(value, maxLen = 500) {
|
|
817
|
-
const str = safeStringify(value, maxLen);
|
|
818
|
-
return str.replace(
|
|
819
|
-
/"(password|token|secret|key|auth)":\s*"[^"]*"/gi,
|
|
820
|
-
'"$1":"[REDACTED]"'
|
|
821
|
-
);
|
|
822
|
-
}
|
|
823
|
-
function summarizeForLog(value, maxLen = 200) {
|
|
824
|
-
if (value === null) return "null";
|
|
825
|
-
if (value === void 0) return "undefined";
|
|
826
|
-
if (typeof value === "string") {
|
|
827
|
-
return value.length > maxLen ? `${value.slice(0, maxLen)}...` : value;
|
|
828
|
-
}
|
|
829
|
-
if (typeof value === "number" || typeof value === "boolean") {
|
|
830
|
-
return String(value);
|
|
831
|
-
}
|
|
832
|
-
if (Array.isArray(value)) {
|
|
833
|
-
return `Array(${value.length})`;
|
|
834
|
-
}
|
|
835
|
-
if (typeof value === "object") {
|
|
836
|
-
const keys = Object.keys(value);
|
|
837
|
-
const shown = keys.slice(0, 5).join(", ");
|
|
838
|
-
return `Object(keys: ${shown}${keys.length > 5 ? ", ..." : ""})`;
|
|
839
|
-
}
|
|
840
|
-
return String(value);
|
|
841
|
-
}
|
|
842
|
-
function safeStringify(value, maxLen) {
|
|
843
|
-
try {
|
|
844
|
-
const json = JSON.stringify(value);
|
|
845
|
-
if (!json) return String(value);
|
|
846
|
-
return json.length > maxLen ? `${json.slice(0, maxLen)}...` : json;
|
|
847
|
-
} catch {
|
|
848
|
-
const fallback = String(value);
|
|
849
|
-
return fallback.length > maxLen ? `${fallback.slice(0, maxLen)}...` : fallback;
|
|
850
|
-
}
|
|
851
|
-
}
|
|
852
|
-
function parseEnvLogLevel() {
|
|
853
|
-
const raw = process.env.TOOLHUB_LOG_LEVEL ?? process.env.TOOLHUB_DEBUG ?? process.env.DEBUG;
|
|
854
|
-
if (!raw) return void 0;
|
|
855
|
-
const value = raw.trim().toLowerCase();
|
|
856
|
-
if (!value || value === "0" || value === "false" || value === "off") {
|
|
857
|
-
return "silent";
|
|
858
|
-
}
|
|
859
|
-
if (value.includes("trace")) return "trace";
|
|
860
|
-
if (value.includes("debug") || value === "1" || value === "true" || value === "yes") {
|
|
861
|
-
return "debug";
|
|
862
|
-
}
|
|
863
|
-
if (value.includes("info")) return "info";
|
|
864
|
-
if (value.includes("warn")) return "warn";
|
|
865
|
-
if (value.includes("error")) return "error";
|
|
866
|
-
if (value.includes("silent")) return "silent";
|
|
867
|
-
return "debug";
|
|
868
|
-
}
|
|
869
|
-
|
|
870
|
-
// src/observability/Metrics.ts
|
|
871
|
-
var Metrics = class {
|
|
872
|
-
counters = /* @__PURE__ */ new Map();
|
|
873
|
-
histograms = /* @__PURE__ */ new Map();
|
|
874
|
-
defaultBuckets = [
|
|
875
|
-
5,
|
|
876
|
-
10,
|
|
877
|
-
25,
|
|
878
|
-
50,
|
|
879
|
-
100,
|
|
880
|
-
250,
|
|
881
|
-
500,
|
|
882
|
-
1e3,
|
|
883
|
-
2500,
|
|
884
|
-
5e3,
|
|
885
|
-
1e4
|
|
886
|
-
];
|
|
887
|
-
/**
|
|
888
|
-
* Increment a counter.
|
|
889
|
-
*/
|
|
890
|
-
increment(name, labels = {}, value = 1) {
|
|
891
|
-
const key = this.makeKey(name, labels);
|
|
892
|
-
this.counters.set(key, (this.counters.get(key) ?? 0) + value);
|
|
893
|
-
}
|
|
894
|
-
/**
|
|
895
|
-
* Record a value in a histogram.
|
|
896
|
-
*/
|
|
897
|
-
observe(name, labels, value) {
|
|
898
|
-
const key = this.makeKey(name, labels);
|
|
899
|
-
let hist = this.histograms.get(key);
|
|
900
|
-
if (!hist) {
|
|
901
|
-
hist = { count: 0, sum: 0, values: [] };
|
|
902
|
-
this.histograms.set(key, hist);
|
|
903
|
-
}
|
|
904
|
-
hist.count++;
|
|
905
|
-
hist.sum += value;
|
|
906
|
-
hist.values.push(value);
|
|
907
|
-
}
|
|
908
|
-
/**
|
|
909
|
-
* Get a counter value.
|
|
910
|
-
*/
|
|
911
|
-
getCounter(name, labels = {}) {
|
|
912
|
-
return this.counters.get(this.makeKey(name, labels)) ?? 0;
|
|
913
|
-
}
|
|
914
|
-
/**
|
|
915
|
-
* Get histogram stats.
|
|
916
|
-
*/
|
|
917
|
-
getHistogram(name, labels) {
|
|
918
|
-
const key = this.makeKey(name, labels);
|
|
919
|
-
const hist = this.histograms.get(key);
|
|
920
|
-
if (!hist) return void 0;
|
|
921
|
-
const buckets = /* @__PURE__ */ new Map();
|
|
922
|
-
for (const bound of this.defaultBuckets) {
|
|
923
|
-
buckets.set(bound, hist.values.filter((v) => v <= bound).length);
|
|
924
|
-
}
|
|
925
|
-
return { name, labels, count: hist.count, sum: hist.sum, buckets };
|
|
926
|
-
}
|
|
927
|
-
/**
|
|
928
|
-
* Get all counter values.
|
|
929
|
-
*/
|
|
930
|
-
getAllCounters() {
|
|
931
|
-
const results = [];
|
|
932
|
-
for (const [key, value] of this.counters) {
|
|
933
|
-
const { name, labels } = this.parseKey(key);
|
|
934
|
-
results.push({ name, labels, value });
|
|
935
|
-
}
|
|
936
|
-
return results;
|
|
937
|
-
}
|
|
938
|
-
/**
|
|
939
|
-
* Get all histogram values.
|
|
940
|
-
*/
|
|
941
|
-
getAllHistograms() {
|
|
942
|
-
const results = [];
|
|
943
|
-
for (const [key, hist] of this.histograms) {
|
|
944
|
-
const { name, labels } = this.parseKey(key);
|
|
945
|
-
const buckets = /* @__PURE__ */ new Map();
|
|
946
|
-
for (const bound of this.defaultBuckets) {
|
|
947
|
-
buckets.set(bound, hist.values.filter((v) => v <= bound).length);
|
|
948
|
-
}
|
|
949
|
-
results.push({ name, labels, count: hist.count, sum: hist.sum, buckets });
|
|
950
|
-
}
|
|
951
|
-
return results;
|
|
952
|
-
}
|
|
953
|
-
/**
|
|
954
|
-
* Record standard tool invocation metrics.
|
|
955
|
-
*/
|
|
956
|
-
recordInvocation(toolName, ok, durationMs) {
|
|
957
|
-
this.increment("tool_invocations_total", {
|
|
958
|
-
toolName,
|
|
959
|
-
ok: String(ok)
|
|
960
|
-
});
|
|
961
|
-
this.observe("tool_latency_ms", { toolName }, durationMs);
|
|
962
|
-
}
|
|
963
|
-
/**
|
|
964
|
-
* Record a retry event.
|
|
965
|
-
*/
|
|
966
|
-
recordRetry(toolName) {
|
|
967
|
-
this.increment("tool_retries_total", { toolName });
|
|
968
|
-
}
|
|
969
|
-
/**
|
|
970
|
-
* Record a policy denial.
|
|
971
|
-
*/
|
|
972
|
-
recordPolicyDenied(toolName, reason) {
|
|
973
|
-
this.increment("policy_denied_total", { toolName, reason });
|
|
974
|
-
}
|
|
975
|
-
/**
|
|
976
|
-
* Reset all metrics (for testing).
|
|
977
|
-
*/
|
|
978
|
-
reset() {
|
|
979
|
-
this.counters.clear();
|
|
980
|
-
this.histograms.clear();
|
|
981
|
-
}
|
|
982
|
-
makeKey(name, labels) {
|
|
983
|
-
const sortedLabels = Object.entries(labels).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => `${k}=${v}`).join(",");
|
|
984
|
-
return `${name}{${sortedLabels}}`;
|
|
985
|
-
}
|
|
986
|
-
parseKey(key) {
|
|
987
|
-
const match = key.match(/^(.+?)\{(.*)\}$/);
|
|
988
|
-
if (!match) return { name: key, labels: {} };
|
|
989
|
-
const labels = {};
|
|
990
|
-
if (match[2]) {
|
|
991
|
-
for (const part of match[2].split(",")) {
|
|
992
|
-
const [k, v] = part.split("=");
|
|
993
|
-
if (k && v !== void 0) labels[k] = v;
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
return { name: match[1], labels };
|
|
997
|
-
}
|
|
998
|
-
};
|
|
999
|
-
var Tracing = class {
|
|
1000
|
-
spans = /* @__PURE__ */ new Map();
|
|
1001
|
-
traceSpans = /* @__PURE__ */ new Map();
|
|
1002
|
-
// traceId → spanIds
|
|
1003
|
-
/**
|
|
1004
|
-
* Start a new span.
|
|
1005
|
-
*/
|
|
1006
|
-
startSpan(options) {
|
|
1007
|
-
const span = {
|
|
1008
|
-
spanId: uuid.v4(),
|
|
1009
|
-
traceId: options.traceId ?? uuid.v4(),
|
|
1010
|
-
parentSpanId: options.parentSpanId,
|
|
1011
|
-
name: options.name,
|
|
1012
|
-
startTime: Date.now(),
|
|
1013
|
-
status: "in_progress",
|
|
1014
|
-
attributes: options.attributes ?? {},
|
|
1015
|
-
events: []
|
|
1016
|
-
};
|
|
1017
|
-
this.spans.set(span.spanId, span);
|
|
1018
|
-
const traceList = this.traceSpans.get(span.traceId) ?? [];
|
|
1019
|
-
traceList.push(span.spanId);
|
|
1020
|
-
this.traceSpans.set(span.traceId, traceList);
|
|
1021
|
-
return span;
|
|
1022
|
-
}
|
|
1023
|
-
/**
|
|
1024
|
-
* End a span and calculate duration.
|
|
1025
|
-
*/
|
|
1026
|
-
endSpan(spanId, status = "ok") {
|
|
1027
|
-
const span = this.spans.get(spanId);
|
|
1028
|
-
if (!span) return void 0;
|
|
1029
|
-
span.endTime = Date.now();
|
|
1030
|
-
span.durationMs = span.endTime - span.startTime;
|
|
1031
|
-
span.status = status;
|
|
1032
|
-
return span;
|
|
1033
|
-
}
|
|
1034
|
-
/**
|
|
1035
|
-
* Add an event to a span.
|
|
1036
|
-
*/
|
|
1037
|
-
addEvent(spanId, name, attributes) {
|
|
1038
|
-
const span = this.spans.get(spanId);
|
|
1039
|
-
if (!span) return;
|
|
1040
|
-
span.events.push({ name, timestamp: Date.now(), attributes });
|
|
1041
|
-
}
|
|
1042
|
-
/**
|
|
1043
|
-
* Set attributes on a span.
|
|
1044
|
-
*/
|
|
1045
|
-
setAttributes(spanId, attributes) {
|
|
1046
|
-
const span = this.spans.get(spanId);
|
|
1047
|
-
if (!span) return;
|
|
1048
|
-
Object.assign(span.attributes, attributes);
|
|
1049
|
-
}
|
|
1050
|
-
/**
|
|
1051
|
-
* Get a span by ID.
|
|
1052
|
-
*/
|
|
1053
|
-
getSpan(spanId) {
|
|
1054
|
-
return this.spans.get(spanId);
|
|
1055
|
-
}
|
|
1056
|
-
/**
|
|
1057
|
-
* Get all spans for a trace.
|
|
1058
|
-
*/
|
|
1059
|
-
getTrace(traceId) {
|
|
1060
|
-
const spanIds = this.traceSpans.get(traceId) ?? [];
|
|
1061
|
-
return spanIds.map((id) => this.spans.get(id)).filter((s) => s !== void 0);
|
|
1062
|
-
}
|
|
1063
|
-
/**
|
|
1064
|
-
* Create a child span from a parent.
|
|
1065
|
-
*/
|
|
1066
|
-
createChildSpan(parentSpanId, name, attributes) {
|
|
1067
|
-
const parent = this.spans.get(parentSpanId);
|
|
1068
|
-
if (!parent) return void 0;
|
|
1069
|
-
return this.startSpan({
|
|
1070
|
-
name,
|
|
1071
|
-
traceId: parent.traceId,
|
|
1072
|
-
parentSpanId: parent.spanId,
|
|
1073
|
-
attributes
|
|
1074
|
-
});
|
|
1075
|
-
}
|
|
1076
|
-
/**
|
|
1077
|
-
* Clear all traces (for testing).
|
|
1078
|
-
*/
|
|
1079
|
-
clear() {
|
|
1080
|
-
this.spans.clear();
|
|
1081
|
-
this.traceSpans.clear();
|
|
1082
|
-
}
|
|
1083
|
-
};
|
|
1084
|
-
var NON_RETRYABLE_ERRORS = /* @__PURE__ */ new Set([
|
|
1085
|
-
"TOOL_NOT_FOUND",
|
|
1086
|
-
"INPUT_SCHEMA_INVALID",
|
|
1087
|
-
"POLICY_DENIED",
|
|
1088
|
-
"HITL_DENIED",
|
|
1089
|
-
"OUTPUT_SCHEMA_INVALID",
|
|
1090
|
-
"PATH_OUTSIDE_SANDBOX",
|
|
1091
|
-
"FILE_TOO_LARGE",
|
|
1092
|
-
"HTTP_DISALLOWED_HOST",
|
|
1093
|
-
"HTTP_TOO_LARGE"
|
|
1094
|
-
]);
|
|
1095
|
-
function isRetryable(error) {
|
|
1096
|
-
if (error instanceof Error) {
|
|
1097
|
-
const kind = error.kind;
|
|
1098
|
-
if (kind && NON_RETRYABLE_ERRORS.has(kind)) return false;
|
|
1099
|
-
}
|
|
1100
|
-
return true;
|
|
1101
|
-
}
|
|
1102
|
-
async function withRetry(fn, options = {}) {
|
|
1103
|
-
const {
|
|
1104
|
-
maxRetries = 2,
|
|
1105
|
-
baseDelayMs = 1e3,
|
|
1106
|
-
maxDelayMs = 1e4,
|
|
1107
|
-
jitter = 0.1,
|
|
1108
|
-
shouldRetry,
|
|
1109
|
-
onRetry
|
|
1110
|
-
} = options;
|
|
1111
|
-
if (maxRetries <= 0) {
|
|
1112
|
-
return fn();
|
|
1113
|
-
}
|
|
1114
|
-
const pRetryOptions = {
|
|
1115
|
-
retries: maxRetries,
|
|
1116
|
-
minTimeout: baseDelayMs,
|
|
1117
|
-
maxTimeout: maxDelayMs,
|
|
1118
|
-
randomize: true,
|
|
1119
|
-
factor: 2,
|
|
1120
|
-
onFailedAttempt: (error) => {
|
|
1121
|
-
if (jitter > 0 && error.retriesLeft > 0) ;
|
|
1122
|
-
if (shouldRetry && !shouldRetry(error)) {
|
|
1123
|
-
throw error;
|
|
1124
|
-
}
|
|
1125
|
-
if (!isRetryable(error)) {
|
|
1126
|
-
throw error;
|
|
1127
|
-
}
|
|
1128
|
-
onRetry?.(error, maxRetries - error.retriesLeft);
|
|
1129
|
-
}
|
|
1130
|
-
};
|
|
1131
|
-
return pRetry__default.default(fn, pRetryOptions);
|
|
1132
|
-
}
|
|
1133
|
-
function createTaggedError(kind, message, details) {
|
|
1134
|
-
const error = new Error(message);
|
|
1135
|
-
error.kind = kind;
|
|
1136
|
-
error.details = details;
|
|
1137
|
-
return error;
|
|
1138
|
-
}
|
|
1139
|
-
function resolveTool(toolName, registry) {
|
|
1140
|
-
const spec = registry.get(toolName);
|
|
1141
|
-
if (!spec) {
|
|
1142
|
-
throw createTaggedError(
|
|
1143
|
-
"TOOL_NOT_FOUND",
|
|
1144
|
-
`Tool not found: ${toolName}`,
|
|
1145
|
-
{ availableTools: registry.snapshot().slice(0, 20).map((s) => s.name) }
|
|
1146
|
-
);
|
|
1147
|
-
}
|
|
1148
|
-
return spec;
|
|
1149
|
-
}
|
|
1150
|
-
function validateInput(spec, args, validator) {
|
|
1151
|
-
try {
|
|
1152
|
-
return validator.validateOrThrow(
|
|
1153
|
-
spec.inputSchema,
|
|
1154
|
-
args,
|
|
1155
|
-
`Input validation failed for ${spec.name}`
|
|
1156
|
-
);
|
|
1157
|
-
} catch (error) {
|
|
1158
|
-
if (error instanceof SchemaValidationError) {
|
|
1159
|
-
throw createTaggedError("INPUT_SCHEMA_INVALID", error.message, {
|
|
1160
|
-
errors: error.errors,
|
|
1161
|
-
schema: spec.inputSchema
|
|
1162
|
-
});
|
|
1163
|
-
}
|
|
1164
|
-
throw error;
|
|
1165
|
-
}
|
|
1166
|
-
}
|
|
1167
|
-
function enrichDefaults(spec, args, validator) {
|
|
1168
|
-
return validator.enrichDefaults(spec.inputSchema, args);
|
|
1169
|
-
}
|
|
1170
|
-
function enforcePolicy(spec, args, ctx, deps) {
|
|
1171
|
-
try {
|
|
1172
|
-
deps.policy.enforce(spec, args, ctx);
|
|
1173
|
-
} catch (error) {
|
|
1174
|
-
if (error instanceof PolicyDeniedError) {
|
|
1175
|
-
const event = {
|
|
1176
|
-
type: "POLICY_DENIED",
|
|
1177
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1178
|
-
requestId: ctx.requestId,
|
|
1179
|
-
taskId: ctx.taskId,
|
|
1180
|
-
toolName: spec.name,
|
|
1181
|
-
traceId: ctx.traceId,
|
|
1182
|
-
userId: ctx.userId,
|
|
1183
|
-
reason: error.message,
|
|
1184
|
-
missingCapabilities: error.missingCapabilities?.map(String)
|
|
1185
|
-
};
|
|
1186
|
-
deps.eventLog.append(event);
|
|
1187
|
-
deps.metrics.recordPolicyDenied(spec.name, error.message);
|
|
1188
|
-
}
|
|
1189
|
-
throw error;
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1192
|
-
var HITL_GATED_SIDE_EFFECTS = ["external_write", "destructive"];
|
|
1193
|
-
async function requireHumanApproval(spec, args, ctx, deps) {
|
|
1194
|
-
const sideEffect = spec._meta?.hitl?.sideEffect ?? "none";
|
|
1195
|
-
if (!HITL_GATED_SIDE_EFFECTS.includes(sideEffect)) return;
|
|
1196
|
-
const onApproval = deps.onApprovalRequired;
|
|
1197
|
-
if (!onApproval) return;
|
|
1198
|
-
const baseEvent = {
|
|
1199
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1200
|
-
requestId: ctx.requestId,
|
|
1201
|
-
taskId: ctx.taskId,
|
|
1202
|
-
toolName: spec.name,
|
|
1203
|
-
traceId: ctx.traceId,
|
|
1204
|
-
userId: ctx.userId
|
|
1205
|
-
};
|
|
1206
|
-
const requested = {
|
|
1207
|
-
...baseEvent,
|
|
1208
|
-
type: "HITL_APPROVAL_REQUESTED",
|
|
1209
|
-
sideEffect
|
|
1210
|
-
};
|
|
1211
|
-
deps.eventLog.append(requested);
|
|
1212
|
-
deps.logger.trace("hitl.requested", { tool: spec.name, sideEffect, requestId: ctx.requestId });
|
|
1213
|
-
let approved;
|
|
1214
|
-
try {
|
|
1215
|
-
approved = await onApproval(spec, args, ctx);
|
|
1216
|
-
} catch (err) {
|
|
1217
|
-
deps.eventLog.append({
|
|
1218
|
-
...baseEvent,
|
|
1219
|
-
type: "HITL_APPROVAL_DENIED",
|
|
1220
|
-
sideEffect,
|
|
1221
|
-
reason: err instanceof Error ? err.message : String(err)
|
|
1222
|
-
});
|
|
1223
|
-
throw createTaggedError(
|
|
1224
|
-
"HITL_DENIED",
|
|
1225
|
-
`Human denied approval for ${spec.name} (${sideEffect})`,
|
|
1226
|
-
{ reason: err instanceof Error ? err.message : String(err) }
|
|
1227
|
-
);
|
|
1228
|
-
}
|
|
1229
|
-
if (approved === false) {
|
|
1230
|
-
deps.eventLog.append({
|
|
1231
|
-
...baseEvent,
|
|
1232
|
-
type: "HITL_APPROVAL_DENIED",
|
|
1233
|
-
sideEffect,
|
|
1234
|
-
reason: "User rejected"
|
|
1235
|
-
});
|
|
1236
|
-
throw createTaggedError("HITL_DENIED", `Human denied approval for ${spec.name} (${sideEffect})`);
|
|
1237
|
-
}
|
|
1238
|
-
deps.eventLog.append({
|
|
1239
|
-
...baseEvent,
|
|
1240
|
-
type: "HITL_APPROVAL_GRANTED",
|
|
1241
|
-
sideEffect
|
|
1242
|
-
});
|
|
1243
|
-
deps.logger.trace("hitl.granted", { tool: spec.name, sideEffect, requestId: ctx.requestId });
|
|
1244
|
-
}
|
|
1245
|
-
async function executeWithBudget(spec, args, ctx, spanId, deps) {
|
|
1246
|
-
const adapter = deps.adapters.get(spec.kind);
|
|
1247
|
-
if (!adapter) {
|
|
1248
|
-
throw createTaggedError(
|
|
1249
|
-
"TOOL_NOT_FOUND",
|
|
1250
|
-
`No adapter registered for kind: ${spec.kind}`
|
|
1251
|
-
);
|
|
1252
|
-
}
|
|
1253
|
-
const timeoutMs = deps.budget.getTimeout(
|
|
1254
|
-
spec.name,
|
|
1255
|
-
ctx.budget?.timeoutMs
|
|
1256
|
-
);
|
|
1257
|
-
const maxRetries = ctx.budget?.maxRetries ?? deps.defaultMaxRetries ?? 2;
|
|
1258
|
-
const executeFn = async () => {
|
|
1259
|
-
return deps.budget.execute(spec.name, async () => {
|
|
1260
|
-
deps.tracing.addEvent(spanId, "execute_start");
|
|
1261
|
-
deps.logger.trace("execute.start", {
|
|
1262
|
-
tool: spec.name,
|
|
1263
|
-
requestId: ctx.requestId,
|
|
1264
|
-
timeoutMs,
|
|
1265
|
-
maxRetries
|
|
1266
|
-
});
|
|
1267
|
-
const result = await adapter.invoke(spec, args, ctx);
|
|
1268
|
-
deps.tracing.addEvent(spanId, "execute_end");
|
|
1269
|
-
deps.logger.trace("execute.end", {
|
|
1270
|
-
tool: spec.name,
|
|
1271
|
-
requestId: ctx.requestId
|
|
1272
|
-
});
|
|
1273
|
-
return result;
|
|
1274
|
-
});
|
|
1275
|
-
};
|
|
1276
|
-
const retryFn = () => withRetry(executeFn, {
|
|
1277
|
-
maxRetries,
|
|
1278
|
-
onRetry: (error, attempt) => {
|
|
1279
|
-
deps.metrics.recordRetry(spec.name);
|
|
1280
|
-
const event = {
|
|
1281
|
-
type: "RETRY",
|
|
1282
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1283
|
-
requestId: ctx.requestId,
|
|
1284
|
-
taskId: ctx.taskId,
|
|
1285
|
-
toolName: spec.name,
|
|
1286
|
-
traceId: ctx.traceId,
|
|
1287
|
-
userId: ctx.userId,
|
|
1288
|
-
attempt,
|
|
1289
|
-
maxRetries,
|
|
1290
|
-
reason: error.message
|
|
1291
|
-
};
|
|
1292
|
-
deps.eventLog.append(event);
|
|
1293
|
-
deps.tracing.addEvent(spanId, "retry", { attempt, reason: error.message });
|
|
1294
|
-
}
|
|
1295
|
-
});
|
|
1296
|
-
try {
|
|
1297
|
-
return await pTimeout__default.default(retryFn(), {
|
|
1298
|
-
milliseconds: timeoutMs,
|
|
1299
|
-
message: `Tool ${spec.name} timed out after ${timeoutMs}ms`
|
|
1300
|
-
});
|
|
1301
|
-
} catch (error) {
|
|
1302
|
-
if (error instanceof Error && error.message.includes("timed out")) {
|
|
1303
|
-
throw createTaggedError("TIMEOUT", error.message);
|
|
1304
|
-
}
|
|
1305
|
-
throw error;
|
|
1306
|
-
}
|
|
1307
|
-
}
|
|
1308
|
-
function validateOutput(spec, result, validator) {
|
|
1309
|
-
try {
|
|
1310
|
-
return validator.validateOrThrow(
|
|
1311
|
-
spec.outputSchema,
|
|
1312
|
-
result,
|
|
1313
|
-
`Output validation failed for ${spec.name}`
|
|
1314
|
-
);
|
|
1315
|
-
} catch (error) {
|
|
1316
|
-
if (error instanceof SchemaValidationError) {
|
|
1317
|
-
throw createTaggedError("OUTPUT_SCHEMA_INVALID", error.message, {
|
|
1318
|
-
errors: error.errors
|
|
1319
|
-
});
|
|
1320
|
-
}
|
|
1321
|
-
throw error;
|
|
1322
|
-
}
|
|
1323
|
-
}
|
|
1324
|
-
|
|
1325
|
-
// src/runtime/PTCRuntimeObservability.ts
|
|
1326
|
-
function emitToolCalled(intent, ctx, deps) {
|
|
1327
|
-
const event = {
|
|
1328
|
-
type: "TOOL_CALLED",
|
|
1329
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1330
|
-
requestId: ctx.requestId,
|
|
1331
|
-
taskId: ctx.taskId,
|
|
1332
|
-
toolName: intent.tool,
|
|
1333
|
-
traceId: ctx.traceId,
|
|
1334
|
-
userId: ctx.userId,
|
|
1335
|
-
argsSummary: sanitizeArgs(intent.args),
|
|
1336
|
-
purpose: intent.purpose,
|
|
1337
|
-
idempotencyKey: intent.idempotencyKey
|
|
1338
|
-
};
|
|
1339
|
-
deps.eventLog.append(event);
|
|
1340
|
-
}
|
|
1341
|
-
function recordSuccess(spec, durationMs, _evidence, spanId, deps) {
|
|
1342
|
-
deps.metrics.recordInvocation(spec.name, true, durationMs);
|
|
1343
|
-
deps.tracing.setAttributes(spanId, {
|
|
1344
|
-
"tool.duration_ms": durationMs,
|
|
1345
|
-
"tool.ok": true
|
|
1346
|
-
});
|
|
1347
|
-
deps.tracing.endSpan(spanId, "ok");
|
|
1348
|
-
}
|
|
1349
|
-
function handleError(error, intent, ctx, durationMs, spanId, deps) {
|
|
1350
|
-
const kind = error?.kind ?? "UPSTREAM_ERROR";
|
|
1351
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1352
|
-
const details = error?.details;
|
|
1353
|
-
deps.metrics.recordInvocation(intent.tool, false, durationMs);
|
|
1354
|
-
deps.tracing.setAttributes(spanId, {
|
|
1355
|
-
"tool.duration_ms": durationMs,
|
|
1356
|
-
"tool.ok": false,
|
|
1357
|
-
"tool.error_kind": kind
|
|
1358
|
-
});
|
|
1359
|
-
deps.tracing.endSpan(spanId, "error");
|
|
1360
|
-
const event = {
|
|
1361
|
-
type: "TOOL_RESULT",
|
|
1362
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1363
|
-
requestId: ctx.requestId,
|
|
1364
|
-
taskId: ctx.taskId,
|
|
1365
|
-
toolName: intent.tool,
|
|
1366
|
-
traceId: ctx.traceId,
|
|
1367
|
-
userId: ctx.userId,
|
|
1368
|
-
ok: false,
|
|
1369
|
-
durationMs,
|
|
1370
|
-
resultSummary: message,
|
|
1371
|
-
evidence: [],
|
|
1372
|
-
error: { kind, message, details }
|
|
1373
|
-
};
|
|
1374
|
-
deps.eventLog.append(event);
|
|
1375
|
-
deps.logger.warn("invoke.error", {
|
|
1376
|
-
tool: intent.tool,
|
|
1377
|
-
requestId: ctx.requestId,
|
|
1378
|
-
taskId: ctx.taskId,
|
|
1379
|
-
traceId: ctx.traceId,
|
|
1380
|
-
kind,
|
|
1381
|
-
message,
|
|
1382
|
-
durationMs,
|
|
1383
|
-
details: deps.logger.options.includeResults ? summarizeForLog(details) : void 0
|
|
1384
|
-
});
|
|
1385
|
-
return {
|
|
1386
|
-
ok: false,
|
|
1387
|
-
evidence: [],
|
|
1388
|
-
error: { kind, message, details }
|
|
1389
|
-
};
|
|
1390
|
-
}
|
|
1391
|
-
function sanitizeArgs(args) {
|
|
1392
|
-
if (!args) return "{}";
|
|
1393
|
-
return sanitizeForLog(args);
|
|
1394
|
-
}
|
|
1395
|
-
|
|
1396
|
-
// src/runtime/PTCRuntime.ts
|
|
1397
|
-
var PTCRuntime = class {
|
|
1398
|
-
registry;
|
|
1399
|
-
adapters = /* @__PURE__ */ new Map();
|
|
1400
|
-
validator;
|
|
1401
|
-
policy;
|
|
1402
|
-
budget;
|
|
1403
|
-
eventLog;
|
|
1404
|
-
metrics;
|
|
1405
|
-
tracing;
|
|
1406
|
-
config;
|
|
1407
|
-
logger;
|
|
1408
|
-
constructor(options = {}) {
|
|
1409
|
-
this.config = options.config ?? {};
|
|
1410
|
-
this.registry = options.registry ?? new ToolRegistry();
|
|
1411
|
-
this.validator = options.validator ?? new SchemaValidator();
|
|
1412
|
-
this.policy = options.policy ?? new PolicyEngine(this.config.policy);
|
|
1413
|
-
this.budget = options.budget ?? new BudgetManager(this.config.budget);
|
|
1414
|
-
this.eventLog = options.eventLog ?? new EventLog();
|
|
1415
|
-
this.metrics = options.metrics ?? new Metrics();
|
|
1416
|
-
this.tracing = options.tracing ?? new Tracing();
|
|
1417
|
-
this.logger = createLogger({ ...this.config.debug, prefix: "PTCRuntime" });
|
|
1418
|
-
if (this.logger.options.logEvents) {
|
|
1419
|
-
this.eventLog.on((entry) => {
|
|
1420
|
-
const event = entry.event;
|
|
1421
|
-
this.logger.debug("event", {
|
|
1422
|
-
seq: entry.seq,
|
|
1423
|
-
type: event.type,
|
|
1424
|
-
toolName: event.toolName,
|
|
1425
|
-
requestId: event.requestId,
|
|
1426
|
-
taskId: event.taskId,
|
|
1427
|
-
ok: "ok" in event ? event.ok : void 0
|
|
1428
|
-
});
|
|
1429
|
-
});
|
|
1430
|
-
}
|
|
1431
|
-
}
|
|
1432
|
-
/**
|
|
1433
|
-
* Register an adapter for a tool kind.
|
|
1434
|
-
*/
|
|
1435
|
-
registerAdapter(adapter) {
|
|
1436
|
-
this.adapters.set(adapter.kind, adapter);
|
|
1437
|
-
}
|
|
1438
|
-
/**
|
|
1439
|
-
* Get an adapter by kind (e.g. "mcp"). Use to set MCP client via adapter.setClient().
|
|
1440
|
-
*/
|
|
1441
|
-
getAdapter(kind) {
|
|
1442
|
-
return this.adapters.get(kind);
|
|
1443
|
-
}
|
|
1444
|
-
/**
|
|
1445
|
-
* Get the tool registry.
|
|
1446
|
-
*/
|
|
1447
|
-
getRegistry() {
|
|
1448
|
-
return this.registry;
|
|
1449
|
-
}
|
|
1450
|
-
/**
|
|
1451
|
-
* Get the event log.
|
|
1452
|
-
*/
|
|
1453
|
-
getEventLog() {
|
|
1454
|
-
return this.eventLog;
|
|
1455
|
-
}
|
|
1456
|
-
/**
|
|
1457
|
-
* Get the metrics collector.
|
|
1458
|
-
*/
|
|
1459
|
-
getMetrics() {
|
|
1460
|
-
return this.metrics;
|
|
1461
|
-
}
|
|
1462
|
-
/**
|
|
1463
|
-
* Get the tracing system.
|
|
1464
|
-
*/
|
|
1465
|
-
getTracing() {
|
|
1466
|
-
return this.tracing;
|
|
1467
|
-
}
|
|
1468
|
-
/**
|
|
1469
|
-
* Invoke a tool through the PTC pipeline.
|
|
1470
|
-
* Never throws - always returns a structured ToolResult.
|
|
1471
|
-
*/
|
|
1472
|
-
async invoke(intent, ctx) {
|
|
1473
|
-
const startTime = Date.now();
|
|
1474
|
-
if (this.logger.isEnabled("debug")) {
|
|
1475
|
-
this.logger.debug("invoke.start", {
|
|
1476
|
-
tool: intent.tool,
|
|
1477
|
-
requestId: ctx.requestId,
|
|
1478
|
-
taskId: ctx.taskId,
|
|
1479
|
-
traceId: ctx.traceId,
|
|
1480
|
-
purpose: intent.purpose,
|
|
1481
|
-
args: this.logger.options.includeArgs ? sanitizeForLog(intent.args) : void 0
|
|
1482
|
-
});
|
|
1483
|
-
}
|
|
1484
|
-
const span = this.tracing.startSpan({
|
|
1485
|
-
name: `tool:${intent.tool}`,
|
|
1486
|
-
traceId: ctx.traceId,
|
|
1487
|
-
attributes: {
|
|
1488
|
-
"tool.name": intent.tool,
|
|
1489
|
-
"tool.purpose": intent.purpose,
|
|
1490
|
-
requestId: ctx.requestId,
|
|
1491
|
-
taskId: ctx.taskId
|
|
1492
|
-
}
|
|
1493
|
-
});
|
|
1494
|
-
emitToolCalled(intent, ctx, this.getObservabilityDeps());
|
|
1495
|
-
try {
|
|
1496
|
-
const spec = resolveTool(intent.tool, this.registry);
|
|
1497
|
-
this.tracing.addEvent(span.spanId, "resolved", {
|
|
1498
|
-
kind: spec.kind,
|
|
1499
|
-
version: spec.version
|
|
1500
|
-
});
|
|
1501
|
-
const validatedArgs = validateInput(spec, intent.args, this.validator);
|
|
1502
|
-
const enrichedArgs = enrichDefaults(spec, validatedArgs, this.validator);
|
|
1503
|
-
enforcePolicy(spec, enrichedArgs, ctx, {
|
|
1504
|
-
policy: this.policy,
|
|
1505
|
-
eventLog: this.eventLog,
|
|
1506
|
-
metrics: this.metrics,
|
|
1507
|
-
tracing: this.tracing
|
|
1508
|
-
});
|
|
1509
|
-
if (!this.budget.checkRateLimit(spec.name)) {
|
|
1510
|
-
throw createTaggedError(
|
|
1511
|
-
"BUDGET_EXCEEDED",
|
|
1512
|
-
`Rate limit exceeded for tool: ${spec.name}`
|
|
1513
|
-
);
|
|
1514
|
-
}
|
|
1515
|
-
await requireHumanApproval(spec, enrichedArgs, ctx, {
|
|
1516
|
-
onApprovalRequired: this.config.onApprovalRequired,
|
|
1517
|
-
eventLog: this.eventLog,
|
|
1518
|
-
logger: this.logger
|
|
1519
|
-
});
|
|
1520
|
-
if (ctx.dryRun) {
|
|
1521
|
-
return this.buildDryRunResult(spec, enrichedArgs, ctx, startTime, span.spanId);
|
|
1522
|
-
}
|
|
1523
|
-
const { result, raw } = await executeWithBudget(
|
|
1524
|
-
spec,
|
|
1525
|
-
enrichedArgs,
|
|
1526
|
-
ctx,
|
|
1527
|
-
span.spanId,
|
|
1528
|
-
this.getPipelineDeps()
|
|
1529
|
-
);
|
|
1530
|
-
const validatedOutput = validateOutput(spec, result, this.validator);
|
|
1531
|
-
const durationMs = Date.now() - startTime;
|
|
1532
|
-
const builtEvidence = buildEvidence({
|
|
1533
|
-
spec,
|
|
1534
|
-
args: enrichedArgs,
|
|
1535
|
-
result: validatedOutput,
|
|
1536
|
-
raw,
|
|
1537
|
-
ctx,
|
|
1538
|
-
durationMs
|
|
1539
|
-
});
|
|
1540
|
-
const adapterEvidence = raw && typeof raw === "object" && Array.isArray(raw.evidence) ? raw.evidence : [];
|
|
1541
|
-
const evidence = [...adapterEvidence, ...builtEvidence];
|
|
1542
|
-
recordSuccess(spec, durationMs, evidence, span.spanId, this.getObservabilityDeps());
|
|
1543
|
-
if (this.logger.isEnabled("debug")) {
|
|
1544
|
-
this.logger.debug("invoke.ok", {
|
|
1545
|
-
tool: spec.name,
|
|
1546
|
-
durationMs,
|
|
1547
|
-
result: this.logger.options.includeResults ? summarizeForLog(validatedOutput) : void 0,
|
|
1548
|
-
raw: this.logger.options.includeRaw ? summarizeForLog(raw) : void 0
|
|
1549
|
-
});
|
|
1550
|
-
}
|
|
1551
|
-
return {
|
|
1552
|
-
ok: true,
|
|
1553
|
-
result: validatedOutput,
|
|
1554
|
-
evidence,
|
|
1555
|
-
raw: this.config.includeRaw !== false ? raw : void 0
|
|
1556
|
-
};
|
|
1557
|
-
} catch (error) {
|
|
1558
|
-
const durationMs = Date.now() - startTime;
|
|
1559
|
-
return handleError(error, intent, ctx, durationMs, span.spanId, this.getObservabilityDeps());
|
|
1560
|
-
}
|
|
1561
|
-
}
|
|
1562
|
-
/**
|
|
1563
|
-
* Search for tools in the registry.
|
|
1564
|
-
*/
|
|
1565
|
-
searchTools(query, filters) {
|
|
1566
|
-
return this.registry.search({
|
|
1567
|
-
text: query,
|
|
1568
|
-
kind: filters?.kind,
|
|
1569
|
-
capabilities: filters?.capabilities,
|
|
1570
|
-
tags: filters?.tags
|
|
1571
|
-
});
|
|
1572
|
-
}
|
|
1573
|
-
/**
|
|
1574
|
-
* Get the schema for a tool.
|
|
1575
|
-
*/
|
|
1576
|
-
getToolSchema(toolName) {
|
|
1577
|
-
const spec = this.registry.get(toolName);
|
|
1578
|
-
if (!spec) return void 0;
|
|
1579
|
-
return { input: spec.inputSchema, output: spec.outputSchema };
|
|
1580
|
-
}
|
|
1581
|
-
// --- Helper Methods ---
|
|
1582
|
-
getPipelineDeps() {
|
|
1583
|
-
return {
|
|
1584
|
-
registry: this.registry,
|
|
1585
|
-
adapters: this.adapters,
|
|
1586
|
-
validator: this.validator,
|
|
1587
|
-
policy: this.policy,
|
|
1588
|
-
budget: this.budget,
|
|
1589
|
-
eventLog: this.eventLog,
|
|
1590
|
-
metrics: this.metrics,
|
|
1591
|
-
tracing: this.tracing,
|
|
1592
|
-
logger: this.logger,
|
|
1593
|
-
defaultMaxRetries: this.config.defaultMaxRetries,
|
|
1594
|
-
onApprovalRequired: this.config.onApprovalRequired
|
|
1595
|
-
};
|
|
1596
|
-
}
|
|
1597
|
-
getObservabilityDeps() {
|
|
1598
|
-
return {
|
|
1599
|
-
eventLog: this.eventLog,
|
|
1600
|
-
metrics: this.metrics,
|
|
1601
|
-
tracing: this.tracing,
|
|
1602
|
-
logger: this.logger
|
|
1603
|
-
};
|
|
1604
|
-
}
|
|
1605
|
-
buildDryRunResult(spec, args, _ctx, startTime, spanId) {
|
|
1606
|
-
this.tracing.endSpan(spanId, "ok");
|
|
1607
|
-
return {
|
|
1608
|
-
ok: true,
|
|
1609
|
-
result: {
|
|
1610
|
-
dryRun: true,
|
|
1611
|
-
tool: spec.name,
|
|
1612
|
-
kind: spec.kind,
|
|
1613
|
-
args,
|
|
1614
|
-
capabilities: spec.capabilities
|
|
1615
|
-
},
|
|
1616
|
-
evidence: [
|
|
1617
|
-
{
|
|
1618
|
-
type: "tool",
|
|
1619
|
-
ref: `${spec.name}@${spec.version}`,
|
|
1620
|
-
summary: `Dry-run: would execute ${spec.kind}:${spec.name}`,
|
|
1621
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1622
|
-
}
|
|
1623
|
-
]
|
|
1624
|
-
};
|
|
1625
|
-
}
|
|
1626
|
-
};
|
|
1627
|
-
|
|
1628
|
-
// src/toolDescriptor.ts
|
|
1629
|
-
var NPM_TOOL_DESCRIPTOR_REGEX = /^npm:(@[\w.-]+\/[\w.-]+)#(.+)$/;
|
|
1630
|
-
function isNpmToolDescriptor(descriptor) {
|
|
1631
|
-
return NPM_TOOL_DESCRIPTOR_REGEX.test(descriptor.trim());
|
|
1632
|
-
}
|
|
1633
|
-
function parseNpmToolDescriptor(descriptor) {
|
|
1634
|
-
const s = descriptor.trim();
|
|
1635
|
-
const m = s.match(NPM_TOOL_DESCRIPTOR_REGEX);
|
|
1636
|
-
if (!m) return null;
|
|
1637
|
-
return { fullPackage: m[1], toolPath: m[2] };
|
|
1638
|
-
}
|
|
1639
|
-
var KNOWN_PACKAGE_PREFIX = {
|
|
1640
|
-
"@easynet/agent-tool-builtin-tools": "core/",
|
|
1641
|
-
"@easynet/agent-tool-buildin-tools": "core/",
|
|
1642
|
-
// alias (e.g. npm:@easynet/agent-tool-buildin#fs.readText)
|
|
1643
|
-
"@easynet/agent-tool-buildin": "core/",
|
|
1644
|
-
// shorthand
|
|
1645
|
-
"@easynet/agent-tool-example-tools": "example/"
|
|
1646
|
-
};
|
|
1647
|
-
function resolveNpmToolDescriptor(descriptor) {
|
|
1648
|
-
const parsed = parseNpmToolDescriptor(descriptor);
|
|
1649
|
-
if (!parsed) return null;
|
|
1650
|
-
const prefix = KNOWN_PACKAGE_PREFIX[parsed.fullPackage];
|
|
1651
|
-
if (!prefix) return null;
|
|
1652
|
-
const path = parsed.toolPath;
|
|
1653
|
-
if (path.startsWith(prefix)) return path;
|
|
1654
|
-
return prefix + path;
|
|
1655
|
-
}
|
|
1656
|
-
function resolveToolDescriptor(descriptor) {
|
|
1657
|
-
const s = descriptor.trim();
|
|
1658
|
-
const resolved = resolveNpmToolDescriptor(s);
|
|
1659
|
-
if (resolved !== null) return resolved;
|
|
1660
|
-
return s;
|
|
1661
|
-
}
|
|
1662
|
-
function normalizeToolList(descriptors) {
|
|
1663
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1664
|
-
const out = [];
|
|
1665
|
-
for (const d of descriptors) {
|
|
1666
|
-
if (typeof d !== "string" || !d.trim()) continue;
|
|
1667
|
-
const name = resolveToolDescriptor(d);
|
|
1668
|
-
if (!seen.has(name)) {
|
|
1669
|
-
seen.add(name);
|
|
1670
|
-
out.push(name);
|
|
1671
|
-
}
|
|
1672
|
-
}
|
|
1673
|
-
return out;
|
|
1674
|
-
}
|
|
1675
|
-
function isCursorFormat(obj) {
|
|
1676
|
-
return typeof obj === "object" && obj !== null && "mcpServers" in obj && typeof obj.mcpServers === "object" && obj.mcpServers !== null;
|
|
1677
|
-
}
|
|
1678
|
-
function extractMCPConfig(parsed, toolName) {
|
|
1679
|
-
if (isCursorFormat(parsed)) {
|
|
1680
|
-
const servers = parsed.mcpServers;
|
|
1681
|
-
const keys = Object.keys(servers);
|
|
1682
|
-
if (keys.length === 0) {
|
|
1683
|
-
return {};
|
|
1684
|
-
}
|
|
1685
|
-
const name = toolName && keys.includes(toolName) ? toolName : keys[0];
|
|
1686
|
-
return servers[name];
|
|
1687
|
-
}
|
|
1688
|
-
return parsed;
|
|
1689
|
-
}
|
|
1690
|
-
async function loadMCPTool(dirPath, manifest) {
|
|
1691
|
-
const mcpPath = path.join(dirPath, manifest.entryPoint ?? "mcp.json");
|
|
1692
|
-
let raw;
|
|
1693
|
-
try {
|
|
1694
|
-
raw = await promises.readFile(mcpPath, "utf-8");
|
|
1695
|
-
} catch (err) {
|
|
1696
|
-
throw new chunkZ7TGIG77_cjs.DiscoveryError(
|
|
1697
|
-
dirPath,
|
|
1698
|
-
"load",
|
|
1699
|
-
`Failed to read MCP config: ${mcpPath}`,
|
|
1700
|
-
err
|
|
1701
|
-
);
|
|
1702
|
-
}
|
|
1703
|
-
let parsed;
|
|
1704
|
-
try {
|
|
1705
|
-
parsed = JSON.parse(raw);
|
|
1706
|
-
} catch (err) {
|
|
1707
|
-
throw new chunkZ7TGIG77_cjs.DiscoveryError(
|
|
1708
|
-
dirPath,
|
|
1709
|
-
"load",
|
|
1710
|
-
`Invalid JSON in ${mcpPath}`,
|
|
1711
|
-
err
|
|
1712
|
-
);
|
|
1713
|
-
}
|
|
1714
|
-
const baseName = manifest.name?.split("/").pop();
|
|
1715
|
-
const config = extractMCPConfig(parsed, baseName);
|
|
1716
|
-
if (!config.command && !config.url) {
|
|
1717
|
-
throw new chunkZ7TGIG77_cjs.DiscoveryError(
|
|
1718
|
-
dirPath,
|
|
1719
|
-
"validate",
|
|
1720
|
-
`mcp.json must have either "command" or "url" field`
|
|
1721
|
-
);
|
|
1722
|
-
}
|
|
1723
|
-
return { manifest, dirPath, mcpConfig: config };
|
|
1724
|
-
}
|
|
1725
|
-
var DEFAULT_EXTENSIONS = [".js", ".mjs"];
|
|
1726
|
-
async function resolveEntryPoint(dirPath, baseName, extensions = DEFAULT_EXTENSIONS) {
|
|
1727
|
-
if (extensions.some((ext) => baseName.endsWith(ext))) {
|
|
1728
|
-
const fullPath = path.join(dirPath, baseName);
|
|
1729
|
-
await promises.stat(fullPath);
|
|
1730
|
-
return fullPath;
|
|
1731
|
-
}
|
|
1732
|
-
for (const ext of extensions) {
|
|
1733
|
-
const fullPath = path.join(dirPath, `${baseName}${ext}`);
|
|
1734
|
-
try {
|
|
1735
|
-
await promises.stat(fullPath);
|
|
1736
|
-
return fullPath;
|
|
1737
|
-
} catch {
|
|
1738
|
-
}
|
|
1739
|
-
}
|
|
1740
|
-
throw new Error(
|
|
1741
|
-
`Could not find entry point in ${dirPath}. Tried: ${extensions.map((e) => baseName + e).join(", ")}`
|
|
1742
|
-
);
|
|
1743
|
-
}
|
|
1744
|
-
|
|
1745
|
-
// src/discovery/load/LangChainLoader.ts
|
|
1746
|
-
async function loadLangChainTool(dirPath, manifest, extensions) {
|
|
1747
|
-
let entryFile;
|
|
1748
|
-
try {
|
|
1749
|
-
entryFile = await resolveEntryPoint(
|
|
1750
|
-
dirPath,
|
|
1751
|
-
manifest.entryPoint ?? "index",
|
|
1752
|
-
extensions
|
|
1753
|
-
);
|
|
1754
|
-
} catch (err) {
|
|
1755
|
-
throw new chunkZ7TGIG77_cjs.DiscoveryError(
|
|
1756
|
-
dirPath,
|
|
1757
|
-
"load",
|
|
1758
|
-
`Cannot find LangChain entry point`,
|
|
1759
|
-
err
|
|
1760
|
-
);
|
|
1761
|
-
}
|
|
1762
|
-
let mod;
|
|
1763
|
-
try {
|
|
1764
|
-
mod = await import(url.pathToFileURL(entryFile).href);
|
|
1765
|
-
} catch (err) {
|
|
1766
|
-
throw new chunkZ7TGIG77_cjs.DiscoveryError(
|
|
1767
|
-
dirPath,
|
|
1768
|
-
"load",
|
|
1769
|
-
`Failed to import ${entryFile}`,
|
|
1770
|
-
err
|
|
1771
|
-
);
|
|
1772
|
-
}
|
|
1773
|
-
const tool = mod.default ?? mod.tool ?? mod;
|
|
1774
|
-
if (!tool || typeof tool.invoke !== "function") {
|
|
1775
|
-
throw new chunkZ7TGIG77_cjs.DiscoveryError(
|
|
1776
|
-
dirPath,
|
|
1777
|
-
"validate",
|
|
1778
|
-
`Entry point must export an object with invoke() method (LangChainToolLike)`
|
|
1779
|
-
);
|
|
1780
|
-
}
|
|
1781
|
-
return { manifest, dirPath, impl: tool };
|
|
1782
|
-
}
|
|
1783
|
-
var DEFAULT_EXTENSIONS2 = [".js", ".mjs"];
|
|
1784
|
-
async function listSkillProgramFiles(dirPath, extensions = DEFAULT_EXTENSIONS2) {
|
|
1785
|
-
let entries;
|
|
1786
|
-
try {
|
|
1787
|
-
const dirEntries = await promises.readdir(dirPath, { withFileTypes: true });
|
|
1788
|
-
entries = dirEntries.map((entry) => ({
|
|
1789
|
-
name: entry.name,
|
|
1790
|
-
isFile: entry.isFile()
|
|
1791
|
-
}));
|
|
1792
|
-
} catch {
|
|
1793
|
-
return [];
|
|
1794
|
-
}
|
|
1795
|
-
return entries.filter((e) => e.isFile).map((e) => e.name).filter((name) => {
|
|
1796
|
-
if (name.startsWith(".") || name.startsWith("_")) return false;
|
|
1797
|
-
if (name.includes(".test.") || name.includes(".spec.")) return false;
|
|
1798
|
-
return extensions.some((ext) => name.endsWith(ext));
|
|
1799
|
-
}).sort((a, b) => {
|
|
1800
|
-
if (a === "handler.js" || a === "index.js") return -1;
|
|
1801
|
-
if (b === "handler.js" || b === "index.js") return 1;
|
|
1802
|
-
return a.localeCompare(b);
|
|
1803
|
-
});
|
|
1804
|
-
}
|
|
1805
|
-
function isLangChainLikeTool(val) {
|
|
1806
|
-
return val != null && typeof val === "object" && "invoke" in val && typeof val.invoke === "function";
|
|
1807
|
-
}
|
|
1808
|
-
function isConstructable(val) {
|
|
1809
|
-
return typeof val === "function" && typeof val.prototype === "object";
|
|
1810
|
-
}
|
|
1811
|
-
async function loadOneSkillProgram(dirPath, manifest, entryFile, skillDef, programKey, extensions) {
|
|
1812
|
-
let impl;
|
|
1813
|
-
try {
|
|
1814
|
-
const fullPath = await resolveEntryPoint(dirPath, entryFile, extensions ?? [".js", ".mjs"]);
|
|
1815
|
-
const mod = await import(url.pathToFileURL(fullPath).href);
|
|
1816
|
-
const fn = mod.default ?? mod.handler ?? mod.Tool;
|
|
1817
|
-
if (isLangChainLikeTool(fn)) {
|
|
1818
|
-
impl = fn;
|
|
1819
|
-
} else if (isConstructable(fn)) {
|
|
1820
|
-
const instance = new fn();
|
|
1821
|
-
if (isLangChainLikeTool(instance)) impl = instance;
|
|
1822
|
-
} else if (typeof fn === "function") {
|
|
1823
|
-
impl = fn;
|
|
1824
|
-
}
|
|
1825
|
-
} catch {
|
|
1826
|
-
}
|
|
1827
|
-
return {
|
|
1828
|
-
manifest,
|
|
1829
|
-
dirPath,
|
|
1830
|
-
impl,
|
|
1831
|
-
skillDefinition: skillDef,
|
|
1832
|
-
programKey
|
|
1833
|
-
};
|
|
1834
|
-
}
|
|
1835
|
-
async function loadSkillTools(dirPath, manifest, extensions) {
|
|
1836
|
-
let skillDef;
|
|
1837
|
-
try {
|
|
1838
|
-
skillDef = await chunkZ7TGIG77_cjs.loadSkillDefinition(dirPath);
|
|
1839
|
-
} catch (err) {
|
|
1840
|
-
throw new chunkZ7TGIG77_cjs.DiscoveryError(
|
|
1841
|
-
dirPath,
|
|
1842
|
-
"load",
|
|
1843
|
-
`Failed to parse SKILL.md: ${err.message}`,
|
|
1844
|
-
err
|
|
1845
|
-
);
|
|
1846
|
-
}
|
|
1847
|
-
const programs = manifest.programs;
|
|
1848
|
-
if (programs && typeof programs === "object" && Object.keys(programs).length > 0) {
|
|
1849
|
-
const result = [];
|
|
1850
|
-
for (const [programKey, entryFile2] of Object.entries(programs)) {
|
|
1851
|
-
const loaded2 = await loadOneSkillProgram(
|
|
1852
|
-
dirPath,
|
|
1853
|
-
manifest,
|
|
1854
|
-
entryFile2,
|
|
1855
|
-
skillDef,
|
|
1856
|
-
programKey,
|
|
1857
|
-
extensions
|
|
1858
|
-
);
|
|
1859
|
-
result.push(loaded2);
|
|
1860
|
-
}
|
|
1861
|
-
return result;
|
|
1862
|
-
}
|
|
1863
|
-
const exts = extensions ?? DEFAULT_EXTENSIONS2;
|
|
1864
|
-
const files = await listSkillProgramFiles(dirPath, exts);
|
|
1865
|
-
if (files.length >= 2) {
|
|
1866
|
-
const result = [];
|
|
1867
|
-
for (let i = 0; i < files.length; i++) {
|
|
1868
|
-
const file = files[i];
|
|
1869
|
-
const programKey = i === 0 ? "default" : file.replace(/\.[^.]+$/, "");
|
|
1870
|
-
const loaded2 = await loadOneSkillProgram(
|
|
1871
|
-
dirPath,
|
|
1872
|
-
manifest,
|
|
1873
|
-
file,
|
|
1874
|
-
skillDef,
|
|
1875
|
-
programKey,
|
|
1876
|
-
extensions
|
|
1877
|
-
);
|
|
1878
|
-
result.push(loaded2);
|
|
1879
|
-
}
|
|
1880
|
-
return result;
|
|
1881
|
-
}
|
|
1882
|
-
const entryFile = manifest.entryPoint ?? files[0] ?? "handler";
|
|
1883
|
-
const loaded = await loadOneSkillProgram(
|
|
1884
|
-
dirPath,
|
|
1885
|
-
manifest,
|
|
1886
|
-
entryFile,
|
|
1887
|
-
skillDef,
|
|
1888
|
-
void 0,
|
|
1889
|
-
extensions
|
|
1890
|
-
);
|
|
1891
|
-
return [loaded];
|
|
1892
|
-
}
|
|
1893
|
-
|
|
1894
|
-
// src/discovery/scan/DirectoryScanner.ts
|
|
1895
|
-
var DEFAULT_EXTENSIONS3 = [".js", ".mjs"];
|
|
1896
|
-
var DirectoryScanner = class {
|
|
1897
|
-
roots;
|
|
1898
|
-
extensions;
|
|
1899
|
-
onError;
|
|
1900
|
-
constructor(options) {
|
|
1901
|
-
const defaultNamespace = options.namespace ?? "dir";
|
|
1902
|
-
this.roots = options.roots.map((root) => {
|
|
1903
|
-
if (typeof root === "string") {
|
|
1904
|
-
return { path: root, namespace: defaultNamespace };
|
|
1905
|
-
}
|
|
1906
|
-
return {
|
|
1907
|
-
path: root.path,
|
|
1908
|
-
namespace: root.namespace ?? defaultNamespace
|
|
1909
|
-
};
|
|
1910
|
-
});
|
|
1911
|
-
this.extensions = options.extensions ?? DEFAULT_EXTENSIONS3;
|
|
1912
|
-
this.onError = options.onError;
|
|
1913
|
-
}
|
|
1914
|
-
/**
|
|
1915
|
-
* Scan all root directories and return discovered ToolSpecs.
|
|
1916
|
-
* Errors in individual tool directories are reported via onError
|
|
1917
|
-
* and do not prevent other tools from loading.
|
|
1918
|
-
*/
|
|
1919
|
-
async scan() {
|
|
1920
|
-
const specs = [];
|
|
1921
|
-
for (const root of this.roots) {
|
|
1922
|
-
const rootSpecs = await this.scanRoot(root.path, root.namespace);
|
|
1923
|
-
specs.push(...rootSpecs);
|
|
1924
|
-
}
|
|
1925
|
-
return specs;
|
|
1926
|
-
}
|
|
1927
|
-
async scanRoot(rootPath, namespace) {
|
|
1928
|
-
return this.scanRecursive(rootPath, namespace);
|
|
1929
|
-
}
|
|
1930
|
-
/**
|
|
1931
|
-
* Recursively scan directories for tool definitions.
|
|
1932
|
-
* Directories can be detected via tool.json or inferred markers.
|
|
1933
|
-
*/
|
|
1934
|
-
async scanRecursive(dirPath, namespace) {
|
|
1935
|
-
const specs = [];
|
|
1936
|
-
let dirEntries;
|
|
1937
|
-
try {
|
|
1938
|
-
const entries = await promises.readdir(dirPath, { withFileTypes: true });
|
|
1939
|
-
dirEntries = entries.map((entry) => ({
|
|
1940
|
-
name: entry.name,
|
|
1941
|
-
isDirectory: entry.isDirectory()
|
|
1942
|
-
}));
|
|
1943
|
-
} catch (error) {
|
|
1944
|
-
this.onError?.(dirPath, error);
|
|
1945
|
-
return specs;
|
|
1946
|
-
}
|
|
1947
|
-
const dirName = path.basename(dirPath);
|
|
1948
|
-
try {
|
|
1949
|
-
const loadedSpecs = await this.loadToolDir(dirPath, dirName, namespace);
|
|
1950
|
-
if (loadedSpecs.length > 0) {
|
|
1951
|
-
specs.push(...loadedSpecs);
|
|
1952
|
-
}
|
|
1953
|
-
} catch (error) {
|
|
1954
|
-
this.onError?.(dirPath, error);
|
|
1955
|
-
}
|
|
1956
|
-
for (const entry of dirEntries) {
|
|
1957
|
-
if (!entry.isDirectory) {
|
|
1958
|
-
continue;
|
|
1959
|
-
}
|
|
1960
|
-
const childPath = path.join(dirPath, entry.name);
|
|
1961
|
-
try {
|
|
1962
|
-
const childSpecs = await this.scanRecursive(childPath, namespace);
|
|
1963
|
-
specs.push(...childSpecs);
|
|
1964
|
-
} catch (error) {
|
|
1965
|
-
this.onError?.(childPath, error);
|
|
1966
|
-
}
|
|
1967
|
-
}
|
|
1968
|
-
return specs;
|
|
1969
|
-
}
|
|
1970
|
-
async loadToolDir(dirPath, dirName, namespace) {
|
|
1971
|
-
const manifestPath = path.join(dirPath, "tool.json");
|
|
1972
|
-
let manifestRaw;
|
|
1973
|
-
try {
|
|
1974
|
-
manifestRaw = await promises.readFile(manifestPath, "utf-8");
|
|
1975
|
-
} catch {
|
|
1976
|
-
const inferred = await this.inferManifest(dirPath, dirName);
|
|
1977
|
-
if (!inferred) {
|
|
1978
|
-
return [];
|
|
1979
|
-
}
|
|
1980
|
-
if (inferred.kind === "langchain") {
|
|
1981
|
-
if (inferred.entryPoint) {
|
|
1982
|
-
const loaded3 = await loadLangChainTool(dirPath, inferred, this.extensions);
|
|
1983
|
-
return [this.toToolSpec(loaded3, dirName, dirPath, namespace)];
|
|
1984
|
-
}
|
|
1985
|
-
return this.loadLangChainTools(dirPath, dirName, inferred, false, namespace);
|
|
1986
|
-
}
|
|
1987
|
-
if (inferred.kind === "skill") {
|
|
1988
|
-
const loadedList = await loadSkillTools(dirPath, inferred, this.extensions);
|
|
1989
|
-
return loadedList.map(
|
|
1990
|
-
(loaded3) => this.toToolSpec(loaded3, dirName, dirPath, namespace)
|
|
1991
|
-
);
|
|
1992
|
-
}
|
|
1993
|
-
const loaded2 = await this.loadByKind(dirPath, inferred);
|
|
1994
|
-
return [this.toToolSpec(loaded2, dirName, dirPath, namespace)];
|
|
1995
|
-
}
|
|
1996
|
-
let manifest;
|
|
1997
|
-
try {
|
|
1998
|
-
manifest = JSON.parse(manifestRaw);
|
|
1999
|
-
} catch (err) {
|
|
2000
|
-
throw new chunkZ7TGIG77_cjs.DiscoveryError(
|
|
2001
|
-
dirPath,
|
|
2002
|
-
"manifest",
|
|
2003
|
-
"Invalid JSON in tool.json",
|
|
2004
|
-
err
|
|
2005
|
-
);
|
|
2006
|
-
}
|
|
2007
|
-
if (!manifest.kind) {
|
|
2008
|
-
throw new chunkZ7TGIG77_cjs.DiscoveryError(
|
|
2009
|
-
dirPath,
|
|
2010
|
-
"manifest",
|
|
2011
|
-
`tool.json must have a "kind" field`
|
|
2012
|
-
);
|
|
2013
|
-
}
|
|
2014
|
-
if (manifest.enabled === false) {
|
|
2015
|
-
return [];
|
|
2016
|
-
}
|
|
2017
|
-
if (manifest.kind === "langchain") {
|
|
2018
|
-
if (manifest.entryPoint) {
|
|
2019
|
-
const loaded2 = await loadLangChainTool(dirPath, manifest, this.extensions);
|
|
2020
|
-
return [this.toToolSpec(loaded2, dirName, dirPath, namespace)];
|
|
2021
|
-
}
|
|
2022
|
-
return this.loadLangChainTools(dirPath, dirName, manifest, true, namespace);
|
|
2023
|
-
}
|
|
2024
|
-
if (manifest.kind === "skill") {
|
|
2025
|
-
const loadedList = await loadSkillTools(dirPath, manifest, this.extensions);
|
|
2026
|
-
return loadedList.map(
|
|
2027
|
-
(loaded2) => this.toToolSpec(loaded2, dirName, dirPath, namespace)
|
|
2028
|
-
);
|
|
2029
|
-
}
|
|
2030
|
-
const loaded = await this.loadByKind(dirPath, manifest);
|
|
2031
|
-
return [this.toToolSpec(loaded, dirName, dirPath, namespace)];
|
|
2032
|
-
}
|
|
2033
|
-
async inferManifest(dirPath, dirName) {
|
|
2034
|
-
const hasSkill = await this.fileExists(path.join(dirPath, "SKILL.md"));
|
|
2035
|
-
const hasN8n = await this.fileExists(path.join(dirPath, "workflow.json"));
|
|
2036
|
-
const hasMcp = await this.fileExists(path.join(dirPath, "mcp.json"));
|
|
2037
|
-
const isLangchainDir = dirName === "langchain";
|
|
2038
|
-
const hasLangchain = isLangchainDir ? await this.hasLangchainFiles(dirPath) : dirName !== "skill" && await this.hasEntryPoint(dirPath, "index");
|
|
2039
|
-
const kinds = [
|
|
2040
|
-
hasSkill ? "skill" : null,
|
|
2041
|
-
hasN8n ? "n8n" : null,
|
|
2042
|
-
hasMcp ? "mcp" : null,
|
|
2043
|
-
hasLangchain ? "langchain" : null
|
|
2044
|
-
].filter(Boolean);
|
|
2045
|
-
if (kinds.length === 0) return null;
|
|
2046
|
-
if (kinds.length > 1) {
|
|
2047
|
-
throw new chunkZ7TGIG77_cjs.DiscoveryError(
|
|
2048
|
-
dirPath,
|
|
2049
|
-
"manifest",
|
|
2050
|
-
`Ambiguous tool kind (found ${kinds.join(", ")}). Add tool.json to disambiguate.`
|
|
2051
|
-
);
|
|
2052
|
-
}
|
|
2053
|
-
const kind = kinds[0];
|
|
2054
|
-
const manifest = { kind };
|
|
2055
|
-
if (kind === "n8n") manifest.entryPoint = "workflow.json";
|
|
2056
|
-
if (kind === "mcp") manifest.entryPoint = "mcp.json";
|
|
2057
|
-
if (kind === "langchain" && !isLangchainDir) manifest.entryPoint = "index";
|
|
2058
|
-
if (kind === "skill") manifest.entryPoint = "handler";
|
|
2059
|
-
return manifest;
|
|
2060
|
-
}
|
|
2061
|
-
async fileExists(path) {
|
|
2062
|
-
try {
|
|
2063
|
-
await promises.access(path);
|
|
2064
|
-
return true;
|
|
2065
|
-
} catch {
|
|
2066
|
-
return false;
|
|
2067
|
-
}
|
|
2068
|
-
}
|
|
2069
|
-
async hasEntryPoint(dirPath, baseName) {
|
|
2070
|
-
try {
|
|
2071
|
-
await resolveEntryPoint(dirPath, baseName, this.extensions);
|
|
2072
|
-
return true;
|
|
2073
|
-
} catch {
|
|
2074
|
-
return false;
|
|
2075
|
-
}
|
|
2076
|
-
}
|
|
2077
|
-
async hasLangchainFiles(dirPath) {
|
|
2078
|
-
const entryFiles = await this.listLangchainEntryFiles(dirPath);
|
|
2079
|
-
return entryFiles.length > 0;
|
|
2080
|
-
}
|
|
2081
|
-
async listLangchainEntryFiles(dirPath) {
|
|
2082
|
-
let entries;
|
|
2083
|
-
try {
|
|
2084
|
-
const dirEntries = await promises.readdir(dirPath, { withFileTypes: true });
|
|
2085
|
-
entries = dirEntries.map((entry) => ({
|
|
2086
|
-
name: entry.name,
|
|
2087
|
-
isFile: entry.isFile()
|
|
2088
|
-
}));
|
|
2089
|
-
} catch {
|
|
2090
|
-
return [];
|
|
2091
|
-
}
|
|
2092
|
-
return entries.filter((entry) => entry.isFile).map((entry) => entry.name).filter((name) => {
|
|
2093
|
-
if (name.startsWith(".") || name.startsWith("_")) return false;
|
|
2094
|
-
if (name.endsWith(".d.ts")) return false;
|
|
2095
|
-
if (name.includes(".test.") || name.includes(".spec.")) return false;
|
|
2096
|
-
return this.extensions.some((ext) => name.endsWith(ext));
|
|
2097
|
-
});
|
|
2098
|
-
}
|
|
2099
|
-
async loadByKind(dirPath, manifest) {
|
|
2100
|
-
switch (manifest.kind) {
|
|
2101
|
-
case "mcp":
|
|
2102
|
-
return loadMCPTool(dirPath, manifest);
|
|
2103
|
-
case "langchain":
|
|
2104
|
-
return loadLangChainTool(dirPath, manifest, this.extensions);
|
|
2105
|
-
case "skill": {
|
|
2106
|
-
const list = await loadSkillTools(dirPath, manifest, this.extensions);
|
|
2107
|
-
if (list.length === 0) {
|
|
2108
|
-
throw new chunkZ7TGIG77_cjs.DiscoveryError(dirPath, "load", "No skill programs loaded", new Error("empty"));
|
|
2109
|
-
}
|
|
2110
|
-
return list[0];
|
|
2111
|
-
}
|
|
2112
|
-
case "n8n":
|
|
2113
|
-
return chunkZ7TGIG77_cjs.loadN8nTool(dirPath, manifest);
|
|
2114
|
-
default:
|
|
2115
|
-
throw new chunkZ7TGIG77_cjs.DiscoveryError(
|
|
2116
|
-
dirPath,
|
|
2117
|
-
"manifest",
|
|
2118
|
-
`Unknown tool kind: "${manifest.kind}"`
|
|
2119
|
-
);
|
|
2120
|
-
}
|
|
2121
|
-
}
|
|
2122
|
-
async loadLangChainTools(dirPath, dirName, manifest, strict, namespace) {
|
|
2123
|
-
const entryFiles = await this.listLangchainEntryFiles(dirPath);
|
|
2124
|
-
if (entryFiles.length === 0) {
|
|
2125
|
-
if (strict) {
|
|
2126
|
-
throw new chunkZ7TGIG77_cjs.DiscoveryError(
|
|
2127
|
-
dirPath,
|
|
2128
|
-
"load",
|
|
2129
|
-
"No LangChain entry files found"
|
|
2130
|
-
);
|
|
2131
|
-
}
|
|
2132
|
-
return [];
|
|
2133
|
-
}
|
|
2134
|
-
const specs = [];
|
|
2135
|
-
const useDirNameForSingle = dirName !== "langchain";
|
|
2136
|
-
for (const entryFile of entryFiles) {
|
|
2137
|
-
const fileManifest = {
|
|
2138
|
-
...manifest,
|
|
2139
|
-
entryPoint: entryFile
|
|
2140
|
-
};
|
|
2141
|
-
try {
|
|
2142
|
-
const loaded = await loadLangChainTool(dirPath, fileManifest, this.extensions);
|
|
2143
|
-
const fileBase = path.basename(entryFile).replace(/\.[^.]+$/, "");
|
|
2144
|
-
const nameHint = entryFiles.length === 1 && useDirNameForSingle ? dirName : fileBase;
|
|
2145
|
-
specs.push(this.toToolSpec(loaded, nameHint, dirPath, namespace));
|
|
2146
|
-
} catch (error) {
|
|
2147
|
-
const err = error;
|
|
2148
|
-
if (err instanceof chunkZ7TGIG77_cjs.DiscoveryError && err.phase === "validate") {
|
|
2149
|
-
if (strict) {
|
|
2150
|
-
throw err;
|
|
2151
|
-
}
|
|
2152
|
-
continue;
|
|
2153
|
-
}
|
|
2154
|
-
this.onError?.(path.join(dirPath, entryFile), err);
|
|
2155
|
-
if (strict) {
|
|
2156
|
-
throw err;
|
|
2157
|
-
}
|
|
2158
|
-
}
|
|
2159
|
-
}
|
|
2160
|
-
return specs;
|
|
2161
|
-
}
|
|
2162
|
-
toToolSpec(loaded, dirName, dirPath, namespace) {
|
|
2163
|
-
const { manifest } = loaded;
|
|
2164
|
-
const kindDirNames = /* @__PURE__ */ new Set(["mcp", "langchain", "skill", "n8n"]);
|
|
2165
|
-
const parentName = path.basename(path.join(dirPath, ".."));
|
|
2166
|
-
const isKindDir = kindDirNames.has(dirName);
|
|
2167
|
-
const defaultDirName = isKindDir ? parentName : dirName;
|
|
2168
|
-
const inferredName = isKindDir ? `${namespace}/${defaultDirName}-${dirName}` : `${namespace}/${defaultDirName}`;
|
|
2169
|
-
const name = manifest.name ?? inferredName;
|
|
2170
|
-
const spec = this.buildBaseSpec(manifest, name, dirName);
|
|
2171
|
-
this.applyKindSpecificFields(spec, loaded, manifest, defaultDirName, namespace);
|
|
2172
|
-
return spec;
|
|
2173
|
-
}
|
|
2174
|
-
buildBaseSpec(manifest, name, dirName) {
|
|
2175
|
-
return {
|
|
2176
|
-
name,
|
|
2177
|
-
version: manifest.version ?? "1.0.0",
|
|
2178
|
-
kind: manifest.kind,
|
|
2179
|
-
description: manifest.description ?? `${manifest.kind} tool: ${dirName}`,
|
|
2180
|
-
tags: manifest.tags,
|
|
2181
|
-
inputSchema: manifest.inputSchema ?? {
|
|
2182
|
-
type: "object",
|
|
2183
|
-
additionalProperties: true
|
|
2184
|
-
},
|
|
2185
|
-
outputSchema: manifest.outputSchema ?? {
|
|
2186
|
-
type: "object",
|
|
2187
|
-
additionalProperties: true
|
|
2188
|
-
},
|
|
2189
|
-
capabilities: manifest.capabilities ?? [],
|
|
2190
|
-
costHints: manifest.costHints
|
|
2191
|
-
};
|
|
2192
|
-
}
|
|
2193
|
-
applyKindSpecificFields(spec, loaded, manifest, defaultDirName, namespace) {
|
|
2194
|
-
switch (manifest.kind) {
|
|
2195
|
-
case "mcp":
|
|
2196
|
-
if (loaded.mcpConfig?.url) {
|
|
2197
|
-
spec.endpoint = loaded.mcpConfig.url;
|
|
2198
|
-
}
|
|
2199
|
-
spec.impl = loaded.mcpConfig;
|
|
2200
|
-
break;
|
|
2201
|
-
case "langchain":
|
|
2202
|
-
spec.impl = loaded.impl;
|
|
2203
|
-
if (!manifest.name) {
|
|
2204
|
-
const toolName = loaded.impl?.name;
|
|
2205
|
-
if (toolName) {
|
|
2206
|
-
spec.name = `${namespace}/${toolName}`;
|
|
2207
|
-
}
|
|
2208
|
-
}
|
|
2209
|
-
if (!manifest.description) {
|
|
2210
|
-
const toolDescription = loaded.impl?.description;
|
|
2211
|
-
if (toolDescription) {
|
|
2212
|
-
spec.description = toolDescription;
|
|
2213
|
-
}
|
|
2214
|
-
}
|
|
2215
|
-
if (!manifest.inputSchema && loaded.impl) {
|
|
2216
|
-
const tool = loaded.impl;
|
|
2217
|
-
if (tool.schema) {
|
|
2218
|
-
spec.inputSchema = tool.schema;
|
|
2219
|
-
}
|
|
2220
|
-
}
|
|
2221
|
-
break;
|
|
2222
|
-
case "skill": {
|
|
2223
|
-
if (loaded.skillDefinition) {
|
|
2224
|
-
spec.name = manifest.name ?? loaded.skillDefinition.frontmatter.name;
|
|
2225
|
-
spec.description = loaded.skillDefinition.frontmatter.description;
|
|
2226
|
-
if (loaded.programKey === "default") {
|
|
2227
|
-
spec.name = `${namespace}/${defaultDirName}`;
|
|
2228
|
-
} else if (loaded.programKey) {
|
|
2229
|
-
spec.name = `${namespace}/${defaultDirName}/${loaded.programKey}`;
|
|
2230
|
-
}
|
|
2231
|
-
const impl = loaded.impl;
|
|
2232
|
-
if (impl && typeof impl === "object" && typeof impl.invoke === "function") {
|
|
2233
|
-
if (impl.description != null && impl.description !== "") spec.description = impl.description;
|
|
2234
|
-
if (impl.schema != null && typeof impl.schema === "object") spec.inputSchema = impl.schema;
|
|
2235
|
-
}
|
|
2236
|
-
spec.impl = {
|
|
2237
|
-
...loaded.skillDefinition,
|
|
2238
|
-
handler: loaded.impl
|
|
2239
|
-
};
|
|
2240
|
-
} else {
|
|
2241
|
-
spec.impl = loaded.impl;
|
|
2242
|
-
}
|
|
2243
|
-
break;
|
|
2244
|
-
}
|
|
2245
|
-
case "n8n": {
|
|
2246
|
-
const workflow = loaded.workflowDef;
|
|
2247
|
-
if (workflow?.id) {
|
|
2248
|
-
spec.resourceId = String(workflow.id);
|
|
2249
|
-
}
|
|
2250
|
-
if (!manifest.description && workflow) {
|
|
2251
|
-
const workflowDesc = workflow.description ?? workflow.meta?.description ?? (typeof workflow.name === "string" ? workflow.name : void 0);
|
|
2252
|
-
if (workflowDesc) {
|
|
2253
|
-
spec.description = workflowDesc;
|
|
2254
|
-
}
|
|
2255
|
-
}
|
|
2256
|
-
spec.impl = loaded.workflowDef;
|
|
2257
|
-
break;
|
|
2258
|
-
}
|
|
2259
|
-
}
|
|
2260
|
-
}
|
|
2261
|
-
};
|
|
2262
|
-
|
|
2263
|
-
// src/discovery/MCPProcessManager.ts
|
|
2264
|
-
var MCPProcessManager = class {
|
|
2265
|
-
connections = /* @__PURE__ */ new Map();
|
|
2266
|
-
/**
|
|
2267
|
-
* Get connection info for an MCP tool based on its config.
|
|
2268
|
-
* Caches the result by tool name.
|
|
2269
|
-
*/
|
|
2270
|
-
getConnectionInfo(toolName, config) {
|
|
2271
|
-
const cached = this.connections.get(toolName);
|
|
2272
|
-
if (cached) return cached;
|
|
2273
|
-
const info = config.url ? { type: "url", url: config.url } : {
|
|
2274
|
-
type: "stdio",
|
|
2275
|
-
command: config.command,
|
|
2276
|
-
args: config.args,
|
|
2277
|
-
env: config.env,
|
|
2278
|
-
cwd: config.cwd
|
|
2279
|
-
};
|
|
2280
|
-
this.connections.set(toolName, info);
|
|
2281
|
-
return info;
|
|
2282
|
-
}
|
|
2283
|
-
/**
|
|
2284
|
-
* Remove cached connection info for a tool.
|
|
2285
|
-
*/
|
|
2286
|
-
remove(toolName) {
|
|
2287
|
-
return this.connections.delete(toolName);
|
|
2288
|
-
}
|
|
2289
|
-
/**
|
|
2290
|
-
* Get all registered tool names.
|
|
2291
|
-
*/
|
|
2292
|
-
getToolNames() {
|
|
2293
|
-
return [...this.connections.keys()];
|
|
2294
|
-
}
|
|
2295
|
-
/**
|
|
2296
|
-
* Clear all cached connection info.
|
|
2297
|
-
*/
|
|
2298
|
-
dispose() {
|
|
2299
|
-
this.connections.clear();
|
|
2300
|
-
}
|
|
2301
|
-
};
|
|
12
|
+
var child_process = require('child_process');
|
|
13
|
+
var fs = require('fs');
|
|
14
|
+
var os = require('os');
|
|
15
|
+
var url = require('url');
|
|
2302
16
|
|
|
2303
|
-
// src/mcp/MCPClientAdapter.ts
|
|
17
|
+
// src/tools/mcp/MCPClientAdapter.ts
|
|
2304
18
|
function textFromCallToolResult(result) {
|
|
2305
19
|
if (result.content?.length) {
|
|
2306
20
|
const parts = result.content.filter((c) => c.type === "text" && c.text != null).map((c) => c.text);
|
|
@@ -2313,7 +27,7 @@ var MCPClientAdapter = class {
|
|
|
2313
27
|
constructor(client) {
|
|
2314
28
|
this.client = client;
|
|
2315
29
|
}
|
|
2316
|
-
kind =
|
|
30
|
+
kind = chunkFA2ZEICE_cjs.MCP_KIND;
|
|
2317
31
|
async invoke(spec, args, _ctx) {
|
|
2318
32
|
const params = args != null && typeof args === "object" && !Array.isArray(args) ? args : {};
|
|
2319
33
|
const result = await this.client.callTool({ name: spec.name, arguments: params });
|
|
@@ -2327,7 +41,7 @@ var MCPClientAdapter = class {
|
|
|
2327
41
|
}
|
|
2328
42
|
};
|
|
2329
43
|
|
|
2330
|
-
// src/mcp/connectMCP.ts
|
|
44
|
+
// src/tools/mcp/connectMCP.ts
|
|
2331
45
|
async function connectMCP(connectionInfo) {
|
|
2332
46
|
if (connectionInfo.type !== "stdio" || !connectionInfo.command) {
|
|
2333
47
|
throw new Error(
|
|
@@ -2354,19 +68,48 @@ function mcpToolsToSpecs(tools) {
|
|
|
2354
68
|
return tools.map((t) => ({
|
|
2355
69
|
name: t.name,
|
|
2356
70
|
version: "1.0.0",
|
|
2357
|
-
kind:
|
|
71
|
+
kind: chunkFA2ZEICE_cjs.MCP_KIND,
|
|
2358
72
|
description: t.description ?? `MCP tool: ${t.name}`,
|
|
2359
|
-
inputSchema: t.inputSchema ??
|
|
2360
|
-
outputSchema:
|
|
73
|
+
inputSchema: t.inputSchema ?? chunkSOFUWEZ6_cjs.DEFAULT_INPUT_SCHEMA,
|
|
74
|
+
outputSchema: chunkSOFUWEZ6_cjs.DEFAULT_OUTPUT_SCHEMA,
|
|
2361
75
|
capabilities: []
|
|
2362
76
|
}));
|
|
2363
77
|
}
|
|
78
|
+
|
|
79
|
+
// src/tools/mcp/MCPProcessManager.ts
|
|
80
|
+
var MCPProcessManager = class {
|
|
81
|
+
connections = /* @__PURE__ */ new Map();
|
|
82
|
+
getConnectionInfo(toolName, config) {
|
|
83
|
+
const cached = this.connections.get(toolName);
|
|
84
|
+
if (cached) return cached;
|
|
85
|
+
const info = config.url ? { type: "url", url: config.url } : {
|
|
86
|
+
type: "stdio",
|
|
87
|
+
command: config.command,
|
|
88
|
+
args: config.args,
|
|
89
|
+
env: config.env,
|
|
90
|
+
cwd: config.cwd
|
|
91
|
+
};
|
|
92
|
+
this.connections.set(toolName, info);
|
|
93
|
+
return info;
|
|
94
|
+
}
|
|
95
|
+
remove(toolName) {
|
|
96
|
+
return this.connections.delete(toolName);
|
|
97
|
+
}
|
|
98
|
+
getToolNames() {
|
|
99
|
+
return [...this.connections.keys()];
|
|
100
|
+
}
|
|
101
|
+
dispose() {
|
|
102
|
+
this.connections.clear();
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// src/tools/mcp/registerMCPTools.ts
|
|
2364
107
|
async function registerMCPToolsFromConfig(runtime, registry, options = {}) {
|
|
2365
108
|
const configPath = options.configPath ?? process.env.MCP_CONFIG_PATH ?? path.join(process.cwd(), "mcp.json");
|
|
2366
109
|
const dirPath = path.dirname(configPath);
|
|
2367
110
|
const entryPoint = path.basename(configPath);
|
|
2368
|
-
const toolName = options.toolName ??
|
|
2369
|
-
const loaded = await loadMCPTool(dirPath, { kind:
|
|
111
|
+
const toolName = options.toolName ?? chunkFA2ZEICE_cjs.MCP_KIND;
|
|
112
|
+
const loaded = await chunkZBNRHRGM_cjs.loadMCPTool(dirPath, { kind: chunkFA2ZEICE_cjs.MCP_KIND, name: toolName, entryPoint });
|
|
2370
113
|
if (!loaded.mcpConfig) {
|
|
2371
114
|
throw new Error("mcp.json must have command or url");
|
|
2372
115
|
}
|
|
@@ -2379,481 +122,269 @@ async function registerMCPToolsFromConfig(runtime, registry, options = {}) {
|
|
|
2379
122
|
runtime.registerAdapter(new MCPClientAdapter(client));
|
|
2380
123
|
return { transport };
|
|
2381
124
|
}
|
|
2382
|
-
var
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
"read:web",
|
|
2387
|
-
"read:fs",
|
|
2388
|
-
"write:fs",
|
|
2389
|
-
"read:db",
|
|
2390
|
-
"write:db",
|
|
2391
|
-
"network",
|
|
2392
|
-
"workflow",
|
|
2393
|
-
"danger:destructive"
|
|
2394
|
-
]
|
|
2395
|
-
});
|
|
2396
|
-
var LangChainToolsHub = class {
|
|
2397
|
-
constructor(runtime, ctxFactory = DEFAULT_CTX_FACTORY) {
|
|
2398
|
-
this.runtime = runtime;
|
|
2399
|
-
this.ctxFactory = ctxFactory;
|
|
2400
|
-
}
|
|
2401
|
-
/**
|
|
2402
|
-
* Returns all registered tools as LangChain tools (DynamicTool[]).
|
|
2403
|
-
* Each tool invokes the runtime through the full pipeline (policy, HITL, etc.).
|
|
2404
|
-
*/
|
|
2405
|
-
getLangChainTools() {
|
|
2406
|
-
const registry = this.runtime.getRegistry();
|
|
2407
|
-
const specs = registry.snapshot();
|
|
2408
|
-
return specs.map((spec) => this.specToLangChainTool(spec));
|
|
2409
|
-
}
|
|
2410
|
-
/**
|
|
2411
|
-
* Returns LangChain tools for a subset of tools (by name or query).
|
|
2412
|
-
*/
|
|
2413
|
-
getLangChainToolsForNames(toolNames) {
|
|
2414
|
-
const registry = this.runtime.getRegistry();
|
|
2415
|
-
const set = new Set(toolNames);
|
|
2416
|
-
const specs = registry.snapshot().filter((s) => set.has(s.name));
|
|
2417
|
-
return specs.map((spec) => this.specToLangChainTool(spec));
|
|
2418
|
-
}
|
|
2419
|
-
specToLangChainTool(spec) {
|
|
2420
|
-
const runtime = this.runtime;
|
|
2421
|
-
const ctxFactory = this.ctxFactory;
|
|
2422
|
-
return new tools.DynamicTool({
|
|
2423
|
-
name: spec.name,
|
|
2424
|
-
description: spec.description ?? `Tool: ${spec.name}`,
|
|
2425
|
-
func: async (input) => {
|
|
2426
|
-
const args = parseToolInput(input);
|
|
2427
|
-
const intent = {
|
|
2428
|
-
tool: spec.name,
|
|
2429
|
-
args,
|
|
2430
|
-
purpose: "langchain"
|
|
2431
|
-
};
|
|
2432
|
-
const ctx = ctxFactory();
|
|
2433
|
-
const result = await runtime.invoke(intent, ctx);
|
|
2434
|
-
if (result.ok) {
|
|
2435
|
-
return typeof result.result === "string" ? result.result : JSON.stringify(result.result);
|
|
2436
|
-
}
|
|
2437
|
-
const err = result.error;
|
|
2438
|
-
const message = err?.message ?? "Tool failed";
|
|
2439
|
-
const details = err?.details;
|
|
2440
|
-
return JSON.stringify(
|
|
2441
|
-
details != null ? { error: message, details } : { error: message }
|
|
2442
|
-
);
|
|
2443
|
-
}
|
|
2444
|
-
});
|
|
2445
|
-
}
|
|
2446
|
-
};
|
|
2447
|
-
function parseToolInput(input) {
|
|
2448
|
-
const s = input.trim();
|
|
2449
|
-
if (!s) return {};
|
|
2450
|
-
try {
|
|
2451
|
-
const parsed = JSON.parse(s);
|
|
2452
|
-
if (parsed != null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
2453
|
-
return parsed;
|
|
2454
|
-
}
|
|
2455
|
-
} catch {
|
|
2456
|
-
}
|
|
2457
|
-
const lastBrace = s.lastIndexOf("{");
|
|
2458
|
-
if (lastBrace !== -1) {
|
|
2459
|
-
try {
|
|
2460
|
-
const parsed = JSON.parse(s.slice(lastBrace));
|
|
2461
|
-
if (parsed != null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
2462
|
-
return parsed;
|
|
2463
|
-
}
|
|
2464
|
-
} catch {
|
|
2465
|
-
}
|
|
2466
|
-
}
|
|
2467
|
-
return {};
|
|
2468
|
-
}
|
|
2469
|
-
|
|
2470
|
-
// src/llm/AgentLLMAdapter.ts
|
|
2471
|
-
function createAgentLLMAdapter(client) {
|
|
2472
|
-
if (!client.chatWithTools) {
|
|
2473
|
-
throw new Error(
|
|
2474
|
-
`agent-llm client "${client.id}" does not support chatWithTools; ReAct agent requires tool-calling.`
|
|
2475
|
-
);
|
|
2476
|
-
}
|
|
2477
|
-
return new AgentLLMAdapter(client);
|
|
2478
|
-
}
|
|
2479
|
-
var AgentLLMAdapter = class {
|
|
2480
|
-
constructor(client) {
|
|
2481
|
-
this.client = client;
|
|
2482
|
-
}
|
|
2483
|
-
async chat(messages, options) {
|
|
2484
|
-
const result = await this.client.chat(messages);
|
|
2485
|
-
return { content: result.content, raw: result.usage ?? {} };
|
|
2486
|
-
}
|
|
2487
|
-
async chatWithTools(messages, tools, options) {
|
|
2488
|
-
const agentLlmTools = tools.map((t) => ({
|
|
2489
|
-
type: "function",
|
|
2490
|
-
function: {
|
|
2491
|
-
name: t.function.name,
|
|
2492
|
-
description: t.function.description,
|
|
2493
|
-
parameters: t.function.parameters
|
|
2494
|
-
}
|
|
2495
|
-
}));
|
|
2496
|
-
const result = await this.client.chatWithTools(messages, agentLlmTools, {
|
|
2497
|
-
timeoutMs: options?.timeoutMs
|
|
2498
|
-
});
|
|
2499
|
-
return {
|
|
2500
|
-
message: result.message,
|
|
2501
|
-
raw: result.usage ?? {}
|
|
2502
|
-
};
|
|
2503
|
-
}
|
|
2504
|
-
};
|
|
2505
|
-
var DEFAULT_ALLOWED_HOSTS = ["*"];
|
|
2506
|
-
var DEFAULT_SANDBOX_ROOT = process.cwd();
|
|
2507
|
-
function loadAgentConfig(configPath) {
|
|
2508
|
-
const abs = path.resolve(configPath);
|
|
2509
|
-
const raw = fs.readFileSync(abs, "utf8");
|
|
2510
|
-
const parsed = yaml__default.default.load(raw);
|
|
2511
|
-
if (!parsed || typeof parsed !== "object") return {};
|
|
2512
|
-
return parsed;
|
|
2513
|
-
}
|
|
2514
|
-
function createRuntimeWithTools(options) {
|
|
2515
|
-
const sandboxRoot = options.sandboxRoot ?? DEFAULT_SANDBOX_ROOT;
|
|
2516
|
-
const allowedHosts = options.allowedHosts ?? DEFAULT_ALLOWED_HOSTS;
|
|
2517
|
-
const registry = new ToolRegistry();
|
|
2518
|
-
const coreConfig = { sandboxRoot, allowedHosts };
|
|
2519
|
-
const coreAdapter = agentToolBuiltinTools.registerCoreTools(registry, coreConfig);
|
|
2520
|
-
const exampleConfig = { sandboxRoot, allowedHosts };
|
|
2521
|
-
const exampleAdapter = agentToolExampleTools.registerExampleTools(registry, exampleConfig);
|
|
2522
|
-
const runtime = new PTCRuntime({ registry });
|
|
2523
|
-
runtime.registerAdapter(coreAdapter);
|
|
2524
|
-
runtime.registerAdapter(exampleAdapter);
|
|
2525
|
-
return { runtime, coreAdapter, exampleAdapter };
|
|
2526
|
-
}
|
|
2527
|
-
async function runAgent(configPath, task, options) {
|
|
2528
|
-
const config = loadAgentConfig(configPath);
|
|
2529
|
-
const llmSection = config.llm ?? null;
|
|
2530
|
-
const registry = agentLlm.createLLMRegistry({ llmSection });
|
|
2531
|
-
const defaultId = registry.defaultId();
|
|
2532
|
-
if (!defaultId) {
|
|
2533
|
-
throw new Error(
|
|
2534
|
-
"agent.yaml has no llm section or no LLM instances. Add an llm block (see agent.yaml.example)."
|
|
2535
|
-
);
|
|
2536
|
-
}
|
|
2537
|
-
const client = registry.get(defaultId);
|
|
2538
|
-
if (!client) {
|
|
2539
|
-
throw new Error(`LLM "${defaultId}" not found in registry.`);
|
|
2540
|
-
}
|
|
2541
|
-
const adapter = createAgentLLMAdapter(client);
|
|
2542
|
-
const sandboxRoot = options?.sandboxRoot ?? DEFAULT_SANDBOX_ROOT;
|
|
2543
|
-
const allowedHosts = options?.allowedHosts ?? DEFAULT_ALLOWED_HOSTS;
|
|
2544
|
-
const { runtime } = createRuntimeWithTools({ sandboxRoot, allowedHosts });
|
|
2545
|
-
const ctxFactory = () => ({
|
|
2546
|
-
requestId: `run-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
|
|
2547
|
-
taskId: `task-${Date.now()}`,
|
|
2548
|
-
permissions: [
|
|
2549
|
-
"read:web",
|
|
2550
|
-
"read:fs",
|
|
2551
|
-
"write:fs",
|
|
2552
|
-
"read:db",
|
|
2553
|
-
"write:db",
|
|
2554
|
-
"network",
|
|
2555
|
-
"workflow",
|
|
2556
|
-
"danger:destructive",
|
|
2557
|
-
"exec"
|
|
2558
|
-
]
|
|
2559
|
-
});
|
|
2560
|
-
const hub = {
|
|
2561
|
-
getRegistry: () => runtime.getRegistry(),
|
|
2562
|
-
invokeTool: async (name, args) => {
|
|
2563
|
-
const ctx = ctxFactory();
|
|
2564
|
-
const result = await runtime.invoke(
|
|
2565
|
-
{ tool: name, args, purpose: "langchain" },
|
|
2566
|
-
ctx
|
|
2567
|
-
);
|
|
2568
|
-
return result;
|
|
2569
|
-
}
|
|
2570
|
-
};
|
|
2571
|
-
const agent = new chunkP3UEAZHK_cjs.ReActAgent(adapter, hub);
|
|
2572
|
-
const toolNames = Array.isArray(config.tools) && config.tools.length > 0 ? normalizeToolList(config.tools) : void 0;
|
|
2573
|
-
return agent.run(task, {
|
|
2574
|
-
systemPrompt: options?.systemPrompt,
|
|
2575
|
-
toolNames,
|
|
2576
|
-
...options?.runOptions
|
|
2577
|
-
});
|
|
2578
|
-
}
|
|
2579
|
-
var PLACEHOLDER = "__REPORT_DATA__";
|
|
2580
|
-
function getReportTemplateDir() {
|
|
2581
|
-
if (typeof __dirname !== "undefined") return __dirname;
|
|
2582
|
-
return path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))));
|
|
2583
|
-
}
|
|
2584
|
-
var DEFAULT_REPORT_TEMPLATE_PATH = (() => {
|
|
2585
|
-
const dir = getReportTemplateDir();
|
|
2586
|
-
const nextToModule = path.join(dir, "agent-report-template.html");
|
|
2587
|
-
if (fs.existsSync(nextToModule)) return nextToModule;
|
|
2588
|
-
return path.join(dir, "report", "agent-report-template.html");
|
|
2589
|
-
})();
|
|
2590
|
-
function generateAgentReport(data, options) {
|
|
2591
|
-
const templatePath = options.templatePath ?? DEFAULT_REPORT_TEMPLATE_PATH;
|
|
2592
|
-
const template = fs.readFileSync(templatePath, "utf8");
|
|
2593
|
-
let json = JSON.stringify(data);
|
|
2594
|
-
json = json.replace(/<\/script/gi, "<\\/script");
|
|
2595
|
-
const html = template.replace(PLACEHOLDER, json);
|
|
2596
|
-
const outPath = path.resolve(options.outputPath);
|
|
2597
|
-
fs.writeFileSync(outPath, html, "utf8");
|
|
2598
|
-
return outPath;
|
|
125
|
+
var DEFAULT_CACHE_BASE = path.join(os.homedir(), ".agent", "cache");
|
|
126
|
+
function packagePathSegments(name) {
|
|
127
|
+
const withoutScope = name.replace(/^@/, "");
|
|
128
|
+
return withoutScope.split("/").filter(Boolean);
|
|
2599
129
|
}
|
|
2600
|
-
function
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
const v = value;
|
|
2604
|
-
const out = {};
|
|
2605
|
-
if (Array.isArray(v.messages)) {
|
|
2606
|
-
out.messages = v.messages.map((m) => serializeMessage(m));
|
|
2607
|
-
}
|
|
2608
|
-
if (v.__state__ && typeof v.__state__ === "object") {
|
|
2609
|
-
const state = v.__state__;
|
|
2610
|
-
if (Array.isArray(state.messages)) {
|
|
2611
|
-
out.messages = state.messages.map((m) => serializeMessage(m));
|
|
2612
|
-
}
|
|
2613
|
-
}
|
|
2614
|
-
if (Object.keys(out).length === 0) {
|
|
2615
|
-
try {
|
|
2616
|
-
return JSON.parse(JSON.stringify(value));
|
|
2617
|
-
} catch {
|
|
2618
|
-
return { _raw: String(value) };
|
|
2619
|
-
}
|
|
2620
|
-
}
|
|
2621
|
-
return out;
|
|
130
|
+
function resolveCacheDir(cacheBase, packageName, version) {
|
|
131
|
+
const segments = packagePathSegments(packageName);
|
|
132
|
+
return path.join(cacheBase, ...segments, version);
|
|
2622
133
|
}
|
|
2623
|
-
function
|
|
2624
|
-
|
|
2625
|
-
const
|
|
2626
|
-
|
|
2627
|
-
type: m.type ?? "message",
|
|
2628
|
-
content: m.content ?? ""
|
|
2629
|
-
};
|
|
2630
|
-
if (m.tool_calls) out.tool_calls = m.tool_calls;
|
|
2631
|
-
if (m.usage_metadata) out.usage_metadata = m.usage_metadata;
|
|
2632
|
-
if (m.name) out.name = m.name;
|
|
2633
|
-
return out;
|
|
134
|
+
function getVersionFromTarball(tgzName) {
|
|
135
|
+
const base = tgzName.replace(/\.tgz$/i, "");
|
|
136
|
+
const match = base.match(/-(\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?)$/);
|
|
137
|
+
return match ? match[1] : base;
|
|
2634
138
|
}
|
|
2635
|
-
function
|
|
2636
|
-
const
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
139
|
+
function ensurePackageInCache(packageName, version = "latest", options = {}) {
|
|
140
|
+
const cacheBase = options.cacheBase ?? DEFAULT_CACHE_BASE;
|
|
141
|
+
const packDest = path.join(cacheBase, ".pack-tmp", packageName.replace(/@/g, "").replace(/\//g, "_"));
|
|
142
|
+
fs.mkdirSync(packDest, { recursive: true });
|
|
143
|
+
try {
|
|
144
|
+
child_process.execSync(`npm pack ${packageName}@${version} --pack-destination "${packDest}"`, {
|
|
145
|
+
cwd: process.cwd(),
|
|
146
|
+
stdio: "pipe",
|
|
147
|
+
encoding: "utf-8"
|
|
2641
148
|
});
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
const
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
}
|
|
2682
|
-
function getMessageContent(msg) {
|
|
2683
|
-
if (!msg || typeof msg !== "object") return "";
|
|
2684
|
-
let c = msg.content ?? msg.kwargs?.content;
|
|
2685
|
-
if (typeof c === "string") return c;
|
|
2686
|
-
if (Array.isArray(c)) {
|
|
2687
|
-
return c.map((p) => p && typeof p === "object" && "text" in p ? p.text : String(p)).filter(Boolean).join("");
|
|
2688
|
-
}
|
|
2689
|
-
return "";
|
|
2690
|
-
}
|
|
2691
|
-
function extractAiContent(msg) {
|
|
2692
|
-
if (!msg || !isAiMessage(msg)) return "";
|
|
2693
|
-
return getMessageContent(msg);
|
|
2694
|
-
}
|
|
2695
|
-
async function collectStreamSteps(stream, options) {
|
|
2696
|
-
const steps = [];
|
|
2697
|
-
let stepIndex = 0;
|
|
2698
|
-
let lastAiContent = "";
|
|
2699
|
-
for await (const chunk of stream) {
|
|
2700
|
-
const nodeMap = Array.isArray(chunk) && chunk.length >= 2 && typeof chunk[chunk.length - 1] === "object" && chunk[chunk.length - 1] !== null && !Array.isArray(chunk[chunk.length - 1]) ? chunk[chunk.length - 1] : chunk;
|
|
2701
|
-
for (const [node, value] of Object.entries(nodeMap)) {
|
|
2702
|
-
if (value === void 0 || value === null) continue;
|
|
2703
|
-
stepIndex += 1;
|
|
2704
|
-
const step = buildStep(stepIndex, node, value);
|
|
2705
|
-
steps.push(step);
|
|
2706
|
-
options?.onStep?.(step);
|
|
2707
|
-
const v = value;
|
|
2708
|
-
const messages = v?.messages ?? v?.__state__?.messages;
|
|
2709
|
-
const lastMsg = Array.isArray(messages) ? messages.slice(-1)[0] : void 0;
|
|
2710
|
-
let content = extractAiContent(lastMsg);
|
|
2711
|
-
if (!content && node === "agent" && lastMsg && typeof lastMsg === "object" && !("tool_call_id" in lastMsg && lastMsg.tool_call_id)) {
|
|
2712
|
-
content = getMessageContent(lastMsg);
|
|
2713
|
-
}
|
|
2714
|
-
if (content) lastAiContent = content;
|
|
149
|
+
const files = fs.readdirSync(packDest);
|
|
150
|
+
const tgz = files.find((f) => f.endsWith(".tgz"));
|
|
151
|
+
if (!tgz) {
|
|
152
|
+
throw new Error(`npm pack did not produce a .tgz in ${packDest}`);
|
|
153
|
+
}
|
|
154
|
+
const resolvedVersion = getVersionFromTarball(tgz);
|
|
155
|
+
const cacheDir = resolveCacheDir(cacheBase, packageName, resolvedVersion);
|
|
156
|
+
const packageJsonPath = path.join(cacheDir, "package.json");
|
|
157
|
+
const nodeModulesPath = path.join(cacheDir, "node_modules");
|
|
158
|
+
if (fs.existsSync(packageJsonPath) && fs.existsSync(nodeModulesPath)) {
|
|
159
|
+
options.afterInstall?.(cacheDir, packageName);
|
|
160
|
+
fs.rmSync(packDest, { recursive: true, force: true });
|
|
161
|
+
return cacheDir;
|
|
162
|
+
}
|
|
163
|
+
const extractDir = path.join(packDest, "extract");
|
|
164
|
+
fs.mkdirSync(extractDir, { recursive: true });
|
|
165
|
+
child_process.execSync(`tar -xzf "${path.join(packDest, tgz)}" -C "${extractDir}"`, {
|
|
166
|
+
stdio: "pipe",
|
|
167
|
+
encoding: "utf-8"
|
|
168
|
+
});
|
|
169
|
+
const extractedPackage = path.join(extractDir, "package");
|
|
170
|
+
if (!fs.existsSync(extractedPackage)) {
|
|
171
|
+
throw new Error(`Extracted tarball did not contain "package" dir in ${extractDir}`);
|
|
172
|
+
}
|
|
173
|
+
fs.mkdirSync(path.join(cacheDir, ".."), { recursive: true });
|
|
174
|
+
if (fs.existsSync(cacheDir)) {
|
|
175
|
+
fs.rmSync(cacheDir, { recursive: true, force: true });
|
|
176
|
+
}
|
|
177
|
+
fs.renameSync(extractedPackage, cacheDir);
|
|
178
|
+
child_process.execSync("npm install", {
|
|
179
|
+
cwd: cacheDir,
|
|
180
|
+
stdio: "pipe",
|
|
181
|
+
encoding: "utf-8"
|
|
182
|
+
});
|
|
183
|
+
options.afterInstall?.(cacheDir, packageName);
|
|
184
|
+
return cacheDir;
|
|
185
|
+
} finally {
|
|
186
|
+
if (fs.existsSync(packDest)) {
|
|
187
|
+
fs.rmSync(packDest, { recursive: true, force: true });
|
|
2715
188
|
}
|
|
2716
189
|
}
|
|
2717
|
-
for (let i = 1; i < steps.length; i++) {
|
|
2718
|
-
const prev = steps[i - 1];
|
|
2719
|
-
const curr = steps[i];
|
|
2720
|
-
if (prev && curr) curr.input = prev.output;
|
|
2721
|
-
}
|
|
2722
|
-
const first = steps[0];
|
|
2723
|
-
if (first && first.input === void 0) {
|
|
2724
|
-
first.input = { __info: "Initial state (see System and User Prompt above)" };
|
|
2725
|
-
}
|
|
2726
|
-
return { steps, lastAiContent };
|
|
2727
190
|
}
|
|
2728
|
-
|
|
2729
|
-
const
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
if (options.reportPath) {
|
|
2733
|
-
const reportPath = path.resolve(options.reportPath);
|
|
2734
|
-
if (fs.existsSync(reportPath)) {
|
|
2735
|
-
reportMarkdown = fs.readFileSync(reportPath, "utf8");
|
|
2736
|
-
}
|
|
191
|
+
function getPackageEntryPath(packageRoot) {
|
|
192
|
+
const pkgPath = path.join(packageRoot, "package.json");
|
|
193
|
+
if (!fs.existsSync(pkgPath)) {
|
|
194
|
+
throw new Error(`No package.json in ${packageRoot}`);
|
|
2737
195
|
}
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
userPrompt: options.userPrompt,
|
|
2744
|
-
reportMarkdown,
|
|
2745
|
-
steps
|
|
2746
|
-
},
|
|
2747
|
-
{
|
|
2748
|
-
outputPath: options.htmlReportPath,
|
|
2749
|
-
templatePath: options.templatePath
|
|
2750
|
-
}
|
|
2751
|
-
);
|
|
196
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
197
|
+
const main = pkg.main ?? "dist/index.js";
|
|
198
|
+
const entry = path.join(packageRoot, main);
|
|
199
|
+
if (!fs.existsSync(entry)) {
|
|
200
|
+
throw new Error(`Entry not found: ${entry}`);
|
|
2752
201
|
}
|
|
2753
|
-
return
|
|
202
|
+
return entry;
|
|
2754
203
|
}
|
|
2755
|
-
async function
|
|
2756
|
-
const
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
}
|
|
2763
|
-
}
|
|
2764
|
-
let htmlPath;
|
|
2765
|
-
if (options.htmlReportPath) {
|
|
2766
|
-
htmlPath = generateAgentReport(
|
|
2767
|
-
{
|
|
2768
|
-
systemPrompt: options.systemPrompt,
|
|
2769
|
-
userPrompt: options.userPrompt,
|
|
2770
|
-
reportMarkdown,
|
|
2771
|
-
steps
|
|
2772
|
-
},
|
|
2773
|
-
{
|
|
2774
|
-
outputPath: options.htmlReportPath,
|
|
2775
|
-
templatePath: options.templatePath
|
|
2776
|
-
}
|
|
2777
|
-
);
|
|
2778
|
-
}
|
|
2779
|
-
return { steps, reportMarkdown, htmlPath };
|
|
204
|
+
async function importFromCache(packageRoot) {
|
|
205
|
+
const entryPath = getPackageEntryPath(packageRoot);
|
|
206
|
+
const fileUrl = url.pathToFileURL(entryPath).href;
|
|
207
|
+
return import(
|
|
208
|
+
/* @vite-ignore */
|
|
209
|
+
fileUrl
|
|
210
|
+
);
|
|
2780
211
|
}
|
|
2781
212
|
|
|
213
|
+
Object.defineProperty(exports, "LangChainToolsHub", {
|
|
214
|
+
enumerable: true,
|
|
215
|
+
get: function () { return chunkBZOKPJMP_cjs.LangChainToolsHub; }
|
|
216
|
+
});
|
|
217
|
+
Object.defineProperty(exports, "createAgentTools", {
|
|
218
|
+
enumerable: true,
|
|
219
|
+
get: function () { return chunkBZOKPJMP_cjs.createAgentTools; }
|
|
220
|
+
});
|
|
221
|
+
Object.defineProperty(exports, "DirectoryScanner", {
|
|
222
|
+
enumerable: true,
|
|
223
|
+
get: function () { return chunkZBNRHRGM_cjs.DirectoryScanner; }
|
|
224
|
+
});
|
|
2782
225
|
Object.defineProperty(exports, "DiscoveryError", {
|
|
2783
226
|
enumerable: true,
|
|
2784
|
-
get: function () { return
|
|
227
|
+
get: function () { return chunkZBNRHRGM_cjs.DiscoveryError; }
|
|
2785
228
|
});
|
|
2786
229
|
Object.defineProperty(exports, "SkillManifestError", {
|
|
2787
230
|
enumerable: true,
|
|
2788
|
-
get: function () { return
|
|
231
|
+
get: function () { return chunkZBNRHRGM_cjs.SkillManifestError; }
|
|
2789
232
|
});
|
|
2790
233
|
Object.defineProperty(exports, "buildFunctionToTool", {
|
|
2791
234
|
enumerable: true,
|
|
2792
|
-
get: function () { return
|
|
235
|
+
get: function () { return chunkZBNRHRGM_cjs.buildFunctionToTool; }
|
|
2793
236
|
});
|
|
2794
237
|
Object.defineProperty(exports, "buildMcpPackage", {
|
|
2795
238
|
enumerable: true,
|
|
2796
|
-
get: function () { return
|
|
239
|
+
get: function () { return chunkZBNRHRGM_cjs.buildMcpPackage; }
|
|
2797
240
|
});
|
|
2798
241
|
Object.defineProperty(exports, "initProject", {
|
|
2799
242
|
enumerable: true,
|
|
2800
|
-
get: function () { return
|
|
243
|
+
get: function () { return chunkZBNRHRGM_cjs.initProject; }
|
|
244
|
+
});
|
|
245
|
+
Object.defineProperty(exports, "loadMCPTool", {
|
|
246
|
+
enumerable: true,
|
|
247
|
+
get: function () { return chunkZBNRHRGM_cjs.loadMCPTool; }
|
|
2801
248
|
});
|
|
2802
249
|
Object.defineProperty(exports, "loadSkillDefinition", {
|
|
2803
250
|
enumerable: true,
|
|
2804
|
-
get: function () { return
|
|
251
|
+
get: function () { return chunkZBNRHRGM_cjs.loadSkillDefinition; }
|
|
2805
252
|
});
|
|
2806
253
|
Object.defineProperty(exports, "parseSkillMd", {
|
|
2807
254
|
enumerable: true,
|
|
2808
|
-
get: function () { return
|
|
255
|
+
get: function () { return chunkZBNRHRGM_cjs.parseSkillMd; }
|
|
2809
256
|
});
|
|
2810
257
|
Object.defineProperty(exports, "runGeneratedMCP", {
|
|
2811
258
|
enumerable: true,
|
|
2812
|
-
get: function () { return
|
|
259
|
+
get: function () { return chunkZBNRHRGM_cjs.runGeneratedMCP; }
|
|
2813
260
|
});
|
|
2814
261
|
Object.defineProperty(exports, "runMcpServer", {
|
|
2815
262
|
enumerable: true,
|
|
2816
|
-
get: function () { return
|
|
263
|
+
get: function () { return chunkZBNRHRGM_cjs.runMcpServer; }
|
|
264
|
+
});
|
|
265
|
+
Object.defineProperty(exports, "scan", {
|
|
266
|
+
enumerable: true,
|
|
267
|
+
get: function () { return chunkZBNRHRGM_cjs.scan; }
|
|
2817
268
|
});
|
|
2818
269
|
Object.defineProperty(exports, "scanForTools", {
|
|
2819
270
|
enumerable: true,
|
|
2820
|
-
get: function () { return
|
|
271
|
+
get: function () { return chunkZBNRHRGM_cjs.scanForTools; }
|
|
2821
272
|
});
|
|
2822
273
|
Object.defineProperty(exports, "scanSkillResources", {
|
|
2823
274
|
enumerable: true,
|
|
2824
|
-
get: function () { return
|
|
275
|
+
get: function () { return chunkZBNRHRGM_cjs.scanSkillResources; }
|
|
2825
276
|
});
|
|
2826
277
|
Object.defineProperty(exports, "validateFrontmatter", {
|
|
2827
278
|
enumerable: true,
|
|
2828
|
-
get: function () { return
|
|
279
|
+
get: function () { return chunkZBNRHRGM_cjs.validateFrontmatter; }
|
|
2829
280
|
});
|
|
2830
281
|
Object.defineProperty(exports, "DEFAULT_INPUT_SCHEMA", {
|
|
2831
282
|
enumerable: true,
|
|
2832
|
-
get: function () { return
|
|
283
|
+
get: function () { return chunkSOFUWEZ6_cjs.DEFAULT_INPUT_SCHEMA; }
|
|
2833
284
|
});
|
|
2834
285
|
Object.defineProperty(exports, "DEFAULT_OUTPUT_SCHEMA", {
|
|
2835
286
|
enumerable: true,
|
|
2836
|
-
get: function () { return
|
|
287
|
+
get: function () { return chunkSOFUWEZ6_cjs.DEFAULT_OUTPUT_SCHEMA; }
|
|
2837
288
|
});
|
|
2838
289
|
Object.defineProperty(exports, "createToolSpec", {
|
|
2839
290
|
enumerable: true,
|
|
2840
|
-
get: function () { return
|
|
291
|
+
get: function () { return chunkSOFUWEZ6_cjs.createToolSpec; }
|
|
292
|
+
});
|
|
293
|
+
Object.defineProperty(exports, "BudgetManager", {
|
|
294
|
+
enumerable: true,
|
|
295
|
+
get: function () { return chunkFA2ZEICE_cjs.BudgetManager; }
|
|
296
|
+
});
|
|
297
|
+
Object.defineProperty(exports, "EventLog", {
|
|
298
|
+
enumerable: true,
|
|
299
|
+
get: function () { return chunkFA2ZEICE_cjs.EventLog; }
|
|
300
|
+
});
|
|
301
|
+
Object.defineProperty(exports, "Metrics", {
|
|
302
|
+
enumerable: true,
|
|
303
|
+
get: function () { return chunkFA2ZEICE_cjs.Metrics; }
|
|
304
|
+
});
|
|
305
|
+
Object.defineProperty(exports, "PTCRuntime", {
|
|
306
|
+
enumerable: true,
|
|
307
|
+
get: function () { return chunkFA2ZEICE_cjs.PTCRuntime; }
|
|
308
|
+
});
|
|
309
|
+
Object.defineProperty(exports, "PolicyDeniedError", {
|
|
310
|
+
enumerable: true,
|
|
311
|
+
get: function () { return chunkFA2ZEICE_cjs.PolicyDeniedError; }
|
|
312
|
+
});
|
|
313
|
+
Object.defineProperty(exports, "PolicyEngine", {
|
|
314
|
+
enumerable: true,
|
|
315
|
+
get: function () { return chunkFA2ZEICE_cjs.PolicyEngine; }
|
|
316
|
+
});
|
|
317
|
+
Object.defineProperty(exports, "SchemaValidationError", {
|
|
318
|
+
enumerable: true,
|
|
319
|
+
get: function () { return chunkFA2ZEICE_cjs.SchemaValidationError; }
|
|
320
|
+
});
|
|
321
|
+
Object.defineProperty(exports, "SchemaValidator", {
|
|
322
|
+
enumerable: true,
|
|
323
|
+
get: function () { return chunkFA2ZEICE_cjs.SchemaValidator; }
|
|
324
|
+
});
|
|
325
|
+
Object.defineProperty(exports, "Tracing", {
|
|
326
|
+
enumerable: true,
|
|
327
|
+
get: function () { return chunkFA2ZEICE_cjs.Tracing; }
|
|
328
|
+
});
|
|
329
|
+
Object.defineProperty(exports, "buildEvidence", {
|
|
330
|
+
enumerable: true,
|
|
331
|
+
get: function () { return chunkFA2ZEICE_cjs.buildEvidence; }
|
|
332
|
+
});
|
|
333
|
+
Object.defineProperty(exports, "createLogger", {
|
|
334
|
+
enumerable: true,
|
|
335
|
+
get: function () { return chunkFA2ZEICE_cjs.createLogger; }
|
|
336
|
+
});
|
|
337
|
+
Object.defineProperty(exports, "expandToolDescriptorsToRegistryNames", {
|
|
338
|
+
enumerable: true,
|
|
339
|
+
get: function () { return chunkFA2ZEICE_cjs.expandToolDescriptorsToRegistryNames; }
|
|
340
|
+
});
|
|
341
|
+
Object.defineProperty(exports, "isNpmToolDescriptor", {
|
|
342
|
+
enumerable: true,
|
|
343
|
+
get: function () { return chunkFA2ZEICE_cjs.isNpmToolDescriptor; }
|
|
344
|
+
});
|
|
345
|
+
Object.defineProperty(exports, "loadToolConfig", {
|
|
346
|
+
enumerable: true,
|
|
347
|
+
get: function () { return chunkFA2ZEICE_cjs.loadToolConfig; }
|
|
348
|
+
});
|
|
349
|
+
Object.defineProperty(exports, "normalizeToolList", {
|
|
350
|
+
enumerable: true,
|
|
351
|
+
get: function () { return chunkFA2ZEICE_cjs.normalizeToolList; }
|
|
352
|
+
});
|
|
353
|
+
Object.defineProperty(exports, "parseNpmToolDescriptor", {
|
|
354
|
+
enumerable: true,
|
|
355
|
+
get: function () { return chunkFA2ZEICE_cjs.parseNpmToolDescriptor; }
|
|
356
|
+
});
|
|
357
|
+
Object.defineProperty(exports, "resolveNpmToolDescriptor", {
|
|
358
|
+
enumerable: true,
|
|
359
|
+
get: function () { return chunkFA2ZEICE_cjs.resolveNpmToolDescriptor; }
|
|
360
|
+
});
|
|
361
|
+
Object.defineProperty(exports, "resolveToolDescriptor", {
|
|
362
|
+
enumerable: true,
|
|
363
|
+
get: function () { return chunkFA2ZEICE_cjs.resolveToolDescriptor; }
|
|
364
|
+
});
|
|
365
|
+
Object.defineProperty(exports, "sanitizeForLog", {
|
|
366
|
+
enumerable: true,
|
|
367
|
+
get: function () { return chunkFA2ZEICE_cjs.sanitizeForLog; }
|
|
368
|
+
});
|
|
369
|
+
Object.defineProperty(exports, "summarizeForLog", {
|
|
370
|
+
enumerable: true,
|
|
371
|
+
get: function () { return chunkFA2ZEICE_cjs.summarizeForLog; }
|
|
2841
372
|
});
|
|
2842
|
-
Object.defineProperty(exports, "
|
|
373
|
+
Object.defineProperty(exports, "ToolRegistry", {
|
|
2843
374
|
enumerable: true,
|
|
2844
|
-
get: function () { return
|
|
375
|
+
get: function () { return chunkZNJBRLKN_cjs.ToolRegistry; }
|
|
2845
376
|
});
|
|
2846
|
-
Object.defineProperty(exports, "
|
|
377
|
+
Object.defineProperty(exports, "createTaggedError", {
|
|
2847
378
|
enumerable: true,
|
|
2848
|
-
get: function () { return
|
|
379
|
+
get: function () { return chunkZNJBRLKN_cjs.createTaggedError; }
|
|
2849
380
|
});
|
|
2850
|
-
Object.defineProperty(exports, "
|
|
381
|
+
Object.defineProperty(exports, "isRetryable", {
|
|
2851
382
|
enumerable: true,
|
|
2852
|
-
get: function () { return
|
|
383
|
+
get: function () { return chunkZNJBRLKN_cjs.isRetryable; }
|
|
2853
384
|
});
|
|
2854
|
-
Object.defineProperty(exports, "
|
|
385
|
+
Object.defineProperty(exports, "withRetry", {
|
|
2855
386
|
enumerable: true,
|
|
2856
|
-
get: function () { return
|
|
387
|
+
get: function () { return chunkZNJBRLKN_cjs.withRetry; }
|
|
2857
388
|
});
|
|
2858
389
|
Object.defineProperty(exports, "CoreAdapter", {
|
|
2859
390
|
enumerable: true,
|
|
@@ -2971,44 +502,13 @@ Object.defineProperty(exports, "yahooQuoteSpec", {
|
|
|
2971
502
|
enumerable: true,
|
|
2972
503
|
get: function () { return agentToolExampleTools.yahooQuoteSpec; }
|
|
2973
504
|
});
|
|
2974
|
-
exports.BudgetManager = BudgetManager;
|
|
2975
|
-
exports.DirectoryScanner = DirectoryScanner;
|
|
2976
|
-
exports.EventLog = EventLog;
|
|
2977
|
-
exports.LangChainToolsHub = LangChainToolsHub;
|
|
2978
505
|
exports.MCPClientAdapter = MCPClientAdapter;
|
|
2979
506
|
exports.MCPProcessManager = MCPProcessManager;
|
|
2980
|
-
exports.Metrics = Metrics;
|
|
2981
|
-
exports.PTCRuntime = PTCRuntime;
|
|
2982
|
-
exports.PolicyDeniedError = PolicyDeniedError;
|
|
2983
|
-
exports.PolicyEngine = PolicyEngine;
|
|
2984
|
-
exports.SchemaValidationError = SchemaValidationError;
|
|
2985
|
-
exports.SchemaValidator = SchemaValidator;
|
|
2986
|
-
exports.ToolRegistry = ToolRegistry;
|
|
2987
|
-
exports.Tracing = Tracing;
|
|
2988
|
-
exports.buildEvidence = buildEvidence;
|
|
2989
|
-
exports.collectStreamSteps = collectStreamSteps;
|
|
2990
507
|
exports.connectMCP = connectMCP;
|
|
2991
|
-
exports.
|
|
2992
|
-
exports.
|
|
2993
|
-
exports.
|
|
2994
|
-
exports.formatStepProgress = formatStepProgress;
|
|
2995
|
-
exports.generateAgentReport = generateAgentReport;
|
|
2996
|
-
exports.isNpmToolDescriptor = isNpmToolDescriptor;
|
|
2997
|
-
exports.isRetryable = isRetryable;
|
|
2998
|
-
exports.loadAgentConfig = loadAgentConfig;
|
|
2999
|
-
exports.loadMCPTool = loadMCPTool;
|
|
508
|
+
exports.ensurePackageInCache = ensurePackageInCache;
|
|
509
|
+
exports.getPackageEntryPath = getPackageEntryPath;
|
|
510
|
+
exports.importFromCache = importFromCache;
|
|
3000
511
|
exports.mcpToolsToSpecs = mcpToolsToSpecs;
|
|
3001
|
-
exports.normalizeToolList = normalizeToolList;
|
|
3002
|
-
exports.parseNpmToolDescriptor = parseNpmToolDescriptor;
|
|
3003
512
|
exports.registerMCPToolsFromConfig = registerMCPToolsFromConfig;
|
|
3004
|
-
exports.resolveNpmToolDescriptor = resolveNpmToolDescriptor;
|
|
3005
|
-
exports.resolveToolDescriptor = resolveToolDescriptor;
|
|
3006
|
-
exports.runAgent = runAgent;
|
|
3007
|
-
exports.runAgentWithReport = runAgentWithReport;
|
|
3008
|
-
exports.sanitizeForLog = sanitizeForLog;
|
|
3009
|
-
exports.serializeStepOutput = serializeStepOutput;
|
|
3010
|
-
exports.summarizeForLog = summarizeForLog;
|
|
3011
|
-
exports.withRetry = withRetry;
|
|
3012
|
-
exports.writeReportFromStream = writeReportFromStream;
|
|
3013
513
|
//# sourceMappingURL=index.cjs.map
|
|
3014
514
|
//# sourceMappingURL=index.cjs.map
|