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
@@ -1,5 +1,6 @@
1
1
  /**
2
- * lib/compile.ts — the one YAML → ADK agent-graph compiler.
2
+ * lib/compile.ts — the one YAML → agent compiler: a runtime-neutral
3
+ * AgentSpec, and the ADK agent graph built from it.
3
4
  *
4
5
  * WHY this file exists:
5
6
  * The A2A server carried this logic as two closures inside its executor,
@@ -26,19 +27,31 @@
26
27
  * paths build subagents through the same function, so the agent a route
27
28
  * dispatches to is identical to the one DELEGATE would have wrapped.
28
29
  * Contract and rationale: lib/dispatch.ts.
30
+ *
31
+ * ── One spec, two runtimes (ADR 0073) ─────────────────────────────────────
32
+ * compileSpec and compileSubagentSpec do the work every runtime shares:
33
+ * resolve and gate the tools, append the skills index, resolve the model
34
+ * once, build the generateContentConfig. The result is an AgentSpec.
35
+ * lib/compileAdk.ts builds ADK's LlmAgent from it (compileGraph and
36
+ * compileSubagent are spec + compileAdk), and lib/compileNative.ts builds
37
+ * the native loop's NativeAgent (ADR 0045). runSyndicateTurn picks one by
38
+ * MELCHIZEDEK_RUNTIME or its `runtime` option.
29
39
  */
30
- import { AgentTool, BaseLlm, BuiltInCodeExecutor, ExampleTool, FunctionTool, LLMRegistry, LlmAgent, LlmSummarizer, TokenBasedContextCompactor } from '@google/adk';
40
+ import { BaseLlm, FunctionTool } from './adkPeer.js';
31
41
  import { relative } from 'node:path';
42
+ import { compileAdk } from './compileAdk.js';
32
43
  import { isDispatchSyndicate } from './dispatch.js';
44
+ import { isWorkflowSyndicate, nodeKind } from './workflowConfig.js';
33
45
  import { loadSyndicate, nestedLoader } from './loadSyndicate.js';
46
+ import { REASONING_OLDER_SPELLING } from './syndicateSchema.js';
47
+ import { reasoningConfig } from './models/reasoning.js';
34
48
  import { resolveTools as resolveNamedTools } from './toolRegistry.js';
35
49
  import { createMcpTools } from './tools/mcpToolFactory.js';
50
+ import { toAdkInstructionTool, toAdkToolset } from './tools/adkTool.js';
51
+ import { examplesInstructionTool } from './tools/examples.js';
36
52
  import { capabilitySummary, describeCapabilities } from './models/capabilities.js';
37
- import { FallbackLlm } from './models/fallback.js';
38
- import { resolveModel as resolveRegistryModel } from './models/registry.js';
39
- import { remoteAgentTool } from './a2a/remoteAgent.js';
40
53
  import { buildSkillHarness } from './tools/skillToolset.js';
41
- import { buildOpenApiTools, isOpenApiTool, namesTool } from './tools/openapiTools.js';
54
+ import { buildOpenApiTools, namesTool, openApiOperationId } from './tools/openapiTools.js';
42
55
  /** generateContentConfig as every entrypoint has always sent it to ADK. */
43
56
  function withServerSideToolInvocations(generateContentConfig) {
44
57
  const cfg = (generateContentConfig ?? {});
@@ -50,59 +63,31 @@ function withServerSideToolInvocations(generateContentConfig) {
50
63
  },
51
64
  };
52
65
  }
66
+ // ── Reasoning (ADR 0047) ─────────────────────────────────────────────────────
67
+ // REASONING_BUDGETS and reasoningConfig live in lib/models/reasoning.ts, so a
68
+ // model adapter can map `reasoning:` without importing the compiler (and ADK).
69
+ export { REASONING_BUDGETS, reasoningConfig } from './models/reasoning.js';
53
70
  /**
54
- * The LlmAgent fields a YAML agent may set beyond model, instruction, tools
55
- * and schemas. The schema reference (config/agents/syndicateSchema.yaml)
56
- * documents each as mapping 1:1 to its ADK counterpart; before this they
57
- * were parsed and silently dropped, so `includeContents: none` — which the
58
- * intake template relies on so that a document never sees an earlier one —
59
- * changed nothing. Only fields the YAML sets are passed, so ADK's defaults
60
- * stay in force otherwise.
61
- */
62
- function passthroughFields(cfg) {
63
- const out = {};
64
- if (cfg.includeContents !== undefined)
65
- out.includeContents = cfg.includeContents;
66
- if (cfg.outputKey !== undefined)
67
- out.outputKey = cfg.outputKey;
68
- if (cfg.globalInstruction !== undefined)
69
- out.globalInstruction = cfg.globalInstruction;
70
- if (cfg.disallowTransferToParent !== undefined)
71
- out.disallowTransferToParent = cfg.disallowTransferToParent;
72
- if (cfg.disallowTransferToPeers !== undefined)
73
- out.disallowTransferToPeers = cfg.disallowTransferToPeers;
74
- return out;
75
- }
76
- export const DEFAULT_KEEP_RECENT_EVENTS = 6;
77
- /**
78
- * The LlmAgent fields the engine builds from YAML rather than passing
79
- * through (ADR 0033): `code_execution: gemini` (Gemini's server-side
80
- * sandbox runs the model's Python; nothing runs on this host), `context:`
81
- * (ADK's token-based compactor with an LLM summarizer, so a long
82
- * conversation is summarized instead of overflowing the window), and
83
- * `mode: task` (the agent works until it calls finish_task; on a workflow
84
- * node, its arguments become the node's output).
71
+ * An agent's generateContentConfig with its `reasoning:` key mapped in for
72
+ * the model it runs on. Unchanged (the same object) when the agent sets no
73
+ * `reasoning`. The loader refuses `reasoning` next to the older spelling;
74
+ * this refuses it too, for a config built in code.
85
75
  */
86
- function executionFields(cfg, opts) {
87
- const out = {};
88
- if (cfg.code_execution === 'gemini')
89
- out.codeExecutor = new BuiltInCodeExecutor();
90
- if (cfg.mode)
91
- out.mode = cfg.mode;
92
- if (cfg.context) {
93
- const resolve = opts.resolveModel ?? ((m) => m);
94
- const summaryModel = resolve(cfg.context.summary_model ?? cfg.model);
95
- const llm = typeof summaryModel === 'string' || !summaryModel ? LLMRegistry.newLlm(String(summaryModel ?? cfg.model)) : summaryModel;
96
- out.contextCompactors = [
97
- new TokenBasedContextCompactor({
98
- tokenThreshold: cfg.context.compact_after_tokens,
99
- eventRetentionSize: cfg.context.keep_recent_events ?? DEFAULT_KEEP_RECENT_EVENTS,
100
- summarizer: new LlmSummarizer({ llm }),
101
- }),
102
- ];
76
+ export function withReasoning(agent, model) {
77
+ const cfg = agent.generateContentConfig;
78
+ if (agent.reasoning === undefined)
79
+ return cfg;
80
+ const clash = REASONING_OLDER_SPELLING.filter((k) => cfg?.[k] !== undefined);
81
+ if (clash.length) {
82
+ throw new Error(`${agent.name ?? 'agent'}: reasoning cannot be combined with ${clash.map((k) => `generateContentConfig.${k}`).join(' or ')}; reasoning replaces it (ADR 0047)`);
103
83
  }
104
- return out;
84
+ return { ...cfg, ...reasoningConfig(model ?? '', agent.reasoning) };
105
85
  }
86
+ /** The model id an agent runs on, from its YAML or its resolved adapter. */
87
+ function modelIdOf(yamlModel, resolved) {
88
+ return yamlModel ?? (typeof resolved === 'string' ? resolved : resolved instanceof BaseLlm ? resolved.model : undefined);
89
+ }
90
+ export { DEFAULT_KEEP_RECENT_EVENTS } from './runtime/native/compaction.js';
106
91
  /**
107
92
  * Says, once per compiled agent, what its resolved path cannot honour — a
108
93
  * dropped server-side tool, a gateway stand-in, or no route at all. Quiet
@@ -131,9 +116,13 @@ export function requireApprovalOn(tool) {
131
116
  return gated;
132
117
  }
133
118
  /**
134
- * A copy of an OpenAPI tool (lib/tools/openapiTools.ts) that runs only after
135
- * a person approves the call: the same confirmation interrupt FunctionTool's
136
- * own gate raises, so the turn pauses and resumes exactly as ADR 0028 says.
119
+ * A copy of an ADK BaseTool that runs only after a person approves the
120
+ * call: the same confirmation interrupt FunctionTool's own gate raises, so
121
+ * the turn pauses and resumes exactly as ADR 0028 says. The engine no
122
+ * longer uses it: an OpenAPI operation is a FunctionTool over an own Tool
123
+ * (ADR 0067) and takes requireApprovalOn like every registry tool.
124
+ * @deprecated Gate a FunctionTool with requireApprovalOn, or an own Tool
125
+ * with requireApproval (lib/tools/tool.ts).
137
126
  */
138
127
  export function requireApprovalOnBaseTool(tool) {
139
128
  const gated = Object.create(tool);
@@ -157,17 +146,16 @@ function gateTools(tools, names, agentName) {
157
146
  return tools;
158
147
  const wanted = new Set(names);
159
148
  const out = tools.map((t) => {
160
- const tool = t;
161
- const name = tool?.name;
149
+ const name = t?.name;
162
150
  if (!name)
163
151
  return t;
164
152
  // An OpenAPI operation may be named as the YAML named it (its operationId).
165
- const match = [...wanted].find((w) => w === name || (isOpenApiTool(t) && namesTool(w, { name, operation: tool.operation })));
153
+ const operationId = openApiOperationId(t);
154
+ const match = [...wanted].find((w) => w === name || (operationId !== undefined && namesTool(w, { name, operation: { operationId } })));
166
155
  if (!match)
167
156
  return t;
168
157
  wanted.delete(match);
169
- if (isOpenApiTool(t))
170
- return requireApprovalOnBaseTool(t);
158
+ // An OpenAPI operation is a FunctionTool over an own Tool (ADR 0067): one gate for both.
171
159
  if (!(t instanceof FunctionTool)) {
172
160
  throw new Error(`${agentName}: '${name}' cannot require approval — only function tools from the registry and OpenAPI operations can be gated (ADR 0028).`);
173
161
  }
@@ -185,27 +173,14 @@ export function declaresApprovals(config) {
185
173
  return agentGates(config.orchestrator) || (config.subagents ?? []).some((s) => agentGates(s));
186
174
  }
187
175
  /**
188
- * ADK's ExampleTool from YAML pairs: never called by the model, it adds the
189
- * exchanges to every request's instruction as few-shot examples.
176
+ * An agent's `examples:` as the ADK tool for their InstructionTool
177
+ * (lib/tools/examples.ts): never called by the model, it adds the exchanges
178
+ * to every request's instruction as few-shot examples, in the words ADK's
179
+ * ExampleTool used.
190
180
  */
191
181
  export function examplesTool(examples) {
192
- if (!examples?.length)
193
- return [];
194
- return [
195
- new ExampleTool(examples.map((e) => ({ input: { role: 'user', parts: [{ text: e.input }] }, output: [{ role: 'model', parts: [{ text: e.output }] }] }))),
196
- ];
197
- }
198
- /**
199
- * An agent with `fallback_model:` gets its model wrapped (lib/models/fallback.ts):
200
- * the fallback answers a provider-side failure, and a provider that keeps
201
- * failing is skipped for a cooldown. A model id string is resolved to its
202
- * adapter first, so the wrapper always holds two adapters.
203
- */
204
- function withFallback(primary, fallbackId, resolve, opts) {
205
- if (!fallbackId)
206
- return primary;
207
- const asLlm = (m) => (m instanceof BaseLlm ? m : resolveRegistryModel(String(m)));
208
- return new FallbackLlm(asLlm(primary), asLlm(resolve(fallbackId)), opts.log ?? ((m) => console.warn(m)));
182
+ const tool = examplesInstructionTool(examples);
183
+ return tool ? [toAdkInstructionTool(tool)] : [];
209
184
  }
210
185
  async function resolveAgentTools(toolNames, mcpServerUrl, opts, openapi, examples, mcpAllowed) {
211
186
  const tools = [...resolveNamedTools(toolNames, opts.onUnknownTool), ...examplesTool(examples)];
@@ -258,94 +233,200 @@ async function withSkills(instruction, tools, skills, agentName, opts) {
258
233
  opts.log?.(`skills · ${agentName}: ${count} skill${count === 1 ? '' : 's'} from ${skills.dir}${skills.scripts === 'local' ? ' · scripts run after approval' : ''}`);
259
234
  for (const problem of harness.problems)
260
235
  opts.log?.(`⚠ skills · ${skills.dir}: not loaded — ${problem}`);
261
- return { instruction: `${instruction.trimEnd()}\n\n${harness.instruction}`, tools: [...tools, harness.toolset] };
236
+ // The ADK face of the engine's own toolset; compileNative reads the toolset back (toolsetOf).
237
+ return { instruction: `${instruction.trimEnd()}\n\n${harness.instruction}`, tools: [...tools, toAdkToolset(harness.toolset)] };
262
238
  }
263
239
  /** True when a turn running this agent directly may pause for a person (ADR 0028). */
264
240
  export function agentGates(agent) {
265
241
  return !!agent?.require_approval?.length || agent?.skills?.scripts === 'local';
266
242
  }
243
+ function specOf(yaml, name, description, instruction, tools, opts) {
244
+ const resolvedModel = (opts.resolveModel ?? ((m) => m))(yaml.model);
245
+ const modelId = modelIdOf(yaml.model, resolvedModel);
246
+ const spec = {
247
+ name,
248
+ instruction,
249
+ tools,
250
+ resolvedModel,
251
+ generateContentConfig: withServerSideToolInvocations(withReasoning(yaml, modelId)),
252
+ };
253
+ if (description !== undefined)
254
+ spec.description = description;
255
+ if (yaml.model !== undefined)
256
+ spec.model = yaml.model;
257
+ if (modelId !== undefined)
258
+ spec.modelId = modelId;
259
+ if (yaml.fallback_model)
260
+ spec.fallbackModel = yaml.fallback_model;
261
+ if (yaml.outputSchema)
262
+ spec.outputSchema = yaml.outputSchema;
263
+ if (yaml.includeContents !== undefined)
264
+ spec.includeContents = yaml.includeContents;
265
+ if (yaml.outputKey !== undefined)
266
+ spec.outputKey = yaml.outputKey;
267
+ if (yaml.globalInstruction !== undefined)
268
+ spec.globalInstruction = yaml.globalInstruction;
269
+ if (yaml.disallowTransferToParent !== undefined)
270
+ spec.disallowTransferToParent = yaml.disallowTransferToParent;
271
+ if (yaml.disallowTransferToPeers !== undefined)
272
+ spec.disallowTransferToPeers = yaml.disallowTransferToPeers;
273
+ if (yaml.code_execution)
274
+ spec.codeExecution = yaml.code_execution;
275
+ if (yaml.context)
276
+ spec.context = yaml.context;
277
+ if (yaml.mode)
278
+ spec.mode = yaml.mode;
279
+ return spec;
280
+ }
281
+ const asTools = (tools) => tools.map((tool) => ({ kind: 'tool', tool }));
282
+ /**
283
+ * A nested `yaml_reference:` syndicate, loaded. A nested syndicate runs
284
+ * inside a tool call (or as a route whose own subagents do): a pause there
285
+ * cannot reach the caller (ADR 0028), so one that declares approval gates is
286
+ * refused.
287
+ */
288
+ /** Where the yaml_reference chain a compile is inside is kept: an own symbol on the options, so a spread copy keeps it. */
289
+ const NESTING = Symbol('melchizedek.compile.nesting');
290
+ /** The deepest a yaml_reference chain may go: well past any syndicate the engine ships, short of the stack. */
291
+ const MAX_NESTING_DEPTH = 16;
267
292
  /**
268
- * Builds ONE runnable agent from a subagent entry. A `yaml_reference` entry
269
- * compiles the nested syndicate's whole graph under this entry's name and
293
+ * The options a nested `ref` compiles with: `opts` and the chain of
294
+ * references above it. A reference already on the chain (a syndicate that
295
+ * reaches itself) or a chain past MAX_NESTING_DEPTH is refused by name (WS5-5,
296
+ * ADR 0101): the compile would otherwise recurse until the stack gave out,
297
+ * which took the process with it.
298
+ */
299
+ function nestedOptions(ref, opts) {
300
+ const chain = (opts[NESTING] ?? []);
301
+ if (chain.includes(ref))
302
+ throw new Error(`${ref}: a nested syndicate reaches itself (${[...chain, ref].join(' → ')}); a yaml_reference chain must end.`);
303
+ if (chain.length >= MAX_NESTING_DEPTH)
304
+ throw new Error(`${ref}: nested syndicates go deeper than ${MAX_NESTING_DEPTH} levels (${[...chain, ref].join(' → ')}).`);
305
+ return { ...opts, [NESTING]: [...chain, ref] };
306
+ }
307
+ function loadNestedSyndicate(ref, opts) {
308
+ opts.log?.(`Loading nested syndicate: ${ref}`);
309
+ const nested = (opts.loadNested ?? loadSyndicate)(ref);
310
+ if (declaresApprovals(nested)) {
311
+ throw new Error(`${ref}: approval gates (require_approval) are not supported inside a nested syndicate.`);
312
+ }
313
+ return nested;
314
+ }
315
+ /**
316
+ * The spec of a workflow syndicate: every agent through compileSubagentSpec
317
+ * (the orchestrator first, as a node like any other), and the registry's
318
+ * lookup for its tool nodes. `name` and `description` name a nested one
319
+ * after its subagent entry (ADR 0098); `ref` is the file it came from.
320
+ *
321
+ * A nested workflow runs inside its caller's tool call, so a pause inside it
322
+ * could not reach the caller (ADR 0028, as for any nested syndicate): an
323
+ * `ask_user` node is refused by name here, on both runtimes.
324
+ */
325
+ export async function compileWorkflowSpec(config, opts = {}, name, description, ref) {
326
+ if (!isWorkflowSyndicate(config))
327
+ throw new Error(`${config.syndicate_name}: no workflow block`);
328
+ if (name) {
329
+ const asking = Object.entries(config.workflow.nodes ?? {}).find(([, node]) => nodeKind(node) === 'ask_user');
330
+ if (asking) {
331
+ throw new Error(`${ref ?? config.syndicate_name}: the ask_user node '${asking[0]}' pauses for a person, which a workflow nested as a subagent (${name}) cannot carry to its caller; run the workflow as its own syndicate, or remove the node.`);
332
+ }
333
+ }
334
+ const workflowName = name || config.syndicate_name;
335
+ const agents = [];
336
+ for (const yaml of [{ description: '', ...config.orchestrator }, ...(config.subagents ?? [])]) {
337
+ agents.push({ yaml, spec: await compileSubagentSpec(yaml, opts) });
338
+ }
339
+ return {
340
+ name: workflowName,
341
+ description: description ?? '',
342
+ config: { ...config, syndicate_name: workflowName },
343
+ agents,
344
+ resolveTool: (tool) => resolveNamedTools([tool], opts.onUnknownTool)[0],
345
+ };
346
+ }
347
+ /**
348
+ * The spec of ONE agent from a subagent entry. A `yaml_reference` entry is
349
+ * the nested syndicate's whole graph under this entry's name and
270
350
  * description, so the parent sees one tool (or one route) either way.
271
351
  */
272
- export async function compileSubagent(subCfg, opts = {}) {
352
+ export async function compileSubagentSpec(subCfg, opts = {}) {
273
353
  if (subCfg.a2a_agent_url) {
274
354
  // A remote agent has its own model and prompt on its own server; there
275
355
  // is no local agent to build. It is reached as a delegation tool
276
- // (compileGraph) or a dispatch route (lib/runtime/syndicateTurn.ts).
356
+ // (compileSpec) or a dispatch route (lib/runtime/syndicateTurn.ts).
277
357
  throw new Error(`'${subCfg.name}' is a remote A2A agent (a2a_agent_url) and has no local agent to compile.`);
278
358
  }
279
359
  if (subCfg.yaml_reference) {
280
- opts.log?.(`Loading nested syndicate: ${subCfg.yaml_reference}`);
281
- const nested = (opts.loadNested ?? loadSyndicate)(subCfg.yaml_reference);
282
- if (declaresApprovals(nested)) {
283
- // A nested syndicate runs inside a tool call (or as a route whose
284
- // own subagents do): a pause there cannot reach the caller (ADR 0028).
285
- throw new Error(`${subCfg.yaml_reference}: approval gates (require_approval) are not supported inside a nested syndicate.`);
286
- }
287
- return compileGraph(nested, opts, subCfg.name, subCfg.description);
360
+ const nestedOpts = nestedOptions(subCfg.yaml_reference, opts);
361
+ return compileSpec(loadNestedSyndicate(subCfg.yaml_reference, nestedOpts), nestedOpts, subCfg.name, subCfg.description);
288
362
  }
289
363
  const gated = gateTools(await resolveAgentTools(subCfg.tools, subCfg.mcp_server_url, opts, subCfg.openapi, subCfg.examples, subCfg.mcp_tools), subCfg.require_approval, subCfg.name);
290
364
  const { instruction, tools } = await withSkills(subCfg.instruction ?? '', gated, subCfg.skills, subCfg.name, opts);
291
- const resolveModel = opts.resolveModel ?? ((m) => m);
292
365
  logCapabilities(opts, subCfg.name, subCfg.model, subCfg.tools);
293
- return new LlmAgent({
294
- name: subCfg.name,
295
- description: subCfg.description,
296
- model: withFallback(resolveModel(subCfg.model), subCfg.fallback_model, resolveModel, opts),
297
- instruction,
298
- tools: tools.length > 0 ? tools : undefined,
299
- outputSchema: subCfg.outputSchema,
300
- generateContentConfig: withServerSideToolInvocations(subCfg.generateContentConfig),
301
- ...passthroughFields(subCfg),
302
- ...executionFields(subCfg, opts),
303
- ...(opts.nodeConfig?.(subCfg.name) ?? {}),
304
- });
366
+ return specOf(subCfg, subCfg.name, subCfg.description, instruction, asTools(tools), opts);
305
367
  }
306
368
  /**
307
- * Compiles a syndicate's orchestrator. In DELEGATE mode its subagents are
308
- * attached as AgentTools; in PLAN-DISPATCH mode it gets none (ADK refuses
309
- * outputSchema + AgentTool on one agent — see config/agents/critic.yaml),
310
- * and the caller dispatches to `compileSubagent(route)` itself.
369
+ * The spec of a syndicate's orchestrator. In DELEGATE mode its subagents
370
+ * come first among its tools, as delegations; in PLAN-DISPATCH mode it gets
371
+ * none (ADK refuses outputSchema + AgentTool on one agent — see
372
+ * config/agents/critic.yaml), and the caller dispatches to a route's own
373
+ * spec itself.
311
374
  */
312
- export async function compileGraph(config, opts = {}, overrideName, overrideDescription) {
375
+ export async function compileSpec(config, opts = {}, overrideName, overrideDescription) {
313
376
  // A registry definition carries its nested syndicates (ADR 0018 item 6).
314
377
  if (config.bundled_references && !opts.loadNested)
315
378
  opts = { ...opts, loadNested: nestedLoader(config) };
316
379
  // A graph has no orchestrator-with-tools shape to build: its agents are
317
- // nodes (lib/workflow.ts). Nested as a yaml_reference, only its
318
- // orchestrator runs, since ADK cannot yet make a Workflow a subagent.
380
+ // nodes (lib/workflow.ts). A delegated yaml_reference to one runs the whole
381
+ // graph as the tool (nestedWorkflowSpec, ADR 0098); as a dispatch route or
382
+ // a workflow node it is still its orchestrator alone.
319
383
  if (config.workflow && !overrideName) {
320
384
  throw new Error(`${config.syndicate_name}: a workflow syndicate is compiled with compileWorkflow (lib/workflow.ts), not compileGraph`);
321
385
  }
322
386
  if (config.workflow)
323
- opts.log?.(`${config.syndicate_name}: nested as a subagent, so only its orchestrator runs (a Workflow cannot be a subagent yet)`);
324
- const compiledTools = isDispatchSyndicate(config)
387
+ opts.log?.(`${config.syndicate_name}: a dispatch route or a workflow node, so only its orchestrator runs (a delegated subagent runs the whole graph)`);
388
+ const delegated = isDispatchSyndicate(config)
325
389
  ? []
326
390
  : await Promise.all((config.subagents ?? []).map(async (subCfg) => {
327
391
  if (subCfg.a2a_agent_url) {
328
392
  opts.log?.(`Remote A2A agent: ${subCfg.name} → ${subCfg.a2a_agent_url}`);
329
- return remoteAgentTool({ name: subCfg.name, description: subCfg.description, url: subCfg.a2a_agent_url });
393
+ return { kind: 'remote', name: subCfg.name, description: subCfg.description, url: subCfg.a2a_agent_url };
330
394
  }
331
- return new AgentTool({ agent: await compileSubagent(subCfg, opts) });
395
+ if (subCfg.yaml_reference) {
396
+ const nestedOpts = nestedOptions(subCfg.yaml_reference, opts);
397
+ const nested = loadNestedSyndicate(subCfg.yaml_reference, nestedOpts);
398
+ if (isWorkflowSyndicate(nested))
399
+ return { kind: 'workflow', workflow: await compileWorkflowSpec(nested, nestedOpts, subCfg.name, subCfg.description, subCfg.yaml_reference) };
400
+ return { kind: 'agent', agent: await compileSpec(nested, nestedOpts, subCfg.name, subCfg.description) };
401
+ }
402
+ return { kind: 'agent', agent: await compileSubagentSpec(subCfg, opts) };
332
403
  }));
404
+ const name = overrideName || config.orchestrator.name;
333
405
  // Orchestrator tools are registry names only — no entrypoint has ever
334
406
  // attached an MCP server to an orchestrator, and this compiler preserves
335
407
  // that exactly rather than widening the contract in passing.
336
- compiledTools.push(...gateTools(await resolveAgentTools(config.orchestrator.tools, undefined, opts, config.orchestrator.openapi, config.orchestrator.examples), config.orchestrator.require_approval, overrideName || config.orchestrator.name));
337
- const { instruction, tools: orchestratorTools } = await withSkills(config.orchestrator.instruction, compiledTools, config.orchestrator.skills, overrideName || config.orchestrator.name, opts);
338
- const resolveModel = opts.resolveModel ?? ((m) => m);
339
- logCapabilities(opts, overrideName || config.orchestrator.name, config.orchestrator.model, config.orchestrator.tools);
340
- return new LlmAgent({
341
- name: overrideName || config.orchestrator.name,
342
- description: overrideDescription || config.orchestrator.description,
343
- model: withFallback(resolveModel(config.orchestrator.model), config.orchestrator.fallback_model, resolveModel, opts),
344
- instruction,
345
- tools: orchestratorTools.length > 0 ? orchestratorTools : undefined,
346
- outputSchema: config.orchestrator.outputSchema,
347
- generateContentConfig: withServerSideToolInvocations(config.orchestrator.generateContentConfig),
348
- ...passthroughFields(config.orchestrator),
349
- ...executionFields(config.orchestrator, opts),
350
- });
408
+ const own = gateTools(await resolveAgentTools(config.orchestrator.tools, undefined, opts, config.orchestrator.openapi, config.orchestrator.examples), config.orchestrator.require_approval, name);
409
+ // The skills toolset goes last, after the delegations and the agent's own tools.
410
+ const { instruction, tools } = await withSkills(config.orchestrator.instruction, own, config.orchestrator.skills, name, opts);
411
+ logCapabilities(opts, name, config.orchestrator.model, config.orchestrator.tools);
412
+ return specOf(config.orchestrator, name, overrideDescription || config.orchestrator.description, instruction, [...delegated, ...asTools(tools)], opts);
413
+ }
414
+ // ── The ADK runtime's agents (lib/compileAdk.ts) ─────────────────────────────
415
+ /**
416
+ * Builds ONE runnable ADK agent from a subagent entry: its spec, as
417
+ * lib/compileAdk.ts builds it. A workflow node's settings
418
+ * (CompileOptions.nodeConfig) apply to a local agent, not to a nested
419
+ * syndicate's orchestrator.
420
+ */
421
+ export async function compileSubagent(subCfg, opts = {}) {
422
+ const spec = await compileSubagentSpec(subCfg, opts);
423
+ return compileAdk(spec, opts, subCfg.yaml_reference ? {} : (opts.nodeConfig?.(subCfg.name) ?? {}));
424
+ }
425
+ /**
426
+ * Compiles a syndicate's orchestrator for the ADK runtime. In DELEGATE mode
427
+ * its subagents are attached as AgentTools; in PLAN-DISPATCH mode it gets
428
+ * none, and the caller dispatches to `compileSubagent(route)` itself.
429
+ */
430
+ export async function compileGraph(config, opts = {}, overrideName, overrideDescription) {
431
+ return compileAdk(await compileSpec(config, opts, overrideName, overrideDescription), opts);
351
432
  }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * lib/compileAdk.ts — an AgentSpec as the ADK runtime runs it: today's
3
+ * LlmAgent (ADR 0045, ADR 0073).
4
+ *
5
+ * WHY this file exists:
6
+ * lib/compile.ts turns a YAML agent into a runtime-neutral AgentSpec: its
7
+ * tools resolved and gated, its instruction with the skills index, its
8
+ * model resolved once and its generateContentConfig built for that model.
9
+ * This file adds what only ADK's LlmAgent takes: the model wrapped in a
10
+ * FallbackLlm for `fallback_model:`, each delegated subagent as an
11
+ * AgentTool (a nested workflow's whole Workflow too; a remote one as its
12
+ * A2A tool), Gemini's code executor, the
13
+ * context compactor, task mode and a workflow node's settings. Every field
14
+ * reaches LlmAgent as compileGraph and compileSubagent always passed it, so
15
+ * the ADK runtime runs the agent it ran before the split.
16
+ * lib/compileNative.ts builds the native loop's agent from the same spec.
17
+ *
18
+ * Imports from lib/compile.ts are types only. A nested workflow's Workflow
19
+ * comes from lib/workflow.ts (assembleWorkflow, ADR 0098), which imports
20
+ * lib/compile.ts; every use of either is inside a function, so the modules
21
+ * load in any order.
22
+ */
23
+ import type { LlmAgent } from '@google/adk';
24
+ import type { AgentSpec, CompileOptions } from './compile.ts';
25
+ import { DEFAULT_KEEP_RECENT_EVENTS } from './runtime/native/compaction.ts';
26
+ /** Events kept verbatim after a compaction summary when `context:` names none: the native compactor's default. */
27
+ export { DEFAULT_KEEP_RECENT_EVENTS };
28
+ /**
29
+ * The LlmAgent for `spec`. `extra` is spread last: a workflow node's
30
+ * settings (CompileOptions.nodeConfig), which compileSubagent passes.
31
+ */
32
+ export declare function compileAdk(spec: AgentSpec, opts?: CompileOptions, extra?: Record<string, unknown>): LlmAgent;
@@ -0,0 +1,142 @@
1
+ /**
2
+ * lib/compileAdk.ts — an AgentSpec as the ADK runtime runs it: today's
3
+ * LlmAgent (ADR 0045, ADR 0073).
4
+ *
5
+ * WHY this file exists:
6
+ * lib/compile.ts turns a YAML agent into a runtime-neutral AgentSpec: its
7
+ * tools resolved and gated, its instruction with the skills index, its
8
+ * model resolved once and its generateContentConfig built for that model.
9
+ * This file adds what only ADK's LlmAgent takes: the model wrapped in a
10
+ * FallbackLlm for `fallback_model:`, each delegated subagent as an
11
+ * AgentTool (a nested workflow's whole Workflow too; a remote one as its
12
+ * A2A tool), Gemini's code executor, the
13
+ * context compactor, task mode and a workflow node's settings. Every field
14
+ * reaches LlmAgent as compileGraph and compileSubagent always passed it, so
15
+ * the ADK runtime runs the agent it ran before the split.
16
+ * lib/compileNative.ts builds the native loop's agent from the same spec.
17
+ *
18
+ * Imports from lib/compile.ts are types only. A nested workflow's Workflow
19
+ * comes from lib/workflow.ts (assembleWorkflow, ADR 0098), which imports
20
+ * lib/compile.ts; every use of either is inside a function, so the modules
21
+ * load in any order.
22
+ */
23
+ import { BaseLlm, adk, requireAdk } from './adkPeer.js';
24
+ import { remoteAgentTool } from './a2a/remoteAgent.js';
25
+ import { assembleWorkflow } from './workflow.js';
26
+ import { FallbackLlm } from './models/fallback.js';
27
+ import { resolveModel as resolveRegistryModel } from './models/registry.js';
28
+ import { onLogLevel } from './runtime/logging.js';
29
+ import { DEFAULT_KEEP_RECENT_EVENTS } from './runtime/native/compaction.js';
30
+ /**
31
+ * ADK's logger follows the engine's level (lib/runtime/logging.ts, ADR
32
+ * 0080), so a surface sets one level and never names ADK to quiet it.
33
+ */
34
+ if (adk) {
35
+ const { LogLevel: Level, setLogLevel } = adk;
36
+ const levels = { debug: Level.DEBUG, info: Level.INFO, warn: Level.WARN, error: Level.ERROR };
37
+ onLogLevel((level) => setLogLevel(levels[level]));
38
+ }
39
+ /** What compileAdk builds needs @google/adk; without it, this names the package (ADR 0102). */
40
+ const FEATURE = 'Compiling an agent for the ADK runtime (MELCHIZEDEK_RUNTIME=adk, compileGraph, compileSubagent)';
41
+ /** Events kept verbatim after a compaction summary when `context:` names none: the native compactor's default. */
42
+ export { DEFAULT_KEEP_RECENT_EVENTS };
43
+ /**
44
+ * The LlmAgent fields a YAML agent may set beyond model, instruction, tools
45
+ * and schemas. The schema reference (config/agents/syndicateSchema.yaml)
46
+ * documents each as mapping 1:1 to its ADK counterpart. Only fields the YAML
47
+ * sets are passed, so ADK's defaults stay in force otherwise.
48
+ */
49
+ function passthroughFields(spec) {
50
+ const out = {};
51
+ if (spec.includeContents !== undefined)
52
+ out.includeContents = spec.includeContents;
53
+ if (spec.outputKey !== undefined)
54
+ out.outputKey = spec.outputKey;
55
+ if (spec.globalInstruction !== undefined)
56
+ out.globalInstruction = spec.globalInstruction;
57
+ if (spec.disallowTransferToParent !== undefined)
58
+ out.disallowTransferToParent = spec.disallowTransferToParent;
59
+ if (spec.disallowTransferToPeers !== undefined)
60
+ out.disallowTransferToPeers = spec.disallowTransferToPeers;
61
+ return out;
62
+ }
63
+ /**
64
+ * The LlmAgent fields the engine builds from YAML rather than passing
65
+ * through (ADR 0033): `code_execution: gemini` (Gemini's server-side
66
+ * sandbox runs the model's Python; nothing runs on this host), `context:`
67
+ * (ADK's token-based compactor with an LLM summarizer, so a long
68
+ * conversation is summarized instead of overflowing the window), and
69
+ * `mode: task` (the agent works until it calls finish_task; on a workflow
70
+ * node, its arguments become the node's output).
71
+ */
72
+ function executionFields(cfg, opts) {
73
+ const { BuiltInCodeExecutor, LLMRegistry, LlmSummarizer, TokenBasedContextCompactor } = requireAdk(FEATURE);
74
+ const out = {};
75
+ if (cfg.codeExecution === 'gemini')
76
+ out.codeExecutor = new BuiltInCodeExecutor();
77
+ if (cfg.mode)
78
+ out.mode = cfg.mode;
79
+ if (cfg.context) {
80
+ const resolve = opts.resolveModel ?? ((m) => m);
81
+ const summaryModel = resolve(cfg.context.summary_model ?? cfg.model);
82
+ const llm = typeof summaryModel === 'string' || !summaryModel ? LLMRegistry.newLlm(String(summaryModel ?? cfg.model)) : summaryModel;
83
+ out.contextCompactors = [
84
+ new TokenBasedContextCompactor({
85
+ tokenThreshold: cfg.context.compact_after_tokens,
86
+ eventRetentionSize: cfg.context.keep_recent_events ?? DEFAULT_KEEP_RECENT_EVENTS,
87
+ summarizer: new LlmSummarizer({ llm }),
88
+ }),
89
+ ];
90
+ }
91
+ return out;
92
+ }
93
+ /**
94
+ * An agent with `fallback_model:` gets its model wrapped (lib/models/fallback.ts):
95
+ * the fallback answers a provider-side failure, and a provider that keeps
96
+ * failing is skipped for a cooldown. A model id string is resolved to its
97
+ * adapter first, so the wrapper always holds two adapters.
98
+ */
99
+ function withFallback(primary, fallbackId, opts) {
100
+ if (!fallbackId)
101
+ return primary;
102
+ const resolve = opts.resolveModel ?? ((m) => m);
103
+ const asLlm = (m) => (m instanceof BaseLlm ? m : resolveRegistryModel(String(m)));
104
+ return new FallbackLlm(asLlm(primary), asLlm(resolve(fallbackId)), opts.log ?? ((m) => console.warn(m)));
105
+ }
106
+ /** The spec's tools as LlmAgent takes them: a delegated subagent (a nested workflow's Workflow included) as an AgentTool, a remote one as its A2A tool. */
107
+ function adkTools(spec, opts) {
108
+ const { AgentTool } = requireAdk(FEATURE);
109
+ return spec.tools.map((entry) => {
110
+ switch (entry.kind) {
111
+ case 'tool':
112
+ return entry.tool;
113
+ case 'agent':
114
+ return new AgentTool({ agent: compileAdk(entry.agent, opts) });
115
+ case 'remote':
116
+ return remoteAgentTool({ name: entry.name, description: entry.description, url: entry.url });
117
+ case 'workflow':
118
+ // ADK's AgentTool runs any node its Runner takes, a Workflow included: the whole graph, its last event's text the answer (ADR 0098).
119
+ return new AgentTool({ agent: assembleWorkflow(entry.workflow, opts).workflow });
120
+ }
121
+ });
122
+ }
123
+ /**
124
+ * The LlmAgent for `spec`. `extra` is spread last: a workflow node's
125
+ * settings (CompileOptions.nodeConfig), which compileSubagent passes.
126
+ */
127
+ export function compileAdk(spec, opts = {}, extra = {}) {
128
+ const { LlmAgent } = requireAdk(FEATURE);
129
+ const tools = adkTools(spec, opts);
130
+ return new LlmAgent({
131
+ name: spec.name,
132
+ description: spec.description,
133
+ model: withFallback(spec.resolvedModel, spec.fallbackModel, opts),
134
+ instruction: spec.instruction,
135
+ tools: tools.length > 0 ? tools : undefined,
136
+ outputSchema: spec.outputSchema,
137
+ generateContentConfig: spec.generateContentConfig,
138
+ ...passthroughFields(spec),
139
+ ...executionFields(spec, opts),
140
+ ...extra,
141
+ });
142
+ }