melchizedek-agents 0.18.0 → 0.20.0

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 (293) hide show
  1. package/.env.example +12 -0
  2. package/CHANGELOG.md +1001 -0
  3. package/DOCUMENTATION.md +252 -65
  4. package/QUICKSTART.md +9 -6
  5. package/README.md +42 -4
  6. package/config/agents/examples/harness.yaml +3 -1
  7. package/config/agents/examples/model_zoo.yaml +10 -9
  8. package/config/agents/syndicateSchema.yaml +53 -16
  9. package/config/agents/templates/account_memory.yaml +2 -6
  10. package/config/agents/templates/case_desk.yaml +3 -9
  11. package/config/agents/templates/draft_review.yaml +3 -9
  12. package/config/agents/templates/intake_extractor.yaml +1 -3
  13. package/config/agents/templates/research_brief.yaml +3 -9
  14. package/config/agents/templates/research_desk.yaml +3 -9
  15. package/config/agents/templates/review_panel.yaml +4 -12
  16. package/config/agents/templates/support_triage.yaml +4 -12
  17. package/config/agents/templates/systems_operator.yaml +2 -6
  18. package/db/hardening.sql +7 -1
  19. package/db/migrations/0013_tool_credentials.sql +260 -0
  20. package/dist/lib/a2a/app.d.ts +70 -6
  21. package/dist/lib/a2a/app.js +107 -2
  22. package/dist/lib/a2a/executor.d.ts +20 -3
  23. package/dist/lib/a2a/executor.js +66 -7
  24. package/dist/lib/a2a/remoteAgent.d.ts +24 -9
  25. package/dist/lib/a2a/remoteAgent.js +31 -14
  26. package/dist/lib/adkPeer.d.ts +63 -0
  27. package/dist/lib/adkPeer.js +240 -0
  28. package/dist/lib/compile.d.ts +159 -30
  29. package/dist/lib/compile.js +215 -134
  30. package/dist/lib/compileAdk.d.ts +32 -0
  31. package/dist/lib/compileAdk.js +142 -0
  32. package/dist/lib/compileNative.d.ts +111 -0
  33. package/dist/lib/compileNative.js +278 -0
  34. package/dist/lib/config.d.ts +6 -5
  35. package/dist/lib/config.js +6 -5
  36. package/dist/lib/doctor.d.ts +28 -1
  37. package/dist/lib/doctor.js +64 -2
  38. package/dist/lib/index.d.ts +6 -1
  39. package/dist/lib/index.js +7 -1
  40. package/dist/lib/loadSyndicate.d.ts +18 -0
  41. package/dist/lib/memory/erase.d.ts +5 -3
  42. package/dist/lib/memory/erase.js +5 -2
  43. package/dist/lib/memory/namespace.d.ts +8 -1
  44. package/dist/lib/memory/namespace.js +12 -6
  45. package/dist/lib/memory/providers.js +2 -1
  46. package/dist/lib/memory/supabaseMemoryService.d.ts +37 -3
  47. package/dist/lib/memory/supabaseMemoryService.js +42 -2
  48. package/dist/lib/model.d.ts +47 -0
  49. package/dist/lib/model.js +37 -0
  50. package/dist/lib/models/adapterResolver.d.ts +115 -0
  51. package/dist/lib/models/adapterResolver.js +137 -0
  52. package/dist/lib/models/adkGeminiAdapter.d.ts +90 -0
  53. package/dist/lib/models/adkGeminiAdapter.js +369 -0
  54. package/dist/lib/models/adkShim.d.ts +111 -0
  55. package/dist/lib/models/adkShim.js +136 -0
  56. package/dist/lib/models/capabilities.d.ts +3 -0
  57. package/dist/lib/models/capabilities.js +33 -23
  58. package/dist/lib/models/chatCompletionsAdapter.d.ts +279 -0
  59. package/dist/lib/models/chatCompletionsAdapter.js +854 -0
  60. package/dist/lib/models/circuitBreaker.d.ts +42 -0
  61. package/dist/lib/models/circuitBreaker.js +70 -0
  62. package/dist/lib/models/claudeAdapter.d.ts +103 -0
  63. package/dist/lib/models/claudeAdapter.js +669 -0
  64. package/dist/lib/models/claudeLlm.d.ts +39 -62
  65. package/dist/lib/models/claudeLlm.js +45 -350
  66. package/dist/lib/models/claudeModels.d.ts +127 -0
  67. package/dist/lib/models/claudeModels.js +237 -0
  68. package/dist/lib/models/contract.d.ts +395 -0
  69. package/dist/lib/models/contract.js +39 -0
  70. package/dist/lib/models/endpoints.js +2 -1
  71. package/dist/lib/models/errorResponse.d.ts +50 -0
  72. package/dist/lib/models/errorResponse.js +48 -0
  73. package/dist/lib/models/fallback.d.ts +18 -11
  74. package/dist/lib/models/fallback.js +54 -43
  75. package/dist/lib/models/fallbackAdapter.d.ts +55 -0
  76. package/dist/lib/models/fallbackAdapter.js +62 -0
  77. package/dist/lib/models/gateway.js +2 -1
  78. package/dist/lib/models/gatewayAdapter.d.ts +51 -0
  79. package/dist/lib/models/gatewayAdapter.js +81 -0
  80. package/dist/lib/models/gatewayLlm.d.ts +12 -33
  81. package/dist/lib/models/gatewayLlm.js +16 -77
  82. package/dist/lib/models/geminiAdapter.d.ts +125 -0
  83. package/dist/lib/models/geminiAdapter.js +854 -0
  84. package/dist/lib/models/geminiState.d.ts +46 -0
  85. package/dist/lib/models/geminiState.js +51 -0
  86. package/dist/lib/models/genaiMapping.d.ts +283 -0
  87. package/dist/lib/models/genaiMapping.js +965 -0
  88. package/dist/lib/models/gptAdapter.d.ts +240 -0
  89. package/dist/lib/models/gptAdapter.js +804 -0
  90. package/dist/lib/models/gptLlm.d.ts +63 -123
  91. package/dist/lib/models/gptLlm.js +89 -603
  92. package/dist/lib/models/grokAdapter.d.ts +86 -0
  93. package/dist/lib/models/grokAdapter.js +142 -0
  94. package/dist/lib/models/grokLlm.d.ts +22 -45
  95. package/dist/lib/models/grokLlm.js +24 -69
  96. package/dist/lib/models/kimiAdapter.d.ts +157 -0
  97. package/dist/lib/models/kimiAdapter.js +203 -0
  98. package/dist/lib/models/kimiLlm.d.ts +15 -107
  99. package/dist/lib/models/kimiLlm.js +19 -155
  100. package/dist/lib/models/ollamaAdapter.d.ts +125 -0
  101. package/dist/lib/models/ollamaAdapter.js +155 -0
  102. package/dist/lib/models/ollamaLlm.d.ts +11 -107
  103. package/dist/lib/models/ollamaLlm.js +15 -153
  104. package/dist/lib/models/openAiCompatibleLlm.d.ts +73 -216
  105. package/dist/lib/models/openAiCompatibleLlm.js +109 -671
  106. package/dist/lib/models/providerState.d.ts +63 -0
  107. package/dist/lib/models/providerState.js +61 -0
  108. package/dist/lib/models/reasoning.d.ts +26 -0
  109. package/dist/lib/models/reasoning.js +59 -0
  110. package/dist/lib/models/registry.d.ts +62 -35
  111. package/dist/lib/models/registry.js +100 -124
  112. package/dist/lib/models/retry.d.ts +2 -1
  113. package/dist/lib/models/retry.js +3 -2
  114. package/dist/lib/models/schemaNormalize.d.ts +98 -0
  115. package/dist/lib/models/schemaNormalize.js +321 -1
  116. package/dist/lib/models/tracedGemini.d.ts +41 -0
  117. package/dist/lib/models/tracedGemini.js +98 -0
  118. package/dist/lib/models/urls.d.ts +11 -0
  119. package/dist/lib/models/urls.js +16 -0
  120. package/dist/lib/net/redirects.d.ts +21 -2
  121. package/dist/lib/net/redirects.js +11 -34
  122. package/dist/lib/observability/audit.d.ts +5 -1
  123. package/dist/lib/observability/lineage.d.ts +14 -0
  124. package/dist/lib/observability/lineage.js +33 -0
  125. package/dist/lib/observability/supabaseSpanExporter.d.ts +10 -4
  126. package/dist/lib/observability/supabaseSpanExporter.js +17 -9
  127. package/dist/lib/observability/tracer.d.ts +26 -8
  128. package/dist/lib/observability/tracer.js +43 -18
  129. package/dist/lib/runtime/adkMemoryBridge.d.ts +46 -0
  130. package/dist/lib/runtime/adkMemoryBridge.js +68 -0
  131. package/dist/lib/runtime/adkSessionBridge.d.ts +78 -0
  132. package/dist/lib/runtime/adkSessionBridge.js +176 -0
  133. package/dist/lib/runtime/approvals.d.ts +5 -0
  134. package/dist/lib/runtime/approvals.js +39 -8
  135. package/dist/lib/runtime/credentials.d.ts +61 -0
  136. package/dist/lib/runtime/credentials.js +67 -0
  137. package/dist/lib/runtime/events.d.ts +229 -0
  138. package/dist/lib/runtime/events.js +274 -0
  139. package/dist/lib/runtime/logging.d.ts +32 -0
  140. package/dist/lib/runtime/logging.js +55 -0
  141. package/dist/lib/runtime/memoryService.d.ts +72 -0
  142. package/dist/lib/runtime/memoryService.js +25 -0
  143. package/dist/lib/runtime/native/agentLoop.d.ts +209 -0
  144. package/dist/lib/runtime/native/agentLoop.js +705 -0
  145. package/dist/lib/runtime/native/compaction.d.ts +103 -0
  146. package/dist/lib/runtime/native/compaction.js +191 -0
  147. package/dist/lib/runtime/native/delegate.d.ts +151 -0
  148. package/dist/lib/runtime/native/delegate.js +256 -0
  149. package/dist/lib/runtime/native/history.d.ts +83 -0
  150. package/dist/lib/runtime/native/history.js +312 -0
  151. package/dist/lib/runtime/native/interrupts.d.ts +129 -0
  152. package/dist/lib/runtime/native/interrupts.js +310 -0
  153. package/dist/lib/runtime/native/request.d.ts +215 -0
  154. package/dist/lib/runtime/native/request.js +585 -0
  155. package/dist/lib/runtime/native/selfCorrection.d.ts +164 -0
  156. package/dist/lib/runtime/native/selfCorrection.js +327 -0
  157. package/dist/lib/runtime/native/step.d.ts +156 -0
  158. package/dist/lib/runtime/native/step.js +263 -0
  159. package/dist/lib/runtime/native/taskMode.d.ts +64 -0
  160. package/dist/lib/runtime/native/taskMode.js +126 -0
  161. package/dist/lib/runtime/native/telemetry.d.ts +75 -0
  162. package/dist/lib/runtime/native/telemetry.js +299 -0
  163. package/dist/lib/runtime/native/tempState.d.ts +31 -0
  164. package/dist/lib/runtime/native/tempState.js +56 -0
  165. package/dist/lib/runtime/nativeTurn.d.ts +86 -0
  166. package/dist/lib/runtime/nativeTurn.js +107 -0
  167. package/dist/lib/runtime/questions.d.ts +29 -7
  168. package/dist/lib/runtime/questions.js +47 -32
  169. package/dist/lib/runtime/runtimeFlag.d.ts +38 -0
  170. package/dist/lib/runtime/runtimeFlag.js +58 -0
  171. package/dist/lib/runtime/sessions.d.ts +166 -0
  172. package/dist/lib/runtime/sessions.js +201 -0
  173. package/dist/lib/runtime/syndicateTurn.d.ts +46 -5
  174. package/dist/lib/runtime/syndicateTurn.js +233 -36
  175. package/dist/lib/runtime/valueDepth.d.ts +23 -0
  176. package/dist/lib/runtime/valueDepth.js +41 -0
  177. package/dist/lib/session/supabaseSessionService.d.ts +65 -18
  178. package/dist/lib/session/supabaseSessionService.js +148 -105
  179. package/dist/lib/session/transcript.d.ts +69 -23
  180. package/dist/lib/session/transcript.js +105 -29
  181. package/dist/lib/skills.js +33 -7
  182. package/dist/lib/storage/postgres/credentialStore.d.ts +20 -0
  183. package/dist/lib/storage/postgres/credentialStore.js +82 -0
  184. package/dist/lib/storage/postgres/index.d.ts +12 -0
  185. package/dist/lib/storage/postgres/index.js +6 -1
  186. package/dist/lib/storage/postgres/sessionService.d.ts +44 -16
  187. package/dist/lib/storage/postgres/sessionService.js +128 -66
  188. package/dist/lib/syndicateSchema.d.ts +49 -0
  189. package/dist/lib/syndicateSchema.js +99 -9
  190. package/dist/lib/toolRegistry.d.ts +26 -2
  191. package/dist/lib/toolRegistry.js +73 -17
  192. package/dist/lib/tools/adkTool.d.ts +81 -0
  193. package/dist/lib/tools/adkTool.js +268 -0
  194. package/dist/lib/tools/auth.d.ts +118 -0
  195. package/dist/lib/tools/auth.js +89 -0
  196. package/dist/lib/tools/collectionsSearchTool.d.ts +8 -7
  197. package/dist/lib/tools/collectionsSearchTool.js +12 -27
  198. package/dist/lib/tools/credentialCipher.d.ts +58 -0
  199. package/dist/lib/tools/credentialCipher.js +116 -0
  200. package/dist/lib/tools/credentialStore.d.ts +77 -0
  201. package/dist/lib/tools/credentialStore.js +246 -0
  202. package/dist/lib/tools/examples.d.ts +43 -0
  203. package/dist/lib/tools/examples.js +62 -0
  204. package/dist/lib/tools/generateImageTool.d.ts +15 -6
  205. package/dist/lib/tools/generateImageTool.js +19 -29
  206. package/dist/lib/tools/inspectImageTool.d.ts +9 -6
  207. package/dist/lib/tools/inspectImageTool.js +13 -17
  208. package/dist/lib/tools/mcpToolFactory.d.ts +42 -1
  209. package/dist/lib/tools/mcpToolFactory.js +46 -47
  210. package/dist/lib/tools/memoryTools.d.ts +61 -0
  211. package/dist/lib/tools/memoryTools.js +119 -0
  212. package/dist/lib/tools/nativeTools.d.ts +38 -0
  213. package/dist/lib/tools/nativeTools.js +43 -0
  214. package/dist/lib/tools/oauthConsent.d.ts +181 -0
  215. package/dist/lib/tools/oauthConsent.js +330 -0
  216. package/dist/lib/tools/openapi/call.d.ts +108 -0
  217. package/dist/lib/tools/openapi/call.js +295 -0
  218. package/dist/lib/tools/openapi/parse.d.ts +147 -0
  219. package/dist/lib/tools/openapi/parse.js +570 -0
  220. package/dist/lib/tools/openapiTools.d.ts +25 -17
  221. package/dist/lib/tools/openapiTools.js +124 -121
  222. package/dist/lib/tools/scienceTools.d.ts +14 -14
  223. package/dist/lib/tools/skillToolset.d.ts +58 -87
  224. package/dist/lib/tools/skillToolset.js +61 -142
  225. package/dist/lib/tools/skills/env.d.ts +58 -0
  226. package/dist/lib/tools/skills/env.js +165 -0
  227. package/dist/lib/tools/skills/executor.d.ts +114 -0
  228. package/dist/lib/tools/skills/executor.js +331 -0
  229. package/dist/lib/tools/skills/frontmatter.d.ts +79 -0
  230. package/dist/lib/tools/skills/frontmatter.js +215 -0
  231. package/dist/lib/tools/skills/loader.d.ts +91 -0
  232. package/dist/lib/tools/skills/loader.js +257 -0
  233. package/dist/lib/tools/skills/tools.d.ts +187 -0
  234. package/dist/lib/tools/skills/tools.js +386 -0
  235. package/dist/lib/tools/taskTools.d.ts +15 -15
  236. package/dist/lib/tools/tool.d.ts +354 -0
  237. package/dist/lib/tools/tool.js +304 -0
  238. package/dist/lib/tools/toolContract.d.ts +89 -33
  239. package/dist/lib/tools/toolContract.js +104 -82
  240. package/dist/lib/tools/urlContextTool.d.ts +4 -1
  241. package/dist/lib/tools/urlContextTool.js +6 -2
  242. package/dist/lib/tools/webExtractTool.d.ts +3 -3
  243. package/dist/lib/tools/webExtractTool.js +2 -1
  244. package/dist/lib/tools/webSearchTool.d.ts +7 -10
  245. package/dist/lib/tools/webSearchTool.js +15 -60
  246. package/dist/lib/tools/wikiTools.d.ts +19 -19
  247. package/dist/lib/tools/wikiTools.js +13 -9
  248. package/dist/lib/tools/xApiSearchTool.d.ts +3 -3
  249. package/dist/lib/tools/xApiSearchTool.js +2 -1
  250. package/dist/lib/tools/xSearchTool.d.ts +8 -10
  251. package/dist/lib/tools/xSearchTool.js +12 -63
  252. package/dist/lib/tools/xaiSearchParams.d.ts +41 -0
  253. package/dist/lib/tools/xaiSearchParams.js +126 -0
  254. package/dist/lib/wiki/agentRun.d.ts +12 -0
  255. package/dist/lib/wiki/agentRun.js +74 -35
  256. package/dist/lib/wiki/entities.d.ts +12 -0
  257. package/dist/lib/wiki/entities.js +45 -3
  258. package/dist/lib/workflow/agentNode.d.ts +153 -0
  259. package/dist/lib/workflow/agentNode.js +365 -0
  260. package/dist/lib/workflow/graph.d.ts +178 -0
  261. package/dist/lib/workflow/graph.js +468 -0
  262. package/dist/lib/workflow/nodeEvents.d.ts +50 -0
  263. package/dist/lib/workflow/nodeEvents.js +101 -0
  264. package/dist/lib/workflow/pause.d.ts +122 -0
  265. package/dist/lib/workflow/pause.js +180 -0
  266. package/dist/lib/workflow/resume.d.ts +166 -0
  267. package/dist/lib/workflow/resume.js +441 -0
  268. package/dist/lib/workflow/route.d.ts +58 -0
  269. package/dist/lib/workflow/route.js +69 -0
  270. package/dist/lib/workflow/scheduler.d.ts +418 -0
  271. package/dist/lib/workflow/scheduler.js +756 -0
  272. package/dist/lib/workflow/toolNode.d.ts +127 -0
  273. package/dist/lib/workflow/toolNode.js +236 -0
  274. package/dist/lib/workflow/turn.d.ts +118 -0
  275. package/dist/lib/workflow/turn.js +216 -0
  276. package/dist/lib/workflow.d.ts +33 -11
  277. package/dist/lib/workflow.js +49 -27
  278. package/dist/lib/workflowConfig.d.ts +7 -2
  279. package/dist/lib/workflowConfig.js +7 -12
  280. package/dist/scripts/a2a_server.js +4 -3
  281. package/dist/scripts/assistant_worker.d.ts +2 -1
  282. package/dist/scripts/assistant_worker.js +9 -4
  283. package/dist/scripts/doctor.d.ts +3 -1
  284. package/dist/scripts/doctor.js +4 -2
  285. package/dist/scripts/syndicate_chat.js +19 -10
  286. package/package.json +9 -3
  287. package/skills/briefs/melchizedek-author.md +3 -2
  288. package/skills/briefs/melchizedek-models.md +13 -9
  289. package/skills/briefs/melchizedek.md +3 -3
  290. package/skills/melchizedek/SKILL.md +2 -1
  291. package/skills/melchizedek-author/SKILL.md +2 -1
  292. package/skills/melchizedek-author/assets/minimal.yaml +2 -0
  293. package/skills/melchizedek-models/SKILL.md +23 -6
@@ -0,0 +1,386 @@
1
+ /**
2
+ * lib/tools/skills/tools.ts — the skill tools and the toolset that holds
3
+ * them, on the engine's own tool base (lib/tools/tool.ts; WS3-3, ADR 0083).
4
+ *
5
+ * WHY this file exists:
6
+ * The skills harness (ADR 0029) was built on ADK's SkillToolset until
7
+ * WS3-3. These are the same tools as own Tools, so the native loop runs
8
+ * them directly and the ADK runtime runs them through the one tool
9
+ * adapter (lib/tools/adkTool.ts, toAdkToolset). A model is sent the same
10
+ * names, descriptions and parameters as before, and reads the same
11
+ * results and error texts, on either runtime:
12
+ * - list_skills: the `<available_skills>` index (ADK's ListSkillsTool).
13
+ * The harness leaves it out, since the index is in the instruction.
14
+ * - load_skill: the procedure, the frontmatter and the NAMES of the files
15
+ * the skill ships (ADR 0029's lean load), and it activates the skill.
16
+ * - load_skill_resource: one of those files (ADK's tool, word for word).
17
+ * A binary file is shown to the model as inline data in the next
18
+ * request, through the Tool's `contents` hook, as ADK's tool did in its
19
+ * processLlmRequest.
20
+ * - run_skill_script: asks a person to approve, then runs one script the
21
+ * skill ships on the local executor (./executor.ts).
22
+ *
23
+ * ACTIVATION: load_skill appends the skill's name to the session state key
24
+ * `_adk_activated_skill_<agent>` (ADK's key, so a session stored by
25
+ * either runtime reads the same). SkillToolset.getTools reads it and adds
26
+ * the tools the activated skills name (`metadata.adk_additional_tools`,
27
+ * filled from `allowed-tools`), but only from the tools the YAML handed
28
+ * it under `skills.tools`: a skill cannot grant itself a tool the YAML
29
+ * withheld.
30
+ *
31
+ * WHY NOT defineTool: a defineTool contract validates its arguments with
32
+ * zod and answers a bad call with its own error string. These tools keep
33
+ * ADK's answers to a bad call (`{ error, error_code }`), so their
34
+ * parameters are written here as JSON Schema and their arguments checked
35
+ * in execute.
36
+ *
37
+ * UNTRUSTED INPUT: every argument is the model's. A skill name and a file
38
+ * path are looked up as own keys of the loaded maps (never on a
39
+ * prototype), so nothing a model sends opens a file the skill did not
40
+ * ship or names a script outside its `scripts/`.
41
+ */
42
+ import * as fs from 'node:fs/promises';
43
+ import * as os from 'node:os';
44
+ import * as path from 'node:path';
45
+ import { LocalScriptExecutor, guessMimeType, materializeFiles, scriptLanguage, skillResourceFiles, wrapperCode } from './executor.js';
46
+ // ── The index ────────────────────────────────────────────────────────────────
47
+ /** ADK's escapeHtml, as list_skills writes the index. */
48
+ function escapeHtml(unsafe) {
49
+ return unsafe.replaceAll('&', '&amp;').replaceAll('<', '&lt;').replaceAll('>', '&gt;').replaceAll('"', '&quot;').replaceAll("'", '&#039;');
50
+ }
51
+ /** The `<available_skills>` index, in the skills' order (ADK's formatSkillsAsXml). */
52
+ export function formatSkillsAsXml(skills) {
53
+ if (skills.length === 0)
54
+ return '<available_skills>\n</available_skills>';
55
+ const lines = ['<available_skills>'];
56
+ for (const skill of skills) {
57
+ lines.push(' <skill>');
58
+ lines.push(` <name>${escapeHtml(skill.frontmatter.name)}</name>`);
59
+ lines.push(` <description>${escapeHtml(skill.frontmatter.description)}</description>`);
60
+ lines.push(' </skill>');
61
+ }
62
+ lines.push('</available_skills>');
63
+ return lines.join('\n');
64
+ }
65
+ // ── The toolset ──────────────────────────────────────────────────────────────
66
+ /** The session state key holding the skills an agent has loaded (ADK's). */
67
+ export function activatedSkillsKey(agentName) {
68
+ return `_adk_activated_skill_${agentName}`;
69
+ }
70
+ /** The names of the tools a SkillToolset holds itself; an unlocked tool never shadows one. */
71
+ const OWN_TOOL_NAMES = new Set([
72
+ 'list_skills',
73
+ 'load_skill',
74
+ 'load_skill_resource',
75
+ 'run_skill_script',
76
+ 'run_skill_inline_script',
77
+ 'search_skills',
78
+ ]);
79
+ /** Seconds a skill script may run before the local executor kills it. */
80
+ export const SCRIPT_TIMEOUT_SECONDS = 120;
81
+ function nameOf(tool) {
82
+ const name = tool?.name;
83
+ return typeof name === 'string' ? name : undefined;
84
+ }
85
+ function isToolsetShaped(value) {
86
+ return !!value && typeof value === 'object' && typeof value.getTools === 'function' && typeof value.execute !== 'function' && !('runAsync' in value);
87
+ }
88
+ /**
89
+ * The tools an agent with `skills:` carries: load_skill and
90
+ * load_skill_resource always, run_skill_script with `scripts: local`, and
91
+ * the tools its loaded skills unlock. A toolset by shape (getTools), which
92
+ * the native loop expands and lib/tools/adkTool.ts wraps for ADK.
93
+ */
94
+ export class SkillToolset {
95
+ name = 'skill_toolset';
96
+ skills;
97
+ executor;
98
+ #tools;
99
+ #additionalTools;
100
+ #scriptOutputDir;
101
+ #tempOutputDir;
102
+ constructor(skills, options = {}) {
103
+ this.skills = skills;
104
+ this.#additionalTools = options.additionalTools ?? [];
105
+ this.#scriptOutputDir = options.scriptOutputDir;
106
+ if (options.scripts === 'local')
107
+ this.executor = options.executor ?? new LocalScriptExecutor({ timeoutSeconds: SCRIPT_TIMEOUT_SECONDS, envNames: options.envNames });
108
+ this.#tools = [new LoadSkillTool(this), new LoadSkillResourceTool(this)];
109
+ if (this.executor)
110
+ this.#tools.push(new RunSkillScriptTool(this));
111
+ }
112
+ /** The skill named `name`, or undefined. Only the toolset's own skills, never a prototype key. */
113
+ getSkill(name) {
114
+ return Object.hasOwn(this.skills, name) ? this.skills[name] : undefined;
115
+ }
116
+ /** The harness tools, then the tools the agent's loaded skills unlock. */
117
+ async getTools(context) {
118
+ return [...this.#tools, ...(await this.#unlocked(context))];
119
+ }
120
+ /** ADK's resolveAdditionalTools: the permitted tools the activated skills name, in the order they name them. */
121
+ async #unlocked(context) {
122
+ if (!context)
123
+ return [];
124
+ const activated = context.state.get(activatedSkillsKey(context.agentName));
125
+ if (!Array.isArray(activated) || activated.length === 0)
126
+ return [];
127
+ const wanted = new Set();
128
+ for (const skillName of activated) {
129
+ const extra = typeof skillName === 'string' ? this.getSkill(skillName)?.frontmatter.metadata?.adk_additional_tools : undefined;
130
+ if (Array.isArray(extra))
131
+ for (const t of extra)
132
+ if (typeof t === 'string')
133
+ wanted.add(t);
134
+ }
135
+ if (wanted.size === 0)
136
+ return [];
137
+ const candidates = new Map();
138
+ for (const union of this.#additionalTools) {
139
+ const listed = isToolsetShaped(union) ? await union.getTools(context) : [union];
140
+ for (const tool of listed) {
141
+ const name = nameOf(tool);
142
+ if (name === undefined)
143
+ continue;
144
+ if (candidates.has(name))
145
+ throw new Error(`Duplicate tool name: ${name}`);
146
+ candidates.set(name, tool);
147
+ }
148
+ }
149
+ const out = [];
150
+ const taken = new Set(OWN_TOOL_NAMES);
151
+ for (const name of wanted) {
152
+ const tool = candidates.get(name);
153
+ if (tool !== undefined && !taken.has(name)) {
154
+ out.push(tool);
155
+ taken.add(name);
156
+ }
157
+ }
158
+ return out;
159
+ }
160
+ /**
161
+ * Where a script's output files are copied: the configured directory, or
162
+ * a private temp directory made once per toolset. Output file names are
163
+ * the script's choice, so they are never resolved against the server's
164
+ * working directory.
165
+ */
166
+ scriptOutputDir() {
167
+ if (this.#scriptOutputDir) {
168
+ const dir = path.resolve(this.#scriptOutputDir);
169
+ return fs.mkdir(dir, { recursive: true }).then(() => dir);
170
+ }
171
+ return (this.#tempOutputDir ??= fs.mkdtemp(path.join(os.tmpdir(), 'melchizedek_skill_output_')));
172
+ }
173
+ }
174
+ // ── The tools ────────────────────────────────────────────────────────────────
175
+ class SkillTool {
176
+ toolset;
177
+ constructor(toolset) {
178
+ this.toolset = toolset;
179
+ }
180
+ declaration() {
181
+ return { name: this.name, description: this.description, parameters: structuredClone(this.parameters) };
182
+ }
183
+ }
184
+ /** The arguments' string value, or undefined when absent or empty (ADK's `if (!x)`). */
185
+ function stringArg(args, key) {
186
+ return Object.hasOwn(args, key) ? args[key] : undefined;
187
+ }
188
+ /** list_skills: the index of every installed skill. The harness does not carry it (ADR 0029). */
189
+ export class ListSkillsTool extends SkillTool {
190
+ name = 'list_skills';
191
+ description = 'Lists all available skills with their names and descriptions.';
192
+ parameters = { type: 'object', properties: {} };
193
+ async execute() {
194
+ return formatSkillsAsXml(Object.values(this.toolset.skills));
195
+ }
196
+ }
197
+ /**
198
+ * load_skill, lean (ADR 0029): the procedure, the frontmatter and the names
199
+ * of the files the skill ships, never their contents. Loading activates the
200
+ * skill, which unlocks its permitted `allowed-tools` on the next request.
201
+ */
202
+ export class LoadSkillTool extends SkillTool {
203
+ name = 'load_skill';
204
+ description = 'Read one installed skill in full: its SKILL.md procedure, its frontmatter, and the names of the files it ships. Read a skill before you follow it.';
205
+ parameters = {
206
+ type: 'object',
207
+ properties: { name: { type: 'string', description: "The skill's name, exactly as the index lists it." } },
208
+ required: ['name'],
209
+ };
210
+ async execute(args, ctx) {
211
+ const raw = stringArg(args, 'name');
212
+ const name = typeof raw === 'string' ? raw.trim() : '';
213
+ if (!name)
214
+ return { error: 'Skill name is required.', error_code: 'MISSING_SKILL_NAME' };
215
+ const skill = this.toolset.getSkill(name);
216
+ if (!skill) {
217
+ return { error: `Skill '${name}' not found. Installed: ${Object.keys(this.toolset.skills).sort().join(', ') || '(none)'}.`, error_code: 'SKILL_NOT_FOUND' };
218
+ }
219
+ const key = activatedSkillsKey(ctx.agentName);
220
+ const current = ctx.state.get(key);
221
+ const activated = Array.isArray(current) ? current : [];
222
+ if (!activated.includes(name))
223
+ ctx.state.set(key, [...activated, name]);
224
+ return { skill_name: name, frontmatter: skill.frontmatter, instructions: skill.instructions, files: resourceNames(skill) };
225
+ }
226
+ }
227
+ function resourceNames(skill) {
228
+ const out = [];
229
+ for (const [dir, files] of Object.entries(skill.resources ?? {})) {
230
+ for (const name of Object.keys(files ?? {}))
231
+ out.push(`${dir}/${name}`);
232
+ }
233
+ return out.sort();
234
+ }
235
+ const BINARY_FILE_DETECTED_MSG = 'Binary file detected. The content has been injected into the conversation history for you to analyze.';
236
+ const RESOURCE_KINDS = ['references/', 'assets/', 'scripts/'];
237
+ /** The file at `resourcePath` in `skill`: its content, or undefined. Own keys only. */
238
+ function resourceAt(skill, resourcePath, kinds = RESOURCE_KINDS) {
239
+ const resources = skill.resources ?? {};
240
+ for (const prefix of kinds) {
241
+ if (!resourcePath.startsWith(prefix))
242
+ continue;
243
+ const key = resourcePath.slice(prefix.length);
244
+ if (prefix === 'scripts/') {
245
+ const scripts = resources.scripts ?? {};
246
+ return Object.hasOwn(scripts, key) ? scripts[key]?.src : undefined;
247
+ }
248
+ const files = (prefix === 'references/' ? resources.references : resources.assets) ?? {};
249
+ return Object.hasOwn(files, key) ? files[key] : undefined;
250
+ }
251
+ return undefined;
252
+ }
253
+ /** load_skill_resource: one file a skill ships, by its path (ADK's tool). */
254
+ export class LoadSkillResourceTool extends SkillTool {
255
+ name = 'load_skill_resource';
256
+ description = 'Loads a resource file (from references/, assets/, or scripts/) from within a skill.';
257
+ parameters = {
258
+ type: 'object',
259
+ properties: {
260
+ skill_name: { type: 'string', description: 'The name of the skill.' },
261
+ path: {
262
+ type: 'string',
263
+ description: "The relative path to the resource (e.g., 'references/my_doc.md', 'assets/template.txt', or 'scripts/setup.sh').",
264
+ },
265
+ },
266
+ required: ['skill_name', 'path'],
267
+ };
268
+ async execute(args) {
269
+ const skillName = stringArg(args, 'skill_name');
270
+ const rawPath = stringArg(args, 'path');
271
+ if (!skillName)
272
+ return { error: 'Skill name is required.', error_code: 'MISSING_SKILL_NAME' };
273
+ if (!rawPath)
274
+ return { error: 'Resource path is required.', error_code: 'MISSING_RESOURCE_PATH' };
275
+ const resourcePath = path.posix.normalize(String(rawPath));
276
+ const skill = this.toolset.getSkill(String(skillName));
277
+ if (!skill)
278
+ return { error: `Skill '${String(skillName)}' not found.`, error_code: 'SKILL_NOT_FOUND' };
279
+ if (!RESOURCE_KINDS.some((prefix) => resourcePath.startsWith(prefix))) {
280
+ return { error: "Path must start with 'references/', 'assets/', or 'scripts/'.", error_code: 'INVALID_RESOURCE_PATH' };
281
+ }
282
+ const content = resourceAt(skill, resourcePath);
283
+ if (content === undefined)
284
+ return { error: `Resource '${resourcePath}' not found in skill '${String(skillName)}'.`, error_code: 'RESOURCE_NOT_FOUND' };
285
+ if (Buffer.isBuffer(content))
286
+ return { skill_name: skillName, path: resourcePath, status: BINARY_FILE_DETECTED_MSG };
287
+ return { skill_name: skillName, path: resourcePath, content };
288
+ }
289
+ /**
290
+ * A binary file this tool just answered for is added to the request as
291
+ * inline data, after the history (ADK's processLlmRequest): the latest
292
+ * content, when it is the tools' answer, is searched for this tool's
293
+ * binary notices.
294
+ */
295
+ async contents(contents) {
296
+ const last = contents.at(-1);
297
+ if (!last || last.role !== 'user' || !last.parts)
298
+ return;
299
+ for (const part of last.parts) {
300
+ const fr = part.functionResponse;
301
+ if (!fr || fr.name !== this.name)
302
+ continue;
303
+ const response = (fr.response ?? {});
304
+ if (response.status !== BINARY_FILE_DETECTED_MSG)
305
+ continue;
306
+ const skill = typeof response.skill_name === 'string' ? this.toolset.getSkill(response.skill_name) : undefined;
307
+ const resourcePath = typeof response.path === 'string' ? response.path : undefined;
308
+ if (!skill || resourcePath === undefined)
309
+ continue;
310
+ const content = resourceAt(skill, resourcePath, ['references/', 'assets/']);
311
+ if (!Buffer.isBuffer(content))
312
+ continue;
313
+ contents.push({
314
+ role: 'user',
315
+ parts: [{ text: `The content of binary file '${resourcePath}' is:` }, { inlineData: { data: content.toString('base64'), mimeType: guessMimeType(resourcePath) } }],
316
+ });
317
+ }
318
+ }
319
+ }
320
+ /**
321
+ * run_skill_script behind a person's approval: the first call asks for it
322
+ * (the hint names the skill, the script and the arguments) and returns
323
+ * without running; the call made again with the answer runs only when the
324
+ * answer approved it. The confirmation travels as `adk_request_confirmation`
325
+ * on either runtime, so the turn pauses `input-required` exactly as for
326
+ * `require_approval` (ADR 0028), with this tool's own texts.
327
+ */
328
+ export class RunSkillScriptTool extends SkillTool {
329
+ name = 'run_skill_script';
330
+ description = "Executes a script from a skill's scripts/ directory.";
331
+ parameters = {
332
+ type: 'object',
333
+ properties: {
334
+ skill_name: { type: 'string', description: 'The name of the skill.' },
335
+ script_path: { type: 'string', description: "The relative path to the script (e.g., 'scripts/setup.js')." },
336
+ args: { type: 'object', description: 'Optional arguments to pass to the script as key-value pairs.' },
337
+ },
338
+ required: ['skill_name', 'script_path'],
339
+ };
340
+ async execute(args, ctx) {
341
+ if (!ctx.confirmation) {
342
+ const summary = `${String(args.skill_name ?? '?')}: ${String(args.script_path ?? '?')}${args.args ? ` ${JSON.stringify(args.args)}` : ''}`;
343
+ ctx.requestConfirmation({
344
+ hint: `Approval is required before a skill script runs on this machine. The agent asks to run ${summary}.`,
345
+ payload: { skill_name: args.skill_name, script_path: args.script_path, args: args.args ?? {} },
346
+ });
347
+ ctx.actions.skipSummarization = true;
348
+ return { error: 'This script run requires approval, please approve or reject.' };
349
+ }
350
+ if (!ctx.confirmation.confirmed)
351
+ return { error: 'This script run was rejected.' };
352
+ return this.#run(args);
353
+ }
354
+ /** ADK's RunSkillScriptTool.runAsync, after the gate. */
355
+ async #run(args) {
356
+ const skillName = stringArg(args, 'skill_name');
357
+ const scriptPath = stringArg(args, 'script_path');
358
+ const scriptArgs = (stringArg(args, 'args') || {});
359
+ if (!skillName)
360
+ return { error: 'Skill name is required.', errorCode: 'MISSING_SKILL_NAME' };
361
+ if (!scriptPath)
362
+ return { error: 'Script path is required.', errorCode: 'MISSING_SCRIPT_PATH' };
363
+ const skill = this.toolset.getSkill(String(skillName));
364
+ if (!skill)
365
+ return { error: `Skill '${String(skillName)}' not found.`, errorCode: 'SKILL_NOT_FOUND' };
366
+ const scriptPathText = String(scriptPath);
367
+ const scripts = skill.resources?.scripts ?? {};
368
+ const relative = scriptPathText.startsWith('scripts/') ? scriptPathText.slice('scripts/'.length) : scriptPathText;
369
+ const script = Object.hasOwn(scripts, relative) ? scripts[relative] : Object.hasOwn(scripts, scriptPathText) ? scripts[scriptPathText] : undefined;
370
+ if (!script)
371
+ return { error: `Script '${scriptPathText}' not found in skill '${String(skillName)}'.`, errorCode: 'SCRIPT_NOT_FOUND' };
372
+ const executor = this.toolset.executor;
373
+ if (!executor)
374
+ return { error: 'No code executor configured.', errorCode: 'NO_CODE_EXECUTOR' };
375
+ try {
376
+ const language = scriptLanguage(path.extname(scriptPathText));
377
+ const result = await executor.run({ code: wrapperCode(scriptPathText, language), inputFiles: skillResourceFiles(skill), language, args: scriptArgs });
378
+ const outputDirectory = await this.toolset.scriptOutputDir();
379
+ result.outputFiles = await materializeFiles(result.outputFiles, outputDirectory);
380
+ return { ...result, outputDirectory };
381
+ }
382
+ catch (e) {
383
+ return { error: `Failed to execute script '${scriptPathText}': ${e.message}`, errorCode: 'EXECUTION_ERROR' };
384
+ }
385
+ }
386
+ }
@@ -134,16 +134,16 @@ export declare const fileTaskBackend: TaskBackend;
134
134
  /** Plugs in where tasks live (postgresStorage().taskQueue); default the JSON file. */
135
135
  export declare function setTaskBackend(backend: TaskBackend): void;
136
136
  export declare function getTaskBackend(): TaskBackend;
137
- export declare const taskAddContract: import("./toolContract.ts").ToolContract<z.ZodObject<{
137
+ export declare const taskAddContract: import("./toolContract.ts").DefinedTool<z.ZodObject<{
138
138
  title: z.ZodString;
139
139
  notes: z.ZodOptional<z.ZodString>;
140
140
  due: z.ZodOptional<z.ZodString>;
141
- }, z.core.$strip>>;
142
- export declare const taskQueueContract: import("./toolContract.ts").ToolContract<z.ZodObject<{
141
+ }, z.core.$strip>, string>;
142
+ export declare const taskQueueContract: import("./toolContract.ts").DefinedTool<z.ZodObject<{
143
143
  title: z.ZodString;
144
144
  instruction: z.ZodString;
145
- }, z.core.$strip>>;
146
- export declare const taskListContract: import("./toolContract.ts").ToolContract<z.ZodObject<{
145
+ }, z.core.$strip>, string>;
146
+ export declare const taskListContract: import("./toolContract.ts").DefinedTool<z.ZodObject<{
147
147
  status: z.ZodDefault<z.ZodEnum<{
148
148
  active: "active";
149
149
  all: "all";
@@ -159,11 +159,11 @@ export declare const taskListContract: import("./toolContract.ts").ToolContract<
159
159
  background: "background";
160
160
  todo: "todo";
161
161
  }>>;
162
- }, z.core.$strip>>;
163
- export declare const taskGetContract: import("./toolContract.ts").ToolContract<z.ZodObject<{
162
+ }, z.core.$strip>, string>;
163
+ export declare const taskGetContract: import("./toolContract.ts").DefinedTool<z.ZodObject<{
164
164
  id: z.ZodString;
165
- }, z.core.$strip>>;
166
- export declare const taskUpdateContract: import("./toolContract.ts").ToolContract<z.ZodObject<{
165
+ }, z.core.$strip>, string>;
166
+ export declare const taskUpdateContract: import("./toolContract.ts").DefinedTool<z.ZodObject<{
167
167
  id: z.ZodString;
168
168
  status: z.ZodOptional<z.ZodEnum<{
169
169
  cancelled: "cancelled";
@@ -174,16 +174,16 @@ export declare const taskUpdateContract: import("./toolContract.ts").ToolContrac
174
174
  title: z.ZodOptional<z.ZodString>;
175
175
  notes: z.ZodOptional<z.ZodString>;
176
176
  due: z.ZodOptional<z.ZodString>;
177
- }, z.core.$strip>>;
177
+ }, z.core.$strip>, string>;
178
178
  /** Every task contract, in the order an agent's tool list shows them. */
179
- export declare const TASK_TOOL_CONTRACTS: (import("./toolContract.ts").ToolContract<z.ZodObject<{
179
+ export declare const TASK_TOOL_CONTRACTS: (import("./toolContract.ts").DefinedTool<z.ZodObject<{
180
180
  title: z.ZodString;
181
181
  notes: z.ZodOptional<z.ZodString>;
182
182
  due: z.ZodOptional<z.ZodString>;
183
- }, z.core.$strip>> | import("./toolContract.ts").ToolContract<z.ZodObject<{
183
+ }, z.core.$strip>, string> | import("./toolContract.ts").DefinedTool<z.ZodObject<{
184
184
  title: z.ZodString;
185
185
  instruction: z.ZodString;
186
- }, z.core.$strip>> | import("./toolContract.ts").ToolContract<z.ZodObject<{
186
+ }, z.core.$strip>, string> | import("./toolContract.ts").DefinedTool<z.ZodObject<{
187
187
  status: z.ZodDefault<z.ZodEnum<{
188
188
  active: "active";
189
189
  all: "all";
@@ -199,6 +199,6 @@ export declare const TASK_TOOL_CONTRACTS: (import("./toolContract.ts").ToolContr
199
199
  background: "background";
200
200
  todo: "todo";
201
201
  }>>;
202
- }, z.core.$strip>> | import("./toolContract.ts").ToolContract<z.ZodObject<{
202
+ }, z.core.$strip>, string> | import("./toolContract.ts").DefinedTool<z.ZodObject<{
203
203
  id: z.ZodString;
204
- }, z.core.$strip>>)[];
204
+ }, z.core.$strip>, string>)[];