melchizedek-agents 0.20.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 (207) hide show
  1. package/.env.example +4 -5
  2. package/AGENT_SETUP.md +3 -3
  3. package/CHANGELOG.md +240 -0
  4. package/DOCUMENTATION.md +142 -150
  5. package/QUICKSTART.md +12 -11
  6. package/README.md +11 -11
  7. package/config/agents/examples/image_production.yaml +2 -2
  8. package/config/agents/syndicateSchema.yaml +52 -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/compile.d.ts +76 -86
  16. package/dist/lib/compile.js +100 -116
  17. package/dist/lib/compileNative.d.ts +44 -56
  18. package/dist/lib/compileNative.js +91 -89
  19. package/dist/lib/config.d.ts +6 -6
  20. package/dist/lib/config.js +6 -6
  21. package/dist/lib/doctor.d.ts +8 -14
  22. package/dist/lib/doctor.js +10 -46
  23. package/dist/lib/index.d.ts +12 -9
  24. package/dist/lib/index.js +10 -11
  25. package/dist/lib/loadSyndicate.d.ts +3 -3
  26. package/dist/lib/loadSyndicate.js +2 -2
  27. package/dist/lib/memory/erase.d.ts +1 -1
  28. package/dist/lib/memory/erase.js +1 -1
  29. package/dist/lib/memory/namespace.d.ts +12 -14
  30. package/dist/lib/memory/namespace.js +13 -14
  31. package/dist/lib/memory/providers.d.ts +4 -5
  32. package/dist/lib/memory/providers.js +12 -6
  33. package/dist/lib/memory/supabaseMemoryService.d.ts +9 -30
  34. package/dist/lib/memory/supabaseMemoryService.js +8 -30
  35. package/dist/lib/model.d.ts +6 -12
  36. package/dist/lib/model.js +6 -12
  37. package/dist/lib/models/adapterResolver.d.ts +21 -40
  38. package/dist/lib/models/adapterResolver.js +32 -40
  39. package/dist/lib/models/chatCompletionsAdapter.d.ts +12 -33
  40. package/dist/lib/models/chatCompletionsAdapter.js +13 -18
  41. package/dist/lib/models/circuitBreaker.d.ts +5 -5
  42. package/dist/lib/models/circuitBreaker.js +5 -5
  43. package/dist/lib/models/claudeAdapter.d.ts +9 -26
  44. package/dist/lib/models/claudeAdapter.js +11 -15
  45. package/dist/lib/models/claudeModels.d.ts +4 -4
  46. package/dist/lib/models/claudeModels.js +4 -4
  47. package/dist/lib/models/contract.d.ts +11 -11
  48. package/dist/lib/models/contract.js +6 -6
  49. package/dist/lib/models/errorResponse.d.ts +13 -20
  50. package/dist/lib/models/errorResponse.js +0 -12
  51. package/dist/lib/models/fallbackAdapter.d.ts +7 -8
  52. package/dist/lib/models/gatewayAdapter.d.ts +1 -1
  53. package/dist/lib/models/gatewayAdapter.js +1 -1
  54. package/dist/lib/models/geminiAdapter.d.ts +5 -6
  55. package/dist/lib/models/geminiAdapter.js +9 -10
  56. package/dist/lib/models/geminiState.d.ts +8 -8
  57. package/dist/lib/models/geminiState.js +8 -8
  58. package/dist/lib/models/genaiMapping.d.ts +82 -36
  59. package/dist/lib/models/genaiMapping.js +41 -41
  60. package/dist/lib/models/gptAdapter.d.ts +11 -11
  61. package/dist/lib/models/gptAdapter.js +13 -13
  62. package/dist/lib/models/kimiAdapter.d.ts +6 -7
  63. package/dist/lib/models/kimiAdapter.js +6 -9
  64. package/dist/lib/models/ollamaAdapter.d.ts +3 -3
  65. package/dist/lib/models/ollamaAdapter.js +3 -3
  66. package/dist/lib/models/providerMap.d.ts +6 -5
  67. package/dist/lib/models/providerMap.js +6 -5
  68. package/dist/lib/models/providerState.d.ts +3 -2
  69. package/dist/lib/models/providerState.js +3 -2
  70. package/dist/lib/models/reasoning.d.ts +1 -1
  71. package/dist/lib/models/registry.d.ts +26 -73
  72. package/dist/lib/models/registry.js +31 -144
  73. package/dist/lib/models/retry.d.ts +2 -2
  74. package/dist/lib/models/retry.js +2 -2
  75. package/dist/lib/models/schemaNormalize.d.ts +25 -55
  76. package/dist/lib/models/schemaNormalize.js +30 -100
  77. package/dist/lib/observability/lineage.d.ts +3 -3
  78. package/dist/lib/observability/lineage.js +10 -10
  79. package/dist/lib/observability/supabaseSpanExporter.js +1 -1
  80. package/dist/lib/observability/tracer.d.ts +25 -23
  81. package/dist/lib/observability/tracer.js +26 -63
  82. package/dist/lib/persistence/supabaseProvider.d.ts +4 -3
  83. package/dist/lib/runtime/approvals.d.ts +1 -1
  84. package/dist/lib/runtime/credentials.d.ts +1 -1
  85. package/dist/lib/runtime/events.d.ts +3 -4
  86. package/dist/lib/runtime/events.js +3 -4
  87. package/dist/lib/runtime/logging.d.ts +3 -8
  88. package/dist/lib/runtime/logging.js +3 -8
  89. package/dist/lib/runtime/memoryService.d.ts +4 -6
  90. package/dist/lib/runtime/memoryService.js +3 -5
  91. package/dist/lib/runtime/native/agentLoop.d.ts +18 -16
  92. package/dist/lib/runtime/native/agentLoop.js +38 -26
  93. package/dist/lib/runtime/native/compaction.d.ts +10 -11
  94. package/dist/lib/runtime/native/compaction.js +10 -11
  95. package/dist/lib/runtime/native/delegate.d.ts +13 -14
  96. package/dist/lib/runtime/native/delegate.js +11 -18
  97. package/dist/lib/runtime/native/history.d.ts +5 -6
  98. package/dist/lib/runtime/native/history.js +5 -6
  99. package/dist/lib/runtime/native/interrupts.d.ts +6 -6
  100. package/dist/lib/runtime/native/interrupts.js +6 -6
  101. package/dist/lib/runtime/native/request.d.ts +24 -24
  102. package/dist/lib/runtime/native/request.js +35 -24
  103. package/dist/lib/runtime/native/selfCorrection.d.ts +32 -32
  104. package/dist/lib/runtime/native/selfCorrection.js +34 -34
  105. package/dist/lib/runtime/native/step.d.ts +23 -23
  106. package/dist/lib/runtime/native/step.js +49 -27
  107. package/dist/lib/runtime/native/taskMode.d.ts +8 -8
  108. package/dist/lib/runtime/native/taskMode.js +8 -8
  109. package/dist/lib/runtime/native/telemetry.d.ts +11 -11
  110. package/dist/lib/runtime/native/telemetry.js +11 -11
  111. package/dist/lib/runtime/native/tempState.d.ts +4 -4
  112. package/dist/lib/runtime/native/tempState.js +4 -4
  113. package/dist/lib/runtime/nativeTurn.d.ts +29 -32
  114. package/dist/lib/runtime/nativeTurn.js +30 -41
  115. package/dist/lib/runtime/questions.d.ts +8 -9
  116. package/dist/lib/runtime/questions.js +1 -2
  117. package/dist/lib/runtime/runtimeFlag.d.ts +28 -14
  118. package/dist/lib/runtime/runtimeFlag.js +38 -16
  119. package/dist/lib/runtime/sessions.d.ts +10 -12
  120. package/dist/lib/runtime/sessions.js +10 -12
  121. package/dist/lib/runtime/syndicateTurn.d.ts +44 -45
  122. package/dist/lib/runtime/syndicateTurn.js +163 -158
  123. package/dist/lib/runtime/turnControl.d.ts +8 -8
  124. package/dist/lib/runtime/turnControl.js +8 -8
  125. package/dist/lib/session/supabaseSessionService.d.ts +7 -21
  126. package/dist/lib/session/supabaseSessionService.js +7 -43
  127. package/dist/lib/session/transcript.d.ts +16 -26
  128. package/dist/lib/session/transcript.js +17 -57
  129. package/dist/lib/storage/postgres/sessionService.d.ts +6 -20
  130. package/dist/lib/storage/postgres/sessionService.js +6 -39
  131. package/dist/lib/syndicateSchema.js +7 -6
  132. package/dist/lib/toolRegistry.d.ts +9 -14
  133. package/dist/lib/toolRegistry.js +36 -33
  134. package/dist/lib/tools/auth.d.ts +1 -1
  135. package/dist/lib/tools/auth.js +1 -1
  136. package/dist/lib/tools/examples.d.ts +2 -4
  137. package/dist/lib/tools/examples.js +2 -4
  138. package/dist/lib/tools/generateImageTool.d.ts +3 -3
  139. package/dist/lib/tools/generateImageTool.js +4 -5
  140. package/dist/lib/tools/inspectImageTool.d.ts +2 -2
  141. package/dist/lib/tools/inspectImageTool.js +3 -4
  142. package/dist/lib/tools/mcpToolFactory.d.ts +4 -24
  143. package/dist/lib/tools/mcpToolFactory.js +19 -9
  144. package/dist/lib/tools/memoryTools.d.ts +5 -6
  145. package/dist/lib/tools/memoryTools.js +5 -6
  146. package/dist/lib/tools/nativeTools.d.ts +9 -14
  147. package/dist/lib/tools/nativeTools.js +9 -14
  148. package/dist/lib/tools/openapiTools.d.ts +5 -7
  149. package/dist/lib/tools/openapiTools.js +6 -13
  150. package/dist/lib/tools/scienceTools.d.ts +3 -3
  151. package/dist/lib/tools/scienceTools.js +8 -10
  152. package/dist/lib/tools/skillToolset.d.ts +1 -2
  153. package/dist/lib/tools/skillToolset.js +1 -2
  154. package/dist/lib/tools/skills/executor.d.ts +1 -1
  155. package/dist/lib/tools/skills/executor.js +1 -1
  156. package/dist/lib/tools/skills/frontmatter.d.ts +2 -2
  157. package/dist/lib/tools/skills/frontmatter.js +2 -2
  158. package/dist/lib/tools/skills/tools.d.ts +8 -10
  159. package/dist/lib/tools/skills/tools.js +9 -11
  160. package/dist/lib/tools/tool.d.ts +24 -40
  161. package/dist/lib/tools/tool.js +24 -56
  162. package/dist/lib/tools/toolContract.d.ts +8 -13
  163. package/dist/lib/tools/toolContract.js +6 -17
  164. package/dist/lib/tools/webExtractTool.d.ts +2 -2
  165. package/dist/lib/tools/webExtractTool.js +3 -4
  166. package/dist/lib/tools/wikiTools.d.ts +2 -2
  167. package/dist/lib/tools/wikiTools.js +5 -6
  168. package/dist/lib/tools/xApiSearchTool.d.ts +2 -2
  169. package/dist/lib/tools/xApiSearchTool.js +3 -4
  170. package/dist/lib/tools/xaiSearchParams.d.ts +2 -5
  171. package/dist/lib/tools/xaiSearchParams.js +2 -5
  172. package/dist/lib/wiki/agentRun.d.ts +10 -11
  173. package/dist/lib/wiki/agentRun.js +24 -42
  174. package/dist/lib/workflow/agentNode.d.ts +10 -1
  175. package/dist/lib/workflow/agentNode.js +5 -3
  176. package/dist/lib/workflow/graph.d.ts +8 -9
  177. package/dist/lib/workflow/graph.js +12 -12
  178. package/dist/lib/workflow/nodeEvents.d.ts +5 -5
  179. package/dist/lib/workflow/nodeEvents.js +5 -5
  180. package/dist/lib/workflow/pause.d.ts +5 -4
  181. package/dist/lib/workflow/pause.js +5 -4
  182. package/dist/lib/workflow/resume.d.ts +4 -4
  183. package/dist/lib/workflow/resume.js +4 -4
  184. package/dist/lib/workflow/route.d.ts +7 -7
  185. package/dist/lib/workflow/route.js +8 -8
  186. package/dist/lib/workflow/scheduler.d.ts +44 -2
  187. package/dist/lib/workflow/scheduler.js +60 -6
  188. package/dist/lib/workflow/toolNode.d.ts +18 -29
  189. package/dist/lib/workflow/toolNode.js +29 -35
  190. package/dist/lib/workflow/turn.d.ts +29 -20
  191. package/dist/lib/workflow/turn.js +111 -24
  192. package/dist/lib/workflow.d.ts +34 -60
  193. package/dist/lib/workflow.js +34 -168
  194. package/dist/lib/workflowConfig.d.ts +2 -10
  195. package/dist/lib/workflowConfig.js +2 -31
  196. package/dist/scripts/a2a_server.js +1 -2
  197. package/dist/scripts/assistant_worker.d.ts +2 -2
  198. package/dist/scripts/assistant_worker.js +8 -7
  199. package/dist/scripts/doctor.d.ts +2 -2
  200. package/dist/scripts/doctor.js +2 -2
  201. package/dist/scripts/syndicate_chat.js +14 -24
  202. package/package.json +3 -9
  203. package/skills/briefs/_shared.md +2 -2
  204. package/skills/briefs/melchizedek-author.md +2 -2
  205. package/skills/briefs/melchizedek-models.md +6 -6
  206. package/skills/melchizedek-author/SKILL.md +2 -2
  207. 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,33 +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. Since 0.20.0
60
- the native loop runs every turn by default
61
- ([ADR 0102](./wiki/decisions/0102-native-default-and-optional-adk-peer.md)):
62
- `@google/adk` is an optional peer, needed only when
63
- `MELCHIZEDEK_RUNTIME=adk`, or `runtime: 'adk'` on `runSyndicateTurn`,
64
- selects ADK's Runner, which 1.0.0 removes; without it that choice fails
65
- before the session is touched, naming the package, and
66
- `npx melchizedek-doctor` prints the runtime in use and whether ADK is
67
- installed. The native loop runs a single-agent, delegating or
68
- plan-dispatch syndicate with the same result and the same stored events
69
- the ADK runtime writes, `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
70
67
  ([ADR 0078](./wiki/decisions/0078-native-compaction-ports-adk-compactor.md)),
71
- and a `workflow:` syndicate on the engine's own scheduler, its pause and
72
- resume included
73
- ([ADR 0095](./wiki/decisions/0095-native-workflow-turn-drains-through-the-adk-reader.md));
74
- what it does not run yet throws `UnsupportedOnRuntimeError` before any
75
- 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)
76
73
  ([ADR 0073](./wiki/decisions/0073-one-agent-spec-and-a-runtime-flag.md)).
77
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
+
78
88
  ## 2. The syndicate YAML
79
89
 
80
90
  Minimal complete example:
@@ -120,18 +130,18 @@ Field reference:
120
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). |
121
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). |
122
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`. |
123
- | `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`. |
124
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. |
125
135
  | `name` / `model` / `instruction` | agent | The agent triple. Any Gemini id, `claude-*`, or `ollama/*` for open-weight local models (see §5). |
126
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…"). |
127
137
  | `tools` | agent | Names resolved by the tool registry (§3). Long-term memory agents add `preload_memory` / `load_memory`. |
128
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. |
129
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. |
130
- | `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). |
131
141
  | `yaml_reference` | subagent | Mount another syndicate file as a nested subagent. |
132
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. |
133
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`. |
134
- | `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. |
135
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)). |
136
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)). |
137
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. |
@@ -140,7 +150,7 @@ Field reference:
140
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. |
141
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. |
142
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`. |
143
- | `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/`. |
144
154
 
145
155
  Validation happens at load: missing names, legacy option blocks, and
146
156
  malformed agents fail with pointed errors before any model is called.
@@ -149,16 +159,14 @@ skipped with a warning at compile time.
149
159
 
150
160
  ## 3. Tools
151
161
 
152
- Registered in `lib/toolRegistry.ts` — one map from YAML name to ADK tool
153
- instance. A **Contract** is the engine's own Tool (`lib/tools/tool.ts`),
154
- defined once with `defineTool` and handed to the ADK runtime as a
155
- `FunctionTool` by `toFunctionTool` (`lib/tools/adkTool.ts`). An
156
- **Instruction tool** is the engine's own too: it declares no function and
157
- only writes into each request's instruction, reaching the ADK runtime
158
- 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
159
167
  (`lib/tools/nativeTools.ts`) that names the provider's tool and declares no
160
- function; the ADK runtime runs its sentinel (`toAdkNativeTool`), and every
161
- 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)):
162
170
 
163
171
  | Name | Kind | Does |
164
172
  |---|---|---|
@@ -167,7 +175,7 @@ adapter recognises it by marker ([ADR 0062](./wiki/decisions/0062-server-side-to
167
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). |
168
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. |
169
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. |
170
- | `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`). |
171
179
  | `preload_memory` | Instruction tool | Silently injects similarity-matched facts into every request's instruction (ambient recall). The model never calls it. |
172
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)). |
173
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. |
@@ -179,8 +187,7 @@ adapter recognises it by marker ([ADR 0062](./wiki/decisions/0062-server-side-to
179
187
  **MCP tools** are the exception to the registry: a subagent with
180
188
  `mcp_server_url:` in its YAML gets its tools from a remote MCP server at
181
189
  load time. `lib/tools/mcpToolFactory.ts` dials the server over SSE,
182
- lists its tools, and makes each one an own Tool (`loadMcpTools`), which
183
- the ADK runtime runs as a `FunctionTool` (`createMcpTools`) — the
190
+ lists its tools, and makes each one an own Tool (`loadMcpTools`) — the
184
191
  agent's reach is decided by the server, not compiled in.
185
192
  `config/agents/examples/librarian.yaml` plus the demo catalog server
186
193
  (`npm run mcp:demo`, `scripts/demo_mcp_server.ts`) are the worked
@@ -234,8 +241,8 @@ example: `config/agents/examples/weather.yaml`, two keyless Open-Meteo specs
234
241
  in `examples/specs/`.
235
242
 
236
243
  > **Schema dialects, handled for you.** The factory emits Gemini-style
237
- > UPPERCASE schema types (`'OBJECT'`, `'STRING'`, …) because the ADK is
238
- > 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
239
246
  > standard lowercase JSON-Schema at request-build time
240
247
  > (`lib/models/schemaNormalize.ts`). MCP tools therefore work on any
241
248
  > provider's agents — Gemini, Claude, GPT, Grok, or Kimi.
@@ -346,13 +353,13 @@ accordingly — model optionality is a single YAML line per agent:
346
353
 
347
354
  | Model id | Provider | Adapter | Key | Native `web_search` |
348
355
  |---|---|---|---|---|
349
- | `gemini-*` | Google Gemini | ADK-native (`TracedGemini`) | `GOOGLE_GENAI_API_KEY` | ✅ grounding |
350
- | `claude-*` | Anthropic | `lib/models/claudeAdapter.ts` (Messages API; `ClaudeLlm` is its ADK shim) | `ANTHROPIC_API_KEY` | ✅ server tool |
351
- | `gpt-*`, o-series | OpenAI | `lib/models/gptLlm.ts` around `gptAdapter.ts` (Responses API) | `OPENAI_API_KEY` | ✅ web_search tool |
352
- | `grok-*` | xAI | `lib/models/grokLlm.ts` around `grokAdapter.ts` (Responses API) | `XAI_API_KEY` | ✅ Agent Tools search |
353
- | `kimi-*` | Moonshot AI (Kimi) | `lib/models/kimiLlm.ts` around `kimiAdapter.ts` (chat completions) | `MOONSHOT_API_KEY` | ⚠ omitted + warning |
354
- | `ollama/*` | Local Ollama | `lib/models/ollamaLlm.ts` around `ollamaAdapter.ts` (chat completions) | none | ⚠ omitted + warning |
355
- | *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 |
356
363
 
357
364
  The xAI adapter carries the deepest capability surface: `grok-4.5`
358
365
  requests pin `reasoning.effort: "medium"` (`lib/config.ts`), SSE
@@ -362,9 +369,8 @@ structured outputs ride `outputSchema` → `text.format`, and two
362
369
  xAI-only tools — `x_search` and `collections_search` (§3) — turn on
363
370
  live X search and hosted-document RAG. All verified live on grok-4.5.
364
371
 
365
- **Moonshot AI (Kimi).** `kimi-*` ids route to `lib/models/kimiLlm.ts`, the
366
- ADK shim around `KimiAdapter` (`lib/models/kimiAdapter.ts`, on the
367
- 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`
368
374
  (`MOONSHOT_BASE_URL` for a proxy). Get a key at platform.moonshot.ai; the
369
375
  `.cn` console serves mainland China. The family (USD per 1M tokens, October
370
376
  2026): `kimi-k3`, the flagship — 2.8T-parameter open-weight MoE, 1M context,
@@ -461,11 +467,12 @@ configured platform with its credential source and anything missing. These
461
467
  paths are tested against mocked SDK clients and have **not** been run against
462
468
  the live clouds from this repository.
463
469
 
464
- `lib/models/registry.ts` is the single routing seam:
465
- `registerAvailableProviders()` registers every adapter whose key is
466
- present (Ollama needs none) into the ADK's LLM registry, so the YAML
467
- string finds its provider; missing keys produce clear skip messages,
468
- 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.
469
476
  Mixed graphs are supported — each agent picks its own provider, one
470
477
  line each. `config/agents/examples/claude.yaml` is the minimal Claude example;
471
478
  `config/agents/examples/model_zoo.yaml` declares one lightweight agent per
@@ -475,9 +482,7 @@ prompt to every available provider, printing input, thinking (qwen3
475
482
  Grok reasoning, Kimi reasoning_content), output, and a per-request token/latency trace; add
476
483
  `-- --search` to watch four native web searches plus the local
477
484
  omission. Providers without keys are skipped, never fatal. Each agent
478
- runs as a one-agent syndicate through `runSyndicateTurn`, so
479
- `MELCHIZEDEK_RUNTIME=native npm run demo:models` runs the same demo on
480
- the engine's own loop.
485
+ runs as a one-agent syndicate through `runSyndicateTurn`.
481
486
 
482
487
  Reasoning/thinking: scratchpads from every provider are surfaced as
483
488
  dimmed THINKING output and kept out of session history. On Claude, any
@@ -494,44 +499,33 @@ response (ADR 0050).
494
499
  The engine's own model contract is `lib/models/contract.ts` (ADR 0048),
495
500
  importable as `melchizedek-agents/models/contract`. It defines the message
496
501
  format, request, response stream and adapter interface of the native
497
- runtime (ADR 0045), with no `@google/*` in its import graph, and the
498
- adapters move onto it in stages. `wiki/models/model-contract.md` gives
499
- each field's purpose and its mapping onto every provider's wire. While ADK
500
- runs the turn, an adapter on the contract runs behind `AdkShim`
501
- (`melchizedek-agents/models/adkShim`), an ADK `BaseLlm` that charges each
502
- call against `max_steps`, passes the turn's abort signal and opens the
503
- `llm.request` span, as the ADK-path adapters do (ADR 0053).
504
- GPT and Grok run on the contract already: `GptLlm` and `GrokLlm` are that
505
- shim around `GptAdapter` (`melchizedek-agents/models/gptAdapter`) and
506
- `GrokAdapter` (`melchizedek-agents/models/grokAdapter`), and keep the token
507
- counts and server-side tool record the ledger has always had for them
508
- (ADR 0056).
509
- Gemini has two adapters on the contract:
510
- `melchizedek-agents/models/geminiAdapter` (`GeminiAdapter`, on
511
- `@google/genai` with no ADK) and, until that one passes its live parity
512
- run, `melchizedek-agents/models/adkGeminiAdapter` (`AdkGeminiAdapter`,
513
- a temporary wrapper that runs the request through `TracedGemini`, now in
514
- `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)).
515
511
  `resolveAdapter(modelId, { apiKey, keyProvider, endpoint, gemini })` in
516
512
  `melchizedek-agents/models/registry` returns any id's contract adapter
517
- from the same prefix table, gateway rule, BYOK scoping and endpoints as
518
- `resolveModel`, with no ADK registry (ADR 0060). A Gemini id gets
519
- `AdkGeminiAdapter` unless `GEMINI_ADAPTER=engine` (or `gemini: 'engine'`)
520
- asks for `GeminiAdapter`. `resolveAdapterWithFallback` wraps an agent's
521
- model and `fallback_model` in a `FallbackAdapter`.
522
-
523
- `melchizedek-agents/model` is the model layer on its own, with no
524
- `@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,
525
522
  `ClaudeAdapter`, `GptAdapter`, `GrokAdapter`, `KimiAdapter`,
526
523
  `OllamaAdapter`, `GatewayAdapter`, `GeminiAdapter`, the
527
524
  `ChatCompletionsAdapter` base, `resolveAdapter`,
528
525
  `resolveAdapterWithFallback`, `FallbackAdapter` and the circuit breaker's
529
- helpers. A project that only calls models installs the package without ADK
530
- and imports from there. Its `resolveAdapter` gives a Gemini id
531
- `GeminiAdapter`; asking it for `adk` (`gemini: 'adk'` or
532
- `GEMINI_ADAPTER=adk`) throws and names `melchizedek-agents/models/registry`,
533
- whose `resolveAdapter` keeps the ADK default above. `AdkGeminiAdapter`, the
534
- 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.
535
529
 
536
530
  Every model request also emits an `llm.request` OpenTelemetry span
537
531
  (provider, model, input/output/thinking tokens, latency). Scripts print it
@@ -552,24 +546,24 @@ kept by policy (`TELEMETRY_PAYLOADS=off|errors|sample|all`,
552
546
  `TELEMETRY_PAYLOAD_SAMPLE`, `TELEMETRY_PAYLOAD_TTL_DAYS`) and expired by
553
547
  `melchizedek_prune_telemetry()`. A row from a failed call's `llm.request`
554
548
  span holds the request in the model contract's shape (`model`, `system`,
555
- `messages`, `tools`, …), whichever adapter made the call; a row from ADK's
556
- own `call_llm` span holds ADK's request. On the native runtime the loop
557
- opens `agent.invoke <name>`, `model.call` and `tool.execute <name>` spans
558
- where ADK opens `invoke_agent`, `call_llm` and `execute_tool`, and the ledger
559
- reads both (ADR 0076); a clean call's row then comes from `model.call` and
560
- 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
561
555
  eval and classifier turns. Operate it with `npm run telemetry:stats`,
562
556
  `telemetry:prune` and `telemetry:replay` (the exporter spools failed
563
557
  batches to `outputs/telemetry-deadletter.ndjson`).
564
558
 
565
559
  **Open-weight local models**: `ollama/*` ids (e.g. `ollama/qwen3:8b`)
566
- 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
567
561
  its OpenAI-compatible API (`OLLAMA_BASE_URL`, default
568
562
  `http://localhost:11434/v1`). No key is required, and a syndicate whose
569
563
  *every* agent is `ollama/*` runs with no `.env` at all —
570
564
  `config/agents/examples/tutor.yaml` (single agent), `council.yaml` (council)
571
565
  and `assistant.yaml` (conversation, summaries, a task list, background jobs)
572
- are the worked examples. The adapter translates ADK content to
566
+ are the worked examples. The adapter translates the contract's messages to
573
567
  OpenAI-style messages, including tool calls (so delegation works),
574
568
  image parts as data URIs (so `ollama/qwen3-vl:8b` can see), and JSON
575
569
  response mode; reasoning models' `<think>…</think>` scratchpads are
@@ -790,12 +784,12 @@ same conversation (same `contextId`; the same `taskId` works too) with the text
790
784
  `{ "approval": { "id": "<approval_id>", "approved": true } }`. Approved, the
791
785
  call runs with the arguments shown; rejected, the model is told and answers
792
786
  without it. A message that is not an answer gets the same request back,
793
- without a model call. ADK pins the call and its arguments, so an approval
794
- 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.
795
789
 
796
790
  Gates are allowed on the orchestrator and on the subagents of a
797
791
  plan-dispatch syndicate, which run as the turn's own agent, and on the
798
- agent nodes of a workflow on the native runtime (§6). A delegated
792
+ agent nodes of a workflow (§6). A delegated
799
793
  subagent runs inside a tool call, where a pause cannot reach the caller, so a
800
794
  gate there is a load error, as is any gate inside a nested `yaml_reference`
801
795
  syndicate. Only function tools from the registry can be gated, not MCP tools
@@ -838,8 +832,7 @@ A tool that acts for the person against a third-party API reads their
838
832
  delegated token with `ctx.accessToken(provider)` from the sealed credential
839
833
  store ([ADR 0072](./wiki/decisions/0072-tool-credentials-sealed-per-user.md)).
840
834
  When they have not granted the provider yet, the turn pauses for their
841
- consent ([ADR 0085](./wiki/decisions/0085-oauth-consent-pauses-on-adks-credential-request.md)).
842
- This runs on the native runtime:
835
+ consent ([ADR 0085](./wiki/decisions/0085-oauth-consent-pauses-on-adks-credential-request.md)):
843
836
 
844
837
  ```ts
845
838
  import { createA2AApp } from 'melchizedek-agents/a2a';
@@ -882,8 +875,7 @@ No token, code, client secret or verifier is written to a page, an event, a
882
875
  log line or the model's context. The pending flows live in the process: run
883
876
  one replica, or route the callback to the instance that paused the call. In
884
877
  code, `runSyndicateTurn({ …, toolCredentials })` returns
885
- `status: 'input-required'` with `consent`. On the ADK runtime an open consent
886
- request throws `UnsupportedOnRuntimeError`.
878
+ `status: 'input-required'` with `consent`.
887
879
 
888
880
  #### Limits
889
881
 
@@ -1097,9 +1089,9 @@ emitted the bare tool name in place of a 2,599-character answer.
1097
1089
  Plan-dispatch has no relay turn to fail, and the classifier's output
1098
1090
  shrinks from a whole relayed answer to ~15 tokens of JSON.
1099
1091
 
1100
- **Why the classifier is tool-less.** ADK refuses to combine
1101
- `outputSchema` with AgentTool delegation on one agent (see
1102
- `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).
1103
1095
  That constraint shapes the method: the classifier is a leaf, and the
1104
1096
  hand-off happens in code, where it can be logged, traced, and streamed
1105
1097
  to the user as progress.
@@ -1107,8 +1099,9 @@ to the user as progress.
1107
1099
  **Sessions.** Every *route* runs in the shared `<contextId>` session, so
1108
1100
  one transcript accumulates across routes and long-term memory ingests
1109
1101
  real answers instead of a relay copy of them. Sharing the session is
1110
- necessary but not sufficient: ADK renders an event by comparing
1111
- `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
1112
1105
  every route is its own root agent, so the whole history fails that
1113
1106
  comparison and `convertForeignEvent` rewrites it to `role: "user"`
1114
1107
  prefixed "For context:". A route reading the raw shared session
@@ -1135,11 +1128,11 @@ traffic before any prompt, and the memory service's `serializeEvents` walks
1135
1128
  ~90% of every byte stored (`thoughtSignature` alone 73.3%), so they are
1136
1129
  stripped from the SERIALIZED COPY — the live in-memory session keeps them,
1137
1130
  or the agent's own tool loop breaks mid-turn. An elided tool result keeps
1138
- its `id` and `name` and gains a size marker, because ADK pairs calls to
1139
- 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
1140
1133
  rows shrink retroactively on their next write. Note the constraint this
1141
1134
  rests on: dropping the signature is safe only because stored events are
1142
- never replayed to a model. The quadratic upload is untouched — `appendEvent`
1135
+ never replayed to a model. The quadratic upload is untouched — `append`
1143
1136
  still rewrites the whole array per event — and is the next lever if row size
1144
1137
  returns.
1145
1138
 
@@ -1166,9 +1159,9 @@ contract lives in `lib/dispatch.ts`.
1166
1159
  specialist runs, so an A2A client can show a waiting user what is
1167
1160
  happening. The `reason` field is written for that reader, not for logs.
1168
1161
 
1169
- Implemented in `scripts/a2a_server.ts`; like `yaml_reference`, it is
1170
- A2A-only — the CLI runner (`scripts/syndicate_chat.ts`) still compiles
1171
- 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.
1172
1165
 
1173
1166
  ### Workflows (`workflow:`) — the third orchestration method
1174
1167
 
@@ -1240,30 +1233,30 @@ that node, and the graph with it: the turn ends `input-required` with
1240
1233
  `result.approval`, as any approval does, and the next message, the
1241
1234
  person's decision, resumes the node's own run, which runs or refuses the
1242
1235
  pinned call once and walks on. Any other message repeats the request and
1243
- runs nothing. Gates on workflow nodes run on the native runtime only: on
1244
- ADK, `runSyndicateTurn` refuses such a workflow with
1245
- `UnsupportedOnRuntimeError` before any model call, because ADK's resume
1246
- starts the node afresh and never runs the pinned call. The schema refuses
1247
- a gate on an agent a `map` node runs.
1248
-
1249
- **As a subagent.** A DELEGATE syndicate's `yaml_reference` to a workflow
1250
- syndicate runs the whole graph as the subagent tool, under the entry's
1251
- name and description: the graph's last output is the tool's answer, and
1252
- its events are kept in the subagent's own session, as for any subagent.
1253
- A nested workflow may not have an `ask_user` node (a pause inside a tool
1254
- call cannot reach the caller); it is refused by name. As a dispatch route
1255
- or a workflow node, a workflow syndicate is still its orchestrator alone.
1256
-
1257
- **Not yet.** Skill scripts (`skills.scripts: local`) and remote
1258
- `a2a_agent_url` subagents are refused inside a workflow by the schema. An
1259
- `ask_user` tool on a node agent is refused too: use an `ask_user` node. The records are [ADR 0030](./wiki/decisions/0030-workflow-graphs.md) and
1260
- [ADR 0098](./wiki/decisions/0098-workflow-subagent-and-node-approvals.md);
1261
- the contract is `lib/workflow.ts`, on ADK's `Workflow`, and on the native
1262
- runtime `lib/workflow/turn.ts`, on the engine's own scheduler
1263
- ([ADR 0095](./wiki/decisions/0095-native-workflow-turn-drains-through-the-adk-reader.md)).
1264
- On native, a conversation paused inside an agent node on anything but an
1265
- approval, or inside a map item (which only ADK resumes), fails the next
1266
- turn with `RESUME_UNSUPPORTED`.
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`.
1267
1260
 
1268
1261
  ## 7. Extending the framework
1269
1262
 
@@ -1274,7 +1267,7 @@ the canonical minimal block on the engine's model contract:
1274
1267
  `adapter.generate({ model, system, messages, stream })`, reading partial
1275
1268
  and final responses. The id's prefix picks the provider (`gemini-*`,
1276
1269
  `claude-*`, `gpt-*`, `grok-*`, `kimi-*`, `ollama/*`), the key comes from
1277
- the environment, and nothing in that entry loads `@google/adk`. A turn
1270
+ the environment. A turn
1278
1271
  with tools, sessions and telemetry is `runSyndicateTurn`.
1279
1272
 
1280
1273
  **Add a syndicate**: create `config/agents/<name>.yaml` — copy the
@@ -1286,17 +1279,16 @@ closest starter-pack file from `config/agents/examples/` or start from
1286
1279
  **Add a tool**: write a `defineTool` contract in `lib/tools/` (name,
1287
1280
  description, zod schema, execute), register the name in
1288
1281
  `lib/toolRegistry.ts` (or call `registerTool` from your own code),
1289
- 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
1290
1283
  `wiki/tools/tool-contracts.md`. The two image tools are the worked
1291
1284
  examples — including why binary data forces function tools over
1292
1285
  subagents, and how a tool signature can enforce an epistemic rule (the
1293
1286
  blind inventory).
1294
1287
 
1295
1288
  **Add a provider**: follow `claudeAdapter.ts` (SDK-based, key-gated, a
1296
- `ModelAdapter` on the engine's model contract, run under ADK by its shim
1297
- `claudeLlm.ts`) or, for a chat-completions API, `ollamaAdapter.ts`
1298
- (fetch-based, keyless: a `ChatCompletionsAdapter` subclass, run under ADK
1299
- 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.
1300
1292
 
1301
1293
  **Point an agent at an MCP server**: set `mcp_server_url:` on a
1302
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,22 +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 only for MELCHIZEDEK_RUNTIME=adk
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 { InProcessSessionService, asAdkSessionService, loadSyndicate, registerAvailableProviders, runSyndicateTurn } from 'melchizedek-agents';
190
+ import { InProcessSessionService, loadSyndicate, logProviderStatuses, runSyndicateTurn } from 'melchizedek-agents';
190
191
 
191
- registerAvailableProviders(); // registers every model whose key is present
192
+ logProviderStatuses(console.log); // reports which providers have a key
192
193
  const config = loadSyndicate('mine.yaml'); // reads <your-repo>/config/agents/mine.yaml
193
194
 
194
195
  const result = await runSyndicateTurn({
195
196
  config,
196
197
  parts: [{ text: 'Hello' }],
197
198
  appName: 'my-app', userId: 'u1', sessionId: 'c1',
198
- sessionService: asAdkSessionService(new InProcessSessionService()),
199
+ sessionService: new InProcessSessionService(),
199
200
  });
200
201
  console.log(result.text);
201
202
  ```
@@ -222,10 +223,10 @@ console.log(result.text);
222
223
  - Deeper imports are available as subpaths — `melchizedek-agents/models/registry`,
223
224
  `melchizedek-agents/tools/webExtractTool`, `melchizedek-agents/memory`,
224
225
  and friends — all typed.
225
- - **Native by default; ADK optional.** Since 0.20.0 every turn runs on the
226
- engine's own loop. `@google/adk` is an optional peer: install it
227
- (`npm install @google/adk@~2.2.0`) and set `MELCHIZEDEK_RUNTIME=adk` to
228
- run on ADK, which 1.0.0 removes; your app then owns the ADK version.
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).
229
230
  `npx melchizedek-doctor` prints which runtime is in use.
230
231
  - **Your coding agent can learn all of this.** The package ships a
231
232
  six-skill suite (`skills/`, the open SKILL.md standard) covering the