melchizedek-agents 1.11.0 → 1.12.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 +126 -0
  4. package/DOCUMENTATION.md +108 -7
  5. package/ONBOARDING.md +11 -5
  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/db/hardening.sql +5 -0
  13. package/db/migrations/0020_embedding_flash_grok_pricing.sql +38 -0
  14. package/db/migrations/0021_correct_gemini_flash_grok_rates.sql +46 -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
@@ -0,0 +1,104 @@
1
+ # tier: typesafe — needs only TYPESAFE_API_KEY, or one MODEL_GATEWAY key (Vercel AI Gateway or OpenRouter); `npm run doctor` shows what each key unlocks.
2
+ # ============================================================
3
+ # CLASSIFIER — one decision model, typed answers, calibrated confidence.
4
+ # ============================================================
5
+ #
6
+ # JOB: read one inbound support message and decide three things about it:
7
+ # which team it belongs to, how urgent it is, and whether a person must
8
+ # look before anything is sent back. The reply is one JSON object the
9
+ # `output.schema` below describes, so the software that calls this agent
10
+ # acts on fields, never on prose.
11
+ #
12
+ # WHY A DECISION MODEL: `model: jev-latest` is TypeSafe's Jev, a System One
13
+ # model (https://typesafe.ai). It writes no sentences and calls no tool: it
14
+ # answers typed questions with a probability for every option, in about a
15
+ # tenth of a second, at $0.042 per million input tokens and nothing for
16
+ # output. The engine turns this file's schema into Jev's questions
17
+ # (lib/models/jev.ts): a boolean property is a yes/no question, a string
18
+ # whose `oneOf` describes each constant is a choice, an integer whose
19
+ # `oneOf` describes the levels 0, 1, 2 in order is a score. The property's
20
+ # `description` is the question. The instruction below and the message are
21
+ # the state Jev decides about.
22
+ #
23
+ # WHAT COMES BACK: the schema's object, plus a `jev` key holding the raw
24
+ # answers: each question's probabilities and confidence. Act when the
25
+ # confidence is high and route to a person when it is not: that threshold
26
+ # is yours to set in the code that calls this agent, which is the point.
27
+ #
28
+ # {"department":"technical","urgency":2,"needs_human":false,
29
+ # "jev":{"department":{"type":"choice","choice":"technical","confidence":0.91,
30
+ # "probabilities":{"billing":0.03,"technical":0.91,"sales":0.01,"other":0.05}},
31
+ # "urgency":{"type":"score","score":1.8,"confidence":0.8,...},
32
+ # "needs_human":{"type":"noul","noul":0.12}}}
33
+ #
34
+ # ONE FILE, ANY MODEL: change `model:` to gemini-3.5-flash-lite,
35
+ # claude-haiku-5-5 or ollama/qwen3.5:9b and the same schema is answered by a
36
+ # chat model's structured output (the matrix's `structured_output` cell);
37
+ # the `jev` key then does not appear, since a chat model states no
38
+ # probabilities. The doctor shows what each path keeps.
39
+ #
40
+ # NOT A CONVERSATION: memory_system internal-only and includeContents none
41
+ # make every message stand alone; nothing is kept between calls.
42
+ #
43
+ # MAKE IT YOURS: rename the departments and their descriptions, change the
44
+ # urgency levels (up to 10, each described), add a boolean per policy you
45
+ # enforce. Every property must be a decision: a free string, an array or a
46
+ # nested object is refused before any call (TYPESAFE_SCHEMA_UNSUPPORTED),
47
+ # with the shapes Jev takes named in the error.
48
+ # ============================================================
49
+ syndicate_name: "Classifier"
50
+ memory_system: internal-only
51
+
52
+ orchestrator:
53
+ name: "Triage"
54
+ description: "Decides a support message's department, its urgency and whether a person must look, as typed answers with probabilities."
55
+ model: "jev-latest"
56
+ includeContents: none
57
+ instruction: |
58
+ You triage inbound messages for a software company's support desk. Each message was sent by a customer or a prospect through the help form or by email. You decide where it goes and how fast; you do not answer it.
59
+
60
+ Departments:
61
+ - billing handles charges, refunds, invoices, subscriptions and payment methods.
62
+ - technical handles bugs, outages, errors, integrations and anything about how the product behaves.
63
+ - sales handles pricing questions, quotes, upgrades, trials and new accounts.
64
+ - other is anything else: partnerships, press, job applications, spam.
65
+
66
+ Urgency is about the customer's situation, not their tone: an outage or a blocked payment is urgent however calmly it is written; a question with no deadline is not, however angrily.
67
+
68
+ A person must look before any automated reply when the message mentions legal action, a safety or security concern, a complaint about staff, a request to delete an account or data, or when it is unclear which department it belongs to.
69
+ output:
70
+ schema:
71
+ type: object
72
+ properties:
73
+ department:
74
+ type: string
75
+ description: "Which team should handle this message."
76
+ oneOf:
77
+ - const: billing
78
+ description: "Charges, refunds, invoices, subscriptions, payment methods."
79
+ - const: technical
80
+ description: "Bugs, outages, errors, integrations, product behaviour."
81
+ - const: sales
82
+ description: "Pricing, quotes, upgrades, trials, new accounts."
83
+ - const: other
84
+ description: "Partnerships, press, job applications, spam, or nothing above."
85
+ urgency:
86
+ type: integer
87
+ description: "How soon the company must act on this message."
88
+ oneOf:
89
+ - const: 0
90
+ description: "No deadline and nothing blocked: a question or a request that can wait days."
91
+ - const: 1
92
+ description: "Something is inconvenient or a date is near: within a day."
93
+ - const: 2
94
+ description: "Service is down, money is stuck, or a deadline is today: now."
95
+ needs_human:
96
+ type: boolean
97
+ description: "A person must read this message before any automated reply is sent."
98
+ oneOf:
99
+ - const: true
100
+ description: "Legal action, a safety or security concern, a complaint about staff, a deletion request, or an unclear department."
101
+ - const: false
102
+ description: "A routine message a department can answer on its own."
103
+ required: [department, urgency, needs_human]
104
+ mime: "application/json"
@@ -14,6 +14,11 @@
14
14
  # kimi-* → Moonshot (MOONSHOT_API_KEY)
15
15
  # deepseek-* → DeepSeek (DEEPSEEK_API_KEY)
16
16
  #
17
+ # (jev-* → TypeSafe Jev is the eighth provider, and not in this zoo: a
18
+ # decision model answers a schema, never a question in prose. Its proof
19
+ # is classifier.yaml.) With no direct key, one MODEL_GATEWAY key serves
20
+ # every cloud agent here.
21
+ #
17
22
  # Run the proof: npm run demo:models (scripts/demo_model_optionality.ts
18
23
  # sends "explain quantum mechanics" to every agent whose provider is
19
24
  # available, and prints input, thinking, output, and a token/latency trace.
@@ -22,7 +22,7 @@
22
22
  "model": {
23
23
  "type": "string",
24
24
  "minLength": 1,
25
- "description": "Model id; its prefix picks the provider (gemini-*, claude-*, gpt-*/o*, grok-*, ollama/*)."
25
+ "description": "Model id; its prefix picks the provider (gemini-*, claude-*, gpt-*/o*, grok-*, kimi-*, deepseek-*, jev-*, ollama/*)."
26
26
  },
27
27
  "fallback_model": {
28
28
  "description": "A model on another provider that answers when this agent's model fails provider-side (5xx, 429, network) before producing anything, or while that provider's circuit is open (ADR 0044).",
@@ -448,6 +448,35 @@
448
448
  }
449
449
  ]
450
450
  },
451
+ "typesafe": {
452
+ "type": "object",
453
+ "properties": {
454
+ "instruction": {
455
+ "description": "Replaces the agent's instruction on this provider.",
456
+ "type": "string",
457
+ "minLength": 1
458
+ },
459
+ "instruction_append": {
460
+ "description": "Appended to the agent's instruction, after a blank line, on this provider.",
461
+ "type": "string",
462
+ "minLength": 1
463
+ }
464
+ },
465
+ "additionalProperties": false,
466
+ "description": "The instruction on one provider: exactly one of instruction or instruction_append.",
467
+ "oneOf": [
468
+ {
469
+ "required": [
470
+ "instruction"
471
+ ]
472
+ },
473
+ {
474
+ "required": [
475
+ "instruction_append"
476
+ ]
477
+ }
478
+ ]
479
+ },
451
480
  "ollama": {
452
481
  "type": "object",
453
482
  "properties": {
@@ -1535,6 +1564,35 @@
1535
1564
  }
1536
1565
  ]
1537
1566
  },
1567
+ "typesafe": {
1568
+ "type": "object",
1569
+ "properties": {
1570
+ "instruction": {
1571
+ "description": "Replaces the agent's instruction on this provider.",
1572
+ "type": "string",
1573
+ "minLength": 1
1574
+ },
1575
+ "instruction_append": {
1576
+ "description": "Appended to the agent's instruction, after a blank line, on this provider.",
1577
+ "type": "string",
1578
+ "minLength": 1
1579
+ }
1580
+ },
1581
+ "additionalProperties": false,
1582
+ "description": "The instruction on one provider: exactly one of instruction or instruction_append.",
1583
+ "oneOf": [
1584
+ {
1585
+ "required": [
1586
+ "instruction"
1587
+ ]
1588
+ },
1589
+ {
1590
+ "required": [
1591
+ "instruction_append"
1592
+ ]
1593
+ }
1594
+ ]
1595
+ },
1538
1596
  "ollama": {
1539
1597
  "type": "object",
1540
1598
  "properties": {
@@ -270,7 +270,14 @@ orchestrator:
270
270
  # grok-* → xAI (XAI_API_KEY)
271
271
  # kimi-* → Moonshot Kimi (MOONSHOT_API_KEY)
272
272
  # deepseek-* → DeepSeek (DEEPSEEK_API_KEY)
273
+ # jev-* → TypeSafe Jev (TYPESAFE_API_KEY; a decision model: it answers
274
+ # this agent's output.schema, never prose, so it
275
+ # takes no tools and no subagents)
273
276
  # ollama/* → local Ollama (keyless)
277
+ # With no direct key, MODEL_GATEWAY (vercel | openrouter) serves any cloud id;
278
+ # MODEL_GATEWAY_PREFER=gateway sends every cloud id through it even beside
279
+ # a direct key, and MODEL_GATEWAY_EXCEPT names the providers that do the
280
+ # opposite. Deployment config, never YAML: the file names models, not paths.
274
281
  # Subagents inherit this if not set on their own config.
275
282
  model: "gemini-3.5-flash-lite"
276
283
 
@@ -444,6 +451,7 @@ orchestrator:
444
451
  # that effort; none is the model's off switch,
445
452
  # or low effort on Opus 5 and 5.5, Fable and
446
453
  # Mythos (ADR 0049)
454
+ # jev-* → nothing: Jev decides without reasoning
447
455
  # gpt-*/o*, grok-*, kimi-*, deepseek-*, ollama/*, a gateway
448
456
  # → reasoningEffort (an effort word; where the
449
457
  # provider lacks one, its nearest setting above;
@@ -508,7 +516,7 @@ orchestrator:
508
516
  # ── model_overrides ───────────────────────────────────────
509
517
  # [optional] A prompt nuance for one provider (ADR 0115). Keys are the
510
518
  # providers a model id routes to: gemini, anthropic, openai, xai,
511
- # moonshot, deepseek, ollama. Each holds ONE of:
519
+ # moonshot, deepseek, typesafe, ollama. Each holds ONE of:
512
520
  # instruction: replaces the instruction on that provider
513
521
  # instruction_append: added after the instruction, after a blank line
514
522
  # Applied for the provider of this agent's model, before the skills
package/db/hardening.sql CHANGED
@@ -57,6 +57,8 @@ END $$;
57
57
  -- deny-by-default. service_role is unaffected (it bypasses RLS).
58
58
  ALTER TABLE adk_memory_facts ENABLE ROW LEVEL SECURITY;
59
59
  ALTER TABLE adk_sessions ENABLE ROW LEVEL SECURITY;
60
+ -- The store's one embedder row (migration 0023) names a model, nothing personal; locked all the same.
61
+ ALTER TABLE IF EXISTS melchizedek_memory_embedder ENABLE ROW LEVEL SECURITY;
60
62
 
61
63
  -- Belt and suspenders: also revoke the default table privileges from the
62
64
  -- API roles, so even a future accidentally-created permissive policy
@@ -65,6 +67,9 @@ DO $$
65
67
  BEGIN
66
68
  PERFORM pg_temp.melchizedek_revoke_api('adk_memory_facts');
67
69
  PERFORM pg_temp.melchizedek_revoke_api('adk_sessions');
70
+ IF to_regclass('melchizedek_memory_embedder') IS NOT NULL THEN
71
+ PERFORM pg_temp.melchizedek_revoke_api('melchizedek_memory_embedder');
72
+ END IF;
68
73
  END $$;
69
74
 
70
75
  -- Optional observability ledger (db/telemetry.sql). Guarded: the tables only
@@ -0,0 +1,38 @@
1
+ -- ============================================================================
2
+ -- 0020_embedding_flash_grok_pricing — price rows for three models a ledger
3
+ -- already holds calls of (extends ADR 0136)
4
+ -- ============================================================================
5
+ -- Rows only, in 0017's column layout (USD per million tokens). A deployment's
6
+ -- ledger (penguin's, 2026-10-22) had calls of these three models priced NULL
7
+ -- because no row existed; scripts that re-price NULL rows can now fill them.
8
+ --
9
+ -- grok-4.3: xAI first-party, docs.x.ai/docs/models, checked 2026-10-22. The
10
+ -- row holds the rate under 200k prompt tokens ($1.25 in / $0.20 cached /
11
+ -- $2.50 out); a request of 200k or more is billed at double for all its
12
+ -- tokens ($2.50 / $0.40 / $5.00), which a flat row cannot say: such a call
13
+ -- is underestimated by half.
14
+ --
15
+ -- gemini-embedding-001: Google's GA announcement for the Gemini API
16
+ -- (developers.googleblog.com, "Gemini Embedding now generally available"):
17
+ -- $0.15 per 1M input tokens, no output tokens. Google's current pricing page
18
+ -- lists only its successor (gemini-embedding-2), so verified_at stays NULL.
19
+ --
20
+ -- gemini-3.5-flash: $1.50 in / $0.15 cached / $9.00 out, as two pricing
21
+ -- guides give it, one citing Google's Gemini API pricing documentation
22
+ -- (June 2026). Google's current page no longer lists the model (superseded
23
+ -- by 3.6 and 3.8 Flash), so this could not be checked against the vendor:
24
+ -- verified_at NULL, a steering estimate (0015's convention).
25
+ --
26
+ -- New rows never overwrite a row that exists: an operator's own rates
27
+ -- survive. Nothing secret, nothing personal. Idempotent; safe to re-run.
28
+ -- ============================================================================
29
+
30
+ INSERT INTO model_pricing (model, input_per_mtok, output_per_mtok, cache_read_per_mtok, cache_write_per_mtok, verified_at, source, note) VALUES
31
+ ('grok-4.3', 1.25, 2.50, 0.20, NULL, '2026-10-22', 'docs.x.ai/docs/models', 'xAI first-party, checked 2026-10-22; rate under 200k prompt tokens (a request of 200k or more bills $2.50 / $0.40 / $5.00)'),
32
+ ('gemini-embedding-001', 0.15, 0.00, NULL, NULL, NULL, 'developers.googleblog.com, Gemini Embedding now generally available in the Gemini API', 'Google first-party announcement; input only; no longer on the current pricing page (successor gemini-embedding-2), not re-checked'),
33
+ ('gemini-3.5-flash', 1.50, 9.00, 0.15, NULL, NULL, 'eesel.ai Gemini 3 pricing guide (citing ai.google.dev pricing, June 2026), agreeing with other guides', 'unverified: off Google''s current pricing page (superseded by 3.6 and 3.8 Flash)')
34
+ ON CONFLICT (model) DO NOTHING;
35
+
36
+ INSERT INTO melchizedek_schema_version (version, name)
37
+ VALUES (20, '0020_embedding_flash_grok_pricing')
38
+ ON CONFLICT (version) DO NOTHING;
@@ -0,0 +1,46 @@
1
+ -- ============================================================================
2
+ -- 0021_correct_gemini_flash_grok_rates — two seed rows to their vendors'
3
+ -- current lists (extends ADR 0136)
4
+ -- ============================================================================
5
+ -- 0015 seeded gemini-3.8-flash and grok-4.7 from melch-obs's pricing.toml as
6
+ -- unverified estimates. Checked 2026-10-22 against the vendors' lists, both
7
+ -- were wrong:
8
+ --
9
+ -- gemini-3.8-flash ai.google.dev/gemini-api/docs/pricing (paid, standard):
10
+ -- $0.75 in / $0.075 cached / $3.75 out, thinking billed
11
+ -- as output, through 2026-12-31. Google has announced
12
+ -- $1.50 / $0.15 / $7.50 from 2027-01-01; a flat row cannot
13
+ -- say the date, so that needs its own row change then.
14
+ -- Seed: $0.30 / $2.50 (a placeholder at 3.7's rate).
15
+ -- grok-4.7 docs.x.ai/docs/models: $2.00 in / $0.50 cached / $6.00
16
+ -- out under 200k prompt tokens (a request of 200k or more
17
+ -- bills $4.00 / $1.00 / $12.00 for all its tokens, which a
18
+ -- flat row underestimates by half). Seed: $3.00 / $15.00.
19
+ --
20
+ -- A row changes only while it is still the seed: source melch-obs/pricing.toml,
21
+ -- verified_at NULL, and the seed's own rates. A rate an operator set is kept.
22
+ --
23
+ -- Rows already priced keep what they were priced at: the ledger records the
24
+ -- rate in force at write time (db/telemetry.sql). Re-pricing history is a
25
+ -- deliberate UPDATE, never a migration. Idempotent; safe to re-run.
26
+ -- ============================================================================
27
+
28
+ UPDATE model_pricing
29
+ SET input_per_mtok = 0.75, output_per_mtok = 3.75, cache_read_per_mtok = 0.075,
30
+ verified_at = '2026-10-22', source = 'ai.google.dev/gemini-api/docs/pricing',
31
+ note = 'Gemini API paid standard tier, checked 2026-10-22; rate through 2026-12-31 (Google lists $1.50 / $0.15 / $7.50 from 2027-01-01)',
32
+ updated_at = now()
33
+ WHERE model = 'gemini-3.8-flash' AND source = 'melch-obs/pricing.toml' AND verified_at IS NULL
34
+ AND input_per_mtok = 0.30 AND output_per_mtok = 2.50;
35
+
36
+ UPDATE model_pricing
37
+ SET input_per_mtok = 2.00, output_per_mtok = 6.00, cache_read_per_mtok = 0.50,
38
+ verified_at = '2026-10-22', source = 'docs.x.ai/docs/models',
39
+ note = 'xAI first-party, checked 2026-10-22; rate under 200k prompt tokens (a request of 200k or more bills $4.00 / $1.00 / $12.00)',
40
+ updated_at = now()
41
+ WHERE model = 'grok-4.7' AND source = 'melch-obs/pricing.toml' AND verified_at IS NULL
42
+ AND input_per_mtok = 3.00 AND output_per_mtok = 15.00;
43
+
44
+ INSERT INTO melchizedek_schema_version (version, name)
45
+ VALUES (21, '0021_correct_gemini_flash_grok_rates')
46
+ ON CONFLICT (version) DO NOTHING;
@@ -0,0 +1,36 @@
1
+ -- ============================================================================
2
+ -- 0022_typesafe_jev_pricing — price rows for TypeSafe Jev (extends ADR 0136;
3
+ -- the provider is ADR 0144)
4
+ -- ============================================================================
5
+ -- Rows only, in 0017's column layout (USD per million tokens):
6
+ -- input_per_mtok an input token
7
+ -- output_per_mtok 0: TypeSafe bills nothing for output today
8
+ -- (docs.typesafe.ai/models, "output tokens are free")
9
+ -- cache_read_per_mtok NULL: no cache on this API
10
+ -- cache_write_per_mtok NULL
11
+ --
12
+ -- TypeSafe Jev (lib/models/jevAdapter.ts): $42 per billion input tokens,
13
+ -- which is $0.042 per million, the same on jev-1.14.0 and jev-1.13.0.
14
+ -- `jev-latest` and `jev-preview` are TypeSafe's aliases (both jev-1.14.0 on
15
+ -- 2026-10-23); a call made under an alias is priced under the alias, so the
16
+ -- aliases get rows too. Checked 2026-10-23 against docs.typesafe.ai/models.
17
+ --
18
+ -- Through a gateway (Vercel AI Gateway lists $0.042 input, max output 0;
19
+ -- OpenRouter bills "the rate on the Jev model page") the rate is the same
20
+ -- at the time of writing; an operator whose gateway adds a margin edits the
21
+ -- row.
22
+ --
23
+ -- New rows never overwrite a row that exists: an operator's own rates
24
+ -- survive. Nothing secret, nothing personal. Idempotent; safe to re-run.
25
+ -- ============================================================================
26
+
27
+ INSERT INTO model_pricing (model, input_per_mtok, output_per_mtok, cache_read_per_mtok, cache_write_per_mtok, verified_at, source, note) VALUES
28
+ ('jev-latest', 0.042, 0, NULL, NULL, '2026-10-23', 'docs.typesafe.ai/models', 'TypeSafe first-party, checked 2026-10-23; alias of jev-1.14.0; output is free'),
29
+ ('jev-preview', 0.042, 0, NULL, NULL, '2026-10-23', 'docs.typesafe.ai/models', 'TypeSafe first-party, checked 2026-10-23; alias of the newest build (jev-1.14.0); output is free'),
30
+ ('jev-1.14.0', 0.042, 0, NULL, NULL, '2026-10-23', 'docs.typesafe.ai/models', 'TypeSafe first-party, checked 2026-10-23; output is free'),
31
+ ('jev-1.13.0', 0.042, 0, NULL, NULL, '2026-10-23', 'docs.typesafe.ai/models', 'TypeSafe first-party, checked 2026-10-23; output is free')
32
+ ON CONFLICT (model) DO NOTHING;
33
+
34
+ INSERT INTO melchizedek_schema_version (version, name)
35
+ VALUES (22, '0022_typesafe_jev_pricing')
36
+ ON CONFLICT (version) DO NOTHING;
@@ -0,0 +1,66 @@
1
+ -- ============================================================================
2
+ -- 0023_memory_embedder — the one embedding model a memory store's vectors
3
+ -- come from (ADR 0147)
4
+ -- ============================================================================
5
+ -- Every vector in adk_memory_facts must come from one model: a different
6
+ -- model at the same dimension passes the size check (0007's
7
+ -- melchizedek_memory_dimensions) and quietly degrades recall. This table
8
+ -- holds one row: the provider, model and dimension the store was first
9
+ -- written with. The memory service records it on its first successful
10
+ -- insert and refuses, at start, an embedder whose model differs
11
+ -- (lib/memory/supabaseMemoryService.ts); switching models means re-embedding
12
+ -- the stored facts, never a silent change.
13
+ --
14
+ -- A gateway's spelling of the same model (google/gemini-embedding-001 for
15
+ -- gemini-embedding-001) is the same model: the service compares the last
16
+ -- path segment. Two functions serve the Supabase REST path, which reaches
17
+ -- tables through RPC here (0007's convention):
18
+ -- melchizedek_memory_embedder() the row, or none
19
+ -- melchizedek_memory_record_embedder(p, m, d) record it once; a later
20
+ -- call changes nothing
21
+ -- melchizedek_memory_set_embedder(p, m, d) overwrite it: what a
22
+ -- completed re-embed writes
23
+ -- (lib/memory/reembed.ts)
24
+ -- Nothing secret, nothing personal. Idempotent; safe to re-run.
25
+ -- ============================================================================
26
+
27
+ CREATE TABLE IF NOT EXISTS melchizedek_memory_embedder (
28
+ one BOOLEAN PRIMARY KEY DEFAULT TRUE CHECK (one),
29
+ provider TEXT NOT NULL,
30
+ model TEXT NOT NULL,
31
+ dimensions INTEGER NOT NULL CHECK (dimensions > 0),
32
+ recorded_at TIMESTAMPTZ NOT NULL DEFAULT now()
33
+ );
34
+
35
+ CREATE OR REPLACE FUNCTION melchizedek_memory_embedder()
36
+ RETURNS TABLE (provider text, model text, dimensions integer, recorded_at timestamptz)
37
+ LANGUAGE sql
38
+ STABLE
39
+ SET search_path = public
40
+ AS $$
41
+ SELECT provider, model, dimensions, recorded_at FROM melchizedek_memory_embedder WHERE one;
42
+ $$;
43
+
44
+ CREATE OR REPLACE FUNCTION melchizedek_memory_record_embedder(p_provider text, p_model text, p_dimensions integer)
45
+ RETURNS void
46
+ LANGUAGE sql
47
+ SET search_path = public
48
+ AS $$
49
+ INSERT INTO melchizedek_memory_embedder (one, provider, model, dimensions)
50
+ VALUES (TRUE, p_provider, p_model, p_dimensions)
51
+ ON CONFLICT (one) DO NOTHING;
52
+ $$;
53
+
54
+ CREATE OR REPLACE FUNCTION melchizedek_memory_set_embedder(p_provider text, p_model text, p_dimensions integer)
55
+ RETURNS void
56
+ LANGUAGE sql
57
+ SET search_path = public
58
+ AS $$
59
+ INSERT INTO melchizedek_memory_embedder (one, provider, model, dimensions, recorded_at)
60
+ VALUES (TRUE, p_provider, p_model, p_dimensions, now())
61
+ ON CONFLICT (one) DO UPDATE SET provider = EXCLUDED.provider, model = EXCLUDED.model, dimensions = EXCLUDED.dimensions, recorded_at = now();
62
+ $$;
63
+
64
+ INSERT INTO melchizedek_schema_version (version, name)
65
+ VALUES (23, '0023_memory_embedder')
66
+ ON CONFLICT (version) DO NOTHING;
@@ -100,6 +100,12 @@ export declare const DEFAULT_MAX_STEPS = 50;
100
100
  * qwen3:8b is the smallest pulled model that supports tool calling — the
101
101
  * floor capability for syndicate delegation. Vision work uses ollama/qwen3-vl:8b.
102
102
  */
103
+ /**
104
+ * TypeSafe Jev (lib/models/jevAdapter.ts): `jev-latest` is TypeSafe's alias
105
+ * for the newest stable release (jev-1.14.0 as of 2026-10-14). A decision
106
+ * model: it answers an agent's `output.schema`, never free text.
107
+ */
108
+ export declare const DEFAULT_JEV_MODEL = "jev-latest";
103
109
  export declare const DEFAULT_OLLAMA_MODEL = "ollama/qwen3:8b";
104
110
  /**
105
111
  * Model used by SupabaseVectorMemoryService to extract discrete facts
@@ -101,6 +101,12 @@ export const DEFAULT_MAX_STEPS = 50;
101
101
  * qwen3:8b is the smallest pulled model that supports tool calling — the
102
102
  * floor capability for syndicate delegation. Vision work uses ollama/qwen3-vl:8b.
103
103
  */
104
+ /**
105
+ * TypeSafe Jev (lib/models/jevAdapter.ts): `jev-latest` is TypeSafe's alias
106
+ * for the newest stable release (jev-1.14.0 as of 2026-10-14). A decision
107
+ * model: it answers an agent's `output.schema`, never free text.
108
+ */
109
+ export const DEFAULT_JEV_MODEL = 'jev-latest';
104
110
  export const DEFAULT_OLLAMA_MODEL = 'ollama/qwen3:8b';
105
111
  /**
106
112
  * Model used by SupabaseVectorMemoryService to extract discrete facts
@@ -26,6 +26,7 @@
26
26
  import type { Platform } from './models/endpoints.ts';
27
27
  import type { CapabilityGap, CapabilityReport } from './models/capabilities.ts';
28
28
  import type { ProviderId } from './models/providerMap.ts';
29
+ import type { EmbedderPlan } from './memory/providers.ts';
29
30
  import type { RuntimeName, RuntimeSource } from './runtime/runtimeFlag.ts';
30
31
  import { type ProjectCheck } from './project.ts';
31
32
  /**
@@ -172,6 +173,13 @@ export interface DoctorResult {
172
173
  chatgpt?: DoctorChatGpt;
173
174
  /** The project manifest (ADR 0138) found from the working directory, when there is one. */
174
175
  project?: DoctorProject;
176
+ /** Long-term memory's embedder (ADR 0147), when any syndicate here is long-term or MEMORY_EMBEDDING_PROVIDER is set. */
177
+ memory?: DoctorMemory;
178
+ }
179
+ /** What would embed long-term memory here: the plan, and how many of this directory's syndicates need it. */
180
+ export interface DoctorMemory {
181
+ longTerm: number;
182
+ embedder: EmbedderPlan;
175
183
  }
176
184
  /** A `melchizedek.json` at or above the working directory: its checks, or why it does not load. */
177
185
  export type DoctorProject = ProjectCheck | {
@@ -33,6 +33,7 @@ import { CAPABILITY_LABELS, capabilityGaps, describeCapabilities } from './model
33
33
  import { credentialSource, endpointFromEnv, endpointLabel, endpointProblems, PLATFORM_SDK, PLATFORMS_FOR } from './models/endpoints.js';
34
34
  import { GATEWAY_ENV, GATEWAY_KEY_ENV, GATEWAYS, gatewayConfig, gatewayProblem, gatewayUsable, } from './models/gateway.js';
35
35
  import { PROVIDERS } from './models/providerMap.js';
36
+ import { embedderPlan } from './memory/providers.js';
36
37
  import { describeRuntime } from './runtime/runtimeFlag.js';
37
38
  import { CHATGPT_SIGNIN_ENV, CHATGPT_SIGNIN_FILE_ENV, chatGptSignInRoutesOpenAi, chatGptSignInStatus } from './chatgpt/state.js';
38
39
  import { agentOAuthGrants, oauthEnvNames } from './tools/oauthTools.js';
@@ -179,6 +180,7 @@ export const CONSOLE_URLS = {
179
180
  xai: 'https://console.x.ai',
180
181
  moonshot: 'https://platform.moonshot.ai',
181
182
  deepseek: 'https://platform.deepseek.com/api_keys',
183
+ typesafe: 'https://console.typesafe.ai/keys',
182
184
  ollama: 'https://ollama.com',
183
185
  };
184
186
  // ── Discovery ────────────────────────────────────────────────────────────────
@@ -506,6 +508,9 @@ export function runDoctor(options = {}) {
506
508
  for (const s of syndicates)
507
509
  counts[s.verdict.state]++;
508
510
  flagMemoryNamespaces(syndicates);
511
+ // Long-term memory's embedder (ADR 0147): what would embed, or what to set, names only.
512
+ const longTerm = syndicates.filter((s) => s.memory).length;
513
+ const memory = longTerm || process.env.MEMORY_EMBEDDING_PROVIDER?.trim() ? { longTerm, embedder: embedderPlan() } : undefined;
509
514
  // The server's OAuth setup (ADR 0114): the key, the redirect URI and the allowlist, names only.
510
515
  const grants = syndicates.flatMap((s) => s.grants ?? []).map((g) => ({ agent: g.agent, tools: g.tools, oauth2: { provider: g.provider, grant: g.grant, token_url: '' } }));
511
516
  const set = Object.fromEntries([CREDENTIAL_KEY_ENV, OAUTH_REDIRECT_URI_ENV, OAUTH_HOSTS_ENV].map((name) => [name, !!process.env[name]?.trim()]));
@@ -537,6 +542,7 @@ export function runDoctor(options = {}) {
537
542
  syndicates,
538
543
  unlocks,
539
544
  gateway,
545
+ ...(memory ? { memory } : {}),
540
546
  endpoints: endpointRows(),
541
547
  counts,
542
548
  ...(oauth ? { oauth } : {}),
@@ -605,6 +611,7 @@ const PROBE_ID = {
605
611
  xai: 'grok-x',
606
612
  moonshot: 'kimi-x',
607
613
  deepseek: 'deepseek-x',
614
+ typesafe: 'jev-x',
608
615
  ollama: 'ollama/x',
609
616
  };
610
617
  /**
@@ -695,6 +702,16 @@ export function renderDoctor(result, opts = {}) {
695
702
  ? `gateway ${c.red}✗${c.reset} ${result.gateway.problem}`
696
703
  : `gateway ${c.yellow}◇${c.reset} ${result.gateway.label} fills in for any provider whose direct key is absent ${c.dim}(native search is lost on that path)${c.reset}`);
697
704
  }
705
+ if (result.memory) {
706
+ // Long-term memory's embedder (ADR 0147): funded directly, through the gateway, or what to set. Names only.
707
+ const e = result.memory.embedder;
708
+ const n = result.memory.longTerm;
709
+ const who = n ? `${n} long-term syndicate${n === 1 ? '' : 's'}` : 'MEMORY_EMBEDDING_PROVIDER set';
710
+ const mark = !e.funded ? `${c.red}✗${c.reset}` : e.transport === 'gateway' ? `${c.yellow}◇${c.reset}` : `${c.green}✓${c.reset}`;
711
+ lines.push(e.funded
712
+ ? `memory ${mark} embeddings ${e.provider}/${e.model} (${e.dimensions}d)${e.transport === 'gateway' ? ` via gateway:${e.gateway}` : ''} ${c.dim}· ${e.detail} · ${who}${c.reset}`
713
+ : `memory ${mark} ${c.red}${e.detail}${c.reset} ${c.dim}· ${who}${c.reset}`);
714
+ }
698
715
  if (result.serving) {
699
716
  // Names only: the A2A identity mode, who pays, and what the server would refuse.
700
717
  const sv = result.serving;
@@ -149,7 +149,7 @@ export interface AgentYamlConfig {
149
149
  * appended after a blank line, for the provider of the model the agent runs
150
150
  * on. Applied at compile time, before the skills index; not for fallback_model.
151
151
  */
152
- model_overrides?: Partial<Record<'gemini' | 'anthropic' | 'openai' | 'xai' | 'moonshot' | 'deepseek' | 'ollama', {
152
+ model_overrides?: Partial<Record<'gemini' | 'anthropic' | 'openai' | 'xai' | 'moonshot' | 'deepseek' | 'typesafe' | 'ollama', {
153
153
  instruction?: string;
154
154
  instruction_append?: string;
155
155
  }>>;
@@ -27,6 +27,16 @@
27
27
  * MEMORY_EMBEDDING_API_KEY openai-compatible key (else none)
28
28
  * The vector column is fixed at creation (db/), so changing the model or the
29
29
  * dimension needs a re-embed, not just a new variable.
30
+ *
31
+ * THE GATEWAY (ADR 0146): with no key for the embedding provider, or with
32
+ * MODEL_GATEWAY_PREFER=gateway, the embedder goes through the configured
33
+ * gateway's /embeddings when that gateway carries the SAME model (Vercel
34
+ * carries google/gemini-embedding-001 and openai/text-embedding-3-small
35
+ * and honours `dimensions`; OpenRouter carries OpenAI's). The vectors are
36
+ * the model's own, so a store embedded directly and one embedded through
37
+ * the gateway agree. A gateway that lacks the model changes nothing: the
38
+ * direct path stays, keyless and failing loudly, never a different model
39
+ * behind the store's back.
30
40
  */
31
41
  import type { ProviderEndpoint } from '../models/endpoints.ts';
32
42
  import type { ModelAdapter } from '../models/contract.ts';
@@ -90,6 +100,27 @@ export interface MemoryProviders {
90
100
  extractor: MemoryExtractor;
91
101
  embedder: Embedder;
92
102
  }
103
+ /** What the environment's embedder would be, with no client built (the doctor's memory line, ADR 0147). */
104
+ export interface EmbedderPlan {
105
+ provider: string;
106
+ model: string;
107
+ dimensions: number;
108
+ /** `none` when nothing funds the embedder. */
109
+ transport: 'direct' | 'gateway' | 'none';
110
+ gateway?: string;
111
+ funded: boolean;
112
+ /** For a person: what funds it, or what to set. Never a key. */
113
+ detail: string;
114
+ }
115
+ /**
116
+ * The embedder `memoryProvidersFromEnv` would build, as a plan: provider,
117
+ * model, dimension, the path and whether it is funded, with the fix when it
118
+ * is not. The OpenRouter case gets its documented answer: OpenRouter carries
119
+ * no Gemini embedding model, so `MEMORY_EMBEDDING_PROVIDER=openai` embeds
120
+ * `text-embedding-3-small` through it, with the re-embed caveat for a store
121
+ * already embedded with Gemini (ADR 0147).
122
+ */
123
+ export declare function embedderPlan(env?: NodeJS.ProcessEnv, geminiKey?: string): EmbedderPlan;
93
124
  /**
94
125
  * The deployment's extractor and embedder. `geminiKey` is the key the server
95
126
  * already passes for memory; it is used only when the configured extraction