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