melchizedek-agents 1.11.1 → 1.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/.env.example +53 -10
  2. package/AGENT_SETUP.md +4 -1
  3. package/CHANGELOG.md +125 -0
  4. package/DOCUMENTATION.md +108 -7
  5. package/ONBOARDING.md +15 -9
  6. package/QUICKSTART.md +5 -3
  7. package/README.md +7 -4
  8. package/config/agents/examples/classifier.yaml +104 -0
  9. package/config/agents/examples/model_zoo.yaml +5 -0
  10. package/config/agents/syndicate.schema.json +59 -1
  11. package/config/agents/syndicateSchema.yaml +9 -1
  12. package/config/agents/templates/README.md +2 -1
  13. package/config/agents/templates/prompt_writer.yaml +513 -0
  14. package/db/hardening.sql +5 -0
  15. package/db/migrations/0022_typesafe_jev_pricing.sql +36 -0
  16. package/db/migrations/0023_memory_embedder.sql +66 -0
  17. package/dist/lib/config.d.ts +6 -0
  18. package/dist/lib/config.js +6 -0
  19. package/dist/lib/doctor.d.ts +8 -0
  20. package/dist/lib/doctor.js +17 -0
  21. package/dist/lib/loadSyndicate.d.ts +1 -1
  22. package/dist/lib/memory/providers.d.ts +31 -0
  23. package/dist/lib/memory/providers.js +82 -2
  24. package/dist/lib/memory/reembed.d.ts +47 -0
  25. package/dist/lib/memory/reembed.js +71 -0
  26. package/dist/lib/memory/store.d.ts +22 -0
  27. package/dist/lib/memory/store.js +33 -0
  28. package/dist/lib/memory/supabaseMemoryService.d.ts +17 -0
  29. package/dist/lib/memory/supabaseMemoryService.js +55 -1
  30. package/dist/lib/model.d.ts +4 -0
  31. package/dist/lib/model.js +3 -0
  32. package/dist/lib/models/adapterResolver.js +5 -2
  33. package/dist/lib/models/capabilities.d.ts +2 -0
  34. package/dist/lib/models/capabilities.js +28 -6
  35. package/dist/lib/models/chatCompletionsAdapter.d.ts +6 -1
  36. package/dist/lib/models/chatCompletionsAdapter.js +35 -6
  37. package/dist/lib/models/contract.d.ts +7 -1
  38. package/dist/lib/models/endpoints.d.ts +3 -2
  39. package/dist/lib/models/endpoints.js +6 -2
  40. package/dist/lib/models/gateway.d.ts +123 -7
  41. package/dist/lib/models/gateway.js +204 -22
  42. package/dist/lib/models/gatewayAdapter.d.ts +17 -6
  43. package/dist/lib/models/gatewayAdapter.js +28 -10
  44. package/dist/lib/models/jev.d.ts +190 -0
  45. package/dist/lib/models/jev.js +316 -0
  46. package/dist/lib/models/jevAdapter.d.ts +79 -0
  47. package/dist/lib/models/jevAdapter.js +136 -0
  48. package/dist/lib/models/providerMap.d.ts +2 -1
  49. package/dist/lib/models/providerMap.js +4 -0
  50. package/dist/lib/models/registry.d.ts +3 -3
  51. package/dist/lib/models/registry.js +11 -4
  52. package/dist/lib/observability/tracer.d.ts +1 -1
  53. package/dist/lib/onboarding.js +9 -4
  54. package/dist/lib/storage/postgres/memoryStore.js +27 -0
  55. package/dist/lib/syndicateSchema.d.ts +16 -0
  56. package/dist/lib/syndicateSchema.js +2 -1
  57. package/dist/lib/tools/credentialEnv.js +1 -1
  58. package/package.json +2 -1
  59. package/skills/briefs/melchizedek-author.md +1 -1
  60. package/skills/briefs/melchizedek-models.md +6 -5
  61. package/skills/briefs/melchizedek.md +2 -2
  62. package/skills/melchizedek-onboard/SKILL.md +1 -1
  63. package/skills/melchizedek-onboard-keys/SKILL.md +2 -2
package/.env.example CHANGED
@@ -2,7 +2,38 @@
2
2
  # asks what you have and prints the names to set for it; --auto detects it.
3
3
  # Only names and shapes live here: type the values yourself, never commit .env.
4
4
 
5
- # ── Required for cloud models ─────────────────────────────────────────────────
5
+ # ── The quickest start: ONE gateway key for every cloud model ─────────────────
6
+ # A Vercel AI Gateway or OpenRouter key serves every cloud model id whose
7
+ # direct key is absent (Claude, GPT, Gemini, Grok, Kimi, DeepSeek, and
8
+ # TypeSafe Jev on the gateway's System One route), billed to that one account.
9
+ # Set these two and every multi-provider syndicate runs. By default a direct
10
+ # key set beside it wins for its own provider, at full fidelity: native search
11
+ # tools are dropped on the gateway path (the doctor says which), and the
12
+ # gateway never serves ollama/* models; it embeds for long-term memory only
13
+ # where it carries the same model (Vercel does; OpenRouter has no Gemini one).
14
+ # MODEL_GATEWAY_PREFER=gateway turns that round (every cloud id through the
15
+ # gateway, one bill), and MODEL_GATEWAY_EXCEPT names the providers that take
16
+ # the opposite of the preference, e.g. gemini kept on its own key for grounding.
17
+ # What a gateway gives back: web_search runs as the gateway's own search on
18
+ # any model (Vercel's exa_search server tool; OpenRouter's web plugin, the
19
+ # provider's native search where it has one, with citations), and long-term
20
+ # memory embeds through the gateway when it carries the same embedding model
21
+ # (Vercel: google/gemini-embedding-001). x_search and Collections stay direct-only.
22
+ # A gateway is for billing and breadth, not for grounding: for a search-heavy
23
+ # agent keep the provider that does the searching on its own key and let the
24
+ # gateway serve the rest (a direct key beside the gateway key does that by
25
+ # default; MODEL_GATEWAY_EXCEPT keeps it so under MODEL_GATEWAY_PREFER=gateway).
26
+ # Keys: https://vercel.com/ai-gateway or https://openrouter.ai/keys
27
+ # MODEL_GATEWAY=vercel # or openrouter
28
+ # MODEL_GATEWAY_API_KEY=
29
+ # MODEL_GATEWAY_PREFER=direct # or gateway: the gateway wins even beside a direct key
30
+ # MODEL_GATEWAY_EXCEPT= # optional: providers that take the opposite of the preference, e.g. gemini,xai
31
+ # MODEL_GATEWAY_SEARCH= # optional: off, or the gateway's engine (Vercel: exa | perplexity | parallel | browserbase | tako; OpenRouter: native | exa | firecrawl | parallel | perplexity)
32
+ # MODEL_GATEWAY_SEARCH_RESULTS=3 # optional: results per search, folded into the prompt as input tokens (Exa pages run 2k-10k tokens each; perplexity caps tokens)
33
+ # MODEL_GATEWAY_BASE_URL= # optional: a self-hosted proxy speaking the same chat-completions dialect
34
+ # MODEL_GATEWAY_MODEL_MAP= # optional: "claude-sonnet-4-6=anthropic/claude-sonnet-4.6,jev-latest=typesafe-ai/jev,..."
35
+
36
+ # ── Required for cloud models (without a gateway) ─────────────────────────────
6
37
  # Google AI Studio API key — powers all Gemini model inference.
7
38
  # Also required for the gemini-embedding-001 embedding model used by long-term memory.
8
39
  # Get yours free at: https://aistudio.google.com
@@ -102,6 +133,19 @@ MOONSHOT_API_KEY=
102
133
  DEEPSEEK_API_KEY=
103
134
  # DEEPSEEK_BASE_URL= # a proxy speaking the same chat-completions dialect
104
135
 
136
+ # ── Optional: TypeSafe Jev (a decision model, not a chat model) ──────────────
137
+ # Required only when using jev-* model identifiers in YAML (jev-latest is the
138
+ # alias for the newest release; jev-1.14.0 and jev-1.13.0 are the ids). Jev
139
+ # answers an agent's output.schema as typed decisions with calibrated
140
+ # probabilities, at $0.042 per million input tokens and nothing for output;
141
+ # it writes no prose, calls no tool and shows no reasoning, so it is the model
142
+ # of a classifier agent (examples/classifier.yaml), never of an orchestrator.
143
+ # Get your key at: https://console.typesafe.ai/keys. Without it, MODEL_GATEWAY
144
+ # serves jev-* ids on the gateway's System One route (typesafe-ai/jev on
145
+ # Vercel, typesafe/jev-1.14 on OpenRouter).
146
+ TYPESAFE_API_KEY=
147
+ # TYPESAFE_BASE_URL= # a proxy speaking TypeSafe's System One wire
148
+
105
149
  # XAI_COLLECTION_IDS: comma-separated xAI Collection ids searched by the
106
150
  # `collections_search` tool (grok-* agents only). Create collections and
107
151
  # upload documents at console.x.ai. Declared with no ids set, the tool is
@@ -320,15 +364,6 @@ MCP_WIKI_PORT=
320
364
  # string (gemini-*, claude-*, ollama/*, ...). Default: gemini-3.8-flash.
321
365
  WIKI_AGENT_MODEL=
322
366
 
323
- # ── Optional: one gateway key for providers you have no key for ───────────────
324
- # A model whose direct key is ABSENT is served through the gateway's OpenAI-
325
- # compatible endpoint (native search tools are dropped on that path; the
326
- # doctor says which). A present direct key always wins.
327
- # MODEL_GATEWAY=vercel # or openrouter
328
- # MODEL_GATEWAY_API_KEY=
329
- # MODEL_GATEWAY_BASE_URL= # optional: a self-hosted proxy speaking the same dialect
330
- # MODEL_GATEWAY_MODEL_MAP= # optional: "claude-sonnet-4-6=anthropic/claude-sonnet-4.6,..."
331
-
332
367
  # ── Optional: tracing ─────────────────────────────────────────────────────────
333
368
  # Send every span to any OTLP/HTTP backend (Phoenix, Langfuse, Jaeger, Tempo):
334
369
  # a local Phoenix is `docker run -p 6006:6006 arizephoenix/phoenix`.
@@ -378,6 +413,14 @@ WIKI_AGENT_MODEL=
378
413
  # Fact extraction runs on any model id (routed like an agent's model); the
379
414
  # embedder is gemini (default), openai, ollama or any OpenAI-compatible
380
415
  # endpoint. The dimension must match the vector column (768 in db/migrations).
416
+ # With no key for the embedding provider, or MODEL_GATEWAY_PREFER=gateway, the
417
+ # embedder goes through the gateway when it carries the same model (Vercel does
418
+ # for gemini-embedding-001; OpenRouter has no Gemini one: set
419
+ # MEMORY_EMBEDDING_PROVIDER=openai to embed text-embedding-3-small at 768 through
420
+ # it). The store records the model its vectors come from on the first write
421
+ # (migration 0023) and refuses a different one at start: switching models means
422
+ # re-embedding every stored fact, never mixing them. `npm run doctor` says what
423
+ # would embed here.
381
424
  # MEMORY_EXTRACTION_MODEL=gemini-3.8-flash
382
425
  # MEMORY_EMBEDDING_PROVIDER=gemini
383
426
  # MEMORY_EMBEDDING_MODEL=
package/AGENT_SETUP.md CHANGED
@@ -74,7 +74,10 @@ After the agent reports back:
74
74
  `OPENAI_API_KEY` for `gpt-*` (https://platform.openai.com/api-keys),
75
75
  `XAI_API_KEY` for `grok-*` (https://console.x.ai),
76
76
  `MOONSHOT_API_KEY` for `kimi-*` (https://platform.moonshot.ai),
77
- `DEEPSEEK_API_KEY` for `deepseek-*` (https://platform.deepseek.com/api_keys). Not sure which
77
+ `DEEPSEEK_API_KEY` for `deepseek-*` (https://platform.deepseek.com/api_keys),
78
+ `TYPESAFE_API_KEY` for `jev-*` (https://console.typesafe.ai/keys; a decision
79
+ model for classifier agents). Or one `MODEL_GATEWAY` + `MODEL_GATEWAY_API_KEY`
80
+ (Vercel AI Gateway or OpenRouter) for every cloud id at once. Not sure which
78
81
  you need? `npm run doctor` reads every syndicate and prints what is
79
82
  ready, what is blocked, and which variable unlocks what — read-only,
80
83
  no key value shown. Verify the whole multi-provider surface live with
package/CHANGELOG.md CHANGED
@@ -4,6 +4,131 @@ 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
+ ## 1.13.0 — 2026-10-24
8
+
9
+ **A Prompt Writer template.** `templates/prompt_writer.yaml` writes
10
+ production prompts for an agent or a whole syndicate from a plain
11
+ description, or diagnoses and rewrites a prompt someone pastes. An Editor
12
+ runs a bounded loop: an Architect settles the topology, capabilities and
13
+ trust boundary on a design sheet, a Writer writes every prompt in the
14
+ Lyceum block anatomy (tool and MCP doctrines, subagent descriptions,
15
+ `require_approval` on writes, one `[NEEDS: …]` variable per missing fact),
16
+ and an Auditor checks it against a ten-rule checklist (`prompt_checklist`)
17
+ and, when YAML is asked for, a verified skeleton (`yaml_shape`). Every
18
+ agent runs on `gemini-4-argon`; session memory keeps the design across
19
+ turns. Its prompts were written by `gemini-4-argon` from the course's
20
+ lessons. Run live 2026-10-23: a two-agent MCP design whose YAML loads, a
21
+ prompt repair that the Auditor sent back once, and the off-topic reply.
22
+
23
+ ## 1.12.0 — 2026-10-23
24
+
25
+ A minor release: TypeSafe's Jev joins the providers as a decision model, and
26
+ one gateway key is the first thing the setup offers.
27
+
28
+ **TypeSafe Jev is a provider** (ADR 0144). `jev-*` ids route to the new
29
+ `JevAdapter` (exported from `melchizedek-agents/model`, beside
30
+ `DeepSeekAdapter`), against `https://api.typesafe.ai/v1/systemone` with
31
+ `TYPESAFE_API_KEY` (`TYPESAFE_BASE_URL` for a proxy); `jev-latest` is the
32
+ default (`DEFAULT_JEV_MODEL`). Jev is not a chat model: it answers an
33
+ agent's `output.schema` as typed decisions with calibrated probabilities,
34
+ in about a tenth of a second, at $0.042 per million input tokens and nothing
35
+ for output. The schema is the request: a boolean property becomes a yes/no
36
+ question, a string with `enum` or a `oneOf` of described constants a
37
+ choice, an integer whose `oneOf` describes the levels 0..n-1 a score; the
38
+ instruction and the conversation are the state; the final is the schema's
39
+ object with the raw answers under a reserved `jev` key. The same call from
40
+ code is `decide()`, typed on its questions (`noul`, `choice`, `score`), with
41
+ `questionsFromSchema` and `objectFromAnswers` beside it. Jev takes no tools,
42
+ no reasoning, no streaming and no images, and says so in the capability
43
+ matrix; an agent with no schema, or with a property Jev cannot decide, fails
44
+ before any call (`TYPESAFE_SCHEMA_REQUIRED`, `TYPESAFE_SCHEMA_UNSUPPORTED`,
45
+ naming the property). The starter pack gains `classifier.yaml`, a
46
+ support-triage classifier on `jev-latest` (`npm run syndicate:classifier`).
47
+ The doctor, the setup guide (`ONBOARDING.md`), `.env.example`, the
48
+ `model_overrides` keys (`typesafe`), the onboarding skills and the skill
49
+ briefs know it. Run live through Vercel AI Gateway (the classifier and
50
+ every id, 2026-10-23); TypeSafe's own API and OpenRouter not yet.
51
+
52
+ **A gateway serves Jev too.** With no `TYPESAFE_API_KEY`, `MODEL_GATEWAY`
53
+ serves `jev-*` ids on the gateway's own System One route: Vercel AI
54
+ Gateway's `/typesafe/v1/systemone` as `typesafe-ai/jev`, OpenRouter's
55
+ `/api/v1/systemone` as `typesafe/jev-1.14` (`MODEL_GATEWAY_MODEL_MAP` fixes
56
+ an id). The gateway's `slugs` table has a `typesafe` entry and each gateway a
57
+ `systemOne` route (`GatewayInfo`).
58
+
59
+ **The gateway settings read through the credential source.**
60
+ `MODEL_GATEWAY`, `MODEL_GATEWAY_BASE_URL` and `MODEL_GATEWAY_MODEL_MAP` are
61
+ read with `credentialValue`, as the key already was (ADR 0133), so an
62
+ embedding application that holds them in a keychain, not the environment,
63
+ turns the gateway on too.
64
+
65
+ **The gateway can come first** (ADR 0145). `MODEL_GATEWAY_PREFER=gateway`
66
+ sends every cloud id through the configured gateway even beside its direct
67
+ key (one bill, one dashboard); `MODEL_GATEWAY_EXCEPT=gemini,xai` names the
68
+ providers that take the opposite of the preference either way (Gemini kept
69
+ on its own key for grounding under `prefer=gateway`; Grok sent through the
70
+ gateway under the default). Unset, nothing changes: a direct key wins.
71
+ Ollama and an A2A caller's own key stay direct; a preferred path that is
72
+ not funded falls back to the other; the doctor names a misspelt preference
73
+ or an unknown provider. `gatewayPreference`, `gatewayExceptions` and
74
+ `providerTransport` are exported from `melchizedek-agents/registry`.
75
+
76
+ **A gateway searches and embeds** (ADR 0146). On the gateway path an
77
+ agent's `web_search` is no longer dropped: Vercel AI Gateway runs its
78
+ server search tool (`vercel:exa_search` by default) and OpenRouter its web
79
+ plugin (the provider's native search where the model has one, else Exa),
80
+ whose `url_citation` annotations the chat-completions base now keeps as the
81
+ final's `grounding.citations` (`groundingOf`). `MODEL_GATEWAY_SEARCH` names
82
+ the engine or turns it off; `x_search` and `collections_search` stay
83
+ dropped. Long-term memory's embedder goes through the gateway's
84
+ `/embeddings` when the gateway carries the same model (Vercel:
85
+ `google/gemini-embedding-001`, `openai/text-embedding-3-small`; OpenRouter:
86
+ OpenAI's) and the provider's own key is absent or the gateway is preferred,
87
+ so the vectors stay the model's own. `GatewayInfo` gains `search` and
88
+ `embeddings`; `gatewaySearch`, `gatewaySearchProblem` and
89
+ `gatewayEmbedding` are exported from `melchizedek-agents/models/gateway`;
90
+ `gatewayConfig`, `gatewayPreference`, `gatewayExceptions` and
91
+ `gatewayWanted` take an optional `env`. The capability matrix's gateway
92
+ row reads `native_search` as degraded, with the note.
93
+
94
+ **A gateway's search is bounded, and a memory store can be re-embedded**
95
+ (ADR 0148). `MODEL_GATEWAY_SEARCH_RESULTS` (default 3) is passed as each
96
+ gateway search engine's count, Exa on its instant type and Perplexity under
97
+ a token cap, since the results are billed as prompt tokens (an unbounded Exa
98
+ search measured about 20,000 of them). `npm run memory -- reembed` re-embeds
99
+ every stored fact with the environment's embedder in id-ordered pages and
100
+ records the new model last (`MemoryStore` gains `listFacts`,
101
+ `updateEmbeddings`, `setEmbedder`; migration 0023 gains
102
+ `melchizedek_memory_set_embedder`), under an advisory lock on
103
+ `DATABASE_URL`. The setup note and the env template state the posture: a
104
+ gateway is for billing and breadth, not for grounding; keep the searching
105
+ provider on its own key. The lockfile moves `body-parser`, `fast-uri` and
106
+ `ip-address` past their advisories (no API change).
107
+
108
+ **A memory store records its embedding model; the doctor says what embeds**
109
+ (ADR 0147, migration `0023_memory_embedder`). On its first successful write
110
+ the memory service records the provider, model and dimension the store's
111
+ vectors come from, and at start it refuses an embedder whose model differs,
112
+ naming the recorded one and the two ways out (set the embedder back, or
113
+ re-embed every fact); a gateway's spelling of the same model passes. The
114
+ doctor gains a `memory` line from `embedderPlan` (exported from
115
+ `melchizedek-agents/memory`): what embeds long-term memory, on which path,
116
+ or what to set, with OpenRouter's documented answer
117
+ (`MEMORY_EMBEDDING_PROVIDER=openai`, `text-embedding-3-small` at 768) and
118
+ the re-embed caveat (`memoryProvidersFromEnv` is exported there too). `MemoryStore` gains optional `embedderRecord` and
119
+ `recordEmbedder`; `db/hardening.sql` locks the new table like the others.
120
+
121
+ **One gateway key is the first thing offered.** `.env.example` opens with
122
+ the `MODEL_GATEWAY` block (one Vercel AI Gateway or OpenRouter key for every
123
+ cloud model whose direct key is absent), the README's cloud quick start
124
+ leads with it, and the keys onboarding skill suggests it first when a person
125
+ has no preference. The routing rule is unchanged: a direct key beside it
126
+ always wins for its provider.
127
+
128
+ **Price rows for Jev** (migration `0022_typesafe_jev_pricing`): `jev-latest`,
129
+ `jev-preview`, `jev-1.14.0` and `jev-1.13.0` at $0.042 input, $0 output. An
130
+ existing row is never overwritten.
131
+
7
132
  ## 1.11.1 — 2026-10-22
8
133
 
9
134
  **Price rows for `grok-4.3`, `gemini-embedding-001` and `gemini-3.5-flash`**
package/DOCUMENTATION.md CHANGED
@@ -143,7 +143,7 @@ Field reference:
143
143
  | `reasoning` | agent | How hard the agent reasons, on any provider: `none`, `low`, `medium`, `high`, `xhigh`, `max`, or `{ budget_tokens: <int> }`. The compiler sends each provider the field it reads: a thinking level on Gemini 3, a thinking budget on Claude 4.6 and earlier (2,048 / 8,192 / 16,384 tokens for low / medium / high), adaptive thinking with that effort on later Claude models ([ADR 0049](./wiki/decisions/0049-claude-requests-by-model-generation.md)), an effort word on GPT, Grok, Kimi, DeepSeek (beside its thinking switch), Ollama and the gateway ([ADR 0047](./wiki/decisions/0047-provider-neutral-reasoning-key.md)). `xhigh` and `max` reach the models that take them (both on Claude from Opus 4.7 and Sonnet 5, `max` on Kimi K3, `xhigh` on GPT-5.2 and later and grok-4.7); elsewhere the model's highest setting is sent and the span carries `llm.reasoning.weakened` (`npm run doctor -- --matrix` lists each path, [ADR 0117](./wiki/decisions/0117-tool-choice-and-effort-above-high-in-v2.md)). Unset, each adapter keeps its own default. |
144
144
  | `sampling` | agent | `{ temperature, top_p, max_output_tokens, stop }`, the fields the engine sends to every provider; each adapter sends the ones its API takes ([ADR 0115](./wiki/decisions/0115-yaml-schema-v2-provider-neutral-keys.md)). |
145
145
  | `output` | agent | `{ schema, mime }`. `mime` is `application/json` (JSON mode, with or without a schema) or `text/plain` (the default). `schema` is the structured-JSON contract: the agent ends its turn on one JSON object matching it. An orchestrator may hold one beside its subagents: it delegates first, then answers in the schema itself. The schema travels in the provider's own structured-output field beside the tools on Claude from Opus 4.8, Sonnet 5 and Haiku 5.5, on OpenAI, and on Gemini 2+ through Vertex AI, and as a `set_model_response` tool elsewhere (the capability matrix's `structured_output_with_tools`, [ADR 0109](./wiki/decisions/0109-structured-output-beside-tools.md)). Worked example: `examples/structured_critic.yaml`. A leaf that holds the schema (`critic.yaml`) and plan-dispatch remain the choices when the answer should be a specialist's. |
146
- | `model_overrides` | agent | A prompt nuance for one provider: keyed by `gemini`, `anthropic`, `openai`, `xai`, `moonshot`, `deepseek` or `ollama`, each entry holds `instruction` (replaces the agent's instruction on that provider) or `instruction_append` (added after a blank line). The entry for the provider of the agent's `model` applies, before the skills index is appended; a `fallback_model` gets the primary's instruction. |
146
+ | `model_overrides` | agent | A prompt nuance for one provider: keyed by `gemini`, `anthropic`, `openai`, `xai`, `moonshot`, `deepseek`, `typesafe` or `ollama`, each entry holds `instruction` (replaces the agent's instruction on that provider) or `instruction_append` (added after a blank line). The entry for the provider of the agent's `model` applies, before the skills index is appended; a `fallback_model` gets the primary's instruction. |
147
147
  | `tool_choice` | agent | Which tools the model may call: `auto` (the default), `none`, `required` (some tool), or `{ name: <tool> }` (that tool). A provider that rejects forcing sends a weaker choice and marks the span `llm.tool_choice.weakened` ([ADR 0117](./wiki/decisions/0117-tool-choice-and-effort-above-high-in-v2.md)). |
148
148
  | `generateContentConfig` / `outputSchema` | agent | The deprecated v1 spelling of `sampling`, `output.mime`, `reasoning` (as `thinkingConfig` / `reasoningEffort`), `tool_choice` (as `toolConfig.functionCallingConfig`) and `output.schema`. Both still load and behave the same; a load that finds either prints one deprecation line per file per process (`LoadSyndicateOptions.onWarning`, default `console.warn`), and a v2 key beside its v1 spelling on one agent is a load error. Only `toolConfig.functionCallingConfig.mode: VALIDATED` and Gemini's dynamic budget (`thinkingBudget: -1`) have no v2 form; `topK`, `seed`, the penalties, `candidateCount`, `safetySettings` and `includeThoughts` reach no provider, and the codemod drops `includeThoughts`. `npx melchizedek-codemod [--check] <file|dir>` rewrites a v1 file to v2, comments kept ([ADR 0115](./wiki/decisions/0115-yaml-schema-v2-provider-neutral-keys.md)). |
149
149
  | `yaml_reference` | subagent | Mount another syndicate file as a nested subagent. |
@@ -291,7 +291,8 @@ in `examples/specs/`.
291
291
  > dialect; every non-Gemini adapter normalizes them back to
292
292
  > standard lowercase JSON-Schema at request-build time
293
293
  > (`lib/models/schemaNormalize.ts`). MCP tools therefore work on any
294
- > provider's agents — Gemini, Claude, GPT, Grok, Kimi, or DeepSeek.
294
+ > provider's agents — Gemini, Claude, GPT, Grok, Kimi, or DeepSeek (never
295
+ > Jev, which calls no tool).
295
296
 
296
297
  ## 4. Sessions & long-term memory
297
298
 
@@ -413,8 +414,9 @@ accordingly — model optionality is a single YAML line per agent:
413
414
  | `grok-*` | xAI | `lib/models/grokAdapter.ts` (Responses API) | `XAI_API_KEY` | ✅ Agent Tools search |
414
415
  | `kimi-*` | Moonshot AI (Kimi) | `lib/models/kimiAdapter.ts` (chat completions) | `MOONSHOT_API_KEY` | ⚠ omitted + warning |
415
416
  | `deepseek-*` | DeepSeek | `lib/models/deepseekAdapter.ts` (chat completions) | `DEEPSEEK_API_KEY` | ⚠ omitted + warning |
417
+ | `jev-*` | TypeSafe (Jev, a decision model) | `lib/models/jevAdapter.ts` (System One) | `TYPESAFE_API_KEY` | ✗ no tools at all |
416
418
  | `ollama/*` | Local Ollama | `lib/models/ollamaAdapter.ts` (chat completions) | none | ⚠ omitted + warning |
417
- | *any cloud id whose direct key is absent* | the id's own provider, via a gateway | `lib/models/gatewayAdapter.ts` (chat completions) | `MODEL_GATEWAY` + `MODEL_GATEWAY_API_KEY` | ⚠ omitted + reported |
419
+ | *any cloud id whose direct key is absent, or every cloud id under `MODEL_GATEWAY_PREFER=gateway`* | the id's own provider, via a gateway | `lib/models/gatewayAdapter.ts` (chat completions; `jev-*` keeps `JevAdapter` on the gateway's System One route) | `MODEL_GATEWAY` + `MODEL_GATEWAY_API_KEY` | ◐ the gateway's own search (`MODEL_GATEWAY_SEARCH`) |
418
420
 
419
421
  The xAI adapter carries the deepest capability surface: `grok-4.5`
420
422
  requests pin `reasoning.effort: "medium"` (`lib/config.ts`), SSE
@@ -498,6 +500,102 @@ warning, `web_extract` works). Through `MODEL_GATEWAY` the ids go as
498
500
  capability matrix is asserted against the request body the adapter sends;
499
501
  it has not been run live.
500
502
 
503
+ **TypeSafe (Jev).** `jev-*` ids route to `JevAdapter`
504
+ (`lib/models/jevAdapter.ts`), against `https://api.typesafe.ai/v1/systemone`
505
+ (`TYPESAFE_BASE_URL` for a proxy). Get a key at console.typesafe.ai/keys.
506
+ Jev is a System One model, not a chat model: one request carries a `state`
507
+ and typed `questions`, and the answer is one typed decision per question
508
+ with calibrated probabilities, never prose, never a tool call, in about a
509
+ tenth of a second at $0.042 per million input tokens and nothing for output
510
+ (migration 0022). The engine makes it the model of a classifier agent: the
511
+ agent's `output.schema` becomes the questions (`lib/models/jev.ts`
512
+ `questionsFromSchema`: a boolean property is a yes/no `noul` question, a
513
+ string with `enum` or a `oneOf` of described constants is a `choice`, an
514
+ integer whose `oneOf` describes the levels 0..n-1 in order is a `score`;
515
+ the property's `description` is the question), the instruction and the
516
+ conversation's text are the state, and the final is the schema's object
517
+ with the raw answers under a reserved `jev` key, so code acts on
518
+ confidence. The ids are `jev-latest` (the default, TypeSafe's alias for the
519
+ newest stable release), `jev-preview`, `jev-1.14.0` and `jev-1.13.0`
520
+ (`GET /v1/models` lists them); 64k tokens per request, 32k per question.
521
+ What works: structured output, direct or through either gateway (Vercel AI
522
+ Gateway's `/typesafe/v1/systemone` as `typesafe-ai/jev`, OpenRouter's
523
+ `/api/v1/systemone` as `typesafe/jev-1.14`, `MODEL_GATEWAY_MODEL_MAP` for
524
+ either). What does not, by the nature of the model: tools and delegation
525
+ (dropped; the doctor names an agent with tools on a Jev id as a gap),
526
+ `reasoning:`, streaming (the final is the only response), images (dropped)
527
+ and native search. An agent with no `output.schema`, or with a property Jev
528
+ cannot decide (a free string, an array, a nested object), fails before any
529
+ call with `TYPESAFE_SCHEMA_REQUIRED` or `TYPESAFE_SCHEMA_UNSUPPORTED`,
530
+ naming the property and the shapes Jev takes. `examples/classifier.yaml`
531
+ is the pattern, and `decide()` from `melchizedek-agents/model` is the same
532
+ call from code, typed on its questions (`noul`, `choice`, `score`). The
533
+ row in the capability matrix is asserted against the request body the
534
+ adapter sends; the classifier and all four ids were run live through
535
+ Vercel AI Gateway on 2026-10-23 (answers in 150 to 715 ms); TypeSafe's own
536
+ API and OpenRouter's route were not.
537
+
538
+ **Which path wins.** By default a provider's own key wins for its
539
+ provider and the gateway serves only what has no key (ADR 0012).
540
+ `MODEL_GATEWAY_PREFER=gateway` turns that round: every cloud id goes
541
+ through the configured gateway even beside a direct key, one bill and one
542
+ dashboard, at the gateway's fidelity (no native search). `MODEL_GATEWAY_EXCEPT`
543
+ is a comma list of provider ids that take the opposite of the preference
544
+ either way: `gemini` under `prefer=gateway` keeps Gemini on its own key for
545
+ grounding; `xai` under the default sends Grok through the gateway while
546
+ everything else stays direct. Two things never move: `ollama/*` is always
547
+ direct, and an A2A caller's own key (BYOK) funds its provider directly. A
548
+ preference whose path is not funded falls back to the other; an unknown
549
+ preference word or a provider name the list does not know is named by the
550
+ doctor (ADR 0145). Both variables are read through the credential source,
551
+ like the key.
552
+
553
+ **What a gateway gives back** (ADR 0146). An agent's `web_search` (or
554
+ `google_search`) is not dropped on the gateway path: it runs as the
555
+ gateway's own search, on any model. Vercel AI Gateway runs a server tool
556
+ (`vercel:exa_search` by default; `MODEL_GATEWAY_SEARCH` picks `exa`,
557
+ `perplexity`, `parallel`, `browserbase` or `tako`): the gateway searches,
558
+ folds the results into the model's context and answers in the same
559
+ response, the span counts the calls, and no citations come back. OpenRouter
560
+ runs its web plugin, which is the provider's native search where the model
561
+ has one (OpenAI, Anthropic, Google, xAI) and Exa elsewhere
562
+ (`MODEL_GATEWAY_SEARCH` picks `native`, `exa`, `firecrawl`, `parallel` or
563
+ `perplexity`), and returns `url_citation` annotations the adapter keeps as
564
+ the final's `grounding.citations`. `MODEL_GATEWAY_SEARCH=off` drops the tool
565
+ as before. `MODEL_GATEWAY_SEARCH_RESULTS` (default 3) is passed as each
566
+ engine's count, Exa on its instant type and Perplexity under a cap of
567
+ 2,000 tokens a result (ADR 0148), because the gateway folds the results into
568
+ the prompt as input tokens: measured live, Exa at three results carried
569
+ 7,000 to 17,600 prompt tokens for a one-line question (unbounded, 13,000 to
570
+ 20,000), Perplexity at three 6,200. Each gateway also bills its search on
571
+ top of the tokens (Exa about $0.007 a request on OpenRouter; Vercel prices
572
+ its engines). A gateway is for billing and breadth, not for grounding: for a
573
+ search-heavy agent, keep the provider that does the searching on its own key
574
+ (its native search and citations) and let the gateway serve the rest, which
575
+ a direct key beside the gateway key does by default and
576
+ `MODEL_GATEWAY_EXCEPT` keeps under `MODEL_GATEWAY_PREFER=gateway`. xAI's `x_search`
577
+ and `collections_search` have no gateway form and are dropped. Long-term
578
+ memory's embedder follows the same rule: with no key for the embedding
579
+ provider, or under `MODEL_GATEWAY_PREFER=gateway`, it embeds through the
580
+ gateway's `/embeddings` when the gateway carries the same model (Vercel
581
+ carries `google/gemini-embedding-001` and `openai/text-embedding-3-small`
582
+ and honours `dimensions`, checked live at 768; OpenRouter carries OpenAI's
583
+ only), so a store embedded directly and one embedded through the gateway
584
+ hold the same vectors; a gateway that lacks the model changes nothing.
585
+ OpenRouter carries no Gemini embedding model, so with no Gemini key the
586
+ documented answer there is `MEMORY_EMBEDDING_PROVIDER=openai`
587
+ (`text-embedding-3-small` at 768, a tenth of Gemini's price), with one
588
+ caveat the store now enforces (migration 0023, ADR 0147): a memory store
589
+ records the provider, model and dimension its vectors come from on its
590
+ first write and refuses a different model at start, since two models'
591
+ vectors do not compare even at the same size; switching means re-embedding
592
+ every stored fact, which `npm run memory -- reembed` does (a dry run first;
593
+ `--yes` writes): with `MEMORY_EMBEDDING_*` set to the new embedder it walks
594
+ the facts in id order, writes each page's vectors back and records the new
595
+ model last, under an advisory lock on `DATABASE_URL`, so an interrupted run
596
+ leaves the old record in place (ADR 0148). `npm run doctor` prints a
597
+ `memory` line saying what would embed here, or what to set.
598
+
501
599
  **Which keys do I need?** `npm run doctor` (the `melchizedek-doctor` bin)
502
600
  reads every syndicate YAML, resolves each agent's model under your `.env`,
503
601
  and prints one table — agent, model, provider, which declared server-side
@@ -626,7 +724,9 @@ in a `FallbackAdapter`.
626
724
  `melchizedek-agents/model` is the model layer on its own (ADR 0068): the
627
725
  contract's types,
628
726
  `ClaudeAdapter`, `GptAdapter`, `GrokAdapter`, `KimiAdapter`, `DeepSeekAdapter`,
629
- `OllamaAdapter`, `GatewayAdapter`, `GeminiAdapter`, the
727
+ `JevAdapter` (with `decide`, `noul`, `choice`, `score`, `questionsFromSchema`
728
+ and `objectFromAnswers` beside it), `OllamaAdapter`, `GatewayAdapter`,
729
+ `GeminiAdapter`, the
630
730
  `ChatCompletionsAdapter` base, `resolveAdapter`,
631
731
  `resolveAdapterWithFallback`, `FallbackAdapter` and the circuit breaker's
632
732
  helpers. A project that only calls models imports from there. Its
@@ -698,7 +798,8 @@ calls), and `syndicate.usage` carries `cache_read` / `cache_write` per
698
798
  model. `model_pricing.cache_read_per_mtok` / `cache_write_per_mtok` price
699
799
  them (migration 0017; NULL prices them as input), seeded for Anthropic and
700
800
  OpenAI from their price lists (ADR 0139). Migration 0019 adds DeepSeek (at
701
- its peak rate) and Moonshot Kimi rows.
801
+ its peak rate) and Moonshot Kimi rows; 0022 adds TypeSafe Jev (input only,
802
+ output free).
702
803
  Operate it with `npm run telemetry:stats`,
703
804
  `telemetry:prune` and `telemetry:replay` (the exporter spools failed
704
805
  batches to `outputs/telemetry-deadletter.ndjson`).
@@ -880,7 +981,7 @@ names; nothing is kept by the framework anywhere else.
880
981
  | The prompt: the user's message, the conversation, tool results | The model provider of each agent that runs (the model-id prefix) | The provider's policy | The `model:` lines in the YAML; `ollama/` ids stay on your machine |
881
982
  | Tool calls (`web_search`, `web_extract`, OpenAPI, MCP) | The tool's own host | That host's policy | The agent's `tools:`, `openapi:`, `mcp_server_url` / `mcp_tools` |
882
983
  | Sessions (conversation history) | Your Postgres, `adk_sessions` | 7 days after the last message | `ttlDays` (`postgresStorage`) |
883
- | Long-term memory facts | Your Postgres, `adk_memory_facts`; **the transcript is also sent to the extraction and embedding providers, Gemini by default whatever the agents run on** (the server warns at boot when they differ) | Until erased, or `memory_retention_days` | `MEMORY_EXTRACTION_MODEL`, `MEMORY_EMBEDDING_PROVIDER`, `memory_retention_days` |
984
+ | Long-term memory facts | Your Postgres, `adk_memory_facts`; **the transcript is also sent to the extraction and embedding providers, Gemini by default whatever the agents run on** (the server warns at boot when they differ; through the gateway when it carries the embedding model, ADR 0146) | Until erased, or `memory_retention_days` | `MEMORY_EXTRACTION_MODEL`, `MEMORY_EMBEDDING_PROVIDER`, `memory_retention_days` |
884
985
  | The ledger: each turn's input, output and tool results (key-shaped secrets redacted) | Your Postgres, `adk_turns`, `adk_telemetry` | **Until you prune it**: schedule `melchizedek_prune_telemetry(<days>)` | `TELEMETRY_REDACT`, the prune's `turn_days` |
885
986
  | Sampled full model requests | Your Postgres, `adk_payloads` | 30 days | `TELEMETRY_PAYLOADS`, `TELEMETRY_PAYLOAD_TTL_DAYS` |
886
987
  | Traces, when `OTEL_EXPORTER_OTLP_ENDPOINT` is set | Your OTLP collector, conversation content included with key-shaped secrets redacted (`off` drops it) | Your collector's policy | `OTEL_EXPORT_CONTENT` (`redacted`, `off`, `raw`) |
@@ -1680,7 +1781,7 @@ the canonical minimal block on the engine's model contract:
1680
1781
  `resolveAdapter(modelId)` from `melchizedek-agents/model`, then
1681
1782
  `adapter.generate({ model, system, messages, stream })`, reading partial
1682
1783
  and final responses. The id's prefix picks the provider (`gemini-*`,
1683
- `claude-*`, `gpt-*`, `grok-*`, `kimi-*`, `deepseek-*`, `ollama/*`), the key comes from
1784
+ `claude-*`, `gpt-*`, `grok-*`, `kimi-*`, `deepseek-*`, `jev-*`, `ollama/*`), the key comes from
1684
1785
  the environment. A turn
1685
1786
  with tools, sessions and telemetry is `runSyndicateTurn`.
1686
1787
 
package/ONBOARDING.md CHANGED
@@ -9,7 +9,7 @@ In a clone, the commands are spelled as npm scripts (`npm run doctor`, `npm run
9
9
  | # | You have | Guide |
10
10
  |---|---|---|
11
11
  | 1 | Nothing yet: run open-weight models locally (Ollama, no key) | `--level local` |
12
- | 2 | One provider's API key (Gemini, Anthropic, OpenAI, xAI, Moonshot or DeepSeek) | `--level one-provider` |
12
+ | 2 | One provider's API key (Gemini, Anthropic, OpenAI, xAI, Moonshot, DeepSeek or TypeSafe) | `--level one-provider` |
13
13
  | 3 | API keys for several providers | `--level several-providers` |
14
14
  | 4 | One gateway key (Vercel AI Gateway or OpenRouter) | `--level gateway` |
15
15
  | 5 | Cloud platform credentials (Vertex AI, Amazon Bedrock, Azure OpenAI) | `--level cloud-platform` |
@@ -63,17 +63,19 @@ The model id's prefix picks the provider, and that provider's key funds it. One
63
63
  | `XAI_API_KEY` | an API key from https://console.x.ai | xAI Grok: model ids grok-* |
64
64
  | `MOONSHOT_API_KEY` | an API key from https://platform.moonshot.ai | Moonshot Kimi: model ids kimi-* |
65
65
  | `DEEPSEEK_API_KEY` | an API key from https://platform.deepseek.com/api_keys | DeepSeek: model ids deepseek-* |
66
+ | `TYPESAFE_API_KEY` | an API key from https://console.typesafe.ai/keys | TypeSafe Jev: model ids jev-* (a decision model: it answers an output.schema, never prose) |
66
67
 
67
68
  **Confirm:** `npx melchizedek-doctor`: the providers line shows a ✓ beside your provider, and the files of that tier read `ready`.
68
69
 
69
70
  **Runs at this level:**
70
71
 
71
- - GOOGLE_GENAI_API_KEY: account_memory (template), case_desk (template), draft_review (template), intake_extractor (template), research_brief (template), research_desk (template), review_panel (template), support_triage (template), systems_operator (template), ares (example), cartographers (example), connectors (example), critic (example), current_events (example), delegation (example), harness (example), hierarchical (example), image_production (example), librarian (example), patient_advocate (example), pipeline (example), research (example), scribe (example), scriptorium (example), style_council (example), syndicate (example), weather (example)
72
+ - GOOGLE_GENAI_API_KEY: account_memory (template), case_desk (template), draft_review (template), intake_extractor (template), prompt_writer (template), research_brief (template), research_desk (template), review_panel (template), support_triage (template), systems_operator (template), ares (example), cartographers (example), connectors (example), critic (example), current_events (example), delegation (example), harness (example), hierarchical (example), image_production (example), librarian (example), patient_advocate (example), pipeline (example), research (example), scribe (example), scriptorium (example), style_council (example), syndicate (example), weather (example)
72
73
  - ANTHROPIC_API_KEY: claude (example), structured_critic (example)
73
74
  - OPENAI_API_KEY: no shipped file yet (change a `model:` line to use one)
74
75
  - XAI_API_KEY: no shipped file yet (change a `model:` line to use one)
75
76
  - MOONSHOT_API_KEY: no shipped file yet (change a `model:` line to use one)
76
77
  - DEEPSEEK_API_KEY: no shipped file yet (change a `model:` line to use one)
78
+ - TYPESAFE_API_KEY: classifier (example)
77
79
  - with no key at all: conversational (template), assistant (example), council (example), event_assistant (example), tutor (example)
78
80
 
79
81
  **First commands:**
@@ -104,6 +106,7 @@ Each key funds its own provider, and a syndicate may mix them: one agent on Clau
104
106
  | `XAI_API_KEY` | an API key from https://console.x.ai | xAI Grok: model ids grok-* |
105
107
  | `MOONSHOT_API_KEY` | an API key from https://platform.moonshot.ai | Moonshot Kimi: model ids kimi-* |
106
108
  | `DEEPSEEK_API_KEY` | an API key from https://platform.deepseek.com/api_keys | DeepSeek: model ids deepseek-* |
109
+ | `TYPESAFE_API_KEY` | an API key from https://console.typesafe.ai/keys | TypeSafe Jev: model ids jev-* (a decision model: it answers an output.schema, never prose) |
107
110
 
108
111
  **Confirm:** `npx melchizedek-doctor`: a ✓ beside each provider you set; `multi-provider` files read `ready` once every provider they use has its key.
109
112
 
@@ -127,7 +130,7 @@ npx melchizedek-chat --syndicate model_zoo
127
130
 
128
131
  ## 4. A gateway key
129
132
 
130
- One key serves every cloud model id whose direct key is absent, through the gateway's OpenAI-compatible endpoint. It is a fallback, never a preempt: a direct key always wins for its provider. Ollama never goes through it.
133
+ One key serves every cloud model id whose direct key is absent, through the gateway's OpenAI-compatible endpoint (and TypeSafe Jev on its System One route). By default it is a fallback: a direct key wins for its provider; MODEL_GATEWAY_PREFER=gateway turns that round, and MODEL_GATEWAY_EXCEPT names the providers that take the opposite. Ollama never goes through it.
131
134
 
132
135
  **Set in `.env`** (names and shapes only; you type the values yourself):
133
136
 
@@ -137,12 +140,14 @@ One key serves every cloud model id whose direct key is absent, through the gate
137
140
  | `MODEL_GATEWAY_API_KEY` | the gateway key (https://vercel.com/ai-gateway or https://openrouter.ai/keys) | funds every id with no direct key |
138
141
  | `MODEL_GATEWAY_BASE_URL` | https URL | optional: a self-hosted proxy speaking the same dialect (LiteLLM) |
139
142
  | `MODEL_GATEWAY_MODEL_MAP` | yaml-id=gateway-id,yaml-id=gateway-id | optional: fix an id the default mapping gets wrong |
143
+ | `MODEL_GATEWAY_PREFER` | direct | gateway | optional: gateway sends every cloud id through the gateway even beside a direct key (one bill); direct, the default, lets each provider's own key win |
144
+ | `MODEL_GATEWAY_EXCEPT` | gemini,xai | optional: providers that take the opposite of the preference (never ollama) |
140
145
 
141
146
  **Confirm:** `npx melchizedek-doctor`: a `gateway` line with no ✗, and providers without a direct key marked `◇ via gateway`.
142
147
 
143
148
  **Runs at this level:**
144
149
 
145
- - every cloud file: account_memory (template), case_desk (template), draft_review (template), intake_extractor (template), research_brief (template), research_desk (template), review_panel (template), support_triage (template), systems_operator (template), ares (example), cartographers (example), connectors (example), critic (example), current_events (example), delegation (example), harness (example), hierarchical (example), image_production (example), librarian (example), patient_advocate (example), pipeline (example), research (example), scribe (example), scriptorium (example), style_council (example), syndicate (example), weather (example), claude (example), structured_critic (example), model_zoo (example)
150
+ - every cloud file: account_memory (template), case_desk (template), draft_review (template), intake_extractor (template), prompt_writer (template), research_brief (template), research_desk (template), review_panel (template), support_triage (template), systems_operator (template), ares (example), cartographers (example), connectors (example), critic (example), current_events (example), delegation (example), harness (example), hierarchical (example), image_production (example), librarian (example), patient_advocate (example), pipeline (example), research (example), scribe (example), scriptorium (example), style_council (example), syndicate (example), weather (example), claude (example), structured_critic (example), classifier (example), model_zoo (example)
146
151
 
147
152
  **First commands:**
148
153
 
@@ -153,8 +158,9 @@ npx melchizedek-chat --syndicate research_brief
153
158
 
154
159
  **Notes:**
155
160
 
156
- - Native search is lost on the gateway path (Gemini grounding, Anthropic and OpenAI web_search, xAI x_search); the doctor marks each dropped tool.
157
- - Long-term memory embeds through Gemini by default, which the gateway does not serve: set GOOGLE_GENAI_API_KEY, or MEMORY_EMBEDDING_PROVIDER=openai or ollama.
161
+ - web_search runs as the gateway's own search on the gateway path (Vercel's exa_search server tool; OpenRouter's web plugin, the provider's native search where it has one, with citations); MODEL_GATEWAY_SEARCH names the engine or turns it off, MODEL_GATEWAY_SEARCH_RESULTS (default 3) bounds what it folds into the prompt, and xAI's x_search and Collections are dropped; the doctor marks each.
162
+ - A gateway is for billing and breadth, not for grounding: for a search-heavy agent, keep the provider that does the searching on its own key (its native search, citations and all) and let the gateway serve the rest; a direct key beside the gateway key does that by default, and MODEL_GATEWAY_EXCEPT keeps it so under MODEL_GATEWAY_PREFER=gateway.
163
+ - Long-term memory embeds through the gateway when it carries the same embedding model (Vercel carries google/gemini-embedding-001). OpenRouter has no Gemini one: set GOOGLE_GENAI_API_KEY, or MEMORY_EMBEDDING_PROVIDER=openai to embed text-embedding-3-small at 768 through it; a store already embedded with Gemini must be re-embedded if the model changes, and the store refuses a different model at start (the doctor's memory line says what would embed).
158
164
 
159
165
  **Onboarding skill:** `melchizedek-onboard-keys` (`npx melchizedek-setup --level gateway` prints this guide)
160
166
 
@@ -182,7 +188,7 @@ The model id still picks the provider; these variables pick the cloud it is reac
182
188
 
183
189
  **Runs at this level:**
184
190
 
185
- - Gemini on Vertex AI: account_memory (template), case_desk (template), draft_review (template), intake_extractor (template), research_brief (template), research_desk (template), review_panel (template), support_triage (template), systems_operator (template), ares (example), cartographers (example), connectors (example), critic (example), current_events (example), delegation (example), harness (example), hierarchical (example), image_production (example), librarian (example), patient_advocate (example), pipeline (example), research (example), scribe (example), scriptorium (example), style_council (example), syndicate (example), weather (example)
191
+ - Gemini on Vertex AI: account_memory (template), case_desk (template), draft_review (template), intake_extractor (template), prompt_writer (template), research_brief (template), research_desk (template), review_panel (template), support_triage (template), systems_operator (template), ares (example), cartographers (example), connectors (example), critic (example), current_events (example), delegation (example), harness (example), hierarchical (example), image_production (example), librarian (example), patient_advocate (example), pipeline (example), research (example), scribe (example), scriptorium (example), style_council (example), syndicate (example), weather (example)
186
192
  - Claude on Bedrock or Vertex AI: claude (example), structured_critic (example)
187
193
  - GPT on Azure OpenAI: no shipped file yet (change a `model:` line to use one)
188
194
 
@@ -215,7 +221,7 @@ The A2A server lets each caller fund its own inference: the caller sends its key
215
221
 
216
222
  **Runs at this level:**
217
223
 
218
- - any file; start from a template: account_memory, case_desk, conversational, draft_review, intake_extractor, research_brief, research_desk, review_panel, support_triage, systems_operator
224
+ - any file; start from a template: account_memory, case_desk, conversational, draft_review, intake_extractor, prompt_writer, research_brief, research_desk, review_panel, support_triage, systems_operator
219
225
 
220
226
  **First commands:**
221
227
 
@@ -254,7 +260,7 @@ A2A_AUTH decides who a caller is, and so whose data a request touches. `callers`
254
260
 
255
261
  **Runs at this level:**
256
262
 
257
- - any file; start from a template: account_memory, case_desk, conversational, draft_review, intake_extractor, research_brief, research_desk, review_panel, support_triage, systems_operator
263
+ - any file; start from a template: account_memory, case_desk, conversational, draft_review, intake_extractor, prompt_writer, research_brief, research_desk, review_panel, support_triage, systems_operator
258
264
 
259
265
  **First commands:**
260
266
 
package/QUICKSTART.md CHANGED
@@ -24,8 +24,9 @@ are the two most common paths spelled out.
24
24
  - Optional: **Ollama** ([ollama.com](https://ollama.com)) for the
25
25
  open-weight local syndicates; provider keys only for the models you
26
26
  actually declare — **Anthropic** (`claude-*`), **OpenAI** (`gpt-*`),
27
- **xAI** (`grok-*`), **Moonshot** (`kimi-*`), **DeepSeek** (`deepseek-*`) — or one `MODEL_GATEWAY` key as the fallback for
28
- whatever direct key is missing (native search is lost on that path);
27
+ **xAI** (`grok-*`), **Moonshot** (`kimi-*`), **DeepSeek** (`deepseek-*`), **TypeSafe** (`jev-*`, a decision model) — or one
28
+ `MODEL_GATEWAY` key (Vercel AI Gateway or OpenRouter) that serves every cloud id whose direct key is missing, Jev included
29
+ (web search then runs as the gateway's own search; x_search is lost on that path);
29
30
  and a free **Supabase project** (only for persistent sessions / memory).
30
31
  Not sure which you need? `npm run doctor` tells you, read-only.
31
32
 
@@ -260,7 +261,8 @@ console.log(result.text);
260
261
  |---|---|
261
262
  | `Gemini API Key is not configured` | `.env` missing or key not set — step 2. |
262
263
  | `[400] Tool call context circulation is not enabled` | The agent's `model:` is too old for agent transfer. Use `gemini-3.8-flash` or newer (all shipped configs already do). |
263
- | `Model not found` for `claude-*` / `gpt-*` / `grok-*` / `kimi-*` / `deepseek-*` | The matching provider key (`ANTHROPIC_API_KEY` / `OPENAI_API_KEY` / `XAI_API_KEY` / `MOONSHOT_API_KEY` / `DEEPSEEK_API_KEY`) is not set in `.env`, so the provider wasn't registered — `npm run doctor` names the variable. Or set `MODEL_GATEWAY` + `MODEL_GATEWAY_API_KEY` once for every cloud provider (native search is lost on that path). |
264
+ | `Model not found` for `claude-*` / `gpt-*` / `grok-*` / `kimi-*` / `deepseek-*` / `jev-*` | The matching provider key (`ANTHROPIC_API_KEY` / `OPENAI_API_KEY` / `XAI_API_KEY` / `MOONSHOT_API_KEY` / `DEEPSEEK_API_KEY` / `TYPESAFE_API_KEY`) is not set in `.env`, so the provider wasn't registered — `npm run doctor` names the variable. Or set `MODEL_GATEWAY` + `MODEL_GATEWAY_API_KEY` once for every cloud provider (web search then runs as the gateway's own). |
265
+ | `TYPESAFE_SCHEMA_REQUIRED` / `TYPESAFE_SCHEMA_UNSUPPORTED` | A `jev-*` agent has no `output.schema`, or one of its properties is not a decision Jev can make. Give every property a decision shape: a boolean, a string with `enum` or a `oneOf` of described constants, or an integer whose `oneOf` describes the levels 0..n-1; the error names the property. `examples/classifier.yaml` is the pattern. |
264
266
  | `GATEWAY_HTTP_ERROR … 404/400` | The gateway rejected the mapped model id. Fix the name once in `.env`: `MODEL_GATEWAY_MODEL_MAP=<your id>=<the gateway's id>`. `GATEWAY_KEY_MISSING` means `MODEL_GATEWAY` is set without `MODEL_GATEWAY_API_KEY`. |
265
267
  | `OLLAMA_UNREACHABLE` for `ollama/*` | Ollama isn't running — start the app or `ollama serve`; then check the model is pulled (`ollama list`). |
266
268
  | `Refusing to connect to private/loopback MCP host` | The SSRF guard is on (correctly). For the local demo set `ALLOW_PRIVATE_MCP=true` in `.env`. |
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  A multi-model, multi-agent orchestration framework with its own agent loop, model contract, tools, sessions and workflow engine. Agent hierarchies, prompts, models, tools, and delegation rules are declared in YAML files called **Syndicates**; the engine in `lib/` runs whatever you put in `config/agents/`.
4
4
 
5
- Gemini, Claude, GPT, Grok, Kimi, and DeepSeek each run on the engine's own adapter for their provider's API, and open-weight models run locally through Ollama with no API key. A subagent can also pick up tools at runtime from a Model Context Protocol (MCP) server.
5
+ Gemini, Claude, GPT, Grok, Kimi, and DeepSeek each run on the engine's own adapter for their provider's API, TypeSafe's Jev answers a classifier's schema as calibrated decisions, and open-weight models run locally through Ollama with no API key. One Vercel AI Gateway or OpenRouter key serves every cloud model you have no direct key for. A subagent can also pick up tools at runtime from a Model Context Protocol (MCP) server.
6
6
 
7
7
  > Companion repository for the curriculum at [lyceumagents.com/curriculum](https://lyceumagents.com/curriculum/). The framework works standalone or alongside the course.
8
8
 
@@ -11,7 +11,7 @@ Gemini, Claude, GPT, Grok, Kimi, and DeepSeek each run on the engine's own adapt
11
11
  ## Features
12
12
 
13
13
  - **Declarative YAML configuration** — Orchestrators, subagents, routing, output schemas, and tool assignments in one readable document. Tools and guards are registered in code; YAML names them.
14
- - **Multi-model routing** — Mix providers within the same agent graph (`gemini-*`, `claude-*`, `gpt-*`, `grok-*`, `kimi-*`, `deepseek-*`, and local `ollama/*`). Switching an agent's model is a one-line change.
14
+ - **Multi-model routing** — Mix providers within the same agent graph (`gemini-*`, `claude-*`, `gpt-*`, `grok-*`, `kimi-*`, `deepseek-*`, `jev-*`, and local `ollama/*`). Switching an agent's model is a one-line change, and one gateway key (`MODEL_GATEWAY`) stands in for every direct key you have not set.
15
15
  - **MCP integration** — Give an agent an `mcp_server_url:`, or several servers under `mcp_servers:`, and their tools are discovered over Streamable HTTP (or legacy SSE) and wrapped as agent tools at runtime. URLs are SSRF-guarded; an OAuth server with no pre-issued client is discovered and registered at, within the operator's host allowlist. In the other direction, `melchizedek-mcp` serves your syndicates as MCP tools to Claude Code, Codex and other MCP clients.
16
16
  - **Persistent sessions & long-term memory** — Optional Supabase backend for session persistence and pgvector memory: transcripts are distilled into structured records and recalled by similarity in later sessions. Without it, sessions run in memory.
17
17
  - **Native tools** — Web search, image generation, and a blind image-inventory tool that accepts only a file path, so the expected result can never reach the observer.
@@ -50,13 +50,15 @@ npm run syndicate:council
50
50
 
51
51
  ### 2. Cloud models
52
52
 
53
+ The quickest way to every cloud model is one gateway key: set `MODEL_GATEWAY=vercel` (or `openrouter`) and `MODEL_GATEWAY_API_KEY` in `.env`, and every shipped syndicate runs, billed to that one account (web search runs as the gateway's own search, and xAI's x_search is the one tool a gateway cannot run; a direct key set beside it wins for its provider by default, and `MODEL_GATEWAY_PREFER=gateway` turns that round, with `MODEL_GATEWAY_EXCEPT` for the providers that take the opposite). Or bring the providers' own keys:
54
+
53
55
  ```bash
54
56
  cp .env.example .env # add GOOGLE_GENAI_API_KEY (free from Google AI Studio)
55
57
  npm run chat:syndicate # interactive REPL with the default syndicate (Gemini)
56
58
  npm run doctor # shows which syndicates your current keys unlock
57
59
  ```
58
60
 
59
- Other providers are optional: `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `XAI_API_KEY`, `MOONSHOT_API_KEY`, and `DEEPSEEK_API_KEY` unlock the syndicates that use them (for example `npm run syndicate:claude`).
61
+ Other providers are optional: `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `XAI_API_KEY`, `MOONSHOT_API_KEY`, `DEEPSEEK_API_KEY` and `TYPESAFE_API_KEY` unlock the syndicates that use them (for example `npm run syndicate:claude`, or `npm run syndicate:classifier` for the Jev decision model).
60
62
 
61
63
  Test the providers you have keys for:
62
64
 
@@ -199,6 +201,7 @@ Configurations live in `config/agents/examples/` and each demonstrates a differe
199
201
  | `council.yaml` | Advocate/skeptic council weighed by an orchestrator (local) | [1.05 · Workflows & Voice](https://lyceumagents.com/curriculum/workflows-and-voice/) |
200
202
  | `critic.yaml` | Drafter → Critic loop that re-drafts until a parsed confidence score clears the bar | [1.04 · Testing & Refinement](https://lyceumagents.com/curriculum/testing-and-refinement/) |
201
203
  | `structured_critic.yaml` | The critic as one agent: it delegates to a Drafter, then answers in its own JSON schema (Claude) | — |
204
+ | `classifier.yaml` | A support-triage classifier on TypeSafe's Jev: the output schema is the questions, the answer is typed decisions with calibrated probabilities | — |
202
205
  | `delegation.yaml` | Intent routing to specialists via agent descriptions | [1.05 · Workflows & Voice](https://lyceumagents.com/curriculum/workflows-and-voice/) |
203
206
  | `hierarchical.yaml` | Goal decomposition into sequential research and writing stages, then a checked merge | [1.05 · Workflows & Voice](https://lyceumagents.com/curriculum/workflows-and-voice/) |
204
207
  | `style_council.yaml` | Three stylists with identical knowledge and different voices, behind one router | [1.05 · Workflows & Voice](https://lyceumagents.com/curriculum/workflows-and-voice/) |
@@ -209,7 +212,7 @@ Configurations live in `config/agents/examples/` and each demonstrates a differe
209
212
  | `image_production.yaml` | Spec-first image generation, a blind inventory, and a separate spec auditor | [2.04 · Multimodal Agents](https://lyceumagents.com/curriculum/multimodal-agents/) |
210
213
  | `current_events.yaml` | Current-event aggregation and fact-checking: an X researcher and a web researcher report to a tool-free arbiter | [2.05 · Fact-Checking Arbiter](https://lyceumagents.com/curriculum/fact-checking-agent/) |
211
214
  | `claude.yaml` | Minimal configuration using the Anthropic adapter | — |
212
- | `model_zoo.yaml` | One agent per provider (Qwen, Claude, Grok, GPT, Gemini, Kimi, DeepSeek) | — |
215
+ | `model_zoo.yaml` | One agent per chat provider (Qwen, Claude, Grok, GPT, Gemini, Kimi, DeepSeek); Jev, a decision model, has `classifier.yaml` | — |
213
216
  | `research.yaml` | Plan-and-dispatch over keyless clinical and literature sources, with an identifier and retraction guard | — |
214
217
  | `scriptorium.yaml` | Agents over the `wiki/` bundle: answer with citations, author through a validated save gate | — |
215
218
  | `cartographers.yaml` | Agents that record the judgments in the wiki's prose as graph relations | — |