melchizedek-agents 0.9.6 → 0.16.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 (246) hide show
  1. package/.env.example +272 -0
  2. package/AGENT_SETUP.md +39 -23
  3. package/CHANGELOG.md +623 -0
  4. package/DOCUMENTATION.md +429 -109
  5. package/QUICKSTART.md +92 -18
  6. package/README.md +45 -5
  7. package/config/agents/README.md +46 -1
  8. package/config/agents/examples/ares.yaml +117 -40
  9. package/config/agents/examples/assistant.yaml +159 -0
  10. package/config/agents/examples/augustin.yaml +154 -51
  11. package/config/agents/examples/cartographers.yaml +91 -23
  12. package/config/agents/examples/claude.yaml +45 -6
  13. package/config/agents/examples/council.yaml +23 -8
  14. package/config/agents/examples/critic.yaml +57 -21
  15. package/config/agents/examples/delegation.yaml +76 -9
  16. package/config/agents/examples/hierarchical.yaml +55 -8
  17. package/config/agents/examples/image_production.yaml +54 -16
  18. package/config/agents/examples/librarian.yaml +70 -14
  19. package/config/agents/examples/model_zoo.yaml +105 -29
  20. package/config/agents/examples/patient_advocate.yaml +102 -34
  21. package/config/agents/examples/research.yaml +250 -0
  22. package/config/agents/examples/scribe.yaml +242 -0
  23. package/config/agents/examples/scriptorium.yaml +87 -24
  24. package/config/agents/examples/style_council.yaml +31 -9
  25. package/config/agents/examples/syndicate.yaml +29 -10
  26. package/config/agents/examples/tutor.yaml +10 -3
  27. package/config/agents/syndicateSchema.yaml +44 -9
  28. package/config/agents/templates/README.md +58 -0
  29. package/config/agents/templates/account_memory.yaml +153 -0
  30. package/config/agents/templates/case_desk.yaml +188 -0
  31. package/config/agents/templates/conversational.yaml +110 -0
  32. package/config/agents/templates/draft_review.yaml +130 -0
  33. package/config/agents/templates/intake_extractor.yaml +152 -0
  34. package/config/agents/templates/research_brief.yaml +169 -0
  35. package/config/agents/templates/research_desk.yaml +152 -0
  36. package/config/agents/templates/review_panel.yaml +188 -0
  37. package/config/agents/templates/support_triage.yaml +273 -0
  38. package/config/agents/templates/systems_operator.yaml +157 -0
  39. package/db/hardening.sql +202 -0
  40. package/db/memory_v2.sql +77 -0
  41. package/db/migrations/0001_base.sql +167 -0
  42. package/db/migrations/0002_erase_scope.sql +172 -0
  43. package/db/migrations/0003_postgres_storage.sql +58 -0
  44. package/db/migrations/0004_usage.sql +94 -0
  45. package/db/migrations/0005_agent_registry.sql +200 -0
  46. package/db/migrations/0006_task_leases.sql +25 -0
  47. package/db/migrations/0007_memory_commit.sql +134 -0
  48. package/db/migrations/0008_memory_retention.sql +37 -0
  49. package/db/migrations/0009_task_queue.sql +51 -0
  50. package/db/migrations/0010_erase_complete.sql +180 -0
  51. package/db/telemetry.sql +401 -0
  52. package/demo/README.md +77 -0
  53. package/demo/a2a_demo.mjs +95 -0
  54. package/dist/lib/a2a/app.d.ts +253 -0
  55. package/dist/lib/a2a/app.js +751 -0
  56. package/dist/lib/a2a/executor.d.ts +167 -0
  57. package/dist/lib/a2a/executor.js +548 -0
  58. package/dist/lib/a2a/identity.d.ts +122 -0
  59. package/dist/lib/a2a/identity.js +254 -0
  60. package/dist/lib/a2a/policy.d.ts +110 -0
  61. package/dist/lib/a2a/policy.js +178 -0
  62. package/dist/lib/a2a/redisLimits.d.ts +26 -0
  63. package/dist/lib/a2a/redisLimits.js +31 -0
  64. package/dist/lib/a2a/remoteAgent.d.ts +91 -0
  65. package/dist/lib/a2a/remoteAgent.js +268 -0
  66. package/dist/lib/a2a/turnLock.d.ts +28 -0
  67. package/dist/lib/a2a/turnLock.js +76 -0
  68. package/dist/lib/compile.d.ts +11 -1
  69. package/dist/lib/compile.js +109 -8
  70. package/dist/lib/config.d.ts +7 -7
  71. package/dist/lib/config.js +7 -7
  72. package/dist/lib/doctor.d.ts +145 -0
  73. package/dist/lib/doctor.js +517 -0
  74. package/dist/lib/grounding.d.ts +2 -2
  75. package/dist/lib/grounding.js +2 -2
  76. package/dist/lib/guards/index.d.ts +37 -0
  77. package/dist/lib/guards/index.js +66 -0
  78. package/dist/lib/guards/science.d.ts +117 -0
  79. package/dist/lib/guards/science.js +444 -0
  80. package/dist/lib/index.d.ts +37 -2
  81. package/dist/lib/index.js +35 -4
  82. package/dist/lib/loadEnv.d.ts +23 -11
  83. package/dist/lib/loadEnv.js +77 -29
  84. package/dist/lib/loadSyndicate.d.ts +97 -5
  85. package/dist/lib/loadSyndicate.js +176 -76
  86. package/dist/lib/memory/erase.d.ts +24 -0
  87. package/dist/lib/memory/erase.js +47 -0
  88. package/dist/lib/memory/namespace.d.ts +37 -0
  89. package/dist/lib/memory/namespace.js +74 -0
  90. package/dist/lib/memory/providers.d.ts +99 -0
  91. package/dist/lib/memory/providers.js +240 -0
  92. package/dist/lib/memory/store.d.ts +74 -0
  93. package/dist/lib/memory/store.js +108 -0
  94. package/dist/lib/memory/supabaseMemoryService.d.ts +69 -9
  95. package/dist/lib/memory/supabaseMemoryService.js +239 -125
  96. package/dist/lib/models/capabilities.d.ts +103 -0
  97. package/dist/lib/models/capabilities.js +291 -0
  98. package/dist/lib/models/claudeLlm.d.ts +10 -1
  99. package/dist/lib/models/claudeLlm.js +57 -27
  100. package/dist/lib/models/endpoints.d.ts +100 -0
  101. package/dist/lib/models/endpoints.js +282 -0
  102. package/dist/lib/models/gateway.d.ts +107 -0
  103. package/dist/lib/models/gateway.js +157 -0
  104. package/dist/lib/models/gatewayLlm.d.ts +57 -0
  105. package/dist/lib/models/gatewayLlm.js +105 -0
  106. package/dist/lib/models/gptLlm.d.ts +51 -2
  107. package/dist/lib/models/gptLlm.js +169 -26
  108. package/dist/lib/models/grokLlm.d.ts +19 -10
  109. package/dist/lib/models/grokLlm.js +29 -14
  110. package/dist/lib/models/ollamaLlm.d.ts +26 -0
  111. package/dist/lib/models/ollamaLlm.js +43 -1
  112. package/dist/lib/models/openAiCompatibleLlm.d.ts +67 -2
  113. package/dist/lib/models/openAiCompatibleLlm.js +200 -37
  114. package/dist/lib/models/providerMap.js +9 -2
  115. package/dist/lib/models/registry.d.ts +42 -5
  116. package/dist/lib/models/registry.js +140 -29
  117. package/dist/lib/models/retry.d.ts +146 -0
  118. package/dist/lib/models/retry.js +305 -0
  119. package/dist/lib/models/schemaNormalize.d.ts +20 -0
  120. package/dist/lib/models/schemaNormalize.js +43 -0
  121. package/dist/lib/net/addressGuard.d.ts +60 -0
  122. package/dist/lib/net/addressGuard.js +216 -0
  123. package/dist/lib/observability/embeddings.d.ts +11 -2
  124. package/dist/lib/observability/embeddings.js +18 -14
  125. package/dist/lib/observability/metrics.d.ts +36 -0
  126. package/dist/lib/observability/metrics.js +86 -0
  127. package/dist/lib/observability/redact.d.ts +29 -0
  128. package/dist/lib/observability/redact.js +102 -0
  129. package/dist/lib/observability/supabaseSpanExporter.d.ts +2 -0
  130. package/dist/lib/observability/supabaseSpanExporter.js +22 -6
  131. package/dist/lib/observability/tracer.d.ts +10 -0
  132. package/dist/lib/observability/tracer.js +70 -3
  133. package/dist/lib/persistence/supabaseProvider.d.ts +11 -0
  134. package/dist/lib/persistence/supabaseProvider.js +32 -6
  135. package/dist/lib/registry.d.ts +87 -0
  136. package/dist/lib/registry.js +146 -0
  137. package/dist/lib/runtime/approvals.d.ts +44 -0
  138. package/dist/lib/runtime/approvals.js +67 -0
  139. package/dist/lib/runtime/syndicateTurn.d.ts +233 -0
  140. package/dist/lib/runtime/syndicateTurn.js +597 -0
  141. package/dist/lib/runtime/turnControl.d.ts +90 -0
  142. package/dist/lib/runtime/turnControl.js +131 -0
  143. package/dist/lib/session/supabaseSessionService.js +1 -1
  144. package/dist/lib/session/transcript.d.ts +9 -1
  145. package/dist/lib/session/transcript.js +15 -7
  146. package/dist/lib/skills.d.ts +50 -0
  147. package/dist/lib/skills.js +138 -0
  148. package/dist/lib/storage/postgres/index.d.ts +98 -0
  149. package/dist/lib/storage/postgres/index.js +146 -0
  150. package/dist/lib/storage/postgres/memoryStore.d.ts +11 -0
  151. package/dist/lib/storage/postgres/memoryStore.js +82 -0
  152. package/dist/lib/storage/postgres/sessionService.d.ts +51 -0
  153. package/dist/lib/storage/postgres/sessionService.js +225 -0
  154. package/dist/lib/storage/postgres/taskQueue.d.ts +22 -0
  155. package/dist/lib/storage/postgres/taskQueue.js +101 -0
  156. package/dist/lib/storage/postgres/taskStore.d.ts +55 -0
  157. package/dist/lib/storage/postgres/taskStore.js +168 -0
  158. package/dist/lib/storage/schema.d.ts +27 -0
  159. package/dist/lib/storage/schema.js +50 -0
  160. package/dist/lib/storage/schemaVersion.d.ts +25 -0
  161. package/dist/lib/storage/schemaVersion.js +46 -0
  162. package/dist/lib/syndicateSchema.d.ts +275 -0
  163. package/dist/lib/syndicateSchema.js +534 -0
  164. package/dist/lib/toolRegistry.d.ts +15 -0
  165. package/dist/lib/toolRegistry.js +59 -10
  166. package/dist/lib/tools/collectionsSearchTool.js +1 -1
  167. package/dist/lib/tools/mcpServe.d.ts +45 -0
  168. package/dist/lib/tools/mcpServe.js +88 -0
  169. package/dist/lib/tools/mcpToolFactory.d.ts +2 -0
  170. package/dist/lib/tools/mcpToolFactory.js +41 -21
  171. package/dist/lib/tools/science/corrections.d.ts +42 -0
  172. package/dist/lib/tools/science/corrections.js +115 -0
  173. package/dist/lib/tools/science/europepmc.d.ts +51 -0
  174. package/dist/lib/tools/science/europepmc.js +127 -0
  175. package/dist/lib/tools/science/http.d.ts +31 -0
  176. package/dist/lib/tools/science/http.js +104 -0
  177. package/dist/lib/tools/science/openalex.d.ts +30 -0
  178. package/dist/lib/tools/science/openalex.js +81 -0
  179. package/dist/lib/tools/science/trials.d.ts +58 -0
  180. package/dist/lib/tools/science/trials.js +203 -0
  181. package/dist/lib/tools/science/types.d.ts +69 -0
  182. package/dist/lib/tools/science/types.js +48 -0
  183. package/dist/lib/tools/scienceTools.d.ts +100 -0
  184. package/dist/lib/tools/scienceTools.js +277 -0
  185. package/dist/lib/tools/taskTools.d.ts +204 -0
  186. package/dist/lib/tools/taskTools.js +374 -0
  187. package/dist/lib/tools/toolContract.d.ts +17 -4
  188. package/dist/lib/tools/toolContract.js +13 -5
  189. package/dist/lib/tools/webExtractTool.d.ts +13 -10
  190. package/dist/lib/tools/webExtractTool.js +23 -55
  191. package/dist/lib/tools/webSearchTool.d.ts +2 -1
  192. package/dist/lib/tools/webSearchTool.js +4 -3
  193. package/dist/lib/tools/wikiTools.d.ts +2 -2
  194. package/dist/lib/tools/wikiTools.js +12 -12
  195. package/dist/lib/tools/xApiSearchTool.d.ts +194 -0
  196. package/dist/lib/tools/xApiSearchTool.js +583 -0
  197. package/dist/lib/tools/xSearchTool.js +1 -1
  198. package/dist/lib/wiki/agentRun.js +1 -1
  199. package/dist/lib/wiki/builder.js +21 -6
  200. package/dist/lib/wiki/dive.js +2 -2
  201. package/dist/lib/wiki/entities.d.ts +2 -2
  202. package/dist/lib/wiki/entities.js +7 -7
  203. package/dist/lib/wiki/extract.js +5 -1
  204. package/dist/lib/wiki/fill.js +5 -5
  205. package/dist/lib/wiki/format.d.ts +7 -5
  206. package/dist/lib/wiki/format.js +2 -2
  207. package/dist/lib/wiki/graph.js +2 -2
  208. package/dist/lib/wiki/lint.js +2 -2
  209. package/dist/lib/wiki/markdown.d.ts +1 -1
  210. package/dist/lib/wiki/markdown.js +6 -1
  211. package/dist/lib/wiki/pipeline.js +2 -2
  212. package/dist/lib/wiki/vault.js +2 -2
  213. package/dist/scripts/a2a_server.d.ts +17 -11
  214. package/dist/scripts/a2a_server.js +405 -1028
  215. package/dist/scripts/assistant_worker.d.ts +33 -0
  216. package/dist/scripts/assistant_worker.js +193 -0
  217. package/dist/scripts/db.d.ts +26 -0
  218. package/dist/scripts/db.js +179 -0
  219. package/dist/scripts/doctor.d.ts +23 -0
  220. package/dist/scripts/doctor.js +90 -0
  221. package/dist/scripts/init.d.ts +43 -0
  222. package/dist/scripts/init.js +152 -0
  223. package/dist/scripts/registry.d.ts +25 -0
  224. package/dist/scripts/registry.js +182 -0
  225. package/dist/scripts/skills_install.d.ts +7 -0
  226. package/dist/scripts/skills_install.js +137 -0
  227. package/dist/scripts/syndicate_chat.js +159 -276
  228. package/package.json +90 -16
  229. package/skills/README.md +74 -0
  230. package/skills/briefs/README.md +16 -0
  231. package/skills/briefs/_shared.md +16 -0
  232. package/skills/briefs/melchizedek-author.md +60 -0
  233. package/skills/briefs/melchizedek-memory.md +47 -0
  234. package/skills/briefs/melchizedek-models.md +47 -0
  235. package/skills/briefs/melchizedek-scribe.md +37 -0
  236. package/skills/briefs/melchizedek-serve.md +56 -0
  237. package/skills/briefs/melchizedek.md +69 -0
  238. package/skills/briefs/skills-readme.md +33 -0
  239. package/skills/melchizedek/SKILL.md +159 -0
  240. package/skills/melchizedek-author/SKILL.md +99 -0
  241. package/skills/melchizedek-author/templates/minimal.yaml +60 -0
  242. package/skills/melchizedek-memory/SKILL.md +138 -0
  243. package/skills/melchizedek-models/SKILL.md +137 -0
  244. package/skills/melchizedek-scribe/SKILL.md +72 -0
  245. package/skills/melchizedek-scribe/templates/brief.md +27 -0
  246. package/skills/melchizedek-serve/SKILL.md +119 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,623 @@
1
+ # Changelog — melchizedek-agents (the npm package)
2
+
3
+ Consumers of the package read this file; it records changes to the
4
+ **published API surface** (the exports map in `package.json`, the bins,
5
+ the starter pack and the templates), not the repo's full history.
6
+
7
+ ## 0.16.0 — 2026-10-02
8
+
9
+ ### Breaking — read before upgrading
10
+
11
+ - **The server refuses to start on a database behind its migrations.** With
12
+ durable storage it reads `melchizedek_schema_version` at boot; below the
13
+ highest migration this release ships (0010), it stops and names
14
+ `npx melchizedek-db apply`. `ALLOW_SCHEMA_MISMATCH=true` starts anyway. A
15
+ newer database only warns. supabase-js storage now logs its deprecation
16
+ (ADR 0021); set `DATABASE_URL` to move to `postgresStorage`.
17
+ - **The default Gemini model is `gemini-3.5-flash-lite`** (was
18
+ `gemini-3.1-flash-lite`): `DEFAULT_GEMINI_MODEL` in `lib/config.ts`, and every
19
+ starter-pack, template and schema example that named the old id. An agent
20
+ that omits `model:` now runs on 3.5 Flash Lite; pin the old id in the YAML
21
+ to keep it.
22
+ - **`@google/adk` peer is now `^2.2.0`** (was `^1.3.0`), and `@google/genai`
23
+ is `2.25.0`. Install `@google/adk@2.2.0` beside the package. ADK and genai
24
+ now share one genai copy, and ADK's database drivers and GCP exporters are
25
+ optional peers, so the install is about 40% smaller.
26
+ - **The A2A server's key mode defaults to `server`.** The server's own
27
+ provider keys pay; `X-API-Key` is no longer required; sessions and memory
28
+ are stored under `X-User-Id` (else `default`). The old behaviour — the
29
+ caller's `X-API-Key` pays and its hash scopes the data — is
30
+ `A2A_KEY_MODE=byok` (`keyMode: 'byok'`). **A deployment holding data
31
+ written by an earlier version must set `byok`, or that data is no longer
32
+ found.**
33
+ - **A bare agent id is a file.** `/<agentId>/…` loads `<agentId>.yaml` from
34
+ your agents directory. The registry answers only `registry:<id>`, or bare
35
+ ids listed in `A2A_REGISTRY_AGENTS`; a registry miss is a 404 and a
36
+ registry failure a 503, never a silent fallback to the file. The shipped
37
+ `examples/` and `templates/` answer only ids listed in `A2A_SERVED_AGENTS`.
38
+ - **Syndicate YAML is validated at load.** Unknown keys, an invalid
39
+ `memory_system`, a
40
+ `dispatch.default_route` naming no subagent, and similar mistakes now
41
+ throw one error listing every problem with its key path and a did-you-mean
42
+ suggestion. They used to load and fail later, or silently. `subagents:`
43
+ may be omitted for a single-agent syndicate; it reads as `[]`.
44
+ - **`runSyndicateTurn` registers the framework's model adapters** when the
45
+ caller passes no `compile.resolveModel`, so `max_steps` and cancellation
46
+ hold for a string model id too (ADK's own Gemini class bypassed both).
47
+ - **The agent card is A2A 1.0** (`supportedInterfaces`), served to 0.3
48
+ clients in the 0.3 shape; requests in either version work
49
+ (`@a2a-js/sdk` 1.3 with 0.3 compatibility). File parts are rejected
50
+ (`rejected` state) instead of arriving as empty text.
51
+ - **Without `A2A_SERVER_SECRET` the server binds 127.0.0.1.** Binding another
52
+ `HOST` needs the secret or `ALLOW_UNAUTHENTICATED=true`; the `.env.example`
53
+ placeholder is refused as a secret.
54
+ - **The server no longer prints conversation content** (`[OTEL_SPAN_JSON]`
55
+ lines) unless `OTEL_CONSOLE_SPANS=true`.
56
+ - **Node `>=22.6`** (type stripping); production runs the compiled bins.
57
+ - **`POST /v1/x-packet` and `lib/tools/xPacket.ts` left the engine.** They
58
+ were one deployment's route. Mount your own routes with `routes`, or with
59
+ `startServer(name, { routes })` from the new `melchizedek-agents/server`.
60
+
61
+ ### The engine as a library
62
+
63
+ - **`runSyndicateTurn(options)`** — the one turn runner. The server, the
64
+ CLI, the worker and the eval harness all call it, so plan-dispatch,
65
+ delegation, nested syndicates, guards and the step cap behave the same
66
+ everywhere (the CLI used to run dispatch syndicates in delegate mode).
67
+ Plain data in and out; also `ingestTurnMemory`, `compileGraph`,
68
+ `compileSubagent`.
69
+ - **`createA2AApp(options)`** — the A2A server as a mountable Express app,
70
+ with plug points: `resolveRequest` (your identity system returns the
71
+ scope key), `keyMode`, `credentials` (a provider key per request from your
72
+ secret manager), `storage` (sessions, memory, task store, erase),
73
+ `memory` (extractor, embedder), `routes`, limits. `melchizedek-serve` is a
74
+ thin bin over it.
75
+ - **`registerTool(name, tool)` and `registerGuard(guard)`** — extend what a
76
+ YAML can name, from your own code.
77
+ - **Root exports** now include the capability and gateway helpers the 0.12.0
78
+ entry listed (`describeCapabilities`, `capabilitySummary`, `planTransport`,
79
+ `gatewayConfig`, `gatewayProblem`, `gatewayUsable`, `GATEWAYS`,
80
+ `GatewayLlm`), `validateSyndicateConfig`, `syndicateJsonSchema`, the
81
+ memory providers, `eraseScope` and `namespacedMemoryService`. New subpaths:
82
+ `./compile`, `./runtime`, `./runtime/turnControl`, `./a2a`, `./a2a/remote`,
83
+ `./guards`.
84
+
85
+ ### Fixed — behaviour the docs promised
86
+
87
+ - **The Postgres turn lock works with the server's keys.** It hashed the
88
+ key with Postgres' `hashtextextended`, and the server's keys are joined
89
+ with NUL separators, which Postgres text rejects: with `DATABASE_URL` set,
90
+ every A2A turn failed taking its lock. Keys are now hashed in Node to a
91
+ 64-bit advisory-lock id.
92
+ - **Moving to `DATABASE_URL` keeps conversation history.** The Supabase
93
+ session service stores events as a JSON array on `adk_sessions`; the
94
+ Postgres adapter stores rows, and read none of the array, so following the
95
+ deprecation notice cut every conversation off from its history (and shifted
96
+ memory ingestion's event counts). The first read or append of such a
97
+ conversation now copies its array into rows, once, in order; the array
98
+ stays, so moving back still works.
99
+ - **Erase reaches every store** (migration `0010_erase_complete.sql`).
100
+ `DELETE /memory` and `erase()` left the memory ingestion markers (scope key
101
+ and conversation ids) and the task tools' list and jobs behind; they are now
102
+ deleted too and reported as `memory_markers` and `task_tools`. A namespace
103
+ erase keeps the task list, which belongs to the caller.
104
+ **`npx melchizedek-db apply`** before upgrading.
105
+ - **Non-Gemini orchestrators delegate.** Claude, GPT, Grok, Ollama and
106
+ gateway adapters sent every subagent (and `load_memory`) an empty
107
+ parameter schema; they now send the tool's real declaration.
108
+ - **`max_steps` is enforced**, across the whole turn — orchestrator,
109
+ subagents and nested syndicates share one budget — and exceeding it fails
110
+ the turn with `STEP_LIMIT`. It was passed to a parameter ADK does not have.
111
+ - **`includeContents`, `outputKey`, `globalInstruction`,
112
+ `disallowTransferToParent`, `disallowTransferToPeers`** reach ADK; they
113
+ were parsed and dropped.
114
+ - **`tasks/cancel` cancels**, including the model call in flight; every task
115
+ has a deadline (`A2A_TASK_TIMEOUT_MS`, default 15 minutes).
116
+ - **Per-agent cards advertise their own URLs**, declare their security
117
+ schemes, and are readable without a model key; without `PUBLIC_URL` the
118
+ card uses the host the request reached.
119
+ - **`memory_system: internal-only` keeps transcripts in process memory on the
120
+ server**, as documented.
121
+ - **Memory ingestion is at-least-once**: a failed extraction, embedding or
122
+ insert leaves the turns pending for the next task instead of dropping them.
123
+ - **`.env.example` ships no placeholder values**, and the loader ignores
124
+ `your_..._here` values: copying the template no longer crashes the
125
+ quickstart, funds no provider in the doctor, and cannot become a live
126
+ secret. Installed bins read `.env` from the directory you run them in.
127
+ - **SSRF guard** (`web_extract`, MCP clients, remote A2A agents): one
128
+ implementation that parses every IP encoding the URL parser emits
129
+ (IPv4-mapped, NAT64, 6to4, trailing-dot names) and resolves names, refusing
130
+ any that resolve to a non-public address.
131
+ - **Transient provider failures are retried** on Gemini and the
132
+ chat-completions path (Ollama, gateways): 408/409/425/429/5xx and connection
133
+ resets, jittered backoff, `Retry-After` honoured, never after output has
134
+ started (`MODEL_RETRY_MAX_ATTEMPTS`). Grok's per-attempt timeout is 10
135
+ minutes (`XAI_TIMEOUT_MS`).
136
+ - **`db/hardening.sql` revokes function execution from `PUBLIC`**, so the
137
+ anon key cannot call `SECURITY DEFINER` functions. **Re-run it.**
138
+ - **A thinking model that runs out of room says so instead of answering
139
+ empty.** On the chat-completions path (Ollama, gateways) a turn that ends
140
+ with reasoning but no reply now yields `<PROVIDER>_MAX_TOKENS` when
141
+ `finish_reason` is `length` (the reply never started), or
142
+ `<PROVIDER>_EMPTY_RESPONSE` when the model stopped after thinking. Before,
143
+ ADK dropped the empty final, logged "The last event is partial", and the
144
+ turn returned empty text while still billing the thinking tokens. On Ollama
145
+ the cause is usually its 4,096-token context window, which `/v1` cannot
146
+ raise (`num_ctx` is ignored); the error names the remedies. A `<think>`
147
+ block that never closed is scratchpad, never reply text, and a reply cut
148
+ short keeps its text with `finishReason: MAX_TOKENS`.
149
+ The `model_zoo` example's `qwen_local` agent sets
150
+ `generateContentConfig.reasoningEffort: "none"`, so `npm run demo:models`
151
+ gets an answer from the local model (ADR 0027).
152
+
153
+ ### New
154
+
155
+ - **A local model that thinks without answering is retried once with
156
+ thinking off** (ADR 0027). An Ollama turn that ends in `OLLAMA_MAX_TOKENS`
157
+ (the context window filled while thinking) or `OLLAMA_EMPTY_RESPONSE` is
158
+ sent again with `reasoning_effort: "none"`; the named error reaches the
159
+ caller only if that fails too. Both attempts' tokens are counted. Skipped
160
+ for an agent already running with `reasoningEffort: "none"`; off with
161
+ `OLLAMA_RETRY_WITHOUT_THINKING=false`.
162
+ - The comment on `adk_session_events.ts` now says milliseconds (ADK's
163
+ `Date.now()`), which is what it has always held.
164
+ - **Pool sizes for the server** (ADR 0021). `DATABASE_POOL_MAX` (default 10)
165
+ and `A2A_TURN_LOCK_POOL_MAX` (default 20) bound the connections one
166
+ instance opens, so it fits a session-mode pooler's client limit.
167
+ - **Approval gates** (ADR 0028). `require_approval: [tool]` on an agent makes
168
+ that tool run only after a person approves the exact call: the A2A task
169
+ ends `input-required` with the pending call (text and an
170
+ `approval_request` data part), and `approve` / `reject` (or
171
+ `{ approval: { id, approved } }`) on the conversation resumes it. Allowed on
172
+ the orchestrator and plan-dispatch routes. `runSyndicateTurn` returns
173
+ `status: 'input-required'` with `approval`; `approvalResponsePart` answers
174
+ it. Stored function-call parts now keep Gemini's
175
+ `skip_thought_signature_validator` signature instead of none.
176
+ - **Cloud platforms and proxies** (ADR 0023). `GEMINI_PLATFORM=vertex`,
177
+ `ANTHROPIC_PLATFORM=bedrock|vertex` and `OPENAI_PLATFORM=azure` reach the
178
+ provider through Vertex AI, Bedrock or Azure OpenAI with the cloud's own
179
+ credentials (Google ADC, the AWS chain, an Azure key or Entra ID);
180
+ `ANTHROPIC_BASE_URL` / `OPENAI_BASE_URL` put a proxy in front of the vendor
181
+ API; `<PROVIDER>_MODEL_MAP` maps ids to platform ids or deployments. The A2A
182
+ `credentials` plug point may return a partial endpoint as well as a key.
183
+ `@anthropic-ai/bedrock-sdk`, `@anthropic-ai/vertex-sdk` and `@azure/identity`
184
+ are optional peers. The doctor lists each configured endpoint. Native web
185
+ search is not sent on Bedrock, Claude-on-Vertex or Azure. Tested against
186
+ mocks only; not live-verified.
187
+ - **A private schema** (ADR 0021). `MELCHIZEDEK_DB_SCHEMA=melchizedek` (or
188
+ `melchizedek-db apply --schema melchizedek`) installs every table and
189
+ function into that schema instead of `public`, so a Supabase REST layer
190
+ never sees them; `postgresStorage({ schema })` (the bin reads the same
191
+ variable) points its connections there. The default stays `public`, so an
192
+ existing database needs nothing. A private schema requires `DATABASE_URL`
193
+ (supabase-js reaches only exposed schemas).
194
+ - **Rate limits across replicas** (ADR 0021). `A2A_REDIS_URL` (with the
195
+ optional `redis` package) counts the request limit and the failed-login
196
+ limit in Redis, one window for every replica; in code, `limitStore` with
197
+ `redisRateLimitStore({ command })` from `melchizedek-agents/a2a/limits`.
198
+ - **The task tools on Postgres** (migration `0009_task_queue.sql`). With
199
+ `DATABASE_URL`, the to-do list and job queue live in Postgres: each caller
200
+ has their own list (tool calls now carry their caller, `ToolCallContext`,
201
+ and the task tools file records under the scope key), and any number of
202
+ `melchizedek-worker`s claim jobs with `FOR UPDATE SKIP LOCKED` under a
203
+ renewed lease. The JSON file stays the default. `setTaskBackend()` plugs
204
+ in any other store.
205
+ - **Per-syndicate memory settings** (ADR 0020). `memory_extraction_model`
206
+ picks the model that distils a syndicate's turns (default
207
+ `MEMORY_EXTRACTION_MODEL`); `memory_retention_days` deletes facts in the
208
+ syndicate's own `memory_namespace` older than the window, when the server
209
+ loads it and daily after (migration `0008_memory_retention.sql`).
210
+ - **Memory ingestion commits as one unit** (migration
211
+ `0007_memory_commit.sql`, ADR 0020). New facts, the rows they supersede
212
+ and the session's processed marker are written in one transaction
213
+ (`melchizedek_memory_commit`); the marker is stored, so a restart never
214
+ re-extracts a turn. The server refuses to start when the embedder's
215
+ dimension differs from the stored column. **`npx melchizedek-db apply`.**
216
+ - **A task whose server died is failed, not stuck** (migration
217
+ `0006_task_leases.sql`, Postgres storage). A running task is leased to the
218
+ instance running it and renewed on a heartbeat; when the lease expires
219
+ another instance marks it `failed` with a message saying the server
220
+ stopped. Apply the migration (`npx melchizedek-db apply`); the boot check
221
+ requires it.
222
+ - **One turn at a time per conversation.** A second message on a
223
+ conversation whose turn is still running waits for it (up to
224
+ `A2A_TURN_LOCK_WAIT_MS`, default 30 s) and runs after it, seeing its
225
+ exchange; past the wait it is `rejected` ("still running"). In-process by
226
+ default; with `DATABASE_URL`, a Postgres advisory lock shared by every
227
+ instance (`postgresStorage().turnLock`, its own pool, `lockPoolMax`).
228
+ - **Token streaming on `message/stream`** (`A2A_STREAM_TEXT=true`,
229
+ `streamText` in `createA2AApp`). The answer arrives as chunks of an
230
+ `answer` artifact as the model writes it; narration before a tool call is
231
+ withdrawn, and the artifact is closed with the text the user receives
232
+ (relay fallback and dispatch included). A syndicate with guards never
233
+ streams. Off by default; the final status message is unchanged. The
234
+ runtime exposes the same as `TurnEvents.onTextDelta` / `onTextReset`.
235
+ - **A versioned agent registry** (migration `0005_agent_registry.sql`, ADR
236
+ 0018). Every definition an id has held is kept in an append-only
237
+ `adk_agent_registry_versions`, with its author, note and config hash, and
238
+ the database records a version on every write to the active row, whoever
239
+ writes it. `npx melchizedek-registry publish|versions|show|diff|rollback|retire`
240
+ (library: `melchizedek-agents/registry`) validates before it writes;
241
+ rollback re-activates a stored version. `registry:<id>@<version>` loads one
242
+ version. Existing rows become version 1 when the migration runs:
243
+ **`npx melchizedek-db apply`** to install it. A syndicate is versioned as a
244
+ unit: `publish` (and `publishAgent`) stores every nested `yaml_reference` it
245
+ reaches under `bundled_references`, and the server loads that version's
246
+ nested syndicates from the bundle, not from files (`--no-bundle` /
247
+ `bundle: false` opts out). Republish a nesting syndicate after changing a
248
+ nested file.
249
+ - **The source moved to [github.com/jhwadman/melch-ai](https://github.com/jhwadman/melch-ai).**
250
+ The package name stays `melchizedek-agents`; `repository`, `homepage` and
251
+ `bugs` point at the new repository, which now holds the engine, its tests
252
+ and its wiki directly. `npx skills add jhwadman/melch-ai` installs the skills.
253
+ - **Built-in authenticators** (`melchizedek-agents/a2a/identity`, ADR
254
+ 0025), chosen in the bin with `A2A_AUTH`:
255
+ - `callers`: one bearer token per calling backend. `A2A_CALLERS` holds
256
+ `name:sha256[:scope]`, so the config stores only token hashes. A caller
257
+ owns a scope that does not depend on any model key, so rotating a
258
+ provider key no longer strands sessions and memory. Mint a caller with
259
+ `melchizedek-serve --new-caller <name> [--scope s] [--token-file f]`. A
260
+ still-set `A2A_SERVER_SECRET` keeps working beside the tokens with its
261
+ old scoping, so callers move over one at a time; give a caller its
262
+ existing `a2a-<hash>` silo as its scope and no data moves.
263
+ - `jwt`: your identity provider's tokens, verified with `jose` (JWKS or
264
+ HS256; issuer, audience and expiry required); the scope is the user
265
+ claim, optionally under a tenant claim.
266
+ - `header`: a trusted user header from an authenticating gateway, accepted
267
+ only together with the server secret.
268
+ - In code: `createA2AApp({ ...callerTokens(parseCallers(spec)) })`, or
269
+ `jwtIdentity`, `trustedHeader`, `sharedSecret`, `firstOf`.
270
+ - `RequestIdentity.operator` marks an operator-issued credential (a caller
271
+ token, the server secret); an adopter route reads it through
272
+ `currentRequestContext()` to refuse end users (a JWT, a gateway identity).
273
+ - **Governance** (ADR 0026):
274
+ - `runSyndicateTurn` returns `usage`: model calls plus input, output and
275
+ thinking tokens, summed over every agent in the turn.
276
+ - Budgets: `policy: budgets(config)` (env `A2A_BUDGETS`) sets daily limits per
277
+ caller and per scope on tasks, calls and tokens; a task over budget ends
278
+ `rejected` with the reason. Counters: `memoryUsageStore`,
279
+ `postgresUsageStore`, `supabaseUsageStore` (table from
280
+ `db/migrations/0004_usage.sql`).
281
+ - `onTaskEnd` gives one `TaskRecord` per task; `A2A_LOG_FORMAT=json` makes
282
+ every server line JSON.
283
+ - `GET /metrics` serves Prometheus text behind `A2A_METRICS_TOKEN`
284
+ (`createMetrics`).
285
+ - With an authenticator, the rate limit counts per caller or per scope
286
+ instead of per IP.
287
+ - The telemetry ledger is redacted before it is written: key-shaped
288
+ credentials by default (`TELEMETRY_REDACT`), emails, phones, cards and SSNs
289
+ on request, or your own `setTelemetryRedactor`.
290
+ - **`keyMode: 'byok'` now holds under any authenticator**: the caller's
291
+ `X-API-Key` pays whoever the caller is. A `resolveRequest` used to switch
292
+ BYOK billing off. The key-hash scope applies only without an authenticator.
293
+ - **Remote agents: `a2a_agent_url:` on a subagent** — an agent served over
294
+ A2A (1.0 or 0.3) becomes a delegation tool or a plan-dispatch route.
295
+ Credentials from `A2A_AGENT_TOKENS`; `ALLOW_PRIVATE_A2A` for local hosts.
296
+ - **`melchizedek-init`**: start a project from any template or example in one
297
+ command — writes `config/agents/<name>.yaml` (and what it nests) with a
298
+ schema modeline, gives a long-term syndicate its own `memory_namespace`,
299
+ creates `.env` from the template, and prints the next commands.
300
+ `--list` shows what ships.
301
+ - **Database tooling: `melchizedek-db print | apply | status |
302
+ prune-sessions`** over numbered, idempotent migrations in
303
+ `db/migrations/` (base schema, nightly session expiry, scope erasure), then
304
+ `hardening.sql`.
305
+ - **`DELETE /memory` erases everything stored for the calling scope** —
306
+ facts, sessions with their subagent rows, ledger rows — with per-store
307
+ counts; `?all=1` covers every memory namespace.
308
+ - **`memory_namespace`** (YAML): where a syndicate's long-term memory lives;
309
+ memory tools on subagents read the root syndicate's facts.
310
+ - **Memory providers**: extraction on any model id
311
+ (`MEMORY_EXTRACTION_MODEL`), embeddings from Gemini, OpenAI, Ollama or any
312
+ OpenAI-compatible endpoint (`MEMORY_EMBEDDING_*`).
313
+ - **Capability matrix** (`lib/models/capabilities.ts`): provider × delegation,
314
+ memory tools, structured output, thinking with tools, streaming, vision,
315
+ native search — each cell backed by a request-shape test;
316
+ `melchizedek-doctor --matrix` prints it and flags gaps per agent.
317
+ - **Server operations**: `/healthz`, `/readyz`, SIGTERM drain
318
+ (`A2A_SHUTDOWN_GRACE_MS`), a concurrency cap, configurable rate limits,
319
+ trust-proxy and body limit, a failed-login limiter, a boot summary.
320
+ - **Published JSON Schema** for syndicate YAML:
321
+ `config/agents/syndicate.schema.json` (editor modeline in
322
+ `syndicateSchema.yaml`).
323
+ - **Deploy artefacts**: `Dockerfile`, `compose.yaml` (optional Ollama and
324
+ Phoenix), CI, `SECURITY.md`.
325
+ - The package now ships `db/`, `demo/`, `.env.example` and this changelog,
326
+ and `package.json` names the repository.
327
+
328
+ ## 0.15.0 — 2026-09-27
329
+
330
+ - **Production templates: `config/agents/templates/`.** Ten job-shaped
331
+ syndicates built to be adapted and shipped, beside the starter pack that
332
+ teaches: `conversational` (a keyless conversational agent),
333
+ `support_triage` (plan-dispatch with a `handoff` fallback),
334
+ `research_brief` (three layers, nesting `research_desk`), `review_panel`
335
+ (ship, fix or hold a change), `draft_review` (a policy-checked loop), one
336
+ per memory tier (`intake_extractor`, `case_desk`, `account_memory`), and
337
+ `systems_operator` (your systems over MCP; read, plan, confirm, write).
338
+ The package now ships the directory; `templates/README.md` maps it, and
339
+ `npm run syndicate:conversational` runs the first.
340
+ - **The loader looks in `templates/` too.** A bare name resolves at the
341
+ agents root, then `examples/`, then `templates/`, so an A2A route
342
+ (`/support_triage/…`) and a nested `yaml_reference` find a template
343
+ without a path.
344
+ - **`web_extract` names where a redirect landed.** A URL that redirects (a
345
+ search engine's grounding link, for one) now carries a `Resolved:` line
346
+ with the final address, so a note can cite the publisher, not the
347
+ redirect. Output for a URL that did not redirect is unchanged.
348
+ - **The compile tier of `npm test` walks subdirectories.** It loaded only
349
+ the root before, which in this package meant the schema file alone; it
350
+ now compiles every shipped syndicate.
351
+
352
+ ## 0.14.0 — 2026-09-25
353
+
354
+ - **Starter pack: `assistant.yaml`, the Assistant.** The generic starting
355
+ point for your own agent, keyless (`ollama/qwen3:8b`): the orchestrator
356
+ converses, a Summarizer reads pasted text or up to five URLs
357
+ (`web_extract`), a task list outlives the conversation, and longer work is
358
+ queued as background jobs. `npm run syndicate:assistant`.
359
+ - **Five task tools.** `task_add`, `task_queue`, `task_list`, `task_get`,
360
+ `task_update` (`lib/tools/taskTools.ts`), registered by name in the tool
361
+ registry. One local JSON store for to-dos and jobs:
362
+ `MELCHIZEDEK_TASKS_FILE`, default `outputs/tasks.json`. Single-user by
363
+ design; do not serve them on a shared A2A endpoint.
364
+ - **`melchizedek-worker`: the background worker.** A fifth bin (and
365
+ `npm run assistant:worker`) claims queued jobs one at a time, runs each
366
+ through one agent compiled from YAML (default `--syndicate assistant
367
+ --agent Worker`; any syndicate and agent), and writes the result back for
368
+ `task_get`. `--once` drains the queue and exits (cron); otherwise it polls
369
+ (`--interval`, default 30 s). The tools only write the queue; they never
370
+ run a job.
371
+
372
+ ## 0.13.0 — 2026-09-24
373
+
374
+ - **Starter pack: `research.yaml`, Research.** Questions about clinical and
375
+ biomedical evidence, answered from trial registries and the peer-reviewed
376
+ literature. Plan-dispatch: a triage model names one of three routes
377
+ (`define`, `lookup`, `landscape`), and each route holds its own tools, so
378
+ every tool call is on the answering turn's stream. `guards: [science]`
379
+ marks any DOI, PMID or NCT number no tool returned, checks retractions, and
380
+ catches a trial acronym attached to the wrong identifier.
381
+ - **Seven science tools, keyless.** `search_literature`, `search_preprints`,
382
+ `search_trials`, `resolve_identifier`, `cited_by`, `survey_field`,
383
+ `check_retraction` (`lib/tools/scienceTools.ts`), reading Europe PMC,
384
+ ClinicalTrials.gov, Crossref and OpenAlex. Registered by name in the tool
385
+ registry, and served to MCP clients by `npm run mcp:science`
386
+ (`scripts/science_mcp_server.ts`, :8934). Set `SCIENCE_API_CONTACT` to an
387
+ address you read to join the sources' polite request pools.
388
+ - **The `science` guard** is now registered in `lib/guards/index.ts`.
389
+ - **`melchizedek-skills`: the framework as a skills suite.** A fourth bin
390
+ (and `npm run skills:install`) copies `skills/` — six Agent Skills in the
391
+ open SKILL.md standard — into the directories coding agents read:
392
+ `.claude/skills/` and `.agents/skills/` by default (between them, Claude
393
+ Code, Codex, Cursor, OpenCode and Gemini CLI), or `--for
394
+ claude,codex,cursor,opencode,gemini,agents,all`, `--global`, `--dir`,
395
+ `--only`, `--force`, `--dry-run`; `list` and `paths` subcommands. The
396
+ suite: `melchizedek` (where the syndicates are, what each costs, run one,
397
+ delegate a task from a coding agent), `melchizedek-author`,
398
+ `melchizedek-serve`, `melchizedek-memory`, `melchizedek-models`,
399
+ `melchizedek-scribe`. `skills` joins `files`; engine: `lib/skills.ts`.
400
+ - **Starter pack: `scribe.yaml`, The Scribe.** A Gemini syndicate that
401
+ writes one document from a technical brief and audits it against the
402
+ brief through a JSON-schema leaf (the Auditor) before returning it.
403
+ `npm run syndicate:scribe`. The skills suite above was written with it,
404
+ one brief per skill.
405
+
406
+ ## 0.12.0 — 2026-09-23
407
+
408
+ - **`melchizedek-doctor`: which keys do I need?** A third bin (and
409
+ `npm run doctor`) reads every syndicate YAML the loader can see, resolves
410
+ each agent's model to its provider under the current `.env`, and prints
411
+ one table — agent, model, provider, which declared server-side tools the
412
+ path keeps or drops, and whether the path is funded — with one verdict
413
+ per syndicate and the variables that would unlock the most. Read-only:
414
+ nothing is sent, nothing is written, no key value is printed. `--json`,
415
+ `--check`. Engine: `lib/doctor.ts`.
416
+ - **The gateway fallback (`lib/models/gatewayLlm.ts`, `lib/models/gateway.ts`).**
417
+ `MODEL_GATEWAY=vercel|openrouter` + `MODEL_GATEWAY_API_KEY` serve any
418
+ cloud model id whose direct key is ABSENT through that gateway's
419
+ OpenAI-compatible endpoint. Direct adapters stay canonical: a present
420
+ provider key always wins, Ollama never routes through a gateway, and a
421
+ BYOK `X-API-Key` on the A2A server never selects it. Attribution stays
422
+ with the upstream provider (`llm.provider`); the transport is recorded
423
+ separately (`llm.transport = gateway:<id>`). Optional dials:
424
+ `MODEL_GATEWAY_BASE_URL` (self-hosted proxy), `MODEL_GATEWAY_MODEL_MAP`
425
+ (wire-name overrides). `registerAvailableProviders()` registers the
426
+ stand-in for uncovered providers; `providerStatuses()` gains
427
+ `transport` and `gateway`; `resolveModel()` applies the same rule.
428
+ - **Capability report (`lib/models/capabilities.ts`).** `describeCapabilities`
429
+ states, per agent and on the RESOLVED path, which server-side tool
430
+ sentinels (`web_search`, `google_search`, `x_search`,
431
+ `collections_search`) run natively and which are dropped. The compiler
432
+ logs one `capability ·` line per affected agent; the chat-completions
433
+ base records `llm.transport` and `llm.capability.dropped` on the span.
434
+ New exports from the package root: `describeCapabilities`,
435
+ `capabilitySummary`, `planTransport`, `gatewayConfig`, `gatewayProblem`,
436
+ `gatewayUsable`, `GATEWAYS`, `GatewayLlm`.
437
+ - **Starter pack: `# tier:` headers.** Every example opens with `keyless`,
438
+ a single provider (`gemini`, `anthropic`), or `multi-provider`; the
439
+ doctor checks the claim against the models.
440
+
441
+ ## 0.11.0 — 2026-09-20
442
+
443
+ - **`x_api_search`: the X channel without a Grok dependency.** A new
444
+ client-side tool (`lib/tools/xApiSearchTool.ts`, registered in
445
+ `TOOL_MAP`) searches X's last seven days through the X API v2 recent
446
+ search and transcribes every PHOTO attached to a post through a Gemini
447
+ vision pass, pasted beneath the post. It runs on any provider and needs
448
+ `X_BEARER_TOKEN` (a read-only app token) plus the Gemini key the engine
449
+ already uses; without the token it reports itself unavailable to the
450
+ agent instead of failing the turn. The starter pack's `augustin.yaml`
451
+ moves its XResearcher onto it (`gemini-3.8-flash` + `x_api_search` +
452
+ `web_extract`), so the fact-checking arbiter no longer requires
453
+ `XAI_API_KEY`. `x_search` stays registered for grok-* agents that want
454
+ xAI's semantic ranker. Dials, all environment: `X_API_IMAGE_MAX`
455
+ (photos read per page, default 8), `X_API_MAX_RESULTS` (page ceiling,
456
+ default 50), `X_API_VISION_MODEL` (default `gemini-3.8-flash`).
457
+
458
+ ## 0.10.0 — 2026-09-09
459
+
460
+ - **Post-answer guards.** A syndicate YAML may now carry an optional
461
+ `guards:` list of guard NAMES, run after the answering turn and before
462
+ the reply is published. A guard receives the final text plus every
463
+ tool-result text of that turn and returns the text to ship along with
464
+ notes for the `[STATUS]` stream; it rewrites in place rather than
465
+ re-asking the model. Three shape changes to the published surface:
466
+
467
+ - `SyndicateYamlConfig` (`./loadSyndicate`) gains `guards?: string[]`.
468
+ Optional, so every existing config still typechecks.
469
+ - `./loadSyndicate` gains `collectGuards(config, loadNested?)`, which
470
+ returns the union of guard names declared by a syndicate **and by
471
+ every syndicate it nests through `yaml_reference:`**. Read guards
472
+ with this rather than off `config.guards`: a guard belongs to the
473
+ syndicate that declared it, not to the position it occupies in a
474
+ graph, and reading the top-level field alone silently dropped a
475
+ nested syndicate's guards.
476
+ - A new `lib/guards/index.ts` publishes the `Guard` / `GuardResult`
477
+ interfaces and `resolveGuards(names, onUnknown?)`. The registry ships
478
+ EMPTY — the guards this deployment runs are domain modules that stay
479
+ private, the same arrangement `lib/toolRegistry.ts` uses. Register
480
+ your own by adding it to that file's `GUARD_MAP`; an unregistered
481
+ name warns and is skipped rather than failing the run.
482
+
483
+ `config/agents/syndicateSchema.yaml` documents the field. No bin
484
+ changes; no existing export changes shape.
485
+
486
+ - **`lib/tools/mcpServe.ts` (new, internal).** The express/SSE scaffold
487
+ behind `npm run mcp:wiki` — `serveContracts({ name, label, port,
488
+ contracts })` — extracted from three byte-identical copies that had
489
+ begun to drift on error signalling and on whether they read `.env`.
490
+ Not in the exports map and not a bin, but it now ships because
491
+ `scripts/wiki/mcp_server.ts` imports it. Behaviour change for MCP
492
+ clients: a failed tool call is returned with the spec's `isError`
493
+ flag set instead of as an ordinary successful result, so a client can
494
+ tell "the tool answered" from "the tool failed".
495
+
496
+ ## 0.9.6 — 2026-09-02
497
+
498
+ - **`web_extract` joins the public tool registry.** The tool's source
499
+ (`lib/tools/webExtractTool.ts`) has shipped in the package since
500
+ 2026-08-09, but the sanitized `lib/toolRegistry.ts` never mapped the
501
+ YAML name, so `augustin.yaml`'s two researchers logged an unknown-tool
502
+ warning and ruled from search snippets. Declaring `web_extract` in a
503
+ syndicate now resolves to the client-side page reader on every
504
+ provider, local Ollama included. Additive: no export, bin, or starter
505
+ file changes shape.
506
+
507
+ ## 0.9.5 — 2026-09-02
508
+
509
+ - **The default production Gemini is now `gemini-3.8-flash`.** Two
510
+ exported constants change VALUE (not shape): `MEMORY_EXTRACTION_MODEL`
511
+ and `WIKI_AGENT_MODEL` in `lib/config.ts`, plus the internal
512
+ `VISION_MODEL` behind `inspect_image`. Every starter-pack syndicate
513
+ that shipped on `gemini-3.7-flash` now ships on `gemini-3.8-flash`.
514
+ The cheap tier is untouched: `DEFAULT_GEMINI_MODEL` stays
515
+ `gemini-3.1-flash-lite`, and `ares` / `model_zoo` keep their flash-lite
516
+ pins. Nothing in the exports map or the two bins changes.
517
+
518
+ The id was verified against the live endpoint before pinning:
519
+ `models/gemini-3.8-flash` publishes exactly 3.7's envelope —
520
+ 1,048,576 input, 65,536 output, `thinking: true`, identical
521
+ `supportedGenerationMethods` — so no `maxOutputTokens` in any shipped
522
+ YAML changes and none is an over-ask.
523
+
524
+ If you pin a model explicitly in your own YAML, nothing changes for
525
+ you. If you rely on the defaults and want the old behaviour, set
526
+ `WIKI_AGENT_MODEL=gemini-3.7-flash` (env) or pin `model:` in your
527
+ syndicate.
528
+
529
+ ## 0.9.4 — 2026-09-02
530
+
531
+ - **Thinking and replies stream live.** The OpenAI-compatible adapter
532
+ (Ollama, xAI) now honours ADK's `stream` flag instead of ignoring it:
533
+ it sends `stream: true`, parses the SSE frames, and yields each
534
+ reasoning and text delta as a display-only partial. `melchizedek-chat`
535
+ runs with `streamingMode: SSE`, so a local qwen3 turn shows its
536
+ scratchpad token by token from ~1.5s rather than dumping the whole
537
+ turn after ~15s. `CHAT_STREAMING=false` restores one-block output —
538
+ useful when piping a transcript or for structured-output agents.
539
+ Reasoning is read from a discrete `reasoning` / `reasoning_content`
540
+ delta field where the provider sends one (Ollama does), and otherwise
541
+ from inline `<think>` tags via a new exported `ThinkStreamSplitter`,
542
+ which tracks block state across frames so a tag split mid-delta
543
+ ("<thi" + "nk>") is not mistaken for reply text.
544
+ - **Fix: a streamed Claude turn no longer vanishes from session
545
+ history.** ADK's runner persists only NON-partial events, and the
546
+ Claude streaming path built its final response with the text omitted,
547
+ so a reply would render on screen and leave no record — the next turn
548
+ saw no assistant message. The final response now carries the full
549
+ text; printers skip text on a `turnComplete` event whose partials they
550
+ already rendered. This path was unreachable before this release, since
551
+ nothing requested SSE.
552
+ - **Chat is silent about telemetry.** `melchizedek-chat` and every
553
+ `syndicate:*` script no longer print `[OTEL_SPAN_JSON]` lines; set
554
+ `OTEL_CONSOLE_SPANS=true` (shell or `.env`) to see them, and
555
+ `OTEL_CONSOLE_SPANS=false` to silence them in other scripts. In-process
556
+ span listeners and the Supabase sink are unaffected either way, so no
557
+ telemetry is lost.
558
+
559
+ ## 0.9.3 — 2026-08-22
560
+
561
+ - **`outputSchema` is enforced on every provider, not just Gemini** —
562
+ the Claude adapter now carries an agent's `outputSchema` as a forced
563
+ tool call (`tool_choice` on a synthetic `structured_output` tool whose
564
+ `input_schema` is the schema) and turns the validated `tool_use` block
565
+ back into JSON text, so the keys arrive as declared instead of drifting
566
+ (`"grade"` for `"correctness"`); the OpenAI adapter sends
567
+ `json_schema` with `strict: true` over a schema where every object
568
+ forbids extra properties and requires all of its own
569
+ (`toStrictJsonSchema`), which the API previously rejected; the
570
+ OpenAI-compatible adapter (xAI) does the same, while Ollama keeps
571
+ `json_object`. Anything that reads structured fields by name — critic
572
+ loops, plan-dispatch routers on non-Gemini models, LLM judges — now
573
+ works across providers.
574
+ - **Engine additions behind the A2A server**: the shared YAML→ADK compiler
575
+ (`lib/compile.ts`), provenance stamps (`lib/observability/lineage.ts`),
576
+ embeddings (`lib/observability/embeddings.ts`), the three-tier
577
+ observability ledger in `db/telemetry.sql` with identity and
578
+ provenance on every span, and `scripts/telemetry_admin.ts`. New
579
+ optional dependency `@opentelemetry/exporter-trace-otlp-http` for
580
+ `OTEL_EXPORTER_OTLP_ENDPOINT`.
581
+
582
+ ## 0.9.2 — 2026-08-20
583
+
584
+ - **The starter pack gains Augustin** —
585
+ `config/agents/examples/augustin.yaml`, a fact-checking arbiter of
586
+ world events: a grok X-sweep researcher and a Gemini web-verification
587
+ researcher under a tool-free Arbiter that writes a conversational
588
+ lead plus sourced bullet facts. Multi-provider (needs `XAI_API_KEY`
589
+ and `GOOGLE_GENAI_API_KEY`); `npm run syndicate:augustin` in a clone.
590
+ The pattern is taught as a standalone lesson in the curriculum.
591
+
592
+ ## 0.9.1 — 2026-08-19
593
+
594
+ - **Fix: `melchizedek-serve` actually starts.** The run-as-main guard
595
+ compared `import.meta.url` to argv[1] literally; through the npm bin
596
+ symlink they never match, so the 0.9.0 bin imported everything and
597
+ exited silently. The guard now realpaths argv[1]. `melchizedek-chat`
598
+ was unaffected.
599
+ - `melchizedek-serve` without an argument now explains itself when no
600
+ `syndicate.yaml` exists (name your syndicate: `melchizedek-serve
601
+ <name>.yaml`) instead of failing with a bare ENOENT.
602
+ - QUICKSTART gains §7, the package-consumer path (docs ship in the
603
+ tarball, so they ride this release).
604
+
605
+ ## 0.9.0 — 2026-08-19
606
+
607
+ First packaged release (pre-1.0: the API may still move; 1.0.0 lands
608
+ after the first external consumer migration).
609
+
610
+ - The engine is installable: `npm install melchizedek-agents` ships
611
+ compiled JS + type declarations for `lib/` (`loadSyndicate`, the model
612
+ registry, the tool registry, memory/session/persistence/observability,
613
+ the wiki engine) behind an explicit subpath exports map.
614
+ - `loadSyndicate` accepts `agentsDir` (or the `MELCHIZEDEK_AGENTS_DIR`
615
+ env var) so your syndicates live in **your** repo; default remains
616
+ `<cwd>/config/agents`. The path jail applies relative to whichever
617
+ root is configured.
618
+ - Two bins: `melchizedek-serve` (the A2A server) and `melchizedek-chat`
619
+ (the interactive syndicate CLI).
620
+ - The starter pack ships in the package: `config/agents/examples/*.yaml`
621
+ plus `syndicateSchema.yaml` — copy them out, they are teaching
622
+ material, not wiring.
623
+ - `@google/adk` is a peer dependency: your app owns the ADK version.