melchizedek-agents 0.15.0 → 0.16.1

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