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
package/CHANGELOG.md CHANGED
@@ -4,6 +4,1007 @@ Consumers of the package read this file; it records changes to the
4
4
  **published API surface** (the exports map in `package.json`, the bins,
5
5
  the starter pack and the templates), not the repo's full history.
6
6
 
7
+ ## Unreleased
8
+
9
+ ## 0.20.0 — 2026-10-08
10
+
11
+ Release 0.20.0: the native runtime is the default, and `@google/adk` is an
12
+ optional peer (ADR 0102).
13
+
14
+ ### Breaking — read before upgrading
15
+
16
+ - **Breaking: the native runtime is the default (WS5-1, ADR 0102).** A
17
+ turn with no `runtime` option and no `MELCHIZEDEK_RUNTIME` now runs on the
18
+ engine's own loop and scheduler (`DEFAULT_RUNTIME` is `native`), on every
19
+ surface: `runSyndicateTurn`, the A2A server, the bins, the wiki agents.
20
+ It stores the events the ADK runtime stores, and every session ADK wrote
21
+ resumes under it (`tests/sessionFixtures.test.ts`, ADR 0045's stop rule),
22
+ so a deployment that upgrades keeps its conversations. **To stay on ADK**
23
+ for this release: install `@google/adk@~2.2.0` beside the package and set
24
+ `MELCHIZEDEK_RUNTIME=adk` (or pass `runtime: 'adk'`); a conversation can
25
+ move between the runtimes either way. What differs on native: approval
26
+ gates on workflow nodes run on native only (ADR 0098); `context:`
27
+ compaction, `mode: task` and workflows run on the engine's ports of ADK's
28
+ compactor, task mode and scheduler (ADR 0078, ADR 0081, ADR 0087, ADR
29
+ 0095); a Gemini agent is not shown the reflection tool and stores no
30
+ `turnComplete` (ADR 0097, ADR 0100); self-correction's reflection call on
31
+ Gemini 3 is signed (ADR 0103); a caller's `transformAgent` is ADK-only,
32
+ and an `ask_user` tool listed on a workflow agent node (rather than an
33
+ `ask_user` node) is refused, each with `UnsupportedOnRuntimeError` before
34
+ any model call (ADR 0073, ADR 0092). **1.0.0
35
+ removes the adk runtime** (ADR 0045).
36
+ - **Breaking: `@google/adk` is an optional peer dependency.** npm no longer
37
+ installs it with the package; nothing on the native runtime loads it, and
38
+ `lib/adkPeer.ts` is the one module that tries to. Without it, everything
39
+ only ADK runs fails with the new `AdkNotInstalledError`, which names the
40
+ package and the install command: `MELCHIZEDEK_RUNTIME=adk`,
41
+ `compileGraph` / `compileSubagent` / `compileWorkflow`, `retryPlugins`,
42
+ `GEMINI_ADAPTER=adk`, a wiki agent on adk, and the ADK face of a tool, a
43
+ model shim or a session store (their `runAsync`, `generateContentAsync`,
44
+ `appendEvent`). The engine's classes that extend ADK's (the
45
+ `FunctionTool`s in the tool registry, the model shims, the session
46
+ stores) still construct and still carry their own Tool, adapter or store;
47
+ with ADK installed they are ADK's own classes, as before. An install of
48
+ ADK that fails to load for another reason is still an error. A
49
+ TypeScript consumer without ADK sees ADK's types in the declarations as
50
+ unresolved (use `skipLibCheck`). The package now uses a top-level
51
+ `await` to load the peer, so it cannot be `require()`d from CommonJS.
52
+ - **Breaking: a Gemini id gets the engine's `GeminiAdapter` by default
53
+ (ADR 0100).** `resolveAdapter` from `melchizedek-agents/models/registry`
54
+ and `geminiAdapterChoice()` default to `engine`; `GEMINI_ADAPTER=adk`
55
+ (or `{ gemini: 'adk' }`) keeps `AdkGeminiAdapter` for this release, with
56
+ `@google/adk` installed. The adk runtime keeps `TracedGemini`.
57
+ - **Breaking: `registerTool` refuses the framework's reserved names.**
58
+ `adk_request_confirmation`, `adk_request_credential`,
59
+ `adk_request_input`, `adk_handle_model_error`, `transfer_to_agent`,
60
+ `set_model_response`, `finish_task`, and `ask_user` unless it is the
61
+ framework's own tool, are refused as the registry name or the tool's own
62
+ name, with `{ override: true }` too: a tool under one of them would be
63
+ read as the framework's interrupt, delegation or answer.
64
+ `RESERVED_TOOL_NAMES` is exported from `melchizedek-agents/tools`.
65
+ - **Breaking: a workflow `map:` node refuses `retry` and `timeout`
66
+ (ADR 0103).** Neither runtime ever applied them: each item of a map runs
67
+ under the mapped agent's own node entry, as ADK runs it. A YAML that set
68
+ them on the map entry loaded and silently ignored them; it is now refused
69
+ at load with `workflow.nodes.<Map>.retry — retry on a map node is not
70
+ applied: each item runs under its agent's own retry; set it on
71
+ nodes.<Agent>` (and the same for `timeout`). Move the keys to the mapped
72
+ agent's entry. No shipped example or template sets them.
73
+
74
+ ### Added and changed
75
+
76
+ - **The doctor prints the runtime (ADR 0102).** `melchizedek-doctor` opens
77
+ with a `runtime` line: the runtime in use, where it came from
78
+ (`MELCHIZEDEK_RUNTIME` or the default) and whether `@google/adk` is
79
+ installed, with its version. `--check` also fails when
80
+ `MELCHIZEDEK_RUNTIME=adk` is set without ADK, or holds a value no turn
81
+ accepts. `runDoctor()` returns it as `runtime`, and `runtimeReport` is
82
+ exported from `lib/doctor.ts`.
83
+ - **New exports.** From the barrel and `melchizedek-agents/runtime`:
84
+ `describeRuntime` (the runtime and its source), `RuntimeSource`,
85
+ `AdkNotInstalledError`, `adkInstalled`, `InProcessSessionService` (a
86
+ session store that needs no ADK) and `asAdkSessionService` /
87
+ `asSessionService`; the barrel also exports `DEFAULT_RUNTIME` and
88
+ `RuntimeName`. A turn without ADK takes
89
+ `sessionService: asAdkSessionService(new InProcessSessionService())`.
90
+ The exports map does not change.
91
+ - **CI consumes the packed tarball twice**: without `@google/adk` a shipped
92
+ example's turn runs on native, and with it the same turn runs on adk.
93
+
94
+ - **The native loop's security gate (WS5-5, ADR 0101).** A model's answer is
95
+ now held to the model contract before either runtime stores it:
96
+ `modelResponseToLlmResponse` in `melchizedek-agents/models/genaiMapping`
97
+ drops a part the contract does not allow (an unknown kind, `null`, a text
98
+ part whose text is not a string, a tool result) and coerces a tool call's
99
+ name, id and arguments (`{}` for none, `{ raw }` otherwise); the new
100
+ `contractModelResponse` export is that check. A call's arguments or a
101
+ tool's result nested deeper than 64 levels is replaced by a short note
102
+ (`TOO_DEEP_ARGUMENTS`; on the native runtime `TOO_DEEP_RESULT`), where it
103
+ used to fail that turn and every later one on the session. A
104
+ `yaml_reference` chain that reaches itself, or goes past 16 levels, now
105
+ fails the compile with an Error naming the chain, on both runtimes; it
106
+ used to overflow the stack and stop the process. On the native runtime a
107
+ call id `__proto__` opens its approval as any id does, a credential
108
+ request in an event the user wrote is not pending, a resumed OAuth call
109
+ is the one the agent made, and a replayed grant runs nothing.
110
+ `wiki/operations/native-loop-security.md` is the threat model;
111
+ `tests/nativeFuzz.test.ts` fuzzes the loop.
112
+ - **On the native runtime, self-correction's reflection call is signed on
113
+ Gemini (ADR 0103).** When a Gemini 3 model calls the reserved
114
+ `adk_handle_model_error` tool, or answers `MALFORMED_FUNCTION_CALL`, the
115
+ reflection call stored in its place now carries the replaced call's
116
+ `thoughtSignature`, or Gemini's documented placeholder
117
+ (`skip_thought_signature_validator`) when there was none, so the next
118
+ request no longer fails with Gemini's "missing a thought_signature" 400.
119
+ On Gemini 2.x only a carried signature is added. The ADK runtime is
120
+ unchanged: ADK's plugin still stores the call unsigned. The stored event
121
+ differs from ADK's by that one field. `PLACEHOLDER_THOUGHT_SIGNATURE` is
122
+ still exported from `melchizedek-agents/models/geminiAdapter`.
123
+
124
+ - **A workflow node's `retry` takes `exceptions` and `jitter` (ADR 0103).**
125
+ `retry: { exceptions: [NodeTimeoutError] }` retries only a failure whose
126
+ error class or `name` is listed; `jitter` sets the backoff's randomness
127
+ (0 = none, default 1). Both runtimes honour them: the ADK runtime hands
128
+ them to ADK's `retryConfig`, the native scheduler applies them as ADK's
129
+ `retry_utils` does. `syndicate.schema.json` is regenerated; the `exports`
130
+ map is unchanged.
131
+
132
+ - **The capability matrix's Gemini column is asserted on the engine's own
133
+ Gemini adapter (WS3-6, ADR 0100).** Every Gemini cell is now evidence
134
+ `test`, checked against the request `GeminiAdapter` sends through the
135
+ real `@google/genai` client, as every other column is; `npm run doctor --
136
+ --matrix` says so. On the native runtime a Gemini agent's stored events no
137
+ longer carry `turnComplete`, as the ADK runtime's never have; nothing reads
138
+ the field. A Gemini answer that ran code through the engine's adapter
139
+ (`GEMINI_ADAPTER=engine`, or `GeminiAdapter` behind the shim) now stores
140
+ the `executableCode` and `codeExecutionResult` parts as ADK's Gemini stores
141
+ them, where the session held none before; `partsToGenai` in
142
+ `melchizedek-agents/models/genaiMapping` is the mapping that writes them
143
+ out. `scripts/gemini_engine_check.ts` is the live check gate G3 runs:
144
+ grounding, code execution, a function tool beside server-side tools, and a
145
+ two-turn session, with `GeminiAdapter` on both runtimes. `GeminiAdapter`
146
+ becomes the default in 0.20.0 (see Breaking above).
147
+
148
+ - **A workflow syndicate can be a subagent, and a workflow node can carry
149
+ an approval gate (WS4-7, ADR 0098).** A DELEGATE syndicate's
150
+ `yaml_reference` to a `workflow:` syndicate now runs the whole graph as
151
+ the subagent tool, under the entry's name and description, on both
152
+ runtimes: the graph's last output is the tool's answer. Before, only the
153
+ nested syndicate's orchestrator ran. A nested workflow with an
154
+ `ask_user` node is now refused by name at compile time (its pause could
155
+ not reach the caller); as a dispatch route or a workflow node, a
156
+ workflow syndicate is still its orchestrator alone. `require_approval`
157
+ on a workflow node's agent now validates (except on an agent a `map`
158
+ node runs): on the native runtime the gated call pauses the node and the
159
+ turn ends `input-required` with `result.approval`, and the person's
160
+ decision runs or refuses the pinned call once and walks on; another
161
+ message repeats the request. On the ADK runtime a gated workflow throws
162
+ `UnsupportedOnRuntimeError` before any model call, because ADK's resume
163
+ restarts the node and never runs the call. `melchizedek-agents/compile`
164
+ adds the `workflow` kind to `SpecTool`, and exports
165
+ `compileWorkflowSpec` and the `WorkflowSpec` type.
166
+ - **A Gemini agent on the native runtime is no longer shown the reflection
167
+ tool (WS4-6b, ADR 0097).** With `retries.model_errors` on (the default),
168
+ native declared `adk_handle_model_error` to every model. ADK's own Gemini
169
+ never sends it, and a Gemini 3 model that called it on native failed its
170
+ next step with Gemini's missing `thought_signature` 400 (a workflow
171
+ node then failed the turn `NODE_FAILED`). Native now sends a Gemini model
172
+ the same tools as ADK; a model on any other provider, or a Gemini adapter
173
+ a resolver returns behind `adkShim`, is still told of the tool, as on ADK.
174
+ ADK turns are unchanged.
175
+
176
+ ## 0.19.0 — 2026-10-08
177
+
178
+ The native runtime ships in this release as an opt-in: set
179
+ `MELCHIZEDEK_RUNTIME=native` or pass `runtime: 'native'` to `runSyndicateTurn`.
180
+ `adk` stays the default (ADR 0099). The `@google/adk` peer dependency is
181
+ unchanged.
182
+
183
+ ### Breaking — read before upgrading
184
+
185
+ - **Breaking: a skill script no longer inherits the server's environment
186
+ (ADR 0086).** An approved `run_skill_script` starts from PATH,
187
+ HOME/USERPROFILE, TMPDIR/TEMP/TMP, LANG, LC_*, TZ, the user's name and
188
+ the Windows essentials, and nothing else: provider keys, `DATABASE_URL`
189
+ and the server's bearer secrets no longer reach it. A script that relied
190
+ on an inherited variable must now name it in the agent's YAML, under the
191
+ new `skills.env` (names only), or under `skills.secret_env` when the
192
+ name looks like a secret (KEY, TOKEN, SECRET, PASSWORD, AUTH, DATABASE,
193
+ …), which `skills.env` refuses. Both need `scripts: local`. A script's
194
+ stdout and stderr are each cut at 20,000 characters, ending with
195
+ `[stdout truncated: N more characters not shown (the limit is 20000)]`.
196
+ The same on both runtimes. `LocalScriptExecutor` takes `envNames`,
197
+ `sourceEnv` and `maxOutputChars`; `lib/tools/skills/env.ts` is new. The
198
+ `exports` map is unchanged.
199
+ - **Breaking for subclasses of `OpenAiCompatibleLlm`: the chat-completions
200
+ adapters move onto the model contract (ADR 0057).** New modules under
201
+ `melchizedek-agents/models/`:
202
+ - `chatCompletionsAdapter`: `ChatCompletionsAdapter`, the base that turns a
203
+ `ModelRequest` into a chat-completions body and a completion (JSON or
204
+ SSE) into contract responses; `ChatCompletionsRequest` and
205
+ `OlderSpelling`; `chatUsage` and `sumUsage` (usage in the contract's
206
+ meaning); `splitThinkBlocks`, `ThinkStreamSplitter`,
207
+ `REASONING_CONTENT_KIND` and `ENGINE_CALL_ID_PREFIX`.
208
+ - `ollamaAdapter` (`OllamaAdapter`), `kimiAdapter` (`KimiAdapter`, and
209
+ `isKimiK3`, `wantsReasoningReplay`, `MOONSHOT_BASE_URL`, which
210
+ `models/kimiLlm` still exports) and `gatewayAdapter` (`GatewayAdapter`).
211
+
212
+ `OpenAiCompatibleLlm` is now an `AdkShim` whose constructor takes the
213
+ adapter, and its protected hooks (`endpointUrl`, `headers`,
214
+ `wireModelName`, `extraBodyFields`, `httpError`, `noAnswerError` and the
215
+ rest) move to `ChatCompletionsAdapter`, on contract types. A provider of
216
+ your own subclasses `ChatCompletionsAdapter` and runs under ADK as
217
+ `adkShim(adapter)` or as an `OpenAiCompatibleLlm` subclass. `OllamaLlm`,
218
+ `KimiLlm` and `GatewayLlm` keep their constructors, ids, error codes and
219
+ wording, and the shape of what they yield: usage counts the reasoning in
220
+ `candidatesTokenCount` as before, so the ledger's counts are unchanged.
221
+ `models/openAiCompatibleLlm` adds `olderSpellingOf` and
222
+ `chatUsageMetadata`. `AdkShim` gains a protected `toModelRequest` seam
223
+ beside `toLlmResponse` (ADR 0056); the chat shims override both.
224
+
225
+ What reaches the provider changes only where the contract maps a field
226
+ the old classes ignored or spelled as written:
227
+ - `stopSequences` are sent as `stop`.
228
+ - A function-calling mode is honoured: `NONE` sends no tools; the gateway
229
+ sends `ANY` as `tool_choice: required` or the named tool, and Kimi and
230
+ Ollama weaken it to auto (`llm.tool_choice.weakened` on the span).
231
+ - The older spelling's reasoning follows ADR 0047's mapping, as
232
+ `reasoning:` already did: `thinkingConfig.thinkingBudget` alone now
233
+ travels as its level (`0` is `none`), `reasoningEffort: medium` on
234
+ `kimi-k3` is sent as `high`, and `minimal` as each model's `none`.
235
+ A word that is no level (`max`, `xhigh`) is still sent as written.
236
+ - A tool call stored without an id is sent with one, matched to its
237
+ result, where the result's `tool_call_id` was empty.
238
+ - The no-answer hints name `reasoning: none` (the older spelling too).
239
+ - Every error a chat shim yields carries its retry verdict
240
+ (`customMetadata['error.retryable']`, `false` where there was none) and
241
+ `turnComplete`. A call cut off by a cancelled turn is never retryable,
242
+ even when its last status was a 503, so no fallback answers a
243
+ cancellation.
244
+ - **Breaking for subclasses of `GptLlm`: the vendor hooks move to
245
+ `GptAdapter` (ADR 0056).** `providerId()`, `baseURL()`, `apiKeyFromEnv()`,
246
+ `missingKeyMessage()`, `clientOptions()`, `reasoningParam()`,
247
+ `replaysReasoning()` and `endpoint()` are overridden on a `GptAdapter`
248
+ subclass now, as `GrokAdapter` does, and a `GptLlm` subclass returns it
249
+ from `protected static createAdapter(options)`. Code that only constructs
250
+ or registers `GptLlm` and `GrokLlm`, or imports their exported functions,
251
+ is unaffected.
252
+ - **Breaking for one import path: `toFunctionTool` moves to
253
+ `melchizedek-agents/tools/adkTool` (ADR 0051).**
254
+ `melchizedek-agents/tools/toolContract` no longer exports it, so that
255
+ module loads nothing from `@google/adk`. Import it from
256
+ `melchizedek-agents`, which still exports it, or from the new subpath.
257
+ The `exports` map is unchanged.
258
+
259
+ ### Changes
260
+
261
+ - **Workflow syndicates run on the native runtime (WS4-6, ADR 0095).**
262
+ A `workflow:` syndicate no longer throws `UnsupportedOnRuntimeError` on
263
+ `runtime: 'native'` (or `MELCHIZEDEK_RUNTIME=native`): the engine's own
264
+ scheduler walks the graph, and `runSyndicateTurn` returns the same
265
+ result, stored events, progress lines, `answer.nodeErrors`, text deltas
266
+ and ledger rows as on ADK. An `ask_user` node pauses the turn
267
+ `input-required` with `result.input`, and the next message resumes it,
268
+ also in a session ADK paused. Two new outcomes on native: a session
269
+ paused inside an agent node or a map item (which only ADK resumes) fails
270
+ the turn with error code `RESUME_UNSUPPORTED` instead of starting the
271
+ graph again, and an `ask_user` tool on a workflow node's agent in a
272
+ config that skipped validation throws `UnsupportedOnRuntimeError`
273
+ before any model call (the schema refuses it on both runtimes). A
274
+ native workflow turn traces `workflow.invoke`, `node.execute` and
275
+ `tool.execute` spans, so each model call's ledger row names its node's
276
+ agent. ADK turns are unchanged.
277
+ - **Ollama structured output enforces the schema (ADR 0096).** An
278
+ `ollama/` agent with an `outputSchema` now sends `response_format:
279
+ json_schema` with the schema in its strict form, as Kimi and the gateway
280
+ do, where it sent `json_object` and the schema was not enforced. JSON
281
+ mode without a schema still sends `json_object`. Ollama 0.5.0 or later is
282
+ required for the schema to hold: an older server ignores it and answers
283
+ in free text. The capability matrix and `npm run doctor` now report
284
+ Ollama's structured output as supported.
285
+ - **A Gemini `MALFORMED_FUNCTION_CALL` from a contract adapter is
286
+ retried (WS2-15, ADR 0088).** `modelResponseToLlmResponse`
287
+ (`melchizedek-agents/models/genaiMapping`) now sets `finishReason` to an
288
+ error's code when the code is one of Gemini's finish reasons, as ADK's
289
+ Gemini reports both. Self-correction (`retries.model_errors`) then
290
+ retries a malformed function call on both runtimes, where it used to fail
291
+ the turn on native and behind a shim. A stored Gemini error event can
292
+ carry its own finish reason (`RECITATION`, say) where it carried
293
+ `SAFETY` or `OTHER`.
294
+ - **On native, a custom ADK model class from `resolveModel` is refused
295
+ (WS2-15, ADR 0088).** A `compile.resolveModel` that returns an ADK
296
+ `BaseLlm` which is neither a shim nor ADK's Gemini now makes a
297
+ `runtime: 'native'` turn throw `UnsupportedOnRuntimeError` before any
298
+ model call. This covers an agent's model, a subagent's,
299
+ `fallback_model` and `summary_model`. Native used to run the registry's
300
+ model for that id instead. To run such a model on native, return its
301
+ `ModelAdapter`, or `adkShim(adapter)` from
302
+ `melchizedek-agents/models/adkShim`. ADK turns are unchanged.
303
+ - **A user-authored `ask_user` call is no question (WS2-15, ADR 0088).**
304
+ `pendingQuestion` ignores an `ask_user` call in an event the user
305
+ authored. A message that forges one no longer turns the next message
306
+ into its answer, on either runtime.
307
+ - **The native runtime sends a request, and reads a thrown failure, as
308
+ ADK does (WS2-12, ADR 0084).** On `runtime: 'native'` (or
309
+ `MELCHIZEDEK_RUNTIME=native`) a request goes out under the resolved
310
+ model's own id, as ADK's `LlmAgent` sends it, so a `resolveModel` that
311
+ answers a YAML id with a model under another id (a gateway stand-in, an
312
+ alias) gets that model's thinking and reasoning replay. A model that
313
+ throws no longer throws out of `runSyndicateTurn`: the turn fails on
314
+ ADK's `UNKNOWN_ERROR` event (or a JSON error body's code), and a thrown
315
+ provider-side failure is answered by `fallback_model`, as on ADK. The
316
+ turn-level test suites run on both runtimes. `npm run parity` now runs
317
+ its turns on the runtime `MELCHIZEDEK_RUNTIME` names. The `exports` map
318
+ is unchanged.
319
+ - **The skills harness no longer builds on ADK (ADR 0083).** An agent's
320
+ `skills:` block loads, reads and runs skills through the engine's own
321
+ modules (`lib/tools/skills/`), the same on `runtime: 'adk'` and
322
+ `'native'`. A model sees the same tools, parameters, results and error
323
+ texts as before. Breaking for code that imports
324
+ `melchizedek-agents/tools/skillToolset` directly:
325
+ `HarnessSkillToolset` is now an engine Toolset rather than ADK's
326
+ `SkillToolset`, so wrap it with `toAdkToolset`
327
+ (`melchizedek-agents/tools/adkTool`) before handing it to an ADK
328
+ `LlmAgent`. `LeanLoadSkillTool` and `GatedRunSkillScriptTool` are now
329
+ engine Tools (`execute(args, ctx)`), not ADK `BaseTool`s. Frontmatter
330
+ YAML is read by the `yaml` package, so a timestamp stays a string and
331
+ `<<` merge keys are not merged. A SKILL.md over 1 MiB and a resource
332
+ file over 8 MiB are not loaded. `lib/tools/tool.ts` adds `Toolset`,
333
+ `ToolsetContext`, `isOwnToolset`, `toolsetOf` and an optional
334
+ `Tool.contents` hook. The `exports` map is unchanged.
335
+ - **OAuth consent for tool credentials (ADR 0085).** On the native
336
+ runtime, `runSyndicateTurn` takes `toolCredentials: { store, consent }`
337
+ (both optional additions). `store` is the sealed credential store of ADR
338
+ 0072, and `consent` is `oauthConsent({ providers, redirectUri,
339
+ credentials })` from `melchizedek-agents/tools/oauthConsent`.
340
+ - When a call's provider is not granted, `ctx.accessToken(provider)`
341
+ asks for consent by itself, or a tool calls the new
342
+ `ctx.requestCredential(provider)`. The turn ends `input-required` with
343
+ `result.consent` (`id`, `agent`, `provider`, `authUri`, `state`,
344
+ `scopes`), stored as ADK's own `adk_request_credential` call with no
345
+ secret in it.
346
+ - The person's next message, after the grant is stored, runs the paused
347
+ call again. Until then, a message repeats the request and runs nothing.
348
+ - `createA2AApp` takes the same `toolCredentials` (plus `callbackLimit`
349
+ and `requireCallerIdentity`, default true: the callback refuses a
350
+ browser that does not carry the flow's user's identity). It publishes a `consent_request` data part
351
+ beside `approval_request` and `input_request`, and mounts the consent
352
+ callback at the path of the redirect URI. The callback completes the
353
+ authorization-code flow with PKCE S256 and stores the grant.
354
+ - New exports, all through existing entries: `./a2a` gains
355
+ `consentCallback`. `./runtime` gains `pendingConsent`,
356
+ `credentialResponsePart`, `describeConsent`, `CREDENTIAL_REQUEST` and
357
+ the types `PendingConsent` and `ToolCredentials`. `./tools/*` gains the
358
+ new module `oauthConsent`.
359
+ - Also additive: `RouteDecision.decidedBy` gains `'consent'`, the audit
360
+ trail gains the `consent.callback` event, and `ToolContext` gains
361
+ `requestCredential`.
362
+ - On the ADK runtime, an open consent request throws
363
+ `UnsupportedOnRuntimeError`.
364
+ - No change to the `exports` map.
365
+ - **A question is answered on the native runtime (ADR 0079).** On
366
+ `runtime: 'native'` (or `MELCHIZEDEK_RUNTIME=native`), a plain-text
367
+ message that answers an open `ask_user` call no longer throws
368
+ `UnsupportedOnRuntimeError`: it becomes the call's response and the agent
369
+ that asked resumes, in plan-dispatch the route, as on ADK. Both runtimes
370
+ store the same events, so a question opened on either is answered on the
371
+ other; `result.input` and the A2A `input_request` part are unchanged. No
372
+ change to the `exports` map.
373
+ - **`mode: task` runs on the native runtime (ADR 0081).** It no longer
374
+ throws `UnsupportedOnRuntimeError`: the agent's requests declare
375
+ `finish_task` as ADK's do, and its answers are stored as ADK stores them.
376
+ A `workflow:` syndicate, where task-mode nodes live, is still refused on
377
+ native. `code_execution: gemini` runs on native with the same stored
378
+ events as on ADK. No change to the exports map.
379
+ - **An approval resumes on the native runtime (ADR 0077).** On
380
+ `runtime: 'native'`, a message carrying `approvalResponsePart(id, …)` runs
381
+ or refuses the pinned call before the agent's next step, as on ADK, and
382
+ stores the same events: an approval opened on either runtime resumes on
383
+ the other. An answer whose pinned call does not bind (changed arguments,
384
+ a request the user authored) throws ADK's `IntentMismatchError` text on
385
+ both runtimes. No change to the `exports` map.
386
+ - **`createA2AApp` takes the engine's own stores (ADR 0080).**
387
+ `A2AAppOptions.storage.sessionService` accepts the engine's
388
+ `SessionService` as well as ADK's `BaseSessionService`, and
389
+ `storage.memoryService` the engine's `MemoryService` as well as ADK's
390
+ `BaseMemoryService`; a store or service you pass today works unchanged.
391
+ Without durable storage, sessions live in the engine's
392
+ `InProcessSessionService` instead of ADK's `InMemorySessionService`, with
393
+ the durable stores' meaning (no `app:` or `user:` state shared across
394
+ sessions). `resolveModel` returns what `CompileOptions.resolveModel`
395
+ returns, the same type as before. The `melchizedek-serve` bin no longer
396
+ imports `@google/adk`; ADK's logger follows the level the engine sets.
397
+ No change to the `exports` map, `runSyndicateTurn`, or the A2A surface.
398
+ - **`context:` compaction runs on the native runtime (ADR 0078).** A
399
+ syndicate whose orchestrator sets `context:` no longer throws
400
+ `UnsupportedOnRuntimeError` under `runtime: 'native'`
401
+ (or `MELCHIZEDEK_RUNTIME=native`): the native loop compacts as the ADK
402
+ runtime does, stores the same compacted event, and charges and traces the
403
+ summary call the same way, so a compacted session continues on either
404
+ runtime. No change to the exports map; `ContextConfig` and
405
+ `DEFAULT_KEEP_RECENT_EVENTS` stay exported from
406
+ `melchizedek-agents/compile` under the same names.
407
+ - **A turn can run on the native runtime (ADR 0073).** `runSyndicateTurn`
408
+ takes an optional `runtime` (`'adk'` or `'native'`). Without it,
409
+ `MELCHIZEDEK_RUNTIME` decides (`adk` or `native`), and without that, `adk`,
410
+ so nothing changes unless you ask. On `native` a single-agent, DELEGATE
411
+ or plan-dispatch syndicate runs on the engine's own loop, with
412
+ self-correction from `retries:` and the same root span, and returns the
413
+ same result shape; what native does not run yet (compaction, workflows,
414
+ task mode, `transformAgent`, answering a question) throws `UnsupportedOnRuntimeError` before any model call. Additions under the existing `exports` map:
415
+ - `melchizedek-agents/runtime` exports `RuntimeName`, `RUNTIMES`,
416
+ `DEFAULT_RUNTIME`, `chooseRuntime`, `runtimeSetting` and
417
+ `UnsupportedOnRuntimeError`.
418
+ - `melchizedek-agents/compile` exports `AgentSpec`, `SpecTool`,
419
+ `compileSpec` and `compileSubagentSpec`, the runtime-neutral half of the
420
+ compiler. `compileGraph` and `compileSubagent` build the same `LlmAgent`
421
+ as before.
422
+ - `melchizedek-agents/wiki/agentRun`: `runWikiAgent` follows the same
423
+ flag, and takes `runtime` and (native only) `adapterFor`.
424
+ - `.env.example` lists `MELCHIZEDEK_RUNTIME` and `GEMINI_ADAPTER`.
425
+ - **Third-party tokens for tools, sealed per end user (ADR 0072).** Apply
426
+ migration `0013_tool_credentials.sql` (`npx melchizedek-db apply`, or
427
+ `print` into the SQL editor) before using it. New, all under the existing
428
+ `exports` map:
429
+ - `melchizedek-agents/tools/auth`: the `CredentialStore` interface (`put`,
430
+ `get` with refresh, `revoke`, `eraseUser`), `OAuthProvider` (`refresh`,
431
+ `revoke` hooks), `ToolCredentialError`, `toolAccessToken` and
432
+ `pinnedCredentialStore`.
433
+ - `melchizedek-agents/tools/credentialStore`: `credentialStore({ rows,
434
+ cipher, providers, audit })` and `memoryCredentialRows()`.
435
+ - `melchizedek-agents/tools/credentialCipher`: the `CredentialCipher` plug
436
+ point, `aesGcmCipher` (AES-256-GCM) and `credentialCipherFromEnv`, which
437
+ reads the new `MELCHIZEDEK_CREDENTIAL_KEY` (32 bytes, base64 or hex).
438
+ - `storage/postgres`: `postgresStorage({ credentials: { cipher, providers }
439
+ })` adds `storage.credentials`; `postgresCredentialRows` and
440
+ `postgresCredentialStore` are exported.
441
+ - `tools/tool`: `ToolContext.accessToken(provider)`, a valid token for the
442
+ run's own app and user, present when `createToolContext` is given
443
+ `credentials`. No built-in tool uses it yet.
444
+ - `EraseCounts` gains `credentials`: `melchizedek_erase_scope` and
445
+ `DELETE /memory` remove the user's tokens too. A custom `storage.erase`
446
+ that builds its own counts adds the field.
447
+ - The audit trail gains `credential.put`, `credential.refresh`,
448
+ `credential.revoke` and `credential.erase` (`AuditEventName`), with the
449
+ provider and app and never a token.
450
+ - **The ledger reads the native loop's spans (ADR 0076).** The native loop
451
+ (not yet selectable, WS2-10) opens `agent.invoke <name>`, `model.call` and
452
+ `tool.execute <name>` spans in scope `melchizedek.runtime`, and a native
453
+ run writes the same `adk_turns`, `adk_telemetry` and `adk_payloads` rows as
454
+ an ADK run. `melchizedek-agents/observability/lineage` exports
455
+ `ADK_SPAN_SCOPE`, `RUNTIME_SPAN_SCOPE`, `agentOfSpanName`,
456
+ `isToolSpanName` and `isModelCallSpan`. In `observability/tracer`,
457
+ `agentForSpan` also walks up to an `agent.invoke` span, tool time also
458
+ sums `tool.execute` spans, and the console exporter keeps the
459
+ `melchizedek.runtime` scope quiet as it keeps ADK's
460
+ (`OTEL_CONSOLE_ALL_SPANS=true` prints both). In
461
+ `observability/supabaseSpanExporter`, `isPayloadSpan` also takes a
462
+ `model.call` span that carries `llm.payload.*`, and `toPayloadRow` reads
463
+ `adk.invocation_id` before the turn's.
464
+ - **New entry `melchizedek-agents/model`: the model layer without ADK
465
+ (ADR 0068).** A new path in the `exports` map, so the version is 0.19.0.
466
+ It exports the model contract's types, `ClaudeAdapter`, `GptAdapter`,
467
+ `GrokAdapter`, `ChatCompletionsAdapter`, `KimiAdapter`, `OllamaAdapter`,
468
+ `GatewayAdapter`, `GeminiAdapter`, `resolveAdapter`,
469
+ `resolveAdapterWithFallback`, `geminiAdapterSetting`, `FallbackAdapter`,
470
+ `isProviderError`, the circuit breaker's helpers (`breakerSettings`,
471
+ `circuitOpen`, `recordFailure`, `recordSuccess`, `resetCircuits`) and the
472
+ prefix table (`PROVIDERS`, `providerForModel`, `providerKeyPresent`), and
473
+ loads no `@google/adk`: install with `--legacy-peer-deps` to leave ADK out.
474
+ - Its `resolveAdapter` gives a Gemini id `GeminiAdapter`. Asking it for
475
+ `adk` (`gemini: 'adk'` or `GEMINI_ADAPTER=adk`) throws and names
476
+ `melchizedek-agents/models/registry`, whose `resolveAdapter` is
477
+ unchanged (`AdkGeminiAdapter` by default until gate G3).
478
+ - New module `melchizedek-agents/models/adapterResolver` (through
479
+ `./models/*`): `adapterResolver`, `routeFor`, `scopedKey`,
480
+ `normalizeProvider`, `geminiAdapterSetting` and the resolver types.
481
+ `models/registry` still exports `geminiAdapterChoice`,
482
+ `GeminiAdapterChoice` and `ResolveAdapterOptions`.
483
+ - New module `melchizedek-agents/tools/xaiSearchParams` holds
484
+ `xaiWebSearchParamsFromEnv`, `xSearchParamsFromEnv`,
485
+ `collectionIdsFromEnv` and `collectionsMaxResultsFromEnv`, which
486
+ `tools/webSearchTool`, `tools/xSearchTool` and
487
+ `tools/collectionsSearchTool` still re-export.
488
+ - **Kimi forces a tool where Moonshot allows it** (checked live on
489
+ 2026-10-08). `kimi-k3` sends `toolChoice: 'required'` as asked and a
490
+ named tool as `tool_choice: "required"` (Moonshot refuses a named tool
491
+ while K3 thinks, and K3 always thinks); `kimi-k2.6` sends both forced
492
+ modes as asked when `reasoning` is `none`, and weakens them to auto
493
+ otherwise. Other Kimi ids keep weakening both to auto. A weakened choice
494
+ is still marked `llm.tool_choice.weakened` on the span. In the
495
+ chat-completions base, a subclass's `toolChoiceModes` now also receives
496
+ the request's reasoning.
497
+ - **Fix: `kimi-k2.7-code` with `reasoning: none`.** It sends no thinking
498
+ field (the model thinks at its default) instead of
499
+ `thinking: { type: 'disabled' }`, which Moonshot refuses for K2.7 Code
500
+ and its highspeed variant. `kimi-k2.6` still sends `disabled`.
501
+ - **The genai mapping exports two more readers (ADR 0066).**
502
+ `melchizedek-agents/models/genaiMapping` adds `toolChoiceOf` (an agent's
503
+ function-calling mode as a `ToolChoice`, and `VALIDATED` as strict tools)
504
+ and `samplingOf` (the sampling fields the contract carries). These are
505
+ additions under the existing `exports` map. The native loop
506
+ (`lib/runtime/native/`: one model step, and the agent loop around it,
507
+ ADR 0071) is not in the `exports` map and runs no turn yet.
508
+ - **OpenAPI tools make their own calls (ADR 0067).** Each operation is
509
+ the engine's own Tool, and the ADK runtime runs it through
510
+ `toFunctionTool`; ADK's `RestApiTool` and `OpenAPIToolset` are no longer
511
+ used. An API receives the same request as before. What a consumer sees:
512
+ - `tools/openapiTools`: `buildOpenApiTools` returns `FunctionTool`s
513
+ (it returned `BaseTool`s), and gains `buildOpenApiOwnTools` (own Tools,
514
+ for either runtime) and `openApiOperationId`. `boundResult` is
515
+ deprecated in favour of `capResult` (`tools/tool`).
516
+ - The new module `tools/openapi/call` holds the caller: `buildRequest`,
517
+ `callOperation`, `hostProblem`, `OPENAPI_REDIRECTS`, `redactSecrets`
518
+ and `MAX_RESPONSE_BYTES`.
519
+ - `require_approval` on an OpenAPI operation uses the gate every
520
+ registry tool uses, so the approval hint and the pending and rejected
521
+ texts are ADK's FunctionTool texts. `requireApprovalOnBaseTool`
522
+ (`compile`) is deprecated and no longer used.
523
+ - A credential's value is replaced with `[redacted]` in every error an
524
+ OpenAPI tool returns; at most 8 MiB of a response is read; an operation
525
+ whose spec requires a credential is not called when the entry sets no
526
+ `auth`, and returns an error saying so.
527
+ - A spec that is not OpenAPI 3.x (Swagger 2.0, or no `openapi` version)
528
+ fails the compile with a readable error, and `~1` and `~0` in a
529
+ `$ref` are unescaped.
530
+ - **`GeminiAdapter` covers Gemini's own features (ADR 0065).** In
531
+ `melchizedek-agents/models/geminiAdapter` (which `resolveAdapter`
532
+ returns only with `GEMINI_ADAPTER=engine` until gate G3):
533
+ - Code execution (`executableCode`, `codeExecutionResult`) and
534
+ server-side `toolCall` / `toolResponse` parts ride whole on the next
535
+ output part as `providerState` of the new kind `CARRIED_PARTS_KIND`
536
+ (`carried_parts`, payload `CarriedParts`), and are replayed before it
537
+ within the current turn.
538
+ - `toolConfig.includeServerSideToolInvocations` is sent when native
539
+ tools sit beside function declarations, on the Gemini API only.
540
+ - Grounding citations carry the answer span each supports, and
541
+ urlContext's retrieved pages are cited.
542
+ - Call ids minted by the genai mapping (`genai-noid-`) stay off the wire,
543
+ as `adk-` ids do. `MINTED_CALL_ID_PREFIX` now lives in
544
+ `models/geminiState` and is still exported by `models/genaiMapping`.
545
+ - The adapter reads only `request.signal`; it no longer falls back to the
546
+ turn's signal (ADR 0053: the caller passes it).
547
+ - New option `placeholderSignatures` (default
548
+ `PLACEHOLDER_SIGNATURES_BY_DEFAULT`, false) sends Gemini's documented
549
+ placeholder `PLACEHOLDER_THOUGHT_SIGNATURE` on an unsigned current-turn
550
+ call.
551
+ - **Fix: Gemini on Vertex AI.** The compiler asks every agent's config for
552
+ `includeServerSideToolInvocations`, which `@google/genai` refuses on a
553
+ Vertex AI client before sending anything ("only supported in Gemini
554
+ Developer API mode"), so every Gemini call with `GEMINI_PLATFORM=vertex`
555
+ failed. `TracedGemini` now leaves the flag off on Vertex AI and keeps it
556
+ on the Gemini API.
557
+ - **Web sources for Claude, GPT and Grok.** When one of these models
558
+ searches the web, its events now carry `groundingMetadata`, so a turn's
559
+ grounding and the A2A server's web-sources lines list the pages it used,
560
+ as they already did for Gemini. Before, only Gemini's answers showed
561
+ their sources.
562
+ - **Server-side tools are markers, and MCP, remote-agent and examples tools
563
+ are the engine's own (ADR 0062).** All additions, under the existing
564
+ `exports` map:
565
+ - `melchizedek-agents/tools/tool` gains `NativeToolMarker`,
566
+ `nativeToolMarker`, `nativeToolMarkerOf`, `isNativeToolMarker` and the
567
+ `NATIVE_TOOL` symbol. The new module `tools/nativeTools` holds the
568
+ markers for `web_search`, `x_search`, `url_context`,
569
+ `collections_search` and `google_search`;
570
+ - `tools/adkTool` gains `toAdkNativeTool` and `toAdkTool`, and
571
+ `registerTool` takes a marker;
572
+ - `tools/mcpToolFactory` gains `loadMcpTools` (own Tools) and
573
+ `mcpToolParameters`;
574
+ - `a2a/remote` gains `remoteAgentOwnTool`;
575
+ - the new module `tools/examples` holds an agent's `examples:` as an
576
+ InstructionTool that writes ADK's ExampleTool block word for word.
577
+
578
+ `nativeToolOf`, `wantsWebSearch` and the other sentinel checks now read
579
+ the marker, not the class. A tool that only declares nothing under a
580
+ server-side name is no longer treated as that tool. An MCP tool's nested
581
+ schemas no longer carry `default`, `propertyNames`, `$schema` or a boolean
582
+ `additionalProperties`. `propertyNames` was refused by the Gemini API.
583
+ - **The engine parses OpenAPI specs itself (ADR 0063).** A new module,
584
+ `melchizedek-agents/tools/openapi/parse` (through the existing
585
+ `./tools/*` pattern), exports `parseOpenApiSpec` and
586
+ `parseOpenApiDocument`. They read an OpenAPI 3 spec into
587
+ `OpenApiOperation`s, each with its arguments and the `ToolDeclaration`
588
+ the model receives. `openapi:` tools keep their names and declarations:
589
+ the parser follows ADK's rules, and `buildOpenApiTools` builds the
590
+ same ADK tools from it. A spec is now bounded. A file over 4 MiB, more
591
+ than 100 YAML aliases, more than a million values once its `$ref`s are
592
+ resolved, or nesting deeper than 128 levels fails the compile with a
593
+ readable error, as does a spec that is not an object. `toSnake` and
594
+ `namesTool` are still exported from `tools/openapiTools`.
595
+ - **JSON mode without a schema is on the model contract (ADR 0061).**
596
+ `ModelRequest` (`melchizedek-agents/models/contract`) gains
597
+ `outputFormat?: 'json'`. An agent with
598
+ `generateContentConfig.responseMimeType: "application/json"` and no
599
+ schema sends its provider's JSON mode again on GPT and Grok
600
+ (`text.format: { type: 'json_object' }`, as before they moved onto the
601
+ contract), and keeps it on Kimi, Ollama, the gateway and Gemini, on the
602
+ ADK runtime and on the contract. Claude, whose Messages API has no JSON
603
+ mode, sends nothing for it, as before. `OlderSpelling.jsonMode`
604
+ (`models/chatCompletionsAdapter`, new in this release) is removed:
605
+ the chat-completions adapters read `outputFormat` instead.
606
+ - **The engine's own registry (ADR 0060).** `melchizedek-agents/models/registry`
607
+ adds `resolveAdapter(modelId, { apiKey, keyProvider, endpoint, gemini })`,
608
+ which returns any model id's `ModelAdapter` on the engine's contract from
609
+ the same prefix table, gateway fallback, BYOK scoping and endpoints as
610
+ `resolveModel`, with no ADK `LLMRegistry`; `resolveAdapterWithFallback`,
611
+ which wraps a model and its fallback in a `FallbackAdapter`;
612
+ `geminiAdapterChoice` and the types `ResolveAdapterOptions` and
613
+ `GeminiAdapterChoice`. A Gemini id gets `AdkGeminiAdapter` unless
614
+ `GEMINI_ADAPTER=engine` (or `gemini: 'engine'`) selects `GeminiAdapter`.
615
+ `TracedGemini` moves to the new module `melchizedek-agents/models/tracedGemini`;
616
+ `models/registry` still exports it. `registerAvailableProviders`,
617
+ `resolveModel`, `providerStatuses` and the doctor are unchanged.
618
+ - **Base URLs lose their trailing slashes in one pass.** The Kimi
619
+ adapter, the gateway, the endpoints module and the embeddings provider
620
+ trimmed a base URL with a regular expression that backtracked
621
+ quadratically on a long run of slashes (CodeQL js/polynomial-redos).
622
+ They now share `trimTrailingSlashes` (new module
623
+ `melchizedek-agents/models/urls`). Results are unchanged.
624
+ - **Fix: a message could stall the server in the memory search.**
625
+ `stripHarnessBlocks` (run on every memory query and extraction
626
+ transcript) matched an unclosed `[System Context:` marker with a pattern
627
+ that rescanned the rest of the text once per marker, so a message of
628
+ many such markers took seconds per search (16 s for 800,000 characters).
629
+ The pattern now stops at any bracket and scans the text once.
630
+ - **Memory and its tools are the engine's own (ADR 0059).** Additions
631
+ only; the `exports` map is unchanged.
632
+ - `load_memory` and `preload_memory` are the engine's own tools, in the
633
+ new module `melchizedek-agents/tools/memoryTools` (`loadMemoryTool`,
634
+ `preloadMemoryTool`). A model reads the same declaration, the same
635
+ memory note and the same recalled block as with ADK's tools. Two
636
+ differences: a call without a string `query` returns the readable
637
+ error instead of searching, and a failed call's error reads
638
+ `Error in tool 'load_memory': …`, as every own tool's does.
639
+ `require_approval` can now gate `load_memory`. Neither the preload
640
+ tool nor the memory service's search logs the user's query any more;
641
+ the search logs only its length.
642
+ - `melchizedek-agents/tools/tool`: `ToolContext` gains `userContent` and
643
+ `searchMemory(query)`, which searches the run's own silo only.
644
+ `createToolContext` takes `memory` and `userContent`. A `Tool` may have
645
+ `instruction(ctx)`, text for the system instruction of each request.
646
+ New: `InstructionTool` (a tool that only writes into the instruction),
647
+ `isInstructionTool` and `instructionToolOf`.
648
+ - `melchizedek-agents/tools/adkTool` gains `toAdkInstructionTool`, and
649
+ `registerTool` takes an `InstructionTool`.
650
+ - `SupabaseVectorMemoryService` implements the engine's `MemoryService`
651
+ (`ingest`, `search`) as well as ADK's `BaseMemoryService`, whose
652
+ methods behave as before. `namespacedMemoryService` takes either and
653
+ pins `search` and `ingest` too.
654
+ - **Claude runs on the engine's model contract (ADR 0055).** New module
655
+ `melchizedek-agents/models/claudeAdapter`: `ClaudeAdapter`, a
656
+ `ModelAdapter` that reads a `ModelRequest` and yields `ModelResponse`s on
657
+ the Messages API (`anthropicTools`, `ClaudeModelRequest`,
658
+ `THINKING_STATE_KIND`, `STRUCTURED_OUTPUT_TOOL`, `ANTHROPIC_PROVIDER`).
659
+ `ClaudeLlm` keeps its name, options, `supportedModels`,
660
+ `registerClaudeLlm()`, `buildAnthropicTools()` and `THINKING_STATE_KIND`,
661
+ and is now that adapter behind the ADK shim, a subclass of `AdkShim`.
662
+ Request bodies are unchanged. What does change on a Claude call:
663
+ - its events carry `finishReason`, and `groundingMetadata` when Claude
664
+ searched the web (see the web-sources entry above);
665
+ - a failed tool's `tool_result` carries `is_error: true`;
666
+ - a setup error (`MISSING_API_KEY`, `ENDPOINT_MISCONFIGURED`,
667
+ `SDK_NOT_INSTALLED`) carries `customMetadata['error.retryable']: false`;
668
+ - tool schemas come from `contractToolDeclaration`: `nullable` becomes a
669
+ type that admits null, string integer bounds become integers, and
670
+ `$schema` is left out.
671
+ `AdkShim` gains a protected `toModelRequest(llmRequest, options)` hook.
672
+ `melchizedek-agents/models/claudeModels` adds `ClaudeReasoning`,
673
+ `claudeReasoningOf`, `claudeReasoningFromConfig` and
674
+ `adaptiveThinkingFor`. The `exports` map is unchanged.
675
+ - **The session services serve both runtimes from the same rows, and
676
+ change behaviour in five places (ADR 0058).** `SupabaseSessionService`,
677
+ `PostgresSessionService` and `ProjectedSessionService` also implement
678
+ the engine's own `SessionService` (`create`, `get`, `list`, `delete`,
679
+ `append`) beside ADK's `BaseSessionService`, and
680
+ `ProjectedSessionService` accepts a store with either interface. The
681
+ import paths are unchanged. Through ADK's methods, to match that
682
+ interface:
683
+ - `listSessions` without a `userId` lists every user's sessions of the
684
+ app on the Supabase service too, as it already did on Postgres and as
685
+ ADK's contract says. Before, it filtered on a user named `undefined`.
686
+ Nothing in the engine calls it; check your own callers.
687
+ - `createSession` for an id that exists returns the conversation on the
688
+ Supabase service, as on Postgres, instead of resetting it to no events.
689
+ A create drops `temp:` keys from the initial state.
690
+ - `lastUpdateTime` and `last_update_time` are the appended event's
691
+ timestamp, as in ADK's own store, instead of the clock at append.
692
+ - On Postgres, appending an event whose id the session already holds
693
+ replaces that event's row instead of adding a second one.
694
+ - A listing with no `order` comes back in creation order, and one with
695
+ an `order` breaks ties by id, on both services. A `numRecentEvents`
696
+ below one is ignored.
697
+
698
+ No schema change. The bridge between the two interfaces
699
+ (`lib/runtime/adkSessionBridge.ts`) is internal and not in the exports
700
+ map.
701
+ - **GPT and Grok run on the engine's model contract (ADR 0048, ADR 0056).**
702
+ New modules `melchizedek-agents/models/gptAdapter` (`GptAdapter`, the
703
+ Responses API as a `ModelAdapter`, with `responsesInput`,
704
+ `responsesFunctionTools`, `responsesUsage`, `responsesServerTools`,
705
+ `streamErrorDecision` and `isOpenAiReasoningModel`) and
706
+ `melchizedek-agents/models/grokAdapter` (`GrokAdapter`,
707
+ `GROK_REASONING_IDS`, `XAI_BASE_URL`). `GptLlm` and `GrokLlm` keep their
708
+ names, constructors, `supportedModels` and exports, and are now the ADK
709
+ shim around these adapters. The ledger, the turn's token charge and
710
+ `adk_turns.tool_calls` count GPT and Grok calls as before: output tokens
711
+ include reasoning, and server-side searches stay on the event's
712
+ `customMetadata`. `AdkShim` gains a protected `toLlmResponse(response)`
713
+ hook for that. What changes on the wire and in the events:
714
+ - `grok-4.6` takes `reasoning.effort` and replays its encrypted reasoning,
715
+ as `grok-4.5` and `grok-4.7` do.
716
+ - A failure a stream reports (`response.failed`, an `error` event, or an
717
+ SSE frame named `error`) carries a retry verdict when it names a
718
+ retryable status or the code `server_error`, `rate_limit_exceeded` or
719
+ `vector_store_timeout`, so the fallback model answers it.
720
+ - An aborted stream ends in an error final instead of the text so far.
721
+ - A user-turn image given by an https URL reaches GPT and Grok, and a PDF
722
+ goes as `input_file`; `top_p` is sent beside `temperature`; a call
723
+ without an id gets one minted from its position, shared with its result.
724
+ - JSON mode without a schema (`responseMimeType: 'application/json'`
725
+ alone) and the older spelling's `xhigh` and `max` effort words have no
726
+ contract field and are no longer sent to GPT or Grok.
727
+ - Final events carry `finishReason`, as every shimmed adapter's do.
728
+ - **The engine's own event, session and memory interfaces (ADR 0052).**
729
+ Internal modules for the native runtime, not in the exports map, so
730
+ nothing a consumer imports changes: `lib/runtime/events.ts` (`TurnEvent`,
731
+ the stored ADK Event JSON typed, with a parse that keeps every field and
732
+ ADK's `isFinal`), `lib/runtime/sessions.ts` (`SessionService` and an
733
+ in-process store) and `lib/runtime/memoryService.ts` (`MemoryService`).
734
+ Stored sessions and the session services are unchanged.
735
+ - **The skills say what `reasoning:` does on each Claude generation (ADR 0049).**
736
+ `melchizedek-models`, `melchizedek-author`, their briefs, `DOCUMENTATION.md`
737
+ and `syndicateSchema.yaml` say that later Claude models take `reasoning:` as
738
+ adaptive thinking at an effort, with `none` as the model's off switch, or
739
+ `low` effort on Opus 5 and 5.5, Fable and Mythos. The 1,024 floor holds on
740
+ Claude 4.6 and earlier only, and the non-streaming limit on a
741
+ `budget_tokens` above about 19,000 holds on every Claude model.
742
+ - **Tools are the engine's own (ADR 0051).** New module
743
+ `melchizedek-agents/tools/tool`:
744
+ - `Tool`: `name`, `declaration()` (the model contract's
745
+ `ToolDeclaration`) and `execute(args, ctx)`.
746
+ - `ToolContext`: ids, a `state` view whose writes land in
747
+ `stateDelta`, `actions.skipSummarization`, `requestConfirmation` and
748
+ `confirmation`, and the abort `signal`. `createToolContext()` and
749
+ `toToolContext()` build one.
750
+ - `requireApproval(tool)`, the `longRunning` marker with
751
+ `LONG_RUNNING_NOTE` and `isLongRunning`, `capResult` and
752
+ `MAX_RESULT_CHARS` (20,000, the limit OpenAPI and MCP results already
753
+ use), and `toolOf(value)`, which finds the Tool behind a registry entry.
754
+
755
+ `defineTool` returns a Tool that is still a `ToolContract`. Its
756
+ `execute` validates the arguments before the handler runs, and the
757
+ handler gets a complete `ToolContext`; `executeContract` validates such
758
+ a Tool once. `defineTool` takes `longRunning` and `maxResultChars`.
759
+ `toolContract` also exports `asTool`, `DefinedTool` and `ToolSpec`.
760
+ `toFunctionTool` takes a Tool or a contract, and `registerTool` takes a
761
+ contract, any Tool or an ADK tool.
762
+ - **Every registry tool that declares a function is a Tool**, wrapped for
763
+ the ADK runtime by `toFunctionTool`, except ADK's `load_memory`. The ADK
764
+ runtime runs the same `FunctionTool`s, with the same approval
765
+ interrupts and texts. `generate_image`, `inspect_image` and `ask_user`
766
+ become contracts (`generateImageContract`, `inspectImageContract`):
767
+ - `generate_image` and `inspect_image` now return the readable error for
768
+ arguments their schema refuses, instead of calling Gemini;
769
+ - an `ask_user` call with invalid arguments returns the error to the
770
+ model instead of pausing the turn on it.
771
+ - **Tool schemas: defaults are optional, and records keep their values.**
772
+ On every surface (the declaration, the ADK `FunctionTool` and the MCP
773
+ `tools/list` entry), a zod schema is exported for its input side
774
+ (`io: 'input'`), so a field with a default is no longer listed as
775
+ required. A record's value schema (`additionalProperties`) is kept on
776
+ both paths, and its `propertyNames: { type: 'string' }`, which says
777
+ nothing in JSON, is left out: a live Gemini call refuses that keyword
778
+ with a 400 and accepts the value schema. `toGeminiSchema` walks by schema keyword, so a property named
779
+ `additionalProperties` or `default` keeps its schema. `models/schemaNormalize`
780
+ exports `zodInputJsonSchema`, `zodToolParameters` and `mapSchemaNodes`,
781
+ and `contractToolDeclaration` reads an own Tool's `declaration()`.
782
+ - **Claude requests follow the model generation (ADR 0049).** `ClaudeLlm`
783
+ reads a per-generation table from the model id. Before, every `claude-*`
784
+ id got a thinking budget and a forced tool, which the current models refuse
785
+ with a 400. Now:
786
+ - Claude 4.6 and earlier keep the thinking budget.
787
+ - Later models get adaptive thinking with `output_config.effort` from
788
+ `reasoning:` (or `reasoningEffort`), and a summarized thinking display.
789
+ `none` becomes each model's own off switch at `low` effort, or `low`
790
+ effort where the model has none.
791
+ - Structured output is `output_config.format` from Opus 4.8, Sonnet 5 and
792
+ Haiku 5.5 on. Forced tool use is a 400 on Fable 5.1, Opus 5.5 and
793
+ Sonnet 5.5.
794
+ - Fable 5.1, Opus 5.5, Sonnet 5.5 and Haiku 5.5 bind thinking to the
795
+ conversation. Their requests set `drop_block` under the
796
+ `thinking-binding-controls-2026-08-01` beta, so a turn resumed from
797
+ storage no longer fails on a history that changed in storage.
798
+ - An image URL that names no type is typed by its extension. Claude on
799
+ Bedrock and Vertex AI drops URL images, since those platforms take base64
800
+ only, and the capability matrix says so.
801
+ - `melchizedek-agents/models/claudeModels` exports `claudeGeneration`,
802
+ `adaptiveThinking`, `requestedEffort`, `claudeUrlImagesOn` and
803
+ `THINKING_BINDING_BETA`.
804
+ - **`reasoning:` sets how hard an agent reasons, on any provider (ADR 0047).**
805
+ Write `none`, `low`, `medium` or `high`, or `{ budget_tokens: <int> }`, on
806
+ the orchestrator or a subagent. The compiler sends each provider the field
807
+ it reads:
808
+ - Gemini 3: a thinking level.
809
+ - Claude and Gemini 2.x: a thinking budget of 0, 2,048, 8,192 or 16,384
810
+ tokens.
811
+ - GPT, Grok, Kimi, Ollama and the gateway: an effort word.
812
+ `generateContentConfig.thinkingConfig` and `reasoningEffort` remain
813
+ valid as the older spelling. Setting either beside `reasoning` on the same
814
+ agent is a load error. Agents that set neither are unchanged.
815
+ - **GPT and Grok honour an effort.** `GptLlm` sends `reasoning.effort` when
816
+ the agent sets one (`reasoning:`, or `generateContentConfig.reasoningEffort`),
817
+ and `GrokLlm` sends it in place of its pinned `medium`. Before, both ignored
818
+ it. `reasoningParam` takes the request as an optional argument.
819
+ - **The model zoo and every template use `reasoning:`.** What each agent
820
+ asks of its provider is unchanged: the templates' `includeThoughts: false`
821
+ was already the default, and the zoo's Claude agent keeps its 2,048-token
822
+ budget as `low`.
823
+ - **The shipped skills teach `reasoning:`.** `melchizedek-author` and
824
+ `melchizedek-models` (and their briefs) set reasoning with `reasoning:`, show
825
+ what each level becomes per provider and per Claude model generation, and
826
+ describe `generateContentConfig.thinkingConfig` and `reasoningEffort` as the
827
+ older spelling that still loads. The author skill's `assets/minimal.yaml` sets it.
828
+ - `lib/compile.ts` exports `reasoningConfig`, `withReasoning` and
829
+ `REASONING_BUDGETS`. The `AgentYamlConfig` type gains `reasoning`, and
830
+ `GenerateContentConfig` gains `reasoningEffort`.
831
+ - **Thinking with tool use works on Claude (ADR 0046).** The adapter writes
832
+ the signed `thinking` / `redacted_thinking` blocks into a `providerState`
833
+ field on the part they preceded and replays them verbatim within the
834
+ turn's tool loop, so a thinking Claude agent can use tools and delegate.
835
+ A step continuing another provider's or Claude model's tool call runs
836
+ without thinking.
837
+ New module `melchizedek-agents/models/providerState` (`ProviderState`,
838
+ `providerStateOf`, `withProviderState`): the convention every adapter
839
+ uses for provider-opaque reasoning state. The final event no longer
840
+ carries `customMetadata['anthropic.thinking']`; the same blocks are on
841
+ the part.
842
+ - **Claude agents see images.** `ClaudeLlm` sends a user-turn `inlineData`
843
+ part as a base64 image block (`image/png` when it names no type) and an
844
+ `https` `fileData` part as a URL image block, in the parts' order. Before,
845
+ it dropped both. JPEG, PNG, GIF and WebP are sent; any other type, or a
846
+ non-https URL, is dropped with `llm.image.dropped` on the span and a
847
+ one-time warning naming the type. Images inside tool results are not sent,
848
+ as on GPT. The capability matrix marks Anthropic image input supported.
849
+ - **The engine's own model contract (ADR 0048).** New module
850
+ `melchizedek-agents/models/contract`, types only: `Message`, `Part`,
851
+ `ToolDeclaration`, `NativeTool`, `ModelRequest`, `ModelResponse`,
852
+ `ModelAdapter`, `ProviderCapabilities` and their parts. The native
853
+ runtime and every model adapter will speak it, and no adapter uses it
854
+ yet. `ReasoningLevel` and `ReasoningSetting` are defined there now.
855
+ `melchizedek-agents/loadSyndicate` re-exports them unchanged.
856
+ - **Tool declarations in the contract's shape.** `models/schemaNormalize`
857
+ exports `contractToolDeclaration(tool, { strict? })`, which builds a
858
+ contract `ToolDeclaration` from an ADK tool or straight from a
859
+ `defineTool` contract's zod schema; `nativeToolOf(tool)`, which names the
860
+ `NativeTool` a server-side tool or Gemini's code executor stands for; and
861
+ `toContractJsonSchema(schema, { strict? })`. Gemini's dialect (uppercase
862
+ types, int64 bounds as strings, `nullable`) is converted once, at any
863
+ depth, and the strict form reaches every nested object. Nothing calls
864
+ them yet; `toolDeclarationFor`, `toLowercaseJsonSchema` and
865
+ `toStrictJsonSchema` are unchanged.
866
+ - **genai `Content` maps to and from the model contract (ADR 0048).** New
867
+ module `melchizedek-agents/models/genaiMapping`: `contentsToMessages` and
868
+ `messagesToContents`, `contentToMessage` and `messageToContent`,
869
+ `partToGenai`, `llmRequestToModelRequest`, `modelResponseToLlmResponse`,
870
+ `reasoningOf`, `systemText`, `usageToMetadata`, `usageFromMetadata` and
871
+ `isMintedCallId`, the constants `GEMINI_PROVIDER`,
872
+ `THOUGHT_SIGNATURE_KIND`, `GENAI_PART_KIND` and `MINTED_CALL_ID_PREFIX`,
873
+ and the types `ContractHistory`, `GenaiHistory` and
874
+ `ModelRequestOptions`. A stored event's
875
+ content round-trips to the same JSON: a Gemini `thoughtSignature` becomes
876
+ `providerState` of kind `thought_signature`, a call without an id gets a
877
+ `genai-noid-` id that is left off again on the way back, and a part the
878
+ contract cannot hold (Gemini code execution, ADK's confirmation request)
879
+ rides whole as `providerState` of kind `genai_part`. A failed final keeps
880
+ its retry verdict as `customMetadata['error.retryable']` and
881
+ `['error.status']`, which is what `FallbackLlm` reads. Nothing calls it yet;
882
+ no adapter or stored shape changes.
883
+ - **Thinking with tool use works on GPT and Grok (ADR 0050).** On
884
+ reasoning ids (o-series, `gpt-5*`, `grok-4.5`, `grok-4.7`), the Responses
885
+ adapters write each run of encrypted reasoning items on the part after it
886
+ and replay them before that part within the turn's tool loop, for the same
887
+ provider and model only. These requests now send `store: false` and
888
+ `include: ['reasoning.encrypted_content']`, so OpenAI and xAI no longer
889
+ keep the response server-side, as they did by default. The guarded 400
890
+ retry also drops the `include` and the replayed items.
891
+ `buildResponsesInput` takes an optional `replay` argument;
892
+ `models/gptLlm` exports `REASONING_STATE_KIND`, and `models/providerState`
893
+ exports `currentTurnStart`.
894
+ - **Kimi keeps its reasoning across tool steps (ADR 0046).** On `kimi-k3`,
895
+ `kimi-k2.6` and `kimi-k2.7-code`, the adapter stores each response's
896
+ `reasoning_content` on the part that follows it and sends it back on that
897
+ assistant message within the turn's tool loop, for the same model only,
898
+ as Moonshot asks. A tool loop's later steps bill the replayed reasoning
899
+ as input. `OpenAiCompatibleLlm` gains the opt-in hook
900
+ `replaysReasoningContent()` (off by default; Ollama and the gateway keep
901
+ it off) and exports `REASONING_CONTENT_KIND`; `models/kimiLlm` exports
902
+ `wantsReasoningReplay`. `currentTurnStart` returns -1 when no user
903
+ content opens the turn, so every content is then the current turn's.
904
+ - **The fallback model on the engine's own contract (ADR 0044, ADR 0048).**
905
+ New module `melchizedek-agents/models/fallbackAdapter`: `FallbackAdapter`,
906
+ a `ModelAdapter` around a primary and a fallback adapter, with
907
+ `FallbackAdapterOptions` and `isProviderError`. It applies ADR 0044's
908
+ rules to a failed final's `error.retryable` and `status`, and hands the
909
+ fallback the request with its own model id and the caller's `reasoning`
910
+ unchanged. Nothing uses it yet. The breaker's state moves to the new
911
+ module `melchizedek-agents/models/circuitBreaker` (`circuitOpen`,
912
+ `recordFailure`, `recordSuccess`, `resetCircuits`, `breakerSettings`, and
913
+ `setBreakerClock` for tests), shared by both wrappers, so a provider
914
+ tripped on one path is skipped on the other. `models/fallback` still
915
+ exports `circuitOpen` and `resetCircuits`, and `FallbackLlm` behaves as
916
+ before.
917
+ - **Any adapter on the model contract runs under ADK (ADR 0053).** New module
918
+ `melchizedek-agents/models/adkShim`: `AdkShim`, an ADK `BaseLlm` that
919
+ wraps one `ModelAdapter` and maps ADK's request and responses through
920
+ `models/genaiMapping`; `adkShim(adapter, model?)`; `adkShimClass(supportedModels,
921
+ createAdapter)`, a class ADK's `LLMRegistry` can register; and the types
922
+ `AdkShimOptions` and `ModelAdapterFactory`. The shim charges each call
923
+ against the turn's `max_steps`, refuses a call on a spent or stopped turn
924
+ with the same response the ADK-path adapters give, hands the adapter the
925
+ turn's abort signal, and opens the `llm.request` span, so an adapter on
926
+ the contract does none of these itself. `connect()` is refused. Nothing
927
+ registers it yet; no adapter or stored shape changes.
928
+ - **An elided tool result's size is stored the same on every server.**
929
+ `trimEventForStorage` writes it with en-US digit grouping (`2,563 chars
930
+ dropped before storage — …`), where it followed the server's locale
931
+ (`2.563` in German). An en-US server stores the same bytes as before, and
932
+ rows already stored are untouched.
933
+ - The capability matrix's Ollama and gateway `thinking_with_tools` note names
934
+ `reasoning:` as the lever (ADR 0047), compiled to `reasoningEffort`.
935
+ - **The shipped skills cover Kimi.** `melchizedek-models` adds `kimi-*` to
936
+ Moonshot AI in its routing table, `MOONSHOT_API_KEY` to its key list and
937
+ `kimi-k3` to its verified ids; `melchizedek` adds the key and `kimi-*` to
938
+ its `Model not found` line. Their briefs match.
939
+ - **`wiki_relate` appends.** A new assertion goes at the end of
940
+ `.graph/relations.json` and every stored record keeps its place and bytes,
941
+ where each write used to re-sort the whole file. A store that does not
942
+ parse is refused rather than overwritten. `melchizedek-agents/wiki/entities`
943
+ exports `appendRelation(wikiRoot, record)`, which returns `false` for a
944
+ duplicate, and `saveRelations` writes records in the order given instead of
945
+ sorting them.
946
+ - **Fix: `fallback_model:` answers for Claude, GPT, Grok, Kimi, Ollama and
947
+ gateway primaries (ADR 0044).** In 0.18.0 `FallbackLlm` saw a failure only when
948
+ the primary threw, which only Gemini does. The other adapters yield an
949
+ error response, so their fallback never answered, and the failed call was
950
+ recorded as a success, which reset the provider's circuit breaker. Their
951
+ error responses now carry `customMetadata['error.retryable']` (and
952
+ `'error.status'` when the failure had an HTTP status), set from
953
+ `lib/models/retry.ts`'s classification, and `FallbackLlm` reads them: a
954
+ retryable error before any output is counted on the breaker and answered
955
+ by the fallback, a non-retryable one is passed on, and only a call that
956
+ produced content counts as a success. Error codes and messages are
957
+ unchanged, except that key-shaped text is now removed from the message.
958
+ A failure GPT or Grok report inside an open stream carries a verdict too,
959
+ from the event (see GPT and Grok on the model contract). The retry policy now counts
960
+ HTTP 529, Anthropic's "overloaded", as retryable, so an overloaded Claude
961
+ primary is answered by its fallback. New
962
+ module `melchizedek-agents/models/errorResponse`: `providerErrorResponse`,
963
+ `withRetryVerdict`, `isRetryableErrorResponse`, `errorDecision`,
964
+ `statusDecision`, `errorText`, `ERROR_RETRYABLE_KEY`, `ERROR_STATUS_KEY`.
965
+ - **A Gemini adapter on the model contract, not yet wired.** New module
966
+ `melchizedek-agents/models/geminiAdapter`: `GeminiAdapter` implements
967
+ `ModelAdapter` (ADR 0048) on `@google/genai` directly, with no ADK, on the
968
+ Gemini API or Vertex AI (`lib/models/endpoints.ts`). Schemas go as
969
+ lowercase JSON Schema (`parametersJsonSchema`, `responseJsonSchema`).
970
+ `reasoning:` maps through `reasoningConfig`. Thought signatures ride on
971
+ the part as `providerState` and are replayed within the turn. Every
972
+ failure is a final response. A `clientFactory` option takes an injected
973
+ client. Nothing registers the adapter yet: Gemini ids are still served by
974
+ `TracedGemini`, unchanged. `REASONING_BUDGETS` and `reasoningConfig` move
975
+ to the new module `melchizedek-agents/models/reasoning`, so the adapter
976
+ maps `reasoning:` without importing the compiler or ADK;
977
+ `melchizedek-agents/compile` still exports both.
978
+ - **A temporary Gemini adapter on the contract, over ADK's Gemini.** New
979
+ module `melchizedek-agents/models/adkGeminiAdapter`: `AdkGeminiAdapter`
980
+ (and `AdkGeminiAdapterOptions`) implements `ModelAdapter` by mapping the
981
+ request to an `LlmRequest` and running it through `TracedGemini` with its
982
+ retries. Every failure is a final response: a failed call is
983
+ `GEMINI_ERROR` with its status and retry verdict. Like every contract
984
+ adapter (ADR 0053) it opens no `llm.request` span and charges nothing;
985
+ behind `AdkShim` the span has `TracedGemini`'s attributes, with the
986
+ failed call's code as `GEMINI_ERROR` where `TracedGemini` records the
987
+ HTTP status. It serves Gemini on the native runtime until `GeminiAdapter`
988
+ passes its live parity run, and is removed after that. Nothing registers
989
+ it yet.
990
+ - `models/genaiMapping` adds the reverse directions:
991
+ `modelRequestToLlmRequest`, `llmResponseToModelResponse` (with the type
992
+ `ModelResponseOptions`) and `nativeToolsWithoutGeminiTool`.
993
+ - `TracedGemini` gains `generateWithRetries(llmRequest, stream?,
994
+ abortSignal?)`, the call that `generateContentAsync` wraps in its span.
995
+ Its spans are unchanged.
996
+ - `traceLlmGeneration`'s `LlmCallMeta` gains `request`: a `ModelRequest`,
997
+ or a function that returns one. `llmRequest` is deprecated and still
998
+ recorded when `request` is absent. Every adapter in the package and
999
+ `AdkShim` now pass `request`, so a failed call's `llm.payload.request`, and the
1000
+ `adk_payloads.request` row made from it, hold the request in the model
1001
+ contract's shape (`model`, `system`, `messages`, `tools`, …) instead of
1002
+ ADK's (`contents`, `config`, `toolsDict`). The span's other attributes
1003
+ are unchanged.
1004
+ - `GEMINI_PROVIDER` and `THOUGHT_SIGNATURE_KIND` are defined once, in the
1005
+ new module `melchizedek-agents/models/geminiState`. `models/genaiMapping`
1006
+ and `models/geminiAdapter` still export both, with the same values.
1007
+
7
1008
  ## 0.18.0 — 2026-10-06
8
1009
 
9
1010
  ### Breaking — read before upgrading