melchizedek-agents 1.0.1 → 1.0.3

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/CHANGELOG.md CHANGED
@@ -6,6 +6,84 @@ the starter pack and the templates), not the repo's full history.
6
6
 
7
7
  ## Unreleased
8
8
 
9
+ ## 1.0.3 — 2026-10-09
10
+
11
+ Dependency updates and one packaging fix. No export, bin, YAML key or
12
+ adapter behaviour changes; no source file under `lib/` changes.
13
+
14
+ ### Fixed
15
+
16
+ - **`config/agents/syndicate.schema.json` ships in the package.** The
17
+ shipped `config/agents/syndicateSchema.yaml` names it in its
18
+ `yaml-language-server` modeline, and `melchizedek-init` locates the
19
+ package root by it; it was missing from `files`, so editors could not
20
+ resolve the schema and, in an installed package, `melchizedek-init`
21
+ stopped with "config/agents/ not found next to this package".
22
+ `tests/packageSurface.test.ts` now checks that `files` ships it and
23
+ every shipped modeline's target.
24
+
25
+ ### Changed — dependencies
26
+
27
+ - `@anthropic-ai/sdk` ^0.129.0 → ^0.131.0. Additive (Admin and Managed
28
+ Agents endpoints). The SDK now marks `claude-sonnet-4-5` and
29
+ `claude-sonnet-4-5-20250929` deprecated (end of life 2026-11-30) and
30
+ logs a `console.warn` when a request names them; no shipped syndicate
31
+ uses either id.
32
+ - `openai` ^7.23.0 → ^7.28.0. Additive (Agents, Realtime, Responses
33
+ WebSocket features). The client now keeps a base URL's query string
34
+ when joining endpoints; this reaches the GPT adapter only when
35
+ an `OPENAI_BASE_URL` carries a query (the Azure and xAI base URLs carry none;
36
+ the Kimi, Ollama and gateway adapters do not use the SDK).
37
+ - `@modelcontextprotocol/sdk` ^1.29.0 → ^1.32.1 (lock 1.31.0 → 1.32.1).
38
+ The SDK's HTTP client transports now follow redirects only within the
39
+ endpoint's origin unless `redirectPolicy: 'follow'` is set. The MCP
40
+ client's own fetch (`mcpFetch`, `lib/net/redirects.ts`) already follows
41
+ every hop itself under `MCP_REDIRECTS`, so the SDK sees the final
42
+ response and redirect behaviour is unchanged.
43
+ - `@google/genai` 2.25.0 → 2.27.0, still pinned exact. Additive
44
+ (`continuation_token` in GenerateContent and Interactions, new model
45
+ enum values).
46
+ - `@types/node` ^22 → ^25 (dev only). `engines.node` stays `>=22.6.0`; the
47
+ source type-checks against both the Node 22 and Node 25 types.
48
+ - Dockerfile base image `node:22-slim` → `node:25-slim`, pinned by digest.
49
+
50
+ ## 1.0.2 — 2026-10-09
51
+
52
+ A test and documentation patch. Nothing a consumer imports, configures or
53
+ runs changes behaviour, and no YAML key is added, removed or renamed.
54
+
55
+ ### Fixed
56
+
57
+ - **`npm test`, and so `npm publish`, pass again from 2026-10-09.** The
58
+ harness-example parity test (`tests/skillHarness.test.ts`) compared a
59
+ native run against a recording made on 2026-10-08, and the
60
+ `{{current_date}}` the example's instruction resolves moved with the
61
+ clock, so from 2026-10-09 the comparison failed. The test now pins
62
+ `current_date` to the recording's date.
63
+ - **The SIGTERM test holds under load.** `tests/serverShutdown.test.ts`
64
+ waits up to 30 seconds for the server to start, polls for readiness to
65
+ fail after the signal instead of checking once after a fixed 300 ms,
66
+ and runs with a 3-second delay and a 6-second grace budget, so a busy
67
+ machine no longer fails it on timing.
68
+
69
+ ### Changed
70
+
71
+ - **Wording only: the shipped files describe the engine, not ADK.** The
72
+ example syndicates' comments (`critic.yaml`, `scribe.yaml`,
73
+ `research.yaml`, `image_production.yaml`, `librarian.yaml`,
74
+ `weather.yaml`, `pipeline.yaml`), `config/agents/syndicateSchema.yaml`,
75
+ `DOCUMENTATION.md` and the `melchizedek-author` skill no longer describe
76
+ Google ADK as running or enforcing anything; ADK appears only as history
77
+ or as the origin of a key's spelling. The rule that an `outputSchema`
78
+ belongs on a leaf is stated as what it is: the engine accepts the schema
79
+ on an agent that delegates, and that agent then answers with the JSON
80
+ instead of relaying a subagent's answer. The same wording reaches the
81
+ schema descriptions in `lib/syndicateSchema.ts` and the generated
82
+ `config/agents/syndicate.schema.json` (`outputSchema`, the root agent,
83
+ the workflow `retry` defaults, `retries`), and the reserved-name message
84
+ for an agent called `user`. No key, default or behaviour changes;
85
+ `thinkingBudget` and the other older spellings are still accepted.
86
+
9
87
  ## 1.0.1 — 2026-10-08
10
88
 
11
89
  ### Fixed
package/DOCUMENTATION.md CHANGED
@@ -141,7 +141,7 @@ Field reference:
141
141
  | `yaml_reference` | subagent | Mount another syndicate file as a nested subagent. |
142
142
  | `a2a_agent_url` | subagent | A REMOTE agent over A2A (§6): the orchestrator delegates to it with one `request` argument; in plan-dispatch it can be a route. No `model`/`instruction` — the remote agent has its own. Credentials come from `A2A_AGENT_TOKENS`, never YAML. |
143
143
  | `max_steps` | root | Cap on model calls per turn, counted across every agent the turn reaches (orchestrator, subagents, nested syndicates). Exceeding it fails the turn with `STEP_LIMIT`. |
144
- | `includeContents` / `outputKey` / `globalInstruction` / `disallowTransferToParent` / `disallowTransferToPeers` | agent | Passed through to the agent (the names are ADK's `LlmAgent` fields). `includeContents: none` makes an agent see only the current message. |
144
+ | `includeContents` / `outputKey` / `globalInstruction` / `disallowTransferToParent` / `disallowTransferToPeers` | agent | Passed through to the agent (spelled after ADK's `LlmAgent` fields). `includeContents: none` makes an agent see only the current message. |
145
145
  | `fallback_model` | any agent | A model, ideally on another provider, that answers when this agent's model fails provider-side (5xx, 429, a connection reset, after its own retries) before producing any output, or while that provider's circuit is open: after `MODEL_BREAKER_THRESHOLD` consecutive provider failures (default 5; 0 disables) the provider is skipped for `MODEL_BREAKER_COOLDOWN_MS` (default 30 s). A 4xx and a canceled turn are never redirected, and a stream that already produced text is never replayed elsewhere ([ADR 0044](./wiki/decisions/0044-fallback-model-and-circuit-breaker.md)). |
146
146
  | `mcp_tools` | subagent | The MCP server's tools this agent may use; any other tool the server lists is not exposed. On a dispatch route `require_approval` may name them ([ADR 0041](./wiki/decisions/0041-tool-vendors-get-least-privilege.md)). |
147
147
  | `mcp_server_url` | subagent | Discover this subagent's tools from a remote MCP server at load time (§3). SSRF-guarded; `ALLOW_PRIVATE_MCP=true` permits localhost for development. |
@@ -178,7 +178,7 @@ function, and every adapter recognises it by marker
178
178
  | `google_search` | Gemini built-in | Live web search — Gemini agents only (legacy alias; use `web_search`). |
179
179
  | `preload_memory` | Instruction tool | Silently injects similarity-matched facts into every request's instruction (ambient recall). The model never calls it. |
180
180
  | `load_memory` | Contract | Explicit tool call to search the fact store (deliberate recall). Both memory tools read the caller's own silo only and send the model what ADK's tools of the same names sent ([ADR 0059](./wiki/decisions/0059-memory-on-the-engines-own-interfaces.md)). |
181
- | `generate_image` | Contract | Calls the Gemini image model directly, saves the result under `outputs/`, returns the path. A function tool because binary `inlineData` cannot survive the AgentTool text boundary. |
181
+ | `generate_image` | Contract | Calls the Gemini image model directly, saves the result under `outputs/`, returns the path. A function tool because binary `inlineData` cannot survive delegation, where a subagent returns only its final text. |
182
182
  | `inspect_image` | Contract | **Blind visual inventory** of a file under `outputs/`: subjects with exact counts, composition, light, palette, medium cues, artifacts — zero quality judgments. Its signature accepts *only* a file path, so an orchestrator cannot leak expectations into the observation (see `image_production.yaml`). |
183
183
  | `task_add` / `task_list` / `task_get` / `task_update` | Contract | A to-do list and job queue. Default: a single-user JSON file (`MELCHIZEDEK_TASKS_FILE`, default `outputs/tasks.json`), so every caller of a shared endpoint shares one list. With `DATABASE_URL` (migration 0009) each caller has its own list, scoped by the caller's scope key, and any number of workers take jobs safely. |
184
184
  | `ask_user` | Contract, long-running | Asks the person one question (optionally with `options`) and ends the turn `input-required`; the next message on the conversation is the call's result. Orchestrator or plan-dispatch route only (§6, Questions). |
@@ -575,7 +575,7 @@ Model floor: agent transfer (subagent delegation) requires
575
575
  `gemini-3.8-flash` or newer — older flash models reject it with
576
576
  `[400] Tool call context circulation is not enabled`. For `ollama/*`
577
577
  agents the equivalent floor is tool-calling support in the model
578
- itself; delegation is exercised through AgentTool function calls.
578
+ itself; delegation runs through ordinary function calls to the subagent tools.
579
579
 
580
580
  ## 6. A2A service mode
581
581
 
@@ -1055,7 +1055,7 @@ user:
1055
1055
 
1056
1056
  | | DELEGATE (default) | PLAN-DISPATCH (`dispatch:` present) |
1057
1057
  |---|---|---|
1058
- | Subagents are | `AgentTool`s on the orchestrator | plain configs the server selects from |
1058
+ | Subagents are | tools on the orchestrator | plain configs the server selects from |
1059
1059
  | Orchestrator holds | subagent tools, no `outputSchema` | an `outputSchema`, no subagent tools |
1060
1060
  | Routing decision is | implicit in which tool it calls | an explicit value in code |
1061
1061
  | The final answer comes from | the orchestrator re-emitting the answer | **the specialist itself** |
@@ -1089,9 +1089,11 @@ emitted the bare tool name in place of a 2,599-character answer.
1089
1089
  Plan-dispatch has no relay turn to fail, and the classifier's output
1090
1090
  shrinks from a whole relayed answer to ~15 tokens of JSON.
1091
1091
 
1092
- **Why the classifier is tool-less.** Structured output does not combine
1093
- with delegation on one agent (see `config/agents/examples/critic.yaml`,
1094
- whose header tells how an orchestrator holding both deadlocked on ADK).
1092
+ **Why the classifier is tool-less.** An agent that holds an
1093
+ `outputSchema` answers with that JSON and nothing else, so the schema sits
1094
+ on a leaf that delegates nothing (see `config/agents/examples/critic.yaml`,
1095
+ whose header also tells how an orchestrator holding both deadlocked on
1096
+ ADK before 1.0.0).
1095
1097
  That constraint shapes the method: the classifier is a leaf, and the
1096
1098
  hand-off happens in code, where it can be logged, traced, and streamed
1097
1099
  to the user as progress.
@@ -1100,8 +1102,8 @@ to the user as progress.
1100
1102
  one transcript accumulates across routes and long-term memory ingests
1101
1103
  real answers instead of a relay copy of them. Sharing the session is
1102
1104
  necessary but not sufficient: a stored event is rendered by comparing
1103
- `event.author` against the agent now running (ADK's rule, which the native
1104
- loop keeps), and under plan-dispatch
1105
+ `event.author` against the agent now running (the rule ADK had, which the
1106
+ engine's loop keeps), and under plan-dispatch
1105
1107
  every route is its own root agent, so the whole history fails that
1106
1108
  comparison and `convertForeignEvent` rewrites it to `role: "user"`
1107
1109
  prefixed "For context:". A route reading the raw shared session
@@ -1,15 +1,20 @@
1
1
  # tier: gemini — needs only GOOGLE_GENAI_API_KEY; `npm run doctor` shows what each key unlocks.
2
2
  syndicate_name: "Critic Review Workflow"
3
3
 
4
- # WHY this structure: The ADK enforces that outputSchema cannot co-exist with
5
- # agent transfer (AgentTool) on the same agent. If the orchestrator has both,
6
- # the ADK deadlocks it. Solution: the orchestrator is a plain sequencer that
7
- # routes Drafter → Critic, and the CriticAgent (a leaf with no tools/transfers)
8
- # owns the outputSchema for structured JSON production.
4
+ # WHY this structure: an agent with an outputSchema answers in that schema and
5
+ # nothing else. On an orchestrator that delegates, the engine (on most
6
+ # models) adds a set_model_response tool beside the subagent tools and the
7
+ # turn ends on the JSON it receives (lib/runtime/native/request.ts), so the
8
+ # user would get the review object instead of the answer; under Google ADK,
9
+ # before 1.0.0, an orchestrator holding both deadlocked. Solution: the
10
+ # orchestrator is a plain sequencer that routes Drafter → Critic, and the
11
+ # CriticAgent (a leaf with no tools and no subagents) owns the outputSchema
12
+ # for structured JSON production.
9
13
  #
10
14
  # WHY multi-turn internal looping:
11
- # The ADK's runAsync keeps executing within a single user turn as long as the
12
- # orchestrator continues to call tools rather than producing a final response.
15
+ # The engine's agent loop keeps executing within a single user turn as long
16
+ # as the orchestrator continues to call tools rather than producing a final
17
+ # response (lib/runtime/native/agentLoop.ts, capped by max_steps).
13
18
  # By instructing the orchestrator to inspect the CriticAgent's confidence score
14
19
  # and re-delegate when it's below a threshold, the syndicate autonomously
15
20
  # refines answers through multiple Drafter→Critic passes — all within one
@@ -16,8 +16,8 @@ memory_system: "session-only"
16
16
  # path — the spec physically cannot reach the inventory, so expectation bias
17
17
  # is blocked by the tool signature, not by good intentions. SpecAuditor is a
18
18
  # text-only leaf that receives spec + inventory but never the image, and
19
- # holds the outputSchema (same ADK constraint as critic.yaml: schema-holders
20
- # get no transfer powers). Perception, judgment, and decision are three
19
+ # holds the outputSchema (the same rule as critic.yaml: the schema-holder
20
+ # is a leaf that delegates nothing). Perception, judgment, and decision are three
21
21
  # different minds.
22
22
  #
23
23
  # WHY the instruction maps payload fields to tool parameters by name
@@ -7,7 +7,7 @@
7
7
  # subagent declares NO tools of its own — its entire capability
8
8
  # arrives at runtime from an MCP server (mcp_server_url below).
9
9
  # The framework dials the server, asks "what tools do you offer?",
10
- # and wraps each answer as a live ADK tool (lib/tools/mcpToolFactory.ts).
10
+ # and wraps each answer as a live engine tool (lib/tools/mcpToolFactory.ts).
11
11
  #
12
12
  # That is the point of MCP: the agent's reach is no longer fixed
13
13
  # at design time. Point the same agent at a different server and
@@ -9,7 +9,7 @@
9
9
  # what they produce, edit it, ask the person, then publish". A
10
10
  # `workflow:` block says exactly that: the agents below are the
11
11
  # nodes of a graph, and `edges` says what runs after what
12
- # (lib/workflow.ts; ADK's Workflow underneath).
12
+ # (lib/workflow.ts; the engine's own scheduler, lib/workflow/, runs it).
13
13
  #
14
14
  # START → Planner ─(article)→ Writer ──┐
15
15
  # │ ├→ Both → Editor → Confirm → Publisher
@@ -12,8 +12,9 @@
12
12
  # SHAPE: plan-dispatch (lib/dispatch.ts). A small triage model names one of
13
13
  # three routes, and that route's output IS the answer. Each route HOLDS its
14
14
  # own tools instead of delegating to researcher subagents. That choice is
15
- # deliberate: ADK's AgentTool returns only a subagent's final text, so tool
16
- # output from a delegated subagent never reaches the outer stream, and the
15
+ # deliberate: the engine's subagent tool returns only a subagent's final text
16
+ # (lib/runtime/native/delegate.ts), so tool output from a delegated subagent
17
+ # never reaches the outer stream, and the
17
18
  # `science` guard below checks the answer against exactly that output. When
18
19
  # the answering route makes the calls itself, every identifier it cites is
19
20
  # on its own stream. It also means an A2A client sees each tool call live.
@@ -36,10 +36,11 @@
36
36
  # the two lists lived apart they drifted, and drafts failed rules the
37
37
  # writer had never been given. Edit the rule in one place.
38
38
  #
39
- # WHY the orchestrator has no outputSchema: the ADK does not let
40
- # an agent hold both an outputSchema and AgentTools, so the JSON
41
- # contract sits on the Auditor (the leaf) and the Scribe returns
42
- # plain text. See critic.yaml for the same constraint.
39
+ # WHY the orchestrator has no outputSchema: an agent that holds
40
+ # one answers in that JSON and nothing else, and the Scribe's answer
41
+ # is the document. So the JSON contract sits on the Auditor (the
42
+ # leaf) and the Scribe returns plain text. See critic.yaml for the
43
+ # same rule.
43
44
  #
44
45
  # Run it: npm run syndicate:scribe
45
46
  # npm run syndicate:scribe -- "$(cat brief.md)" # one shot
@@ -7,7 +7,8 @@
7
7
  # that uses it. No tool code: the `openapi:` list below points at two
8
8
  # spec files, and every operation in them becomes a tool, its
9
9
  # parameters the tool's arguments and its summary the description the
10
- # model reads (lib/tools/openapiTools.ts; ADK's OpenAPIToolset).
10
+ # model reads (lib/tools/openapiTools.ts, the engine's own parser and
11
+ # caller, by the rules ADK's OpenAPIToolset had).
11
12
  #
12
13
  # The specs are hand-written subsets of Open-Meteo's free, keyless
13
14
  # APIs (specs/): find a place, then forecast its weather. Swap in