@easynet/agent-tool 1.0.1 → 1.0.3

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