melchizedek-agents 0.16.2 → 0.18.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.
- package/.env.example +40 -3
- package/AGENT_SETUP.md +4 -2
- package/CHANGELOG.md +246 -0
- package/DOCUMENTATION.md +311 -15
- package/QUICKSTART.md +2 -2
- package/README.md +125 -149
- package/config/agents/examples/harness.yaml +135 -0
- package/config/agents/examples/model_zoo.yaml +23 -9
- package/config/agents/examples/pipeline.yaml +120 -0
- package/config/agents/examples/specs/open-meteo-forecast.json +77 -0
- package/config/agents/examples/specs/open-meteo-geocoding.json +53 -0
- package/config/agents/examples/weather.yaml +59 -0
- package/config/agents/syndicateSchema.yaml +125 -1
- package/db/hardening.sql +4 -3
- package/db/migrations/0011_erase_expired.sql +198 -0
- package/db/migrations/0012_audit_log.sql +98 -0
- package/dist/lib/a2a/app.d.ts +27 -0
- package/dist/lib/a2a/app.js +101 -5
- package/dist/lib/a2a/executor.d.ts +34 -4
- package/dist/lib/a2a/executor.js +109 -9
- package/dist/lib/compile.d.ts +41 -3
- package/dist/lib/compile.js +162 -17
- package/dist/lib/config.d.ts +24 -0
- package/dist/lib/config.js +24 -0
- package/dist/lib/doctor.js +17 -4
- package/dist/lib/index.d.ts +2 -0
- package/dist/lib/index.js +1 -0
- package/dist/lib/loadEnv.d.ts +5 -0
- package/dist/lib/loadEnv.js +7 -0
- package/dist/lib/loadSyndicate.d.ts +50 -0
- package/dist/lib/loadSyndicate.js +19 -3
- package/dist/lib/memory/erase.d.ts +5 -0
- package/dist/lib/memory/erase.js +5 -0
- package/dist/lib/memory/providers.d.ts +27 -0
- package/dist/lib/memory/providers.js +28 -0
- package/dist/lib/models/capabilities.js +10 -0
- package/dist/lib/models/endpoints.d.ts +1 -1
- package/dist/lib/models/endpoints.js +4 -1
- package/dist/lib/models/fallback.d.ts +41 -0
- package/dist/lib/models/fallback.js +105 -0
- package/dist/lib/models/gateway.d.ts +2 -2
- package/dist/lib/models/gateway.js +4 -4
- package/dist/lib/models/kimiLlm.d.ts +123 -0
- package/dist/lib/models/kimiLlm.js +171 -0
- package/dist/lib/models/providerMap.d.ts +2 -2
- package/dist/lib/models/providerMap.js +4 -1
- package/dist/lib/models/registry.d.ts +1 -1
- package/dist/lib/models/registry.js +11 -3
- package/dist/lib/net/redirects.d.ts +14 -0
- package/dist/lib/net/redirects.js +94 -0
- package/dist/lib/observability/audit.d.ts +21 -0
- package/dist/lib/observability/audit.js +39 -0
- package/dist/lib/observability/metrics.d.ts +6 -0
- package/dist/lib/observability/tracer.d.ts +14 -1
- package/dist/lib/observability/tracer.js +16 -2
- package/dist/lib/persistence/supabaseProvider.d.ts +2 -6
- package/dist/lib/persistence/supabaseProvider.js +2 -31
- package/dist/lib/runtime/questions.d.ts +55 -0
- package/dist/lib/runtime/questions.js +107 -0
- package/dist/lib/runtime/syndicateTurn.d.ts +45 -5
- package/dist/lib/runtime/syndicateTurn.js +165 -17
- package/dist/lib/storage/postgres/index.d.ts +9 -0
- package/dist/lib/storage/postgres/index.js +13 -0
- package/dist/lib/storage/rlsStatus.d.ts +45 -0
- package/dist/lib/storage/rlsStatus.js +69 -0
- package/dist/lib/syndicateSchema.d.ts +177 -0
- package/dist/lib/syndicateSchema.js +343 -3
- package/dist/lib/toolRegistry.js +9 -0
- package/dist/lib/tools/mcpToolFactory.d.ts +26 -0
- package/dist/lib/tools/mcpToolFactory.js +61 -4
- package/dist/lib/tools/openapiTools.d.ts +52 -0
- package/dist/lib/tools/openapiTools.js +225 -0
- package/dist/lib/tools/skillToolset.d.ts +135 -0
- package/dist/lib/tools/skillToolset.js +247 -0
- package/dist/lib/tools/urlContextTool.d.ts +29 -0
- package/dist/lib/tools/urlContextTool.js +39 -0
- package/dist/lib/workflow.d.ts +72 -0
- package/dist/lib/workflow.js +180 -0
- package/dist/lib/workflowConfig.d.ts +95 -0
- package/dist/lib/workflowConfig.js +93 -0
- package/dist/scripts/a2a_server.js +51 -8
- package/dist/scripts/db.d.ts +9 -0
- package/dist/scripts/db.js +30 -15
- package/dist/scripts/syndicate_chat.js +39 -5
- package/package.json +6 -3
- package/skills/briefs/_shared.md +1 -1
- package/skills/briefs/melchizedek-author.md +8 -4
- package/skills/briefs/melchizedek-memory.md +1 -1
- package/skills/briefs/melchizedek-models.md +1 -1
- package/skills/briefs/melchizedek-scribe.md +4 -4
- package/skills/briefs/melchizedek-serve.md +1 -1
- package/skills/briefs/melchizedek.md +4 -1
- package/skills/melchizedek/SKILL.md +4 -1
- package/skills/melchizedek-author/SKILL.md +7 -3
- package/skills/melchizedek-memory/SKILL.md +1 -1
- package/skills/melchizedek-models/SKILL.md +1 -1
- package/skills/melchizedek-scribe/SKILL.md +3 -3
- package/skills/melchizedek-serve/SKILL.md +1 -1
- /package/skills/melchizedek-author/{templates → assets}/minimal.yaml +0 -0
- /package/skills/melchizedek-scribe/{templates → assets}/brief.md +0 -0
package/.env.example
CHANGED
|
@@ -25,6 +25,13 @@ GOOGLE_GENAI_API_KEY=
|
|
|
25
25
|
# turn it on for local development — e.g. the librarian demo (npm run mcp:demo).
|
|
26
26
|
ALLOW_PRIVATE_MCP=false
|
|
27
27
|
|
|
28
|
+
# ── Optional: OpenAPI tools (an agent's `openapi:` list) ──────────────────────
|
|
29
|
+
# ALLOW_PRIVATE_OPENAPI: set to "true" to let an OpenAPI tool call a localhost /
|
|
30
|
+
# private / link-local server. Off by default as an SSRF guard. Credentials an
|
|
31
|
+
# `openapi:` entry names (auth.bearer_env, auth.api_key.env) are read from this
|
|
32
|
+
# file or the environment, never written in YAML.
|
|
33
|
+
# ALLOW_PRIVATE_OPENAPI=false
|
|
34
|
+
|
|
28
35
|
# ── Optional: Anthropic / Claude ──────────────────────────────────────────────
|
|
29
36
|
# Required only when using claude-* model identifiers in syndicate YAML configs.
|
|
30
37
|
# Get your key at: https://console.anthropic.com
|
|
@@ -54,6 +61,16 @@ OPENAI_API_KEY=
|
|
|
54
61
|
# Get your key at: https://console.x.ai
|
|
55
62
|
XAI_API_KEY=
|
|
56
63
|
|
|
64
|
+
# ── Optional: Moonshot AI / Kimi ─────────────────────────────────────────────
|
|
65
|
+
# Required only when using kimi-* model identifiers in YAML (kimi-k3 is the
|
|
66
|
+
# flagship; kimi-k2.6 the cheaper tier; kimi-k2.7-code[-highspeed] for code).
|
|
67
|
+
# Get your key at: https://platform.moonshot.ai (the .cn console serves
|
|
68
|
+
# mainland China). Without it, MODEL_GATEWAY serves kimi-* ids as
|
|
69
|
+
# moonshotai/kimi-k3 and friends. web_search is never native on Kimi
|
|
70
|
+
# (Moonshot's built-in search retires 2026-10-20); use web_extract.
|
|
71
|
+
MOONSHOT_API_KEY=
|
|
72
|
+
# MOONSHOT_BASE_URL= # a proxy speaking the same chat-completions dialect
|
|
73
|
+
|
|
57
74
|
# XAI_COLLECTION_IDS: comma-separated xAI Collection ids searched by the
|
|
58
75
|
# `collections_search` tool (grok-* agents only). Create collections and
|
|
59
76
|
# upload documents at console.x.ai. Declared with no ids set, the tool is
|
|
@@ -112,6 +129,8 @@ A2A_SERVER_SECRET=
|
|
|
112
129
|
# Used when compiling the AgentCard that advertises this agent to A2A clients.
|
|
113
130
|
# Defaults to http://localhost:4000 if not set.
|
|
114
131
|
# Only needed for cloud deployments where the server has a real public URL.
|
|
132
|
+
# With it set, the server also refuses to start until A2A_AUTH,
|
|
133
|
+
# A2A_SERVED_AGENTS and A2A_TRUST_PROXY are set explicitly (ADR 0039).
|
|
115
134
|
PUBLIC_URL=
|
|
116
135
|
|
|
117
136
|
# ── A2A server: identity and billing (all optional; ADR 0017, 0025) ─────────
|
|
@@ -124,6 +143,7 @@ PUBLIC_URL=
|
|
|
124
143
|
# jwt a JWT from your identity provider; the scope comes from its claims.
|
|
125
144
|
# header an authenticating gateway in front sets the user header; requires
|
|
126
145
|
# A2A_SERVER_SECRET, which only the gateway holds.
|
|
146
|
+
# Required with PUBLIC_URL; prefer callers or jwt there.
|
|
127
147
|
# A2A_AUTH=secret
|
|
128
148
|
# callers: `name:sha256[:scope]` entries separated by ';'. The config holds only
|
|
129
149
|
# each token's SHA-256. Mint one: npx melchizedek-serve --new-caller <name>
|
|
@@ -154,8 +174,8 @@ PUBLIC_URL=
|
|
|
154
174
|
# The server refuses a database behind the migrations it ships (run
|
|
155
175
|
# `npx melchizedek-db apply`); this starts it anyway.
|
|
156
176
|
# ALLOW_SCHEMA_MISMATCH=false
|
|
157
|
-
# Only these agent ids are served at /<agentId>/... (comma list). Unset
|
|
158
|
-
# syndicate the loader can find.
|
|
177
|
+
# Only these agent ids are served at /<agentId>/... (comma list). Unset, or *,
|
|
178
|
+
# = any syndicate the loader can find. Required with PUBLIC_URL (* allowed).
|
|
159
179
|
# A2A_SERVED_AGENTS=support_triage,research_brief
|
|
160
180
|
# Per-task wall-clock budget (ms; 0 = none). Default 15 minutes.
|
|
161
181
|
# A2A_TASK_TIMEOUT_MS=900000
|
|
@@ -174,11 +194,23 @@ PUBLIC_URL=
|
|
|
174
194
|
# A2A_RATE_LIMIT_MAX=60
|
|
175
195
|
# A2A_RATE_LIMIT_WINDOW_MS=900000
|
|
176
196
|
# A2A_AUTH_FAILURE_MAX=30
|
|
177
|
-
# Express trust-proxy: proxy hop count, true/false, or a subnet list. Default
|
|
197
|
+
# Express trust-proxy: proxy hop count, true/false, or a subnet list. Default
|
|
198
|
+
# false (no proxy is trusted). Required with PUBLIC_URL: 1 behind one load
|
|
199
|
+
# balancer, false when clients connect directly.
|
|
178
200
|
# A2A_TRUST_PROXY=1
|
|
201
|
+
# Concurrent tasks for one end user (scope), and for one caller. 0 = unlimited.
|
|
202
|
+
# A2A_MAX_CONCURRENT_PER_SCOPE=4
|
|
203
|
+
# A2A_MAX_CONCURRENT_PER_CALLER=0
|
|
204
|
+
|
|
205
|
+
# OpenAPI tools: the exact environment variables an `auth:` may name. Unset, any
|
|
206
|
+
# variable but the framework's own settings (this file's) is allowed.
|
|
207
|
+
# OPENAPI_CREDENTIAL_ENVS=WEATHER_API_KEY,CRM_TOKEN
|
|
179
208
|
# A2A_BODY_LIMIT=1mb
|
|
180
209
|
# How long SIGTERM waits for running tasks before canceling them.
|
|
181
210
|
# A2A_SHUTDOWN_GRACE_MS=25000
|
|
211
|
+
# Of that, how long /readyz fails while requests are still served, so a load
|
|
212
|
+
# balancer deregisters this instance before the listener closes.
|
|
213
|
+
# A2A_SHUTDOWN_DELAY_MS=5000
|
|
182
214
|
# Daily budgets per UTC day (ADR 0026), per caller and per scope (one end
|
|
183
215
|
# user), on tasks, model calls and tokens. A task over budget ends `rejected`
|
|
184
216
|
# with the reason. Counted in Postgres/Supabase (db/migrations/0004) when
|
|
@@ -262,6 +294,11 @@ WIKI_AGENT_MODEL=
|
|
|
262
294
|
# retried with jittered backoff, honouring Retry-After up to 60 s, before any
|
|
263
295
|
# output is produced. Total attempts per model call; 1 turns retries off.
|
|
264
296
|
# MODEL_RETRY_MAX_ATTEMPTS=3
|
|
297
|
+
# For agents with a fallback_model: after this many consecutive provider-side
|
|
298
|
+
# failures a provider's circuit opens and those agents answer from their
|
|
299
|
+
# fallback for the cooldown. 0 disables the breaker.
|
|
300
|
+
# MODEL_BREAKER_THRESHOLD=5
|
|
301
|
+
# MODEL_BREAKER_COOLDOWN_MS=30000
|
|
265
302
|
# Per-attempt timeout for xAI (Grok) calls, ms; floor 120000.
|
|
266
303
|
# XAI_TIMEOUT_MS=600000
|
|
267
304
|
|
package/AGENT_SETUP.md
CHANGED
|
@@ -70,7 +70,8 @@ After the agent reports back:
|
|
|
70
70
|
of them — set only what you'll declare in YAML:
|
|
71
71
|
`ANTHROPIC_API_KEY` for `claude-*` (https://console.anthropic.com),
|
|
72
72
|
`OPENAI_API_KEY` for `gpt-*` (https://platform.openai.com/api-keys),
|
|
73
|
-
`XAI_API_KEY` for `grok-*` (https://console.x.ai)
|
|
73
|
+
`XAI_API_KEY` for `grok-*` (https://console.x.ai),
|
|
74
|
+
`MOONSHOT_API_KEY` for `kimi-*` (https://platform.moonshot.ai). Not sure which
|
|
74
75
|
you need? `npm run doctor` reads every syndicate and prints what is
|
|
75
76
|
ready, what is blocked, and which variable unlocks what — read-only,
|
|
76
77
|
no key value shown. Verify the whole multi-provider surface live with
|
|
@@ -192,7 +193,8 @@ user id.
|
|
|
192
193
|
|
|
193
194
|
Deploying the server itself (Heroku, Fly, a VPS) needs `PUBLIC_URL` set
|
|
194
195
|
— at which point the server refuses to start without the bearer secret,
|
|
195
|
-
|
|
196
|
+
and until `A2A_AUTH`, `A2A_SERVED_AGENTS` and `A2A_TRUST_PROXY` are set
|
|
197
|
+
explicitly, by design. Run `db/hardening.sql` before real user data arrives, and
|
|
196
198
|
read the deployment notes in `lib/memory/README.md` end to end. The
|
|
197
199
|
patient in module 2.02's specimen would expect no less of you.
|
|
198
200
|
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,252 @@ Consumers of the package read this file; it records changes to the
|
|
|
4
4
|
**published API surface** (the exports map in `package.json`, the bins,
|
|
5
5
|
the starter pack and the templates), not the repo's full history.
|
|
6
6
|
|
|
7
|
+
## 0.18.0 — 2026-10-06
|
|
8
|
+
|
|
9
|
+
### Breaking — read before upgrading
|
|
10
|
+
|
|
11
|
+
- **A public server states its posture (ADR 0039).** With `PUBLIC_URL` set,
|
|
12
|
+
the server refuses to start until all three are set explicitly; the boot
|
|
13
|
+
message names each one missing:
|
|
14
|
+
- `A2A_AUTH`: `callers` or `jwt` (recommended), `header`, or `secret`
|
|
15
|
+
(one shared secret: any holder can act as any user via `X-User-Id`).
|
|
16
|
+
- `A2A_SERVED_AGENTS`: the agent ids to serve, or `*` for every agent.
|
|
17
|
+
- `A2A_TRUST_PROXY`: proxies in front (`1` behind one load balancer), or
|
|
18
|
+
`false` when clients connect directly.
|
|
19
|
+
- **`A2A_TRUST_PROXY` defaults to `false`** (was 1): a server reached
|
|
20
|
+
directly no longer takes the client's `X-Forwarded-For` as its address.
|
|
21
|
+
- **A turn stops at 50 model calls** when the YAML sets no `max_steps`
|
|
22
|
+
(`DEFAULT_MAX_STEPS`). A syndicate that needs more sets `max_steps`.
|
|
23
|
+
- **One end user runs at most 4 tasks at once** (`A2A_MAX_CONCURRENT_PER_SCOPE`,
|
|
24
|
+
`maxConcurrentPerScope`; 0 = unlimited). `A2A_MAX_CONCURRENT_PER_CALLER`
|
|
25
|
+
adds a per-caller cap, off by default. The refusal names the cap.
|
|
26
|
+
|
|
27
|
+
- **The `@google/adk` peer range is `~2.2.0`** (was `^2.2.0`): the tested
|
|
28
|
+
minor. A new ADK minor can bring a second `@google/genai` copy, whose
|
|
29
|
+
response shapes the framework pins; the range widens when a release is
|
|
30
|
+
tested against it. ADK 2.2.0 is the latest published, so no install
|
|
31
|
+
changes today.
|
|
32
|
+
|
|
33
|
+
- **An OpenAPI `auth` may not name one of the framework's own settings**
|
|
34
|
+
(the database URL, a provider key, an `A2A_` secret: anything under the
|
|
35
|
+
framework's prefixes). The YAML chooses the host too, so this was a way
|
|
36
|
+
to send a secret anywhere. `OPENAPI_CREDENTIAL_ENVS` makes the rule an
|
|
37
|
+
exact allowlist. ADR 0041.
|
|
38
|
+
- **MCP tool descriptions are cut at 1,000 characters and results at
|
|
39
|
+
20,000**, each marked where it was cut.
|
|
40
|
+
|
|
41
|
+
### Changes
|
|
42
|
+
|
|
43
|
+
- **An append-only audit trail** (`melchizedek_audit`, migration
|
|
44
|
+
`0012_audit_log`; ADR 0042). Every failed authentication, task outcome
|
|
45
|
+
and erasure is recorded with the caller, the source address, the agent
|
|
46
|
+
and task ids and a scope hash, and no content. A trigger refuses UPDATE
|
|
47
|
+
and DELETE; `melchizedek_prune_audit(days)` is the retention path.
|
|
48
|
+
`postgresStorage` supplies the sink (`audit`), and `createA2AApp` takes
|
|
49
|
+
an `audit` option for any other. Run `npx melchizedek-db apply`.
|
|
50
|
+
- **The server says where memory sends transcripts.** Long-term memory's
|
|
51
|
+
extraction and embedding providers default to Gemini whatever the agents
|
|
52
|
+
run on; a syndicate whose agents use other providers now gets one boot
|
|
53
|
+
warning naming the providers memory reaches and the variables that move
|
|
54
|
+
it (`memoryDestinations`, `memoryCrossesProviders`). DOCUMENTATION gains
|
|
55
|
+
"Where your data goes": every destination, its retention, and the setting
|
|
56
|
+
that changes it.
|
|
57
|
+
- **A request can be followed across systems.** Every task record
|
|
58
|
+
(`onTaskEnd`, and the JSON log line) carries `taskId` and `traceId`; the
|
|
59
|
+
trace id is the one the spans and the ledger row carry. A request with a
|
|
60
|
+
W3C `traceparent` header is linked from the turn's root span
|
|
61
|
+
(`caller.trace_id`, and `callerTraceId` on the record); the turn keeps
|
|
62
|
+
its own trace id. `validTraceparent` and `callerSpanContext` are exported
|
|
63
|
+
from `melchizedek-agents/observability/tracer`. ADR 0043.
|
|
64
|
+
- **`fallback_model:`, an agent key, and a per-provider circuit breaker.**
|
|
65
|
+
When an agent's model fails provider-side (5xx, 429, a reset, after its
|
|
66
|
+
retries) before producing output, its `fallback_model` answers; after
|
|
67
|
+
`MODEL_BREAKER_THRESHOLD` consecutive failures (default 5) the provider
|
|
68
|
+
is skipped for `MODEL_BREAKER_COOLDOWN_MS` (30 s) by agents that have a
|
|
69
|
+
fallback. A 4xx, a canceled turn and a half-finished stream are never
|
|
70
|
+
redirected. ADR 0044.
|
|
71
|
+
- **`mcp_tools:`, an agent key**: the MCP server's tools the agent may use;
|
|
72
|
+
any other tool the server lists is not exposed. On a dispatch route,
|
|
73
|
+
`require_approval` may name a listed MCP tool, so a write waits for a
|
|
74
|
+
person. `closeMcpConnections()` closes every open MCP connection.
|
|
75
|
+
- **`melchizedek-db apply` is one transaction under an advisory lock.** The
|
|
76
|
+
whole install (migrations, hardening, telemetry) runs as one psql
|
|
77
|
+
`--single-transaction` script that takes `pg_advisory_xact_lock` first: a
|
|
78
|
+
failure anywhere rolls everything back, and two applies started together
|
|
79
|
+
run one after the other. The output still names each file.
|
|
80
|
+
- `TaskLimiter` takes per-scope and per-caller limits and says which one
|
|
81
|
+
refused (`refusal()`); `createA2AApp` takes `maxConcurrentPerScope` and
|
|
82
|
+
`maxConcurrentPerCaller`; `DEFAULT_MAX_CONCURRENT_PER_SCOPE` is exported
|
|
83
|
+
from `melchizedek-agents/a2a` and `DEFAULT_MAX_STEPS` from
|
|
84
|
+
`melchizedek-agents/config`.
|
|
85
|
+
|
|
86
|
+
## 0.17.1 — 2026-10-06
|
|
87
|
+
|
|
88
|
+
- **Fix: a rolling deploy no longer refuses requests.** On SIGTERM the
|
|
89
|
+
server closed its listener at once, while the load balancer was still
|
|
90
|
+
sending it traffic. It now fails `/readyz` first and keeps serving for
|
|
91
|
+
`A2A_SHUTDOWN_DELAY_MS` (default 5 s), then closes and drains. The delay
|
|
92
|
+
counts inside `A2A_SHUTDOWN_GRACE_MS`, so a stop takes no longer than
|
|
93
|
+
before. `A2AApp.markUnready()` does the same for an embedding app.
|
|
94
|
+
ADR 0038.
|
|
95
|
+
- **`/readyz` fails while durable storage does not answer** (503,
|
|
96
|
+
`reason: 'storage'`), so an instance that lost its database leaves the
|
|
97
|
+
rotation instead of failing turns. The cause is logged once per outage;
|
|
98
|
+
the answer is cached for 2 s and concurrent probes share one read, so the
|
|
99
|
+
unauthenticated route cannot be used to flood the database.
|
|
100
|
+
- **Fix: the MCP client no longer follows redirects past the SSRF guard.**
|
|
101
|
+
The SSE transport used the default fetch, which follows redirects; it now
|
|
102
|
+
uses `mcpFetch`, under the rule 0.17.0 gave OpenAPI tools: same-origin hops
|
|
103
|
+
get the server's check, cross-origin hops the full guard and no
|
|
104
|
+
credential header.
|
|
105
|
+
- **Fix: a failed MCP connect closes its transport.** The SSE stream's
|
|
106
|
+
reconnect timer kept running after `createMcpTools` gave up, for the life
|
|
107
|
+
of the process.
|
|
108
|
+
- **`MELCHIZEDEK_DOTENV=off`** makes every bin ignore `.env` files and run
|
|
109
|
+
on its environment alone.
|
|
110
|
+
|
|
111
|
+
## 0.17.0 — 2026-10-06
|
|
112
|
+
|
|
113
|
+
### Read before upgrading
|
|
114
|
+
|
|
115
|
+
- **Run `npx melchizedek-db apply`.** Migration `0011_erase_expired` ships
|
|
116
|
+
with this version, and the server refuses to start against a database
|
|
117
|
+
behind the shipped migrations.
|
|
118
|
+
- **A public Supabase deployment on `DATABASE_URL` must be hardened.** The
|
|
119
|
+
boot-time RLS check now runs on that path; `db/hardening.sql` (which
|
|
120
|
+
`melchizedek-db apply` runs) satisfies it, `ALLOW_UNHARDENED_DB=true`
|
|
121
|
+
opts out.
|
|
122
|
+
- **Self-correction is on by default.** Retries count against `max_steps`
|
|
123
|
+
and can raise spend; `retries: { model_errors: 0, tool_errors: 0 }`
|
|
124
|
+
restores the previous behaviour.
|
|
125
|
+
|
|
126
|
+
### Changes
|
|
127
|
+
|
|
128
|
+
- **Behaviour change: the hardening check runs on the `DATABASE_URL` path.**
|
|
129
|
+
The boot-time RLS check ran only on the deprecated supabase-js path, so a
|
|
130
|
+
deployment that followed the recommended setup was never checked, and
|
|
131
|
+
"fatal on public deployments without it" did not hold. `postgresStorage`
|
|
132
|
+
now supplies `rlsHardening()` and the server applies the same rules
|
|
133
|
+
(`lib/storage/rlsStatus.ts`): with `PUBLIC_URL` set, a Supabase database
|
|
134
|
+
whose `public` tables lack RLS stops the server (set
|
|
135
|
+
`ALLOW_UNHARDENED_DB=true` to accept the risk). A database with no `anon`
|
|
136
|
+
or `authenticated` role, or with the tables in a private schema, passes.
|
|
137
|
+
`createA2AApp`'s `storage` option accepts `rlsHardening` for custom storage.
|
|
138
|
+
- **Fix: OpenAPI tools no longer follow redirects past the SSRF guard.**
|
|
139
|
+
ADK's REST tool calls `fetch`, which follows redirects, and the guard
|
|
140
|
+
checked only the configured server: an allowed API with an open redirect
|
|
141
|
+
could send a call to the cloud metadata service, and an `api_key` header
|
|
142
|
+
went with it. A call now follows redirects one hop at a time
|
|
143
|
+
(`lib/net/redirects.ts`): same-origin hops get the server's own check,
|
|
144
|
+
cross-origin hops the full guard (even with `ALLOW_PRIVATE_OPENAPI`) and
|
|
145
|
+
only content-negotiation headers. A refused hop returns an error to the
|
|
146
|
+
model. Nothing changes for a fetch made outside an OpenAPI tool call.
|
|
147
|
+
- **Fix: `DELETE /memory` erases expired conversations.** A namespace erase
|
|
148
|
+
(the default) found conversations through their live session rows, so once
|
|
149
|
+
a session expired after seven idle days its ledger turns, spans, payloads
|
|
150
|
+
and A2A tasks survived the erase while the response reported success.
|
|
151
|
+
Migration `0011_erase_expired` replaces `melchizedek_erase_scope`: a
|
|
152
|
+
namespace erase now keeps a turn or task only when its conversation is
|
|
153
|
+
still live in another namespace. Run `npx melchizedek-db apply`; the server
|
|
154
|
+
refuses to start against a database behind the shipped migrations.
|
|
155
|
+
- **Moonshot AI (Kimi) is a provider.** `kimi-*` model ids route to a new
|
|
156
|
+
direct adapter (`lib/models/kimiLlm.ts`, chat completions against
|
|
157
|
+
`api.moonshot.ai`), funded by `MOONSHOT_API_KEY` (`MOONSHOT_BASE_URL` for a
|
|
158
|
+
proxy). Tool calling, delegation, strict structured output, streaming,
|
|
159
|
+
images and `reasoning_content` work; native `web_search` is dropped with a
|
|
160
|
+
warning (Moonshot's model-side search retires 2026-10-20), and thinking is
|
|
161
|
+
not carried across a tool loop (K3 re-reasons each step; both stated in
|
|
162
|
+
the capability matrix). `kimi-k3` takes `reasoning_effort` (pinned `high`,
|
|
163
|
+
`DEFAULT_KIMI_REASONING_EFFORT`); K2.x ids take a thinking switch. With no
|
|
164
|
+
direct key the gateway serves the ids as `moonshotai/…`. The doctor,
|
|
165
|
+
`.env.example`, the schema comments and the docs know the provider;
|
|
166
|
+
`model_zoo.yaml` gains a sixth agent, `kimi` on `kimi-k3` at low effort,
|
|
167
|
+
and the Zookeeper names six providers. Cost note: `kimi-k3` is priced
|
|
168
|
+
like Claude Sonnet 4.6 ($3 / $15, thinking billed as output), so
|
|
169
|
+
`kimi-k2.6` is the budget tier and the gateway the cheap route to K3.
|
|
170
|
+
One plain turn verified live on 2026-10-03; tool loops were not.
|
|
171
|
+
- **The doctor's providers line names each provider's own key.** It probed
|
|
172
|
+
every provider past the fourth with a `grok-` id, so Moonshot was reported
|
|
173
|
+
as missing `XAI_API_KEY`.
|
|
174
|
+
- **Behaviour change: self-correction is on by default.** Every turn now runs
|
|
175
|
+
ADK's reflect-and-retry plugins. A model reply ADK marks malformed
|
|
176
|
+
(`MALFORMED_FUNCTION_CALL`) is retried up to twice with guidance instead of
|
|
177
|
+
failing the turn; a tool that throws is answered with structured reflection
|
|
178
|
+
guidance and retried at most three times. Every retry counts against
|
|
179
|
+
`max_steps`. Set `retries: { model_errors: 0, tool_errors: 0 }` at the root
|
|
180
|
+
of a syndicate to restore the previous behaviour. ADR 0034.
|
|
181
|
+
- **`url_context` and `examples:`.** `url_context` lets a Gemini agent read
|
|
182
|
+
the pages at URLs in the conversation, server-side; on other providers it is
|
|
183
|
+
a no-op the doctor reports as dropped. An agent's `examples: [{ input,
|
|
184
|
+
output }]` adds few-shot exchanges to every request (ADK's `ExampleTool`).
|
|
185
|
+
- **Three agent keys from ADK: `code_execution`, `context`, `mode`.**
|
|
186
|
+
`code_execution: gemini` lets a Gemini agent write and run Python in
|
|
187
|
+
Gemini's server-side sandbox (nothing runs on the host). `context:
|
|
188
|
+
{ compact_after_tokens, keep_recent_events?, summary_model? }` on a delegate
|
|
189
|
+
orchestrator summarizes earlier turns once a prompt passes the threshold,
|
|
190
|
+
keeping the recent ones verbatim and the full history stored. `mode: task`
|
|
191
|
+
on a workflow node makes its output the arguments of its `finish_task`
|
|
192
|
+
call. The schema places each where it means something. ADR 0033.
|
|
193
|
+
- **`openapi:`: any HTTP API as an agent's tools, from its spec.** An agent
|
|
194
|
+
lists OpenAPI 3 spec files (relative to the syndicate file); every operation
|
|
195
|
+
becomes a tool named from its `operationId`, its parameters the arguments,
|
|
196
|
+
its summary the description. Read-only by default (GET operations only,
|
|
197
|
+
unless `operations` names others); a named operation can be listed under
|
|
198
|
+
`require_approval`. Credentials come from environment variables
|
|
199
|
+
(`auth.bearer_env`, `auth.api_key`), never YAML, and are never stored in
|
|
200
|
+
session state. Every server passes the SSRF guard (literal rules at
|
|
201
|
+
compile, DNS before each call; `ALLOW_PRIVATE_OPENAPI=true` for local
|
|
202
|
+
development); results are capped at 20,000 characters. On ADK's
|
|
203
|
+
`OpenAPIToolset`. Worked example: `config/agents/examples/weather.yaml`
|
|
204
|
+
(`npm run syndicate:weather`), with two keyless Open-Meteo specs. ADR 0032.
|
|
205
|
+
- **`ask_user`: an agent asks the person and waits.** A registry tool,
|
|
206
|
+
`ask_user(question, options?)`, on the orchestrator or a plan-dispatch
|
|
207
|
+
route. Called, it ends the turn `input-required` with `result.input`
|
|
208
|
+
(`node`, `message`, `payload.options`); the next plain-text message on the
|
|
209
|
+
conversation becomes the call's result and the agent resumes its own tool
|
|
210
|
+
loop (a dispatch turn goes straight back to the route that asked). Over A2A
|
|
211
|
+
the task carries an `input_request` data part — the same one a workflow's
|
|
212
|
+
`ask_user` node publishes. A delegated subagent or a workflow node listing
|
|
213
|
+
it is a load error. ADR 0031.
|
|
214
|
+
- **Workflows: the `workflow:` block, the third orchestration method.** A
|
|
215
|
+
syndicate may be a graph: its agents are the nodes, `edges` says what runs
|
|
216
|
+
after what and on which route (a map after a node routes on the `route_key`
|
|
217
|
+
of its JSON output, else its text, with `default`), and `nodes` declares
|
|
218
|
+
what is not an agent — `join` (fan-in), `map` (one run per list item,
|
|
219
|
+
concurrently), `tool` (a registry tool as a node), `ask_user` (a pause: the
|
|
220
|
+
turn ends `input-required` with the question, the next message answers,
|
|
221
|
+
and the node outputs `{ reply, input }`). Any node may carry `retry` and
|
|
222
|
+
`timeout`. Every node receives the previous node's output as its message
|
|
223
|
+
and sees nothing else of the conversation unless its YAML says so. Runs on
|
|
224
|
+
ADK's `Workflow`; `runSyndicateTurn` gains `status: 'input-required'` with
|
|
225
|
+
`input` (the A2A server publishes an `input_request` data part;
|
|
226
|
+
`melchizedek-chat` prints the question and takes the next line);
|
|
227
|
+
`compileWorkflow` and `isWorkflowSyndicate` are exported. Not yet inside a
|
|
228
|
+
workflow: approval gates, skill scripts, remote subagents. Worked example:
|
|
229
|
+
`config/agents/examples/pipeline.yaml` (`npm run syndicate:pipeline`);
|
|
230
|
+
ADR 0030.
|
|
231
|
+
- **Agent Skills in a syndicate: the `skills:` agent key and the Harness.**
|
|
232
|
+
An agent may declare `skills: { dir, scripts?, tools? }`. Every skill's
|
|
233
|
+
frontmatter (name, description) is appended to the agent's instruction at
|
|
234
|
+
compile time, so no turn is spent discovering skills; `load_skill` reads one
|
|
235
|
+
SKILL.md in full with the names of the files it ships, and
|
|
236
|
+
`load_skill_resource` reads one file (`references/`, `assets/`, `scripts/`,
|
|
237
|
+
the open standard's layout). A skill's `allowed-tools` frontmatter unlocks
|
|
238
|
+
the registry tools the YAML lists under `skills.tools`, once that skill is
|
|
239
|
+
loaded. With `scripts: local`, `run_skill_script` runs a skill's own scripts
|
|
240
|
+
on the host, each run only after a person approves it through the same
|
|
241
|
+
pause as `require_approval` (A2A `input-required`; `melchizedek-chat` now
|
|
242
|
+
asks `[y/N]`); the model's own code never executes. Built on ADK's
|
|
243
|
+
`SkillToolset` (`lib/tools/skillToolset.ts`). `config/agents/examples/harness.yaml`
|
|
244
|
+
is the specimen: a generic agent that works from whatever shelf of skills
|
|
245
|
+
`--bind skills_dir=…` points it at (default: this package's own suite).
|
|
246
|
+
- **The suite's files move to the standard `assets/` directory.**
|
|
247
|
+
`melchizedek-author` ships `assets/minimal.yaml` (was `templates/minimal.yaml`)
|
|
248
|
+
and `melchizedek-scribe` ships `assets/brief.md` (was `templates/brief.md`),
|
|
249
|
+
so a harness, this one or any other, can read them as skill resources. A
|
|
250
|
+
skill installed by an earlier release keeps its old path until it is
|
|
251
|
+
reinstalled with `--force`.
|
|
252
|
+
|
|
7
253
|
## 0.16.2 — 2026-10-02
|
|
8
254
|
|
|
9
255
|
- **`OTEL_EXPORT_CONTENT=off` also drops library content attributes.** In
|