melchizedek-agents 0.19.0 → 1.0.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 (242) hide show
  1. package/.env.example +4 -5
  2. package/AGENT_SETUP.md +3 -3
  3. package/CHANGELOG.md +492 -76
  4. package/DOCUMENTATION.md +153 -132
  5. package/QUICKSTART.md +14 -10
  6. package/README.md +12 -15
  7. package/config/agents/examples/image_production.yaml +2 -2
  8. package/config/agents/syndicateSchema.yaml +55 -26
  9. package/dist/lib/a2a/app.d.ts +17 -12
  10. package/dist/lib/a2a/app.js +16 -6
  11. package/dist/lib/a2a/executor.d.ts +10 -14
  12. package/dist/lib/a2a/executor.js +10 -18
  13. package/dist/lib/a2a/remoteAgent.d.ts +5 -12
  14. package/dist/lib/a2a/remoteAgent.js +5 -12
  15. package/dist/lib/adkPeer.d.ts +63 -0
  16. package/dist/lib/adkPeer.js +240 -0
  17. package/dist/lib/compile.d.ts +109 -81
  18. package/dist/lib/compile.js +163 -111
  19. package/dist/lib/compileAdk.d.ts +7 -4
  20. package/dist/lib/compileAdk.js +22 -12
  21. package/dist/lib/compileNative.d.ts +63 -49
  22. package/dist/lib/compileNative.js +136 -78
  23. package/dist/lib/config.d.ts +6 -6
  24. package/dist/lib/config.js +6 -6
  25. package/dist/lib/doctor.d.ts +22 -1
  26. package/dist/lib/doctor.js +27 -2
  27. package/dist/lib/index.d.ts +14 -7
  28. package/dist/lib/index.js +11 -7
  29. package/dist/lib/loadSyndicate.d.ts +3 -3
  30. package/dist/lib/loadSyndicate.js +2 -2
  31. package/dist/lib/memory/erase.d.ts +1 -1
  32. package/dist/lib/memory/erase.js +1 -1
  33. package/dist/lib/memory/namespace.d.ts +12 -14
  34. package/dist/lib/memory/namespace.js +13 -14
  35. package/dist/lib/memory/providers.d.ts +4 -5
  36. package/dist/lib/memory/providers.js +12 -6
  37. package/dist/lib/memory/supabaseMemoryService.d.ts +9 -30
  38. package/dist/lib/memory/supabaseMemoryService.js +8 -30
  39. package/dist/lib/model.d.ts +6 -12
  40. package/dist/lib/model.js +6 -12
  41. package/dist/lib/models/adapterResolver.d.ts +21 -38
  42. package/dist/lib/models/adapterResolver.js +33 -40
  43. package/dist/lib/models/adkGeminiAdapter.js +2 -0
  44. package/dist/lib/models/adkShim.d.ts +1 -1
  45. package/dist/lib/models/adkShim.js +1 -1
  46. package/dist/lib/models/capabilities.js +13 -10
  47. package/dist/lib/models/chatCompletionsAdapter.d.ts +12 -33
  48. package/dist/lib/models/chatCompletionsAdapter.js +13 -18
  49. package/dist/lib/models/circuitBreaker.d.ts +5 -5
  50. package/dist/lib/models/circuitBreaker.js +5 -5
  51. package/dist/lib/models/claudeAdapter.d.ts +9 -26
  52. package/dist/lib/models/claudeAdapter.js +11 -15
  53. package/dist/lib/models/claudeLlm.js +2 -2
  54. package/dist/lib/models/claudeModels.d.ts +4 -4
  55. package/dist/lib/models/claudeModels.js +4 -4
  56. package/dist/lib/models/contract.d.ts +11 -11
  57. package/dist/lib/models/contract.js +6 -6
  58. package/dist/lib/models/errorResponse.d.ts +13 -20
  59. package/dist/lib/models/errorResponse.js +0 -12
  60. package/dist/lib/models/fallback.d.ts +1 -1
  61. package/dist/lib/models/fallback.js +1 -1
  62. package/dist/lib/models/fallbackAdapter.d.ts +7 -8
  63. package/dist/lib/models/gatewayAdapter.d.ts +1 -1
  64. package/dist/lib/models/gatewayAdapter.js +1 -1
  65. package/dist/lib/models/gatewayLlm.js +2 -2
  66. package/dist/lib/models/geminiAdapter.d.ts +11 -10
  67. package/dist/lib/models/geminiAdapter.js +37 -15
  68. package/dist/lib/models/geminiState.d.ts +29 -8
  69. package/dist/lib/models/geminiState.js +34 -8
  70. package/dist/lib/models/genaiMapping.d.ts +104 -38
  71. package/dist/lib/models/genaiMapping.js +146 -43
  72. package/dist/lib/models/gptAdapter.d.ts +11 -11
  73. package/dist/lib/models/gptAdapter.js +13 -13
  74. package/dist/lib/models/gptLlm.js +2 -2
  75. package/dist/lib/models/grokLlm.js +2 -2
  76. package/dist/lib/models/kimiAdapter.d.ts +6 -7
  77. package/dist/lib/models/kimiAdapter.js +6 -9
  78. package/dist/lib/models/kimiLlm.js +2 -2
  79. package/dist/lib/models/ollamaAdapter.d.ts +3 -3
  80. package/dist/lib/models/ollamaAdapter.js +3 -3
  81. package/dist/lib/models/ollamaLlm.js +2 -2
  82. package/dist/lib/models/providerMap.d.ts +6 -5
  83. package/dist/lib/models/providerMap.js +6 -5
  84. package/dist/lib/models/providerState.d.ts +3 -2
  85. package/dist/lib/models/providerState.js +3 -2
  86. package/dist/lib/models/reasoning.d.ts +1 -1
  87. package/dist/lib/models/registry.d.ts +26 -69
  88. package/dist/lib/models/registry.js +32 -140
  89. package/dist/lib/models/retry.d.ts +2 -2
  90. package/dist/lib/models/retry.js +2 -2
  91. package/dist/lib/models/schemaNormalize.d.ts +25 -55
  92. package/dist/lib/models/schemaNormalize.js +30 -100
  93. package/dist/lib/models/tracedGemini.d.ts +1 -1
  94. package/dist/lib/models/tracedGemini.js +1 -1
  95. package/dist/lib/observability/lineage.d.ts +3 -3
  96. package/dist/lib/observability/lineage.js +10 -10
  97. package/dist/lib/observability/supabaseSpanExporter.js +1 -1
  98. package/dist/lib/observability/tracer.d.ts +25 -23
  99. package/dist/lib/observability/tracer.js +26 -63
  100. package/dist/lib/persistence/supabaseProvider.d.ts +4 -3
  101. package/dist/lib/runtime/adkSessionBridge.d.ts +1 -1
  102. package/dist/lib/runtime/adkSessionBridge.js +1 -1
  103. package/dist/lib/runtime/approvals.d.ts +6 -1
  104. package/dist/lib/runtime/approvals.js +39 -8
  105. package/dist/lib/runtime/credentials.d.ts +4 -2
  106. package/dist/lib/runtime/credentials.js +6 -1
  107. package/dist/lib/runtime/events.d.ts +3 -4
  108. package/dist/lib/runtime/events.js +3 -4
  109. package/dist/lib/runtime/logging.d.ts +3 -8
  110. package/dist/lib/runtime/logging.js +3 -8
  111. package/dist/lib/runtime/memoryService.d.ts +4 -6
  112. package/dist/lib/runtime/memoryService.js +3 -5
  113. package/dist/lib/runtime/native/agentLoop.d.ts +24 -16
  114. package/dist/lib/runtime/native/agentLoop.js +67 -37
  115. package/dist/lib/runtime/native/compaction.d.ts +10 -11
  116. package/dist/lib/runtime/native/compaction.js +10 -11
  117. package/dist/lib/runtime/native/delegate.d.ts +64 -12
  118. package/dist/lib/runtime/native/delegate.js +101 -25
  119. package/dist/lib/runtime/native/history.d.ts +5 -6
  120. package/dist/lib/runtime/native/history.js +5 -6
  121. package/dist/lib/runtime/native/interrupts.d.ts +12 -9
  122. package/dist/lib/runtime/native/interrupts.js +29 -10
  123. package/dist/lib/runtime/native/request.d.ts +25 -25
  124. package/dist/lib/runtime/native/request.js +36 -25
  125. package/dist/lib/runtime/native/selfCorrection.d.ts +75 -17
  126. package/dist/lib/runtime/native/selfCorrection.js +93 -19
  127. package/dist/lib/runtime/native/step.d.ts +34 -26
  128. package/dist/lib/runtime/native/step.js +78 -32
  129. package/dist/lib/runtime/native/taskMode.d.ts +8 -8
  130. package/dist/lib/runtime/native/taskMode.js +8 -8
  131. package/dist/lib/runtime/native/telemetry.d.ts +11 -11
  132. package/dist/lib/runtime/native/telemetry.js +11 -11
  133. package/dist/lib/runtime/native/tempState.d.ts +4 -4
  134. package/dist/lib/runtime/native/tempState.js +4 -4
  135. package/dist/lib/runtime/nativeTurn.d.ts +29 -32
  136. package/dist/lib/runtime/nativeTurn.js +30 -41
  137. package/dist/lib/runtime/questions.d.ts +8 -9
  138. package/dist/lib/runtime/questions.js +1 -2
  139. package/dist/lib/runtime/runtimeFlag.d.ts +35 -13
  140. package/dist/lib/runtime/runtimeFlag.js +46 -16
  141. package/dist/lib/runtime/sessions.d.ts +10 -12
  142. package/dist/lib/runtime/sessions.js +10 -12
  143. package/dist/lib/runtime/syndicateTurn.d.ts +46 -42
  144. package/dist/lib/runtime/syndicateTurn.js +182 -150
  145. package/dist/lib/runtime/turnControl.d.ts +8 -8
  146. package/dist/lib/runtime/turnControl.js +8 -8
  147. package/dist/lib/runtime/valueDepth.d.ts +23 -0
  148. package/dist/lib/runtime/valueDepth.js +41 -0
  149. package/dist/lib/session/supabaseSessionService.d.ts +7 -21
  150. package/dist/lib/session/supabaseSessionService.js +7 -43
  151. package/dist/lib/session/transcript.d.ts +16 -26
  152. package/dist/lib/session/transcript.js +17 -55
  153. package/dist/lib/storage/postgres/sessionService.d.ts +6 -20
  154. package/dist/lib/storage/postgres/sessionService.js +6 -39
  155. package/dist/lib/syndicateSchema.d.ts +2 -0
  156. package/dist/lib/syndicateSchema.js +32 -10
  157. package/dist/lib/toolRegistry.d.ts +20 -14
  158. package/dist/lib/toolRegistry.js +76 -33
  159. package/dist/lib/tools/adkTool.d.ts +1 -1
  160. package/dist/lib/tools/adkTool.js +1 -1
  161. package/dist/lib/tools/auth.d.ts +1 -1
  162. package/dist/lib/tools/auth.js +1 -1
  163. package/dist/lib/tools/collectionsSearchTool.d.ts +1 -1
  164. package/dist/lib/tools/collectionsSearchTool.js +1 -1
  165. package/dist/lib/tools/examples.d.ts +2 -4
  166. package/dist/lib/tools/examples.js +2 -4
  167. package/dist/lib/tools/generateImageTool.d.ts +3 -3
  168. package/dist/lib/tools/generateImageTool.js +4 -5
  169. package/dist/lib/tools/inspectImageTool.d.ts +2 -2
  170. package/dist/lib/tools/inspectImageTool.js +3 -4
  171. package/dist/lib/tools/mcpToolFactory.d.ts +4 -24
  172. package/dist/lib/tools/mcpToolFactory.js +19 -9
  173. package/dist/lib/tools/memoryTools.d.ts +5 -6
  174. package/dist/lib/tools/memoryTools.js +5 -6
  175. package/dist/lib/tools/nativeTools.d.ts +9 -14
  176. package/dist/lib/tools/nativeTools.js +9 -14
  177. package/dist/lib/tools/openapiTools.d.ts +5 -7
  178. package/dist/lib/tools/openapiTools.js +6 -13
  179. package/dist/lib/tools/scienceTools.d.ts +3 -3
  180. package/dist/lib/tools/scienceTools.js +8 -10
  181. package/dist/lib/tools/skillToolset.d.ts +1 -2
  182. package/dist/lib/tools/skillToolset.js +1 -2
  183. package/dist/lib/tools/skills/executor.d.ts +1 -1
  184. package/dist/lib/tools/skills/executor.js +1 -1
  185. package/dist/lib/tools/skills/frontmatter.d.ts +2 -2
  186. package/dist/lib/tools/skills/frontmatter.js +2 -2
  187. package/dist/lib/tools/skills/tools.d.ts +8 -10
  188. package/dist/lib/tools/skills/tools.js +9 -11
  189. package/dist/lib/tools/tool.d.ts +24 -40
  190. package/dist/lib/tools/tool.js +24 -56
  191. package/dist/lib/tools/toolContract.d.ts +8 -13
  192. package/dist/lib/tools/toolContract.js +6 -17
  193. package/dist/lib/tools/urlContextTool.d.ts +1 -1
  194. package/dist/lib/tools/urlContextTool.js +1 -1
  195. package/dist/lib/tools/webExtractTool.d.ts +2 -2
  196. package/dist/lib/tools/webExtractTool.js +3 -4
  197. package/dist/lib/tools/webSearchTool.d.ts +1 -1
  198. package/dist/lib/tools/webSearchTool.js +1 -1
  199. package/dist/lib/tools/wikiTools.d.ts +2 -2
  200. package/dist/lib/tools/wikiTools.js +5 -6
  201. package/dist/lib/tools/xApiSearchTool.d.ts +2 -2
  202. package/dist/lib/tools/xApiSearchTool.js +3 -4
  203. package/dist/lib/tools/xSearchTool.d.ts +1 -1
  204. package/dist/lib/tools/xSearchTool.js +1 -1
  205. package/dist/lib/tools/xaiSearchParams.d.ts +2 -5
  206. package/dist/lib/tools/xaiSearchParams.js +2 -5
  207. package/dist/lib/wiki/agentRun.d.ts +10 -11
  208. package/dist/lib/wiki/agentRun.js +24 -41
  209. package/dist/lib/workflow/agentNode.d.ts +31 -5
  210. package/dist/lib/workflow/agentNode.js +101 -8
  211. package/dist/lib/workflow/graph.d.ts +13 -13
  212. package/dist/lib/workflow/graph.js +25 -15
  213. package/dist/lib/workflow/nodeEvents.d.ts +5 -5
  214. package/dist/lib/workflow/nodeEvents.js +5 -5
  215. package/dist/lib/workflow/pause.d.ts +5 -4
  216. package/dist/lib/workflow/pause.js +5 -4
  217. package/dist/lib/workflow/resume.d.ts +14 -13
  218. package/dist/lib/workflow/resume.js +17 -16
  219. package/dist/lib/workflow/route.d.ts +7 -7
  220. package/dist/lib/workflow/route.js +8 -8
  221. package/dist/lib/workflow/scheduler.d.ts +54 -9
  222. package/dist/lib/workflow/scheduler.js +75 -8
  223. package/dist/lib/workflow/toolNode.d.ts +18 -29
  224. package/dist/lib/workflow/toolNode.js +29 -35
  225. package/dist/lib/workflow/turn.d.ts +29 -20
  226. package/dist/lib/workflow/turn.js +111 -24
  227. package/dist/lib/workflow.d.ts +38 -42
  228. package/dist/lib/workflow.js +38 -150
  229. package/dist/lib/workflowConfig.d.ts +6 -10
  230. package/dist/lib/workflowConfig.js +2 -27
  231. package/dist/scripts/a2a_server.js +1 -2
  232. package/dist/scripts/assistant_worker.d.ts +2 -2
  233. package/dist/scripts/assistant_worker.js +8 -7
  234. package/dist/scripts/doctor.d.ts +3 -1
  235. package/dist/scripts/doctor.js +4 -2
  236. package/dist/scripts/syndicate_chat.js +14 -24
  237. package/package.json +3 -6
  238. package/skills/briefs/_shared.md +2 -2
  239. package/skills/briefs/melchizedek-author.md +2 -2
  240. package/skills/briefs/melchizedek-models.md +6 -6
  241. package/skills/melchizedek-author/SKILL.md +2 -2
  242. package/skills/melchizedek-models/SKILL.md +5 -5
package/DOCUMENTATION.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # melchizedek-agents — reference documentation
2
2
 
3
3
  The framework in one sentence: **a syndicate is a YAML file describing an
4
- agent graph; the runtime compiles it into live Google-ADK agents with
4
+ agent graph; the engine compiles it into agents on its own loop, with
5
5
  tools, sessions, and memory attached.** This document is the reference
6
6
  for that file format and the machinery around it. For a guided first run,
7
7
  see [`QUICKSTART.md`](./QUICKSTART.md).
@@ -27,13 +27,14 @@ config/agents/ YOUR syndicate definitions (the engine's input)
27
27
  config/agents/examples/ the starter pack — shipped example syndicates
28
28
  lib/loadSyndicate.ts YAML → validated config (+ variable binding)
29
29
  lib/dispatch.ts plan-dispatch route resolution (§6)
30
- lib/toolRegistry.ts tool name → live ADK tool instance
30
+ lib/toolRegistry.ts tool name → the engine's own Tool
31
31
  lib/models/claudeAdapter.ts Claude on the engine's model contract
32
- lib/models/claudeLlm.ts that adapter behind the ADK shim, in the ADK registry
33
32
  lib/models/ollamaLlm.ts open-weight local adapter (Ollama, keyless)
34
33
  lib/models/chatCompletionsAdapter.ts the chat-completions wire on the model contract
35
- lib/tools/mcpToolFactory.ts MCP client: remote tools → live ADK tools
34
+ lib/tools/mcpToolFactory.ts MCP client: remote tools → the engine's own Tools
36
35
  scripts/demo_mcp_server.ts demo MCP server (library catalog, SSE)
36
+ lib/runtime/native/… the native loop: steps, delegation, compaction, interrupts
37
+ lib/workflow/… the workflow scheduler for `workflow:` syndicates
37
38
  lib/session/… Supabase-backed session service
38
39
  lib/memory/… pgvector long-term memory service
39
40
  lib/observability/… OpenTelemetry run tracing
@@ -48,27 +49,42 @@ tests/agents.test.ts compiles every shipped syndicate; opt-in live check
48
49
  ```
49
50
 
50
51
  Execution flow: `loadSyndicate` reads and validates the YAML and binds
51
- `{{variables}}` → the runner builds an `LlmAgent` per agent, wiring
52
- subagents as `AgentTool`s and tool names through the registry → the ADK
53
- `Runner` executes the turn, persisting events to the session service →
54
- on session end, the memory service distills the transcript into tagged
55
- facts, embeds them (768-d), and stores them for future recall.
52
+ `{{variables}}` → the compiler builds each agent on the engine's own
53
+ loop, wiring subagents as delegation tools and tool names through the
54
+ registry → the loop runs the turn, calling each agent's model through its
55
+ adapter on the engine's model contract and persisting events to the
56
+ session service → on session end, the memory service distills the
57
+ transcript into tagged facts, embeds them (768-d), and stores them for
58
+ future recall.
56
59
 
57
60
  The compiler (`lib/compile.ts`) first builds a runtime-neutral `AgentSpec`
58
- per agent; `lib/compileAdk.ts` turns it into the `LlmAgent`, and
59
- `lib/compileNative.ts` into the engine's own loop's agent. ADK runs every
60
- turn by default. `MELCHIZEDEK_RUNTIME=native`, or `runtime: 'native'` on
61
- `runSyndicateTurn`, runs a single-agent, delegating or plan-dispatch
62
- syndicate on the native loop with the same result and the same stored
63
- events, `context:` compaction and `mode: task` included
61
+ per agent, and `lib/compileNative.ts` turns it into the native loop's
62
+ agent. The native runtime is the only runtime
63
+ ([ADR 0107](./wiki/decisions/0107-release-1-0-0-removes-adk.md)): it owns the
64
+ loop, the model contract and its adapters, the tools, the sessions and
65
+ the workflow scheduler, and runs a single-agent, delegating,
66
+ plan-dispatch or `workflow:` syndicate, `context:` compaction
64
67
  ([ADR 0078](./wiki/decisions/0078-native-compaction-ports-adk-compactor.md)),
65
- and a `workflow:` syndicate on the engine's own scheduler, its pause and
66
- resume included
67
- ([ADR 0095](./wiki/decisions/0095-native-workflow-turn-drains-through-the-adk-reader.md));
68
- what it does not run yet throws `UnsupportedOnRuntimeError` before any
69
- model call
68
+ `mode: task`, and pause and resume included
69
+ ([ADR 0095](./wiki/decisions/0095-native-workflow-turn-drains-through-the-adk-reader.md)).
70
+ Two configurations it refuses with `UnsupportedOnRuntimeError` before any
71
+ model call: a `transformAgent` hook (it transformed ADK agents), and an
72
+ `ask_user` tool on a workflow node (use an `ask_user` node)
70
73
  ([ADR 0073](./wiki/decisions/0073-one-agent-spec-and-a-runtime-flag.md)).
71
74
 
75
+ 1.0.0 removed Google ADK
76
+ ([ADR 0045](./wiki/decisions/0045-own-runtime-behind-the-seam.md),
77
+ [ADR 0107](./wiki/decisions/0107-release-1-0-0-removes-adk.md)).
78
+ `MELCHIZEDEK_RUNTIME=native` (or `runtime: 'native'` on
79
+ `runSyndicateTurn`) changes nothing; `adk` throws `RuntimeRemovedError`,
80
+ naming 1.0.0, at the startup of the A2A server, the chat and the worker,
81
+ and from `runSyndicateTurn` before the session is touched; any other value
82
+ is a configuration error. The engine stores the same event JSON ADK wrote,
83
+ so a session written before 1.0.0 resumes, and `npx melchizedek-doctor`
84
+ prints the runtime in use and where the choice came from. Upgrading from
85
+ 0.x: read the 1.0.0 "Breaking — read before upgrading" section of
86
+ [`CHANGELOG.md`](./CHANGELOG.md).
87
+
72
88
  ## 2. The syndicate YAML
73
89
 
74
90
  Minimal complete example:
@@ -114,18 +130,18 @@ Field reference:
114
130
  | `memory_retention_days` | root | Days a fact in this syndicate's namespace is kept; the server deletes older facts when it loads the syndicate and daily after. Requires `memory_namespace` (never applied to the shared default namespace). |
115
131
  | `dispatch` | root | Switches the syndicate from DELEGATE to PLAN-DISPATCH routing (§6). `default_route` (required) names the fail-static subagent; `route_key` / `reason_key` name the router's JSON properties (defaults `route` / `reason`). Honoured by every surface (the CLI, the server, the worker, evals). |
116
132
  | `workflow` | root | Switches the syndicate to a WORKFLOW (§6): a graph whose nodes are its agents plus declared `join`, `map`, `tool` and `ask_user` nodes, and whose `edges` say what runs after what and on which route. The orchestrator is a node like any other; nothing delegates. Cannot be combined with `dispatch`. Contract: `lib/workflow.ts`; worked example: `examples/pipeline.yaml`. |
117
- | `retries` | root | Self-correction, on by default ([ADR 0034](./wiki/decisions/0034-self-correction.md)): `model_errors` (default 2) retries a model reply ADK marks malformed (`MALFORMED_FUNCTION_CALL`) instead of failing the turn; `tool_errors` (default 3) answers a tool that threw with structured reflection guidance and caps its retries. `0` turns either off. Every retry is a model call under `max_steps`. |
133
+ | `retries` | root | Self-correction, on by default ([ADR 0034](./wiki/decisions/0034-self-correction.md)): `model_errors` (default 2) retries a model reply marked malformed (`MALFORMED_FUNCTION_CALL`) instead of failing the turn; `tool_errors` (default 3) answers a tool that threw with structured reflection guidance and caps its retries. `0` turns either off. Every retry is a model call under `max_steps`. |
118
134
  | `guards` | root | Optional list of post-answer guard NAMES (`lib/guards/index.ts`). Each runs after the answering turn and before the reply publishes, receiving the final text plus every tool-result text of that turn, and rewrites in place rather than re-asking the model; its notes land in the `[STATUS]` stream. Guards declared by a syndicate reached through `yaml_reference:` count too — the server resolves the union via `collectGuards()`. Resolved by name, never by module path, so adding one is a deliberate act in code; **the published registry ships one, `science`** (citation checks for `research.yaml`); `registerGuard()` adds your own from code, and an unregistered name is warned about and skipped. |
119
135
  | `name` / `model` / `instruction` | agent | The agent triple. Any Gemini id, `claude-*`, or `ollama/*` for open-weight local models (see §5). |
120
136
  | `description` | subagent | **The delegation API.** The orchestrator reads this when deciding to hand off — write it like a function signature ("Use this subagent to…, pass it…"). |
121
137
  | `tools` | agent | Names resolved by the tool registry (§3). Long-term memory agents add `preload_memory` / `load_memory`. |
122
138
  | `reasoning` | agent | How hard the agent reasons, on any provider: `none`, `low`, `medium`, `high`, or `{ budget_tokens: <int> }`. The compiler sends each provider the field it reads: a thinking level on Gemini 3, a thinking budget on Claude 4.6 and earlier (2,048 / 8,192 / 16,384 tokens for low / medium / high), adaptive thinking with that effort on later Claude models ([ADR 0049](./wiki/decisions/0049-claude-requests-by-model-generation.md)), an effort word on GPT, Grok, Kimi, Ollama and the gateway ([ADR 0047](./wiki/decisions/0047-provider-neutral-reasoning-key.md)). Unset, each adapter keeps its own default. |
123
139
  | `generateContentConfig` | agent | Temperature, output caps. Its `thinkingConfig` and `reasoningEffort` are the older, provider-specific spelling of `reasoning`; setting either next to `reasoning` is a load error. |
124
- | `outputSchema` | agent | Structured-JSON contract. **Constraint:** an agent holding `outputSchema` cannot also hold transfer powers — the ADK deadlocks it. Keep schema-holders as leaf agents (see `critic.yaml`'s header comment for the war story). |
140
+ | `outputSchema` | agent | Structured-JSON contract. **Constraint:** an agent holding `outputSchema` cannot also hold transfer powers — structured output does not combine with delegation on one agent. Keep schema-holders as leaf agents (see `critic.yaml`'s header comment for the war story). |
125
141
  | `yaml_reference` | subagent | Mount another syndicate file as a nested subagent. |
126
142
  | `a2a_agent_url` | subagent | A REMOTE agent over A2A (§6): the orchestrator delegates to it with one `request` argument; in plan-dispatch it can be a route. No `model`/`instruction` — the remote agent has its own. Credentials come from `A2A_AGENT_TOKENS`, never YAML. |
127
143
  | `max_steps` | root | Cap on model calls per turn, counted across every agent the turn reaches (orchestrator, subagents, nested syndicates). Exceeding it fails the turn with `STEP_LIMIT`. |
128
- | `includeContents` / `outputKey` / `globalInstruction` / `disallowTransferToParent` / `disallowTransferToPeers` | agent | Passed through to ADK's LlmAgent. `includeContents: none` makes an agent see only the current message. |
144
+ | `includeContents` / `outputKey` / `globalInstruction` / `disallowTransferToParent` / `disallowTransferToPeers` | agent | Passed through to the agent (the names are ADK's `LlmAgent` fields). `includeContents: none` makes an agent see only the current message. |
129
145
  | `fallback_model` | any agent | A model, ideally on another provider, that answers when this agent's model fails provider-side (5xx, 429, a connection reset, after its own retries) before producing any output, or while that provider's circuit is open: after `MODEL_BREAKER_THRESHOLD` consecutive provider failures (default 5; 0 disables) the provider is skipped for `MODEL_BREAKER_COOLDOWN_MS` (default 30 s). A 4xx and a canceled turn are never redirected, and a stream that already produced text is never replayed elsewhere ([ADR 0044](./wiki/decisions/0044-fallback-model-and-circuit-breaker.md)). |
130
146
  | `mcp_tools` | subagent | The MCP server's tools this agent may use; any other tool the server lists is not exposed. On a dispatch route `require_approval` may name them ([ADR 0041](./wiki/decisions/0041-tool-vendors-get-least-privilege.md)). |
131
147
  | `mcp_server_url` | subagent | Discover this subagent's tools from a remote MCP server at load time (§3). SSRF-guarded; `ALLOW_PRIVATE_MCP=true` permits localhost for development. |
@@ -134,7 +150,7 @@ Field reference:
134
150
  | `context` | orchestrator | Compacts a long conversation: when the last request's prompt passed `compact_after_tokens`, earlier turns become one summary (written by `summary_model`, default the agent's own) and the last `keep_recent_events` stay verbatim. The full history stays stored; only what the model reads shrinks. The orchestrator of a delegate syndicate only: a dispatch route already reads a bounded projection, a workflow node sees only its input. |
135
151
  | `mode` | workflow node | `"task"`: the agent works with its tools until it calls `finish_task`, whose arguments (matching its `outputSchema`) become the node's output. Workflow nodes only. |
136
152
  | `examples` | any agent | Few-shot exchanges, `[{ input, output }]` (up to 20), added to every request's instruction as a few-shot block, the one ADK's `ExampleTool` wrote (an Instruction tool, `lib/tools/examples.ts`); the model never calls it. Keeps worked examples out of the prose of `instruction`. |
137
- | `skills` | any agent | Agent Skills (a directory of SKILL.md folders) the agent holds the way a coding harness does: every skill's name and description is appended to its instruction at compile time; `load_skill` reads one in full with the names of its files, `load_skill_resource` reads one file. `scripts: local` adds `run_skill_script`, which runs a skill's own scripts on this machine, each after a person approves (the `require_approval` pause), with PATH, HOME, the temp directory and the locale but none of the server's keys, plus the variable names listed under `env:` (or `secret_env:` for a secret-shaped name, ADR 0086), and stdout and stderr each cut at 20,000 characters; `tools:` names registry tools a skill's `allowed-tools` may unlock once loaded. Worked example: `examples/harness.yaml`; engine: `lib/tools/skillToolset.ts` over `lib/tools/skills/`, the same on both runtimes. |
153
+ | `skills` | any agent | Agent Skills (a directory of SKILL.md folders) the agent holds the way a coding harness does: every skill's name and description is appended to its instruction at compile time; `load_skill` reads one in full with the names of its files, `load_skill_resource` reads one file. `scripts: local` adds `run_skill_script`, which runs a skill's own scripts on this machine, each after a person approves (the `require_approval` pause), with PATH, HOME, the temp directory and the locale but none of the server's keys, plus the variable names listed under `env:` (or `secret_env:` for a secret-shaped name, ADR 0086), and stdout and stderr each cut at 20,000 characters; `tools:` names registry tools a skill's `allowed-tools` may unlock once loaded. Worked example: `examples/harness.yaml`; engine: `lib/tools/skillToolset.ts` over `lib/tools/skills/`. |
138
154
 
139
155
  Validation happens at load: missing names, legacy option blocks, and
140
156
  malformed agents fail with pointed errors before any model is called.
@@ -143,16 +159,14 @@ skipped with a warning at compile time.
143
159
 
144
160
  ## 3. Tools
145
161
 
146
- Registered in `lib/toolRegistry.ts` — one map from YAML name to ADK tool
147
- instance. A **Contract** is the engine's own Tool (`lib/tools/tool.ts`),
148
- defined once with `defineTool` and handed to the ADK runtime as a
149
- `FunctionTool` by `toFunctionTool` (`lib/tools/adkTool.ts`). An
150
- **Instruction tool** is the engine's own too: it declares no function and
151
- only writes into each request's instruction, reaching the ADK runtime
152
- through `toAdkInstructionTool`. A **server-side tool** is an own marker
162
+ Registered in `lib/toolRegistry.ts` — one map from YAML name to tool. A
163
+ **Contract** is the engine's own Tool (`lib/tools/tool.ts`), defined once
164
+ with `defineTool`; the native loop runs it as it is. An **Instruction
165
+ tool** is the engine's own too: it declares no function and only writes
166
+ into each request's instruction. A **server-side tool** is an own marker
153
167
  (`lib/tools/nativeTools.ts`) that names the provider's tool and declares no
154
- function; the ADK runtime runs its sentinel (`toAdkNativeTool`), and every
155
- adapter recognises it by marker ([ADR 0062](./wiki/decisions/0062-server-side-tools-as-markers.md)):
168
+ function, and every adapter recognises it by marker
169
+ ([ADR 0062](./wiki/decisions/0062-server-side-tools-as-markers.md)):
156
170
 
157
171
  | Name | Kind | Does |
158
172
  |---|---|---|
@@ -161,7 +175,7 @@ adapter recognises it by marker ([ADR 0062](./wiki/decisions/0062-server-side-to
161
175
  | `x_search` | xAI-only | Live search over X (Twitter) posts via xAI Agent Tools. Self-gates to `grok-*` agents; a silent no-op on every other provider, so mixed-provider YAMLs stay safe. Optional server-side constraints in `.env`: `XAI_X_SEARCH_FROM_DATE`/`_TO_DATE` (inclusive `YYYY-MM-DD`) and `_ALLOWED_HANDLES`/`_EXCLUDED_HANDLES` (max 20, mutually exclusive — allowlist wins). |
162
176
  | `collections_search` | xAI-only | Semantic search over xAI **Collections** — hosted document stores (PDFs/text/CSVs) uploaded at console.x.ai — server-side RAG with `collections://…` citations. Which collections: `XAI_COLLECTION_IDS` in `.env` (optional `XAI_COLLECTIONS_MAX_RESULTS`). Declared with no ids → omitted with a warning; non-xAI providers → silent no-op. |
163
177
  | `url_context` | Gemini built-in | Gemini reads the pages at URLs in the conversation, server-side (Google fetches them, not this host). On any other provider it is a no-op the doctor reports as dropped; use `web_extract` there. |
164
- | `google_search` | ADK built-in | Live web search — Gemini agents only (legacy alias; use `web_search`). |
178
+ | `google_search` | Gemini built-in | Live web search — Gemini agents only (legacy alias; use `web_search`). |
165
179
  | `preload_memory` | Instruction tool | Silently injects similarity-matched facts into every request's instruction (ambient recall). The model never calls it. |
166
180
  | `load_memory` | Contract | Explicit tool call to search the fact store (deliberate recall). Both memory tools read the caller's own silo only and send the model what ADK's tools of the same names sent ([ADR 0059](./wiki/decisions/0059-memory-on-the-engines-own-interfaces.md)). |
167
181
  | `generate_image` | Contract | Calls the Gemini image model directly, saves the result under `outputs/`, returns the path. A function tool because binary `inlineData` cannot survive the AgentTool text boundary. |
@@ -173,8 +187,7 @@ adapter recognises it by marker ([ADR 0062](./wiki/decisions/0062-server-side-to
173
187
  **MCP tools** are the exception to the registry: a subagent with
174
188
  `mcp_server_url:` in its YAML gets its tools from a remote MCP server at
175
189
  load time. `lib/tools/mcpToolFactory.ts` dials the server over SSE,
176
- lists its tools, and makes each one an own Tool (`loadMcpTools`), which
177
- the ADK runtime runs as a `FunctionTool` (`createMcpTools`) — the
190
+ lists its tools, and makes each one an own Tool (`loadMcpTools`) — the
178
191
  agent's reach is decided by the server, not compiled in.
179
192
  `config/agents/examples/librarian.yaml` plus the demo catalog server
180
193
  (`npm run mcp:demo`, `scripts/demo_mcp_server.ts`) are the worked
@@ -228,8 +241,8 @@ example: `config/agents/examples/weather.yaml`, two keyless Open-Meteo specs
228
241
  in `examples/specs/`.
229
242
 
230
243
  > **Schema dialects, handled for you.** The factory emits Gemini-style
231
- > UPPERCASE schema types (`'OBJECT'`, `'STRING'`, …) because the ADK is
232
- > Gemini-native; every non-Gemini adapter normalizes them back to
244
+ > UPPERCASE schema types (`'OBJECT'`, `'STRING'`, …), the `@google/genai`
245
+ > dialect; every non-Gemini adapter normalizes them back to
233
246
  > standard lowercase JSON-Schema at request-build time
234
247
  > (`lib/models/schemaNormalize.ts`). MCP tools therefore work on any
235
248
  > provider's agents — Gemini, Claude, GPT, Grok, or Kimi.
@@ -340,13 +353,13 @@ accordingly — model optionality is a single YAML line per agent:
340
353
 
341
354
  | Model id | Provider | Adapter | Key | Native `web_search` |
342
355
  |---|---|---|---|---|
343
- | `gemini-*` | Google Gemini | ADK-native (`TracedGemini`) | `GOOGLE_GENAI_API_KEY` | ✅ grounding |
344
- | `claude-*` | Anthropic | `lib/models/claudeAdapter.ts` (Messages API; `ClaudeLlm` is its ADK shim) | `ANTHROPIC_API_KEY` | ✅ server tool |
345
- | `gpt-*`, o-series | OpenAI | `lib/models/gptLlm.ts` around `gptAdapter.ts` (Responses API) | `OPENAI_API_KEY` | ✅ web_search tool |
346
- | `grok-*` | xAI | `lib/models/grokLlm.ts` around `grokAdapter.ts` (Responses API) | `XAI_API_KEY` | ✅ Agent Tools search |
347
- | `kimi-*` | Moonshot AI (Kimi) | `lib/models/kimiLlm.ts` around `kimiAdapter.ts` (chat completions) | `MOONSHOT_API_KEY` | ⚠ omitted + warning |
348
- | `ollama/*` | Local Ollama | `lib/models/ollamaLlm.ts` around `ollamaAdapter.ts` (chat completions) | none | ⚠ omitted + warning |
349
- | *any cloud id whose direct key is absent* | the id's own provider, via a gateway | `lib/models/gatewayLlm.ts` around `gatewayAdapter.ts` (chat completions) | `MODEL_GATEWAY` + `MODEL_GATEWAY_API_KEY` | ⚠ omitted + reported |
356
+ | `gemini-*` | Google Gemini | `lib/models/geminiAdapter.ts` (`@google/genai`) | `GOOGLE_GENAI_API_KEY` | ✅ grounding |
357
+ | `claude-*` | Anthropic | `lib/models/claudeAdapter.ts` (Messages API) | `ANTHROPIC_API_KEY` | ✅ server tool |
358
+ | `gpt-*`, o-series | OpenAI | `lib/models/gptAdapter.ts` (Responses API) | `OPENAI_API_KEY` | ✅ web_search tool |
359
+ | `grok-*` | xAI | `lib/models/grokAdapter.ts` (Responses API) | `XAI_API_KEY` | ✅ Agent Tools search |
360
+ | `kimi-*` | Moonshot AI (Kimi) | `lib/models/kimiAdapter.ts` (chat completions) | `MOONSHOT_API_KEY` | ⚠ omitted + warning |
361
+ | `ollama/*` | Local Ollama | `lib/models/ollamaAdapter.ts` (chat completions) | none | ⚠ omitted + warning |
362
+ | *any cloud id whose direct key is absent* | the id's own provider, via a gateway | `lib/models/gatewayAdapter.ts` (chat completions) | `MODEL_GATEWAY` + `MODEL_GATEWAY_API_KEY` | ⚠ omitted + reported |
350
363
 
351
364
  The xAI adapter carries the deepest capability surface: `grok-4.5`
352
365
  requests pin `reasoning.effort: "medium"` (`lib/config.ts`), SSE
@@ -356,9 +369,8 @@ structured outputs ride `outputSchema` → `text.format`, and two
356
369
  xAI-only tools — `x_search` and `collections_search` (§3) — turn on
357
370
  live X search and hosted-document RAG. All verified live on grok-4.5.
358
371
 
359
- **Moonshot AI (Kimi).** `kimi-*` ids route to `lib/models/kimiLlm.ts`, the
360
- ADK shim around `KimiAdapter` (`lib/models/kimiAdapter.ts`, on the
361
- chat-completions base), against `https://api.moonshot.ai/v1`
372
+ **Moonshot AI (Kimi).** `kimi-*` ids route to `KimiAdapter`
373
+ (`lib/models/kimiAdapter.ts`, on the chat-completions base), against `https://api.moonshot.ai/v1`
362
374
  (`MOONSHOT_BASE_URL` for a proxy). Get a key at platform.moonshot.ai; the
363
375
  `.cn` console serves mainland China. The family (USD per 1M tokens, October
364
376
  2026): `kimi-k3`, the flagship — 2.8T-parameter open-weight MoE, 1M context,
@@ -455,11 +467,12 @@ configured platform with its credential source and anything missing. These
455
467
  paths are tested against mocked SDK clients and have **not** been run against
456
468
  the live clouds from this repository.
457
469
 
458
- `lib/models/registry.ts` is the single routing seam:
459
- `registerAvailableProviders()` registers every adapter whose key is
460
- present (Ollama needs none) into the ADK's LLM registry, so the YAML
461
- string finds its provider; missing keys produce clear skip messages,
462
- and only the providers a syndicate actually declares are required.
470
+ `lib/models/registry.ts` is the single routing seam: `resolveAdapter`
471
+ turns the YAML's model string into its provider's adapter, and
472
+ `logProviderStatuses()` reports which providers have a key
473
+ (Ollama needs none) and, given a log function, logs a line per provider;
474
+ it registers nothing. Missing keys produce clear skip messages, and only
475
+ the providers a syndicate actually declares are required.
463
476
  Mixed graphs are supported — each agent picks its own provider, one
464
477
  line each. `config/agents/examples/claude.yaml` is the minimal Claude example;
465
478
  `config/agents/examples/model_zoo.yaml` declares one lightweight agent per
@@ -469,9 +482,7 @@ prompt to every available provider, printing input, thinking (qwen3
469
482
  Grok reasoning, Kimi reasoning_content), output, and a per-request token/latency trace; add
470
483
  `-- --search` to watch four native web searches plus the local
471
484
  omission. Providers without keys are skipped, never fatal. Each agent
472
- runs as a one-agent syndicate through `runSyndicateTurn`, so
473
- `MELCHIZEDEK_RUNTIME=native npm run demo:models` runs the same demo on
474
- the engine's own loop.
485
+ runs as a one-agent syndicate through `runSyndicateTurn`.
475
486
 
476
487
  Reasoning/thinking: scratchpads from every provider are surfaced as
477
488
  dimmed THINKING output and kept out of session history. On Claude, any
@@ -488,44 +499,33 @@ response (ADR 0050).
488
499
  The engine's own model contract is `lib/models/contract.ts` (ADR 0048),
489
500
  importable as `melchizedek-agents/models/contract`. It defines the message
490
501
  format, request, response stream and adapter interface of the native
491
- runtime (ADR 0045), with no `@google/*` in its import graph, and the
492
- adapters move onto it in stages. `wiki/models/model-contract.md` gives
493
- each field's purpose and its mapping onto every provider's wire. While ADK
494
- runs the turn, an adapter on the contract runs behind `AdkShim`
495
- (`melchizedek-agents/models/adkShim`), an ADK `BaseLlm` that charges each
496
- call against `max_steps`, passes the turn's abort signal and opens the
497
- `llm.request` span, as the ADK-path adapters do (ADR 0053).
498
- GPT and Grok run on the contract already: `GptLlm` and `GrokLlm` are that
499
- shim around `GptAdapter` (`melchizedek-agents/models/gptAdapter`) and
500
- `GrokAdapter` (`melchizedek-agents/models/grokAdapter`), and keep the token
501
- counts and server-side tool record the ledger has always had for them
502
- (ADR 0056).
503
- Gemini has two adapters on the contract:
504
- `melchizedek-agents/models/geminiAdapter` (`GeminiAdapter`, on
505
- `@google/genai` with no ADK) and, until that one passes its live parity
506
- run, `melchizedek-agents/models/adkGeminiAdapter` (`AdkGeminiAdapter`,
507
- a temporary wrapper that runs the request through `TracedGemini`, now in
508
- `melchizedek-agents/models/tracedGemini`).
502
+ runtime (ADR 0045), with no `@google/*` in its import graph, and every
503
+ provider's adapter implements it. `wiki/models/model-contract.md` gives
504
+ each field's purpose and its mapping onto every provider's wire. The
505
+ native loop calls the adapters directly, charging each call against
506
+ `max_steps`, passing the turn's abort signal and opening the
507
+ `llm.request` span (ADR 0053).
508
+ Gemini's adapter is `GeminiAdapter`
509
+ (`melchizedek-agents/models/geminiAdapter`, on `@google/genai`)
510
+ ([ADR 0100](./wiki/decisions/0100-gemini-row-asserted-on-the-engine-adapter.md)).
509
511
  `resolveAdapter(modelId, { apiKey, keyProvider, endpoint, gemini })` in
510
512
  `melchizedek-agents/models/registry` returns any id's contract adapter
511
- from the same prefix table, gateway rule, BYOK scoping and endpoints as
512
- `resolveModel`, with no ADK registry (ADR 0060). A Gemini id gets
513
- `AdkGeminiAdapter` unless `GEMINI_ADAPTER=engine` (or `gemini: 'engine'`)
514
- asks for `GeminiAdapter`. `resolveAdapterWithFallback` wraps an agent's
515
- model and `fallback_model` in a `FallbackAdapter`.
516
-
517
- `melchizedek-agents/model` is the model layer on its own, with no
518
- `@google/adk` in its import graph (ADR 0068): the contract's types,
513
+ from the prefix table, with the gateway rule, BYOK scoping and endpoints;
514
+ `resolveModel` returns the same `ModelAdapter` for a BYOK path (ADR 0060).
515
+ Every Gemini id gets `GeminiAdapter`: `GEMINI_ADAPTER=engine` (or
516
+ `gemini: 'engine'`) changes nothing, and `adk` throws, naming 1.0.0.
517
+ `resolveAdapterWithFallback` wraps an agent's model and `fallback_model`
518
+ in a `FallbackAdapter`.
519
+
520
+ `melchizedek-agents/model` is the model layer on its own (ADR 0068): the
521
+ contract's types,
519
522
  `ClaudeAdapter`, `GptAdapter`, `GrokAdapter`, `KimiAdapter`,
520
523
  `OllamaAdapter`, `GatewayAdapter`, `GeminiAdapter`, the
521
524
  `ChatCompletionsAdapter` base, `resolveAdapter`,
522
525
  `resolveAdapterWithFallback`, `FallbackAdapter` and the circuit breaker's
523
- helpers. A project that only calls models installs the package without ADK
524
- and imports from there. Its `resolveAdapter` gives a Gemini id
525
- `GeminiAdapter`; asking it for `adk` (`gemini: 'adk'` or
526
- `GEMINI_ADAPTER=adk`) throws and names `melchizedek-agents/models/registry`,
527
- whose `resolveAdapter` keeps the ADK default above. `AdkGeminiAdapter`, the
528
- ADK shims, `TracedGemini` and `resolveModel` are not in it.
526
+ helpers. A project that only calls models imports from there. Its
527
+ `resolveAdapter` gives a Gemini id `GeminiAdapter`; `resolveModel` is not
528
+ in it.
529
529
 
530
530
  Every model request also emits an `llm.request` OpenTelemetry span
531
531
  (provider, model, input/output/thinking tokens, latency). Scripts print it
@@ -546,24 +546,24 @@ kept by policy (`TELEMETRY_PAYLOADS=off|errors|sample|all`,
546
546
  `TELEMETRY_PAYLOAD_SAMPLE`, `TELEMETRY_PAYLOAD_TTL_DAYS`) and expired by
547
547
  `melchizedek_prune_telemetry()`. A row from a failed call's `llm.request`
548
548
  span holds the request in the model contract's shape (`model`, `system`,
549
- `messages`, `tools`, …), whichever adapter made the call; a row from ADK's
550
- own `call_llm` span holds ADK's request. On the native runtime the loop
551
- opens `agent.invoke <name>`, `model.call` and `tool.execute <name>` spans
552
- where ADK opens `invoke_agent`, `call_llm` and `execute_tool`, and the ledger
553
- reads both (ADR 0076); a clean call's row then comes from `model.call` and
554
- holds the request and the adapter's response in the contract's shapes. The view `adk_turns_production` excludes
549
+ `messages`, `tools`, …), whichever adapter made the call. The native loop
550
+ opens `agent.invoke <name>`, `model.call` and `tool.execute <name>` spans;
551
+ a clean call's row comes from `model.call` and holds the request and the
552
+ adapter's response in the contract's shapes. Rows written before 1.0.0
553
+ under ADK's `invoke_agent`, `call_llm` and `execute_tool` spans hold ADK's
554
+ request, and the ledger still reads them (ADR 0076). The view `adk_turns_production` excludes
555
555
  eval and classifier turns. Operate it with `npm run telemetry:stats`,
556
556
  `telemetry:prune` and `telemetry:replay` (the exporter spools failed
557
557
  batches to `outputs/telemetry-deadletter.ndjson`).
558
558
 
559
559
  **Open-weight local models**: `ollama/*` ids (e.g. `ollama/qwen3:8b`)
560
- route through `lib/models/ollamaLlm.ts` to a local Ollama daemon over
560
+ route through `lib/models/ollamaAdapter.ts` to a local Ollama daemon over
561
561
  its OpenAI-compatible API (`OLLAMA_BASE_URL`, default
562
562
  `http://localhost:11434/v1`). No key is required, and a syndicate whose
563
563
  *every* agent is `ollama/*` runs with no `.env` at all —
564
564
  `config/agents/examples/tutor.yaml` (single agent), `council.yaml` (council)
565
565
  and `assistant.yaml` (conversation, summaries, a task list, background jobs)
566
- are the worked examples. The adapter translates ADK content to
566
+ are the worked examples. The adapter translates the contract's messages to
567
567
  OpenAI-style messages, including tool calls (so delegation works),
568
568
  image parts as data URIs (so `ollama/qwen3-vl:8b` can see), and JSON
569
569
  response mode; reasoning models' `<think>…</think>` scratchpads are
@@ -784,11 +784,12 @@ same conversation (same `contextId`; the same `taskId` works too) with the text
784
784
  `{ "approval": { "id": "<approval_id>", "approved": true } }`. Approved, the
785
785
  call runs with the arguments shown; rejected, the model is told and answers
786
786
  without it. A message that is not an answer gets the same request back,
787
- without a model call. ADK pins the call and its arguments, so an approval
788
- cannot run a different call.
787
+ without a model call. The paused call and its arguments are pinned, so an
788
+ approval cannot run a different call.
789
789
 
790
790
  Gates are allowed on the orchestrator and on the subagents of a
791
- plan-dispatch syndicate, which run as the turn's own agent. A delegated
791
+ plan-dispatch syndicate, which run as the turn's own agent, and on the
792
+ agent nodes of a workflow (§6). A delegated
792
793
  subagent runs inside a tool call, where a pause cannot reach the caller, so a
793
794
  gate there is a load error, as is any gate inside a nested `yaml_reference`
794
795
  syndicate. Only function tools from the registry can be gated, not MCP tools
@@ -831,8 +832,7 @@ A tool that acts for the person against a third-party API reads their
831
832
  delegated token with `ctx.accessToken(provider)` from the sealed credential
832
833
  store ([ADR 0072](./wiki/decisions/0072-tool-credentials-sealed-per-user.md)).
833
834
  When they have not granted the provider yet, the turn pauses for their
834
- consent ([ADR 0085](./wiki/decisions/0085-oauth-consent-pauses-on-adks-credential-request.md)).
835
- This runs on the native runtime:
835
+ consent ([ADR 0085](./wiki/decisions/0085-oauth-consent-pauses-on-adks-credential-request.md)):
836
836
 
837
837
  ```ts
838
838
  import { createA2AApp } from 'melchizedek-agents/a2a';
@@ -875,8 +875,7 @@ No token, code, client secret or verifier is written to a page, an event, a
875
875
  log line or the model's context. The pending flows live in the process: run
876
876
  one replica, or route the callback to the instance that paused the call. In
877
877
  code, `runSyndicateTurn({ …, toolCredentials })` returns
878
- `status: 'input-required'` with `consent`. On the ADK runtime an open consent
879
- request throws `UnsupportedOnRuntimeError`.
878
+ `status: 'input-required'` with `consent`.
880
879
 
881
880
  #### Limits
882
881
 
@@ -1090,9 +1089,9 @@ emitted the bare tool name in place of a 2,599-character answer.
1090
1089
  Plan-dispatch has no relay turn to fail, and the classifier's output
1091
1090
  shrinks from a whole relayed answer to ~15 tokens of JSON.
1092
1091
 
1093
- **Why the classifier is tool-less.** ADK refuses to combine
1094
- `outputSchema` with AgentTool delegation on one agent (see
1095
- `config/agents/examples/critic.yaml` — an orchestrator holding both deadlocks).
1092
+ **Why the classifier is tool-less.** Structured output does not combine
1093
+ with delegation on one agent (see `config/agents/examples/critic.yaml`,
1094
+ whose header tells how an orchestrator holding both deadlocked on ADK).
1096
1095
  That constraint shapes the method: the classifier is a leaf, and the
1097
1096
  hand-off happens in code, where it can be logged, traced, and streamed
1098
1097
  to the user as progress.
@@ -1100,8 +1099,9 @@ to the user as progress.
1100
1099
  **Sessions.** Every *route* runs in the shared `<contextId>` session, so
1101
1100
  one transcript accumulates across routes and long-term memory ingests
1102
1101
  real answers instead of a relay copy of them. Sharing the session is
1103
- necessary but not sufficient: ADK renders an event by comparing
1104
- `event.author` against the agent now running, and under plan-dispatch
1102
+ necessary but not sufficient: a stored event is rendered by comparing
1103
+ `event.author` against the agent now running (ADK's rule, which the native
1104
+ loop keeps), and under plan-dispatch
1105
1105
  every route is its own root agent, so the whole history fails that
1106
1106
  comparison and `convertForeignEvent` rewrites it to `role: "user"`
1107
1107
  prefixed "For context:". A route reading the raw shared session
@@ -1128,11 +1128,11 @@ traffic before any prompt, and the memory service's `serializeEvents` walks
1128
1128
  ~90% of every byte stored (`thoughtSignature` alone 73.3%), so they are
1129
1129
  stripped from the SERIALIZED COPY — the live in-memory session keeps them,
1130
1130
  or the agent's own tool loop breaks mid-turn. An elided tool result keeps
1131
- its `id` and `name` and gains a size marker, because ADK pairs calls to
1132
- responses by id and throws on a widowed half. 21.72 MB → 4.88 MB; existing
1131
+ its `id` and `name` and gains a size marker, because the loop pairs
1132
+ calls to responses by id and a widowed half breaks the history. 21.72 MB → 4.88 MB; existing
1133
1133
  rows shrink retroactively on their next write. Note the constraint this
1134
1134
  rests on: dropping the signature is safe only because stored events are
1135
- never replayed to a model. The quadratic upload is untouched — `appendEvent`
1135
+ never replayed to a model. The quadratic upload is untouched — `append`
1136
1136
  still rewrites the whole array per event — and is the next lever if row size
1137
1137
  returns.
1138
1138
 
@@ -1159,9 +1159,9 @@ contract lives in `lib/dispatch.ts`.
1159
1159
  specialist runs, so an A2A client can show a waiting user what is
1160
1160
  happening. The `reason` field is written for that reader, not for logs.
1161
1161
 
1162
- Implemented in `scripts/a2a_server.ts`; like `yaml_reference`, it is
1163
- A2A-only — the CLI runner (`scripts/syndicate_chat.ts`) still compiles
1164
- every syndicate in DELEGATE mode.
1162
+ Implemented in `runSyndicateTurn`, so every surface honours it: the A2A
1163
+ server, the CLI runner (`scripts/syndicate_chat.ts`), the worker and the
1164
+ evals.
1165
1165
 
1166
1166
  ### Workflows (`workflow:`) — the third orchestration method
1167
1167
 
@@ -1199,7 +1199,11 @@ the list of results); `tool: <registry name>` (runs the tool with the
1199
1199
  node input as its arguments); `ask_user: "<question>"` (below). An entry
1200
1200
  named after an agent carries modifiers only: `route_key`, `retry`
1201
1201
  (`max_attempts`, `initial_delay`, `max_delay`, `backoff_factor`, in
1202
- seconds) and `timeout` (seconds), which any node may carry.
1202
+ seconds; `jitter`, the backoff's randomness, 0 for none; `exceptions`,
1203
+ the error names to retry on, every error when absent) and `timeout`
1204
+ (seconds), which any node but a `map` may carry. A map's items run under
1205
+ the mapped agent's own `retry` and `timeout`, so a `map` entry refuses
1206
+ both and the load error names the agent's entry instead.
1203
1207
 
1204
1208
  **The pause.** An `ask_user` node ends the turn `input-required`
1205
1209
  (`result.input`: the node, the question, and what it was asked about).
@@ -1224,17 +1228,35 @@ again (the attempt is recorded in `answer.nodeErrors`), and a node that
1224
1228
  gives up fails the turn with `NODE_FAILED` naming it. `max_steps` and
1225
1229
  the deadline cap the whole graph as they cap any turn.
1226
1230
 
1227
- **Not yet.** Approval gates (`require_approval`, `skills.scripts: local`)
1228
- and remote `a2a_agent_url` subagents are refused inside a workflow by
1229
- the schema, and a workflow cannot be another syndicate's `yaml_reference`
1230
- (ADK cannot yet make a `Workflow` a subagent; nested, only its
1231
- orchestrator runs). An `ask_user` tool on a node agent is refused too:
1232
- use an `ask_user` node. The record is [ADR 0030](./wiki/decisions/0030-workflow-graphs.md);
1233
- the contract is `lib/workflow.ts`, on ADK's `Workflow`, and on the native
1234
- runtime `lib/workflow/turn.ts`, on the engine's own scheduler
1235
- ([ADR 0095](./wiki/decisions/0095-native-workflow-turn-drains-through-the-adk-reader.md)).
1236
- On native, a conversation paused inside an agent node or a map item
1237
- (which only ADK resumes) fails the next turn with `RESUME_UNSUPPORTED`.
1231
+ **Approval gates.** A tool in a node agent's `require_approval` pauses
1232
+ that node, and the graph with it: the turn ends `input-required` with
1233
+ `result.approval`, as any approval does, and the next message, the
1234
+ person's decision, resumes the node's own run, which runs or refuses the
1235
+ pinned call once and walks on. Any other message repeats the request and
1236
+ runs nothing. Skill scripts (`skills.scripts: local`) on a node agent
1237
+ pause the same way, each `run_skill_script` call waiting for its approval,
1238
+ with the minimal script environment of ADR 0086. The schema refuses a gate or skill scripts on an agent a `map`
1239
+ node runs.
1240
+
1241
+ **Nested.** A `yaml_reference` to a workflow syndicate runs the whole
1242
+ graph, under the entry's name and description, wherever it appears: as a
1243
+ DELEGATE subagent its last output is the tool's answer; as a plan-dispatch
1244
+ route it is the turn's answer, and the conversation keeps the message and
1245
+ that answer; as a node of another workflow it is the node's output. The
1246
+ graph's events are kept in the entry's own session, as for any subagent.
1247
+ A nested workflow may not have an `ask_user` node (a pause inside it
1248
+ cannot reach the caller); it is refused by name, as is a `map` over one.
1249
+
1250
+ **Not yet.** Remote `a2a_agent_url` subagents are refused inside a
1251
+ workflow by the schema. An `ask_user` tool on a node agent is refused
1252
+ too: use an `ask_user` node. The records are [ADR 0030](./wiki/decisions/0030-workflow-graphs.md),
1253
+ [ADR 0098](./wiki/decisions/0098-workflow-subagent-and-node-approvals.md) and
1254
+ [ADR 0106](./wiki/decisions/0106-nested-workflow-routes-nodes-and-node-skill-scripts.md);
1255
+ the turn is `lib/workflow/turn.ts`, on the engine's own scheduler
1256
+ ([ADR 0095](./wiki/decisions/0095-native-workflow-turn-drains-through-the-adk-reader.md)),
1257
+ and `lib/workflow.ts` holds the `workflow:` block's contract. A conversation paused inside an agent node on anything
1258
+ but an approval, or inside a map item, fails the next turn with
1259
+ `RESUME_UNSUPPORTED`.
1238
1260
 
1239
1261
  ## 7. Extending the framework
1240
1262
 
@@ -1245,7 +1267,7 @@ the canonical minimal block on the engine's model contract:
1245
1267
  `adapter.generate({ model, system, messages, stream })`, reading partial
1246
1268
  and final responses. The id's prefix picks the provider (`gemini-*`,
1247
1269
  `claude-*`, `gpt-*`, `grok-*`, `kimi-*`, `ollama/*`), the key comes from
1248
- the environment, and nothing in that entry loads `@google/adk`. A turn
1270
+ the environment. A turn
1249
1271
  with tools, sessions and telemetry is `runSyndicateTurn`.
1250
1272
 
1251
1273
  **Add a syndicate**: create `config/agents/<name>.yaml` — copy the
@@ -1257,17 +1279,16 @@ closest starter-pack file from `config/agents/examples/` or start from
1257
1279
  **Add a tool**: write a `defineTool` contract in `lib/tools/` (name,
1258
1280
  description, zod schema, execute), register the name in
1259
1281
  `lib/toolRegistry.ts` (or call `registerTool` from your own code),
1260
- reference it from YAML. The contract runs on either runtime; see
1282
+ reference it from YAML. The native loop runs the contract as it is; see
1261
1283
  `wiki/tools/tool-contracts.md`. The two image tools are the worked
1262
1284
  examples — including why binary data forces function tools over
1263
1285
  subagents, and how a tool signature can enforce an epistemic rule (the
1264
1286
  blind inventory).
1265
1287
 
1266
1288
  **Add a provider**: follow `claudeAdapter.ts` (SDK-based, key-gated, a
1267
- `ModelAdapter` on the engine's model contract, run under ADK by its shim
1268
- `claudeLlm.ts`) or, for a chat-completions API, `ollamaAdapter.ts`
1269
- (fetch-based, keyless: a `ChatCompletionsAdapter` subclass, run under ADK
1270
- by its shim `ollamaLlm.ts`), and register it behind a model-id prefix.
1289
+ `ModelAdapter` on the engine's model contract) or, for a chat-completions
1290
+ API, `ollamaAdapter.ts` (fetch-based, keyless: a `ChatCompletionsAdapter`
1291
+ subclass), and register it behind a model-id prefix.
1271
1292
 
1272
1293
  **Point an agent at an MCP server**: set `mcp_server_url:` on a
1273
1294
  subagent. `scripts/demo_mcp_server.ts` is a complete server to copy —
package/QUICKSTART.md CHANGED
@@ -82,9 +82,10 @@ after answering:
82
82
  npm run syndicate:critic -- "In two sentences, why did the Library of Alexandria decline?"
83
83
  ```
84
84
 
85
- The syndicate layer itself is optional. `scripts/direct_call.ts` launches
86
- a single ADK agent with no YAML at all — conventional, code-first agent
87
- calling, and the block to copy when embedding an agent in your own code:
85
+ The syndicate layer itself is optional. `scripts/direct_call.ts` makes
86
+ a single model call with no YAML at all — the engine's model contract on
87
+ its own (`melchizedek-agents/model`), and the block to copy when embedding
88
+ a model call in your own code:
88
89
 
89
90
  ```bash
90
91
  npm run demo:direct -- "In one sentence: what is an agent?"
@@ -180,23 +181,22 @@ Everything above runs inside a clone. When your syndicates deserve their
180
181
  own repo, the same engine is a typed dependency:
181
182
 
182
183
  ```bash
183
- npm install melchizedek-agents @google/adk@2.2.0
184
+ npm install melchizedek-agents
184
185
  npx melchizedek-init # config/agents/conversational.yaml + .env; --list for others
185
186
  npx melchizedek-doctor # which keys it needs, and whether it is ready
186
187
  ```
187
188
 
188
189
  ```typescript
189
- import { InMemorySessionService } from '@google/adk';
190
- import { loadSyndicate, registerAvailableProviders, runSyndicateTurn } from 'melchizedek-agents';
190
+ import { InProcessSessionService, loadSyndicate, logProviderStatuses, runSyndicateTurn } from 'melchizedek-agents';
191
191
 
192
- registerAvailableProviders(); // registers every model whose key is present
192
+ logProviderStatuses(console.log); // reports which providers have a key
193
193
  const config = loadSyndicate('mine.yaml'); // reads <your-repo>/config/agents/mine.yaml
194
194
 
195
195
  const result = await runSyndicateTurn({
196
196
  config,
197
197
  parts: [{ text: 'Hello' }],
198
198
  appName: 'my-app', userId: 'u1', sessionId: 'c1',
199
- sessionService: new InMemorySessionService(),
199
+ sessionService: new InProcessSessionService(),
200
200
  });
201
201
  console.log(result.text);
202
202
  ```
@@ -222,8 +222,12 @@ console.log(result.text);
222
222
  `config/agents/`.
223
223
  - Deeper imports are available as subpaths — `melchizedek-agents/models/registry`,
224
224
  `melchizedek-agents/tools/webExtractTool`, `melchizedek-agents/memory`,
225
- and friends — all typed. `@google/adk` installs alongside as a peer:
226
- your app owns the ADK version.
225
+ and friends — all typed.
226
+ - **One engine, no ADK.** Every turn runs on the engine's own agent loop;
227
+ 1.0.0 removed Google ADK, and `MELCHIZEDEK_RUNTIME=adk` is an error.
228
+ Upgrading from 0.x: read the 1.0.0 "Breaking — read before upgrading"
229
+ section of [`CHANGELOG.md`](./CHANGELOG.md).
230
+ `npx melchizedek-doctor` prints which runtime is in use.
227
231
  - **Your coding agent can learn all of this.** The package ships a
228
232
  six-skill suite (`skills/`, the open SKILL.md standard) covering the
229
233
  catalog, authoring, serving, memory, models, and the Scribe: