melchizedek-agents 0.18.0 → 0.19.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 (281) hide show
  1. package/.env.example +12 -0
  2. package/CHANGELOG.md +825 -0
  3. package/DOCUMENTATION.md +217 -59
  4. package/README.md +42 -1
  5. package/config/agents/examples/harness.yaml +3 -1
  6. package/config/agents/examples/model_zoo.yaml +10 -9
  7. package/config/agents/syndicateSchema.yaml +50 -16
  8. package/config/agents/templates/account_memory.yaml +2 -6
  9. package/config/agents/templates/case_desk.yaml +3 -9
  10. package/config/agents/templates/draft_review.yaml +3 -9
  11. package/config/agents/templates/intake_extractor.yaml +1 -3
  12. package/config/agents/templates/research_brief.yaml +3 -9
  13. package/config/agents/templates/research_desk.yaml +3 -9
  14. package/config/agents/templates/review_panel.yaml +4 -12
  15. package/config/agents/templates/support_triage.yaml +4 -12
  16. package/config/agents/templates/systems_operator.yaml +2 -6
  17. package/db/hardening.sql +7 -1
  18. package/db/migrations/0013_tool_credentials.sql +260 -0
  19. package/dist/lib/a2a/app.d.ts +70 -6
  20. package/dist/lib/a2a/app.js +107 -2
  21. package/dist/lib/a2a/executor.d.ts +20 -3
  22. package/dist/lib/a2a/executor.js +66 -7
  23. package/dist/lib/a2a/remoteAgent.d.ts +24 -9
  24. package/dist/lib/a2a/remoteAgent.js +31 -14
  25. package/dist/lib/compile.d.ts +121 -30
  26. package/dist/lib/compile.js +137 -124
  27. package/dist/lib/compileAdk.d.ts +29 -0
  28. package/dist/lib/compileAdk.js +132 -0
  29. package/dist/lib/compileNative.d.ts +85 -0
  30. package/dist/lib/compileNative.js +222 -0
  31. package/dist/lib/config.d.ts +6 -5
  32. package/dist/lib/config.js +6 -5
  33. package/dist/lib/doctor.js +1 -0
  34. package/dist/lib/index.d.ts +2 -1
  35. package/dist/lib/index.js +2 -1
  36. package/dist/lib/loadSyndicate.d.ts +18 -0
  37. package/dist/lib/memory/erase.d.ts +5 -3
  38. package/dist/lib/memory/erase.js +5 -2
  39. package/dist/lib/memory/namespace.d.ts +8 -1
  40. package/dist/lib/memory/namespace.js +12 -6
  41. package/dist/lib/memory/providers.js +2 -1
  42. package/dist/lib/memory/supabaseMemoryService.d.ts +37 -3
  43. package/dist/lib/memory/supabaseMemoryService.js +42 -2
  44. package/dist/lib/model.d.ts +47 -0
  45. package/dist/lib/model.js +37 -0
  46. package/dist/lib/models/adapterResolver.d.ts +113 -0
  47. package/dist/lib/models/adapterResolver.js +136 -0
  48. package/dist/lib/models/adkGeminiAdapter.d.ts +90 -0
  49. package/dist/lib/models/adkGeminiAdapter.js +367 -0
  50. package/dist/lib/models/adkShim.d.ts +111 -0
  51. package/dist/lib/models/adkShim.js +136 -0
  52. package/dist/lib/models/capabilities.d.ts +3 -0
  53. package/dist/lib/models/capabilities.js +20 -13
  54. package/dist/lib/models/chatCompletionsAdapter.d.ts +279 -0
  55. package/dist/lib/models/chatCompletionsAdapter.js +854 -0
  56. package/dist/lib/models/circuitBreaker.d.ts +42 -0
  57. package/dist/lib/models/circuitBreaker.js +70 -0
  58. package/dist/lib/models/claudeAdapter.d.ts +103 -0
  59. package/dist/lib/models/claudeAdapter.js +669 -0
  60. package/dist/lib/models/claudeLlm.d.ts +39 -62
  61. package/dist/lib/models/claudeLlm.js +44 -349
  62. package/dist/lib/models/claudeModels.d.ts +127 -0
  63. package/dist/lib/models/claudeModels.js +237 -0
  64. package/dist/lib/models/contract.d.ts +395 -0
  65. package/dist/lib/models/contract.js +39 -0
  66. package/dist/lib/models/endpoints.js +2 -1
  67. package/dist/lib/models/errorResponse.d.ts +50 -0
  68. package/dist/lib/models/errorResponse.js +48 -0
  69. package/dist/lib/models/fallback.d.ts +17 -10
  70. package/dist/lib/models/fallback.js +53 -42
  71. package/dist/lib/models/fallbackAdapter.d.ts +55 -0
  72. package/dist/lib/models/fallbackAdapter.js +62 -0
  73. package/dist/lib/models/gateway.js +2 -1
  74. package/dist/lib/models/gatewayAdapter.d.ts +51 -0
  75. package/dist/lib/models/gatewayAdapter.js +81 -0
  76. package/dist/lib/models/gatewayLlm.d.ts +12 -33
  77. package/dist/lib/models/gatewayLlm.js +14 -75
  78. package/dist/lib/models/geminiAdapter.d.ts +123 -0
  79. package/dist/lib/models/geminiAdapter.js +831 -0
  80. package/dist/lib/models/geminiState.d.ts +25 -0
  81. package/dist/lib/models/geminiState.js +25 -0
  82. package/dist/lib/models/genaiMapping.d.ts +263 -0
  83. package/dist/lib/models/genaiMapping.js +862 -0
  84. package/dist/lib/models/gptAdapter.d.ts +240 -0
  85. package/dist/lib/models/gptAdapter.js +804 -0
  86. package/dist/lib/models/gptLlm.d.ts +63 -123
  87. package/dist/lib/models/gptLlm.js +88 -602
  88. package/dist/lib/models/grokAdapter.d.ts +86 -0
  89. package/dist/lib/models/grokAdapter.js +142 -0
  90. package/dist/lib/models/grokLlm.d.ts +22 -45
  91. package/dist/lib/models/grokLlm.js +22 -67
  92. package/dist/lib/models/kimiAdapter.d.ts +157 -0
  93. package/dist/lib/models/kimiAdapter.js +203 -0
  94. package/dist/lib/models/kimiLlm.d.ts +15 -107
  95. package/dist/lib/models/kimiLlm.js +17 -153
  96. package/dist/lib/models/ollamaAdapter.d.ts +125 -0
  97. package/dist/lib/models/ollamaAdapter.js +155 -0
  98. package/dist/lib/models/ollamaLlm.d.ts +11 -107
  99. package/dist/lib/models/ollamaLlm.js +13 -151
  100. package/dist/lib/models/openAiCompatibleLlm.d.ts +73 -216
  101. package/dist/lib/models/openAiCompatibleLlm.js +109 -671
  102. package/dist/lib/models/providerState.d.ts +63 -0
  103. package/dist/lib/models/providerState.js +61 -0
  104. package/dist/lib/models/reasoning.d.ts +26 -0
  105. package/dist/lib/models/reasoning.js +59 -0
  106. package/dist/lib/models/registry.d.ts +58 -35
  107. package/dist/lib/models/registry.js +89 -118
  108. package/dist/lib/models/retry.d.ts +2 -1
  109. package/dist/lib/models/retry.js +3 -2
  110. package/dist/lib/models/schemaNormalize.d.ts +98 -0
  111. package/dist/lib/models/schemaNormalize.js +321 -1
  112. package/dist/lib/models/tracedGemini.d.ts +41 -0
  113. package/dist/lib/models/tracedGemini.js +98 -0
  114. package/dist/lib/models/urls.d.ts +11 -0
  115. package/dist/lib/models/urls.js +16 -0
  116. package/dist/lib/net/redirects.d.ts +21 -2
  117. package/dist/lib/net/redirects.js +11 -34
  118. package/dist/lib/observability/audit.d.ts +5 -1
  119. package/dist/lib/observability/lineage.d.ts +14 -0
  120. package/dist/lib/observability/lineage.js +33 -0
  121. package/dist/lib/observability/supabaseSpanExporter.d.ts +10 -4
  122. package/dist/lib/observability/supabaseSpanExporter.js +17 -9
  123. package/dist/lib/observability/tracer.d.ts +26 -8
  124. package/dist/lib/observability/tracer.js +43 -18
  125. package/dist/lib/runtime/adkMemoryBridge.d.ts +46 -0
  126. package/dist/lib/runtime/adkMemoryBridge.js +68 -0
  127. package/dist/lib/runtime/adkSessionBridge.d.ts +78 -0
  128. package/dist/lib/runtime/adkSessionBridge.js +176 -0
  129. package/dist/lib/runtime/credentials.d.ts +59 -0
  130. package/dist/lib/runtime/credentials.js +62 -0
  131. package/dist/lib/runtime/events.d.ts +229 -0
  132. package/dist/lib/runtime/events.js +274 -0
  133. package/dist/lib/runtime/logging.d.ts +32 -0
  134. package/dist/lib/runtime/logging.js +55 -0
  135. package/dist/lib/runtime/memoryService.d.ts +72 -0
  136. package/dist/lib/runtime/memoryService.js +25 -0
  137. package/dist/lib/runtime/native/agentLoop.d.ts +203 -0
  138. package/dist/lib/runtime/native/agentLoop.js +687 -0
  139. package/dist/lib/runtime/native/compaction.d.ts +103 -0
  140. package/dist/lib/runtime/native/compaction.js +191 -0
  141. package/dist/lib/runtime/native/delegate.d.ts +98 -0
  142. package/dist/lib/runtime/native/delegate.js +173 -0
  143. package/dist/lib/runtime/native/history.d.ts +83 -0
  144. package/dist/lib/runtime/native/history.js +312 -0
  145. package/dist/lib/runtime/native/interrupts.d.ts +126 -0
  146. package/dist/lib/runtime/native/interrupts.js +291 -0
  147. package/dist/lib/runtime/native/request.d.ts +215 -0
  148. package/dist/lib/runtime/native/request.js +585 -0
  149. package/dist/lib/runtime/native/selfCorrection.d.ts +106 -0
  150. package/dist/lib/runtime/native/selfCorrection.js +253 -0
  151. package/dist/lib/runtime/native/step.d.ts +148 -0
  152. package/dist/lib/runtime/native/step.js +239 -0
  153. package/dist/lib/runtime/native/taskMode.d.ts +64 -0
  154. package/dist/lib/runtime/native/taskMode.js +126 -0
  155. package/dist/lib/runtime/native/telemetry.d.ts +75 -0
  156. package/dist/lib/runtime/native/telemetry.js +299 -0
  157. package/dist/lib/runtime/native/tempState.d.ts +31 -0
  158. package/dist/lib/runtime/native/tempState.js +56 -0
  159. package/dist/lib/runtime/nativeTurn.d.ts +86 -0
  160. package/dist/lib/runtime/nativeTurn.js +107 -0
  161. package/dist/lib/runtime/questions.d.ts +29 -7
  162. package/dist/lib/runtime/questions.js +47 -32
  163. package/dist/lib/runtime/runtimeFlag.d.ts +30 -0
  164. package/dist/lib/runtime/runtimeFlag.js +50 -0
  165. package/dist/lib/runtime/sessions.d.ts +166 -0
  166. package/dist/lib/runtime/sessions.js +201 -0
  167. package/dist/lib/runtime/syndicateTurn.d.ts +41 -5
  168. package/dist/lib/runtime/syndicateTurn.js +202 -32
  169. package/dist/lib/session/supabaseSessionService.d.ts +64 -17
  170. package/dist/lib/session/supabaseSessionService.js +148 -105
  171. package/dist/lib/session/transcript.d.ts +68 -22
  172. package/dist/lib/session/transcript.js +102 -28
  173. package/dist/lib/skills.js +33 -7
  174. package/dist/lib/storage/postgres/credentialStore.d.ts +20 -0
  175. package/dist/lib/storage/postgres/credentialStore.js +82 -0
  176. package/dist/lib/storage/postgres/index.d.ts +12 -0
  177. package/dist/lib/storage/postgres/index.js +6 -1
  178. package/dist/lib/storage/postgres/sessionService.d.ts +43 -15
  179. package/dist/lib/storage/postgres/sessionService.js +128 -66
  180. package/dist/lib/syndicateSchema.d.ts +47 -0
  181. package/dist/lib/syndicateSchema.js +72 -3
  182. package/dist/lib/toolRegistry.d.ts +15 -2
  183. package/dist/lib/toolRegistry.js +33 -17
  184. package/dist/lib/tools/adkTool.d.ts +81 -0
  185. package/dist/lib/tools/adkTool.js +268 -0
  186. package/dist/lib/tools/auth.d.ts +118 -0
  187. package/dist/lib/tools/auth.js +89 -0
  188. package/dist/lib/tools/collectionsSearchTool.d.ts +7 -6
  189. package/dist/lib/tools/collectionsSearchTool.js +11 -26
  190. package/dist/lib/tools/credentialCipher.d.ts +58 -0
  191. package/dist/lib/tools/credentialCipher.js +116 -0
  192. package/dist/lib/tools/credentialStore.d.ts +77 -0
  193. package/dist/lib/tools/credentialStore.js +246 -0
  194. package/dist/lib/tools/examples.d.ts +43 -0
  195. package/dist/lib/tools/examples.js +62 -0
  196. package/dist/lib/tools/generateImageTool.d.ts +15 -6
  197. package/dist/lib/tools/generateImageTool.js +19 -29
  198. package/dist/lib/tools/inspectImageTool.d.ts +9 -6
  199. package/dist/lib/tools/inspectImageTool.js +13 -17
  200. package/dist/lib/tools/mcpToolFactory.d.ts +42 -1
  201. package/dist/lib/tools/mcpToolFactory.js +46 -47
  202. package/dist/lib/tools/memoryTools.d.ts +61 -0
  203. package/dist/lib/tools/memoryTools.js +119 -0
  204. package/dist/lib/tools/nativeTools.d.ts +38 -0
  205. package/dist/lib/tools/nativeTools.js +43 -0
  206. package/dist/lib/tools/oauthConsent.d.ts +181 -0
  207. package/dist/lib/tools/oauthConsent.js +330 -0
  208. package/dist/lib/tools/openapi/call.d.ts +108 -0
  209. package/dist/lib/tools/openapi/call.js +295 -0
  210. package/dist/lib/tools/openapi/parse.d.ts +147 -0
  211. package/dist/lib/tools/openapi/parse.js +570 -0
  212. package/dist/lib/tools/openapiTools.d.ts +25 -17
  213. package/dist/lib/tools/openapiTools.js +124 -121
  214. package/dist/lib/tools/scienceTools.d.ts +14 -14
  215. package/dist/lib/tools/skillToolset.d.ts +58 -87
  216. package/dist/lib/tools/skillToolset.js +61 -142
  217. package/dist/lib/tools/skills/env.d.ts +58 -0
  218. package/dist/lib/tools/skills/env.js +165 -0
  219. package/dist/lib/tools/skills/executor.d.ts +114 -0
  220. package/dist/lib/tools/skills/executor.js +331 -0
  221. package/dist/lib/tools/skills/frontmatter.d.ts +79 -0
  222. package/dist/lib/tools/skills/frontmatter.js +215 -0
  223. package/dist/lib/tools/skills/loader.d.ts +91 -0
  224. package/dist/lib/tools/skills/loader.js +257 -0
  225. package/dist/lib/tools/skills/tools.d.ts +187 -0
  226. package/dist/lib/tools/skills/tools.js +386 -0
  227. package/dist/lib/tools/taskTools.d.ts +15 -15
  228. package/dist/lib/tools/tool.d.ts +354 -0
  229. package/dist/lib/tools/tool.js +304 -0
  230. package/dist/lib/tools/toolContract.d.ts +89 -33
  231. package/dist/lib/tools/toolContract.js +104 -82
  232. package/dist/lib/tools/urlContextTool.d.ts +3 -0
  233. package/dist/lib/tools/urlContextTool.js +5 -1
  234. package/dist/lib/tools/webExtractTool.d.ts +2 -2
  235. package/dist/lib/tools/webExtractTool.js +2 -1
  236. package/dist/lib/tools/webSearchTool.d.ts +6 -9
  237. package/dist/lib/tools/webSearchTool.js +14 -59
  238. package/dist/lib/tools/wikiTools.d.ts +19 -19
  239. package/dist/lib/tools/wikiTools.js +13 -9
  240. package/dist/lib/tools/xApiSearchTool.d.ts +2 -2
  241. package/dist/lib/tools/xApiSearchTool.js +2 -1
  242. package/dist/lib/tools/xSearchTool.d.ts +7 -9
  243. package/dist/lib/tools/xSearchTool.js +11 -62
  244. package/dist/lib/tools/xaiSearchParams.d.ts +41 -0
  245. package/dist/lib/tools/xaiSearchParams.js +126 -0
  246. package/dist/lib/wiki/agentRun.d.ts +12 -0
  247. package/dist/lib/wiki/agentRun.js +72 -34
  248. package/dist/lib/wiki/entities.d.ts +12 -0
  249. package/dist/lib/wiki/entities.js +45 -3
  250. package/dist/lib/workflow/agentNode.d.ts +136 -0
  251. package/dist/lib/workflow/agentNode.js +274 -0
  252. package/dist/lib/workflow/graph.d.ts +177 -0
  253. package/dist/lib/workflow/graph.js +458 -0
  254. package/dist/lib/workflow/nodeEvents.d.ts +50 -0
  255. package/dist/lib/workflow/nodeEvents.js +101 -0
  256. package/dist/lib/workflow/pause.d.ts +122 -0
  257. package/dist/lib/workflow/pause.js +180 -0
  258. package/dist/lib/workflow/resume.d.ts +165 -0
  259. package/dist/lib/workflow/resume.js +440 -0
  260. package/dist/lib/workflow/route.d.ts +58 -0
  261. package/dist/lib/workflow/route.js +69 -0
  262. package/dist/lib/workflow/scheduler.d.ts +415 -0
  263. package/dist/lib/workflow/scheduler.js +743 -0
  264. package/dist/lib/workflow/toolNode.d.ts +127 -0
  265. package/dist/lib/workflow/toolNode.js +236 -0
  266. package/dist/lib/workflow/turn.d.ts +118 -0
  267. package/dist/lib/workflow/turn.js +216 -0
  268. package/dist/lib/workflowConfig.d.ts +3 -2
  269. package/dist/lib/workflowConfig.js +3 -12
  270. package/dist/scripts/a2a_server.js +4 -3
  271. package/dist/scripts/assistant_worker.d.ts +2 -1
  272. package/dist/scripts/assistant_worker.js +9 -4
  273. package/dist/scripts/syndicate_chat.js +19 -10
  274. package/package.json +4 -1
  275. package/skills/briefs/melchizedek-author.md +3 -2
  276. package/skills/briefs/melchizedek-models.md +13 -9
  277. package/skills/briefs/melchizedek.md +3 -3
  278. package/skills/melchizedek/SKILL.md +2 -1
  279. package/skills/melchizedek-author/SKILL.md +2 -1
  280. package/skills/melchizedek-author/assets/minimal.yaml +2 -0
  281. package/skills/melchizedek-models/SKILL.md +23 -6
@@ -0,0 +1,63 @@
1
+ /**
2
+ * lib/models/providerState.ts — provider-opaque reasoning state carried on a
3
+ * model content part from one model step to the next (ADR 0046).
4
+ *
5
+ * WHY: some providers want back, on the next request of a tool loop, state
6
+ * only they can read: Anthropic's signed `thinking` and `redacted_thinking`
7
+ * blocks, OpenAI's and xAI's reasoning items, Moonshot's reasoning_content.
8
+ * ADK's request is built from each event's `content` alone (event metadata
9
+ * never reaches it), and @google/genai serializes a part field by field, so
10
+ * the state rides as one extra field on a part the model actually produced:
11
+ *
12
+ * { functionCall: {...}, providerState: { provider, kind, payload } }
13
+ *
14
+ * THE RULES:
15
+ * - The adapter that produced the response writes it, on the part the
16
+ * state belongs before (Claude: the part its signed blocks preceded).
17
+ * - Only an adapter of the same `provider` replays it, and only the `kind`
18
+ * it wrote (and, when `model` is set, only that model). Every other
19
+ * adapter ignores the field, so a model switch between steps drops the
20
+ * state rather than misreading it.
21
+ * - `payload` is opaque to everything but the writer, JSON-serializable,
22
+ * and replayed verbatim. The session services store it with the event;
23
+ * the transcript projection drops it with the rest of a past turn's
24
+ * machinery (lib/session/transcript.ts).
25
+ */
26
+ /** The field name on a content part. */
27
+ export declare const PROVIDER_STATE_FIELD = "providerState";
28
+ export interface ProviderState {
29
+ /** The writer's provider id (lib/models/providerMap.ts), e.g. `anthropic`. */
30
+ provider: string;
31
+ /** What the payload is, in the writer's terms, e.g. `thinking_blocks`. */
32
+ kind: string;
33
+ /**
34
+ * The model that wrote it, when the provider binds the state to a model
35
+ * (Anthropic's signed thinking): a reader skips state another model wrote.
36
+ */
37
+ model?: string;
38
+ /** Opaque to everyone but the writer; replayed verbatim. */
39
+ payload: unknown;
40
+ }
41
+ /**
42
+ * The state `provider` wrote on a part, or undefined when the part carries
43
+ * none, another provider's, another kind, a malformed one, or (with `model`
44
+ * given) one another model wrote.
45
+ */
46
+ export declare function providerStateOf(part: unknown, provider: string, kind: string, model?: string): ProviderState | undefined;
47
+ /** A copy of `part` carrying `state`; the input is not mutated. */
48
+ export declare function withProviderState<T extends object>(part: T, state: ProviderState): T & {
49
+ providerState: ProviderState;
50
+ };
51
+ /**
52
+ * Where the current turn starts in `contents`: the index of the last user
53
+ * content that is not purely tool results, or -1 when there is none (every
54
+ * content is then this turn's, the first included). The model contents
55
+ * after it are this turn's tool loop, the only place an adapter replays its
56
+ * state. Earlier turns' state is left out: dropping it from the front of
57
+ * the history is allowed, and the stored history before it may differ from
58
+ * what the model saw (tool payloads are elided before storage).
59
+ */
60
+ export declare function currentTurnStart(contents: ReadonlyArray<{
61
+ role?: string;
62
+ parts?: ReadonlyArray<unknown>;
63
+ }>): number;
@@ -0,0 +1,61 @@
1
+ /**
2
+ * lib/models/providerState.ts — provider-opaque reasoning state carried on a
3
+ * model content part from one model step to the next (ADR 0046).
4
+ *
5
+ * WHY: some providers want back, on the next request of a tool loop, state
6
+ * only they can read: Anthropic's signed `thinking` and `redacted_thinking`
7
+ * blocks, OpenAI's and xAI's reasoning items, Moonshot's reasoning_content.
8
+ * ADK's request is built from each event's `content` alone (event metadata
9
+ * never reaches it), and @google/genai serializes a part field by field, so
10
+ * the state rides as one extra field on a part the model actually produced:
11
+ *
12
+ * { functionCall: {...}, providerState: { provider, kind, payload } }
13
+ *
14
+ * THE RULES:
15
+ * - The adapter that produced the response writes it, on the part the
16
+ * state belongs before (Claude: the part its signed blocks preceded).
17
+ * - Only an adapter of the same `provider` replays it, and only the `kind`
18
+ * it wrote (and, when `model` is set, only that model). Every other
19
+ * adapter ignores the field, so a model switch between steps drops the
20
+ * state rather than misreading it.
21
+ * - `payload` is opaque to everything but the writer, JSON-serializable,
22
+ * and replayed verbatim. The session services store it with the event;
23
+ * the transcript projection drops it with the rest of a past turn's
24
+ * machinery (lib/session/transcript.ts).
25
+ */
26
+ /** The field name on a content part. */
27
+ export const PROVIDER_STATE_FIELD = 'providerState';
28
+ /**
29
+ * The state `provider` wrote on a part, or undefined when the part carries
30
+ * none, another provider's, another kind, a malformed one, or (with `model`
31
+ * given) one another model wrote.
32
+ */
33
+ export function providerStateOf(part, provider, kind, model) {
34
+ const state = part?.[PROVIDER_STATE_FIELD];
35
+ if (!state || typeof state !== 'object')
36
+ return undefined;
37
+ if (state.provider !== provider || state.kind !== kind)
38
+ return undefined;
39
+ return model !== undefined && state.model !== undefined && state.model !== model ? undefined : state;
40
+ }
41
+ /** A copy of `part` carrying `state`; the input is not mutated. */
42
+ export function withProviderState(part, state) {
43
+ return { ...part, [PROVIDER_STATE_FIELD]: state };
44
+ }
45
+ /**
46
+ * Where the current turn starts in `contents`: the index of the last user
47
+ * content that is not purely tool results, or -1 when there is none (every
48
+ * content is then this turn's, the first included). The model contents
49
+ * after it are this turn's tool loop, the only place an adapter replays its
50
+ * state. Earlier turns' state is left out: dropping it from the front of
51
+ * the history is allowed, and the stored history before it may differ from
52
+ * what the model saw (tool payloads are elided before storage).
53
+ */
54
+ export function currentTurnStart(contents) {
55
+ for (let i = contents.length - 1; i >= 0; i--) {
56
+ const c = contents[i];
57
+ if (c.role === 'user' && (c.parts ?? []).some((p) => !p?.functionResponse))
58
+ return i;
59
+ }
60
+ return -1;
61
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * lib/models/reasoning.ts — the generateContentConfig fields a `reasoning:`
3
+ * setting becomes for one model (ADR 0047).
4
+ *
5
+ * WHY HERE: the compiler maps an agent's `reasoning:` key through this, and
6
+ * a model adapter on the contract (lib/models/geminiAdapter.ts) maps a
7
+ * ModelRequest's `reasoning` the same way. Keeping it out of lib/compile.ts
8
+ * keeps ADK out of an adapter's imports. lib/compile.ts re-exports both
9
+ * names, so existing imports keep working.
10
+ */
11
+ import type { ReasoningLevel, ReasoningSetting } from './contract.ts';
12
+ /**
13
+ * Thinking tokens per level, for the providers that take a budget (Claude,
14
+ * Gemini 2.x). The same table rounds a `budget_tokens` value up to a level
15
+ * for the providers that take only a level or an effort word.
16
+ */
17
+ export declare const REASONING_BUDGETS: Readonly<Record<ReasoningLevel, number>>;
18
+ /**
19
+ * The generateContentConfig fields a `reasoning:` setting becomes for one
20
+ * model (ADR 0047). `reasoningEffort` is always set, so the gateway (which
21
+ * may serve any id) carries the level too; the Claude adapter reads it first
22
+ * on the adaptive generations (ADR 0049), and the genai SDK drops it from a
23
+ * Gemini request. Claude and Gemini also get the `thinkingConfig` their
24
+ * adapters read.
25
+ */
26
+ export declare function reasoningConfig(model: string, setting: ReasoningSetting): Record<string, unknown>;
@@ -0,0 +1,59 @@
1
+ import { providerForModel } from './providerMap.js';
2
+ /**
3
+ * Thinking tokens per level, for the providers that take a budget (Claude,
4
+ * Gemini 2.x). The same table rounds a `budget_tokens` value up to a level
5
+ * for the providers that take only a level or an effort word.
6
+ */
7
+ export const REASONING_BUDGETS = { none: 0, low: 2048, medium: 8192, high: 16384 };
8
+ const GEMINI_THINKING_LEVEL = { none: 'MINIMAL', low: 'LOW', medium: 'MEDIUM', high: 'HIGH' };
9
+ /** The smallest level whose budget covers the setting: never less thought than asked. */
10
+ function reasoningLevel(setting) {
11
+ if (typeof setting === 'string')
12
+ return setting;
13
+ const n = setting.budget_tokens;
14
+ return n <= 0 ? 'none' : n <= REASONING_BUDGETS.low ? 'low' : n <= REASONING_BUDGETS.medium ? 'medium' : 'high';
15
+ }
16
+ /**
17
+ * The effort word for `generateContentConfig.reasoningEffort`, which the
18
+ * chat-completions adapters, the gateway and the Responses adapters read.
19
+ * A word the provider lacks becomes its nearest setting above.
20
+ */
21
+ function reasoningEffort(model, level) {
22
+ switch (providerForModel(model)) {
23
+ case 'openai':
24
+ if (level !== 'none')
25
+ return level;
26
+ // o-series cannot stop reasoning; the first GPT-5 generation says
27
+ // "minimal"; GPT-5.1 and later say "none".
28
+ return /^o\d/.test(model) ? 'low' : /^gpt-5(?![.\d])/.test(model) ? 'minimal' : 'none';
29
+ case 'xai':
30
+ return level === 'none' ? 'low' : level; // Grok 4.5/4.7 cannot stop reasoning
31
+ case 'moonshot':
32
+ return level === 'medium' ? 'high' : level; // K3 has low | high | max
33
+ default:
34
+ return level;
35
+ }
36
+ }
37
+ /**
38
+ * The generateContentConfig fields a `reasoning:` setting becomes for one
39
+ * model (ADR 0047). `reasoningEffort` is always set, so the gateway (which
40
+ * may serve any id) carries the level too; the Claude adapter reads it first
41
+ * on the adaptive generations (ADR 0049), and the genai SDK drops it from a
42
+ * Gemini request. Claude and Gemini also get the `thinkingConfig` their
43
+ * adapters read.
44
+ */
45
+ export function reasoningConfig(model, setting) {
46
+ const level = reasoningLevel(setting);
47
+ const budget = typeof setting === 'string' ? REASONING_BUDGETS[setting] : setting.budget_tokens;
48
+ const out = { reasoningEffort: reasoningEffort(model, level) };
49
+ const provider = providerForModel(model);
50
+ if (provider === 'anthropic')
51
+ out.thinkingConfig = { thinkingBudget: budget };
52
+ if (provider === 'gemini') {
53
+ // Gemini 3 takes a level; 2.x and older take only a budget. An explicit
54
+ // budget is sent as one on any Gemini, except 0, which is `none`.
55
+ const budgetOnly = /^gemini-[12]\./.test(model);
56
+ out.thinkingConfig = budgetOnly || (typeof setting !== 'string' && budget > 0) ? { thinkingBudget: budget } : { thinkingLevel: GEMINI_THINKING_LEVEL[level] };
57
+ }
58
+ return out;
59
+ }
@@ -3,28 +3,49 @@
3
3
  * optionality: an agent's YAML declares `model`, and this module makes sure
4
4
  * that string reaches the right provider adapter.
5
5
  *
6
- * TWO RESOLUTION PATHS, ONE PREFIX TABLE (lib/models/providerMap.ts):
6
+ * THREE RESOLUTION PATHS, ONE PREFIX TABLE (lib/models/providerMap.ts):
7
7
  *
8
8
  * 1. registerAvailableProviders() — for entrypoints that pass `model` as a
9
9
  * STRING to LlmAgent (scripts/syndicate_chat.ts). Registers every
10
- * adapter whose credentials exist into the ADK LLMRegistry; the
11
- * registry then string-matches supportedModels patterns:
10
+ * provider's own ADK class whose credentials exist into the ADK
11
+ * LLMRegistry; the registry then string-matches supportedModels patterns:
12
12
  * claude-* → ClaudeLlm gpt-* / o<digit>* → GptLlm
13
13
  * grok-* → GrokLlm ollama/<model> → OllamaLlm
14
14
  * kimi-* → KimiLlm gemini-* → TracedGemini (ADK's Gemini + llm.request spans)
15
+ * Each non-Gemini class is the ADK shim around its contract adapter,
16
+ * with the provider's own toLlmResponse (ADR 0056, ADR 0057); never a
17
+ * bare adkShimClass, which would lose it.
15
18
  *
16
- * 2. resolveModel() — instance factory for BYOK paths (scripts/
17
- * a2a_server.ts), where a per-request API key from an HTTP header must
18
- * be injected into the adapter. Same prefix table; the YAML model
19
- * string always wins over the X-Provider header (which only selects a
20
- * DEFAULT model when the YAML omits `model` — a deprecated affordance).
19
+ * 2. resolveModel() — the ADK BaseLlm INSTANCE for one id, for BYOK paths
20
+ * (lib/a2a/app.ts), where a per-request API key or endpoint must be
21
+ * injected. The same classes. The YAML model string always wins over
22
+ * the X-Provider header (which only selects a DEFAULT model when the
23
+ * YAML omits `model` — a deprecated affordance).
24
+ *
25
+ * 3. resolveAdapter() — the engine's own ModelAdapter (lib/models/
26
+ * contract.ts, ADR 0048) for one id, with no ADK LLMRegistry, for the
27
+ * native loop (ADR 0045). The same transport rule (the gateway when the
28
+ * direct key is absent), the same BYOK and endpoint injection. Gemini
29
+ * ids get the temporary AdkGeminiAdapter until gate G3, or the engine's
30
+ * GeminiAdapter when GEMINI_ADAPTER=engine or `{ gemini: 'engine' }`
31
+ * asks for it (ADR 0060). resolveAdapterWithFallback() wraps a pair in a
32
+ * FallbackAdapter; the ADK path keeps FallbackLlm(shim, shim) (ADR 0053).
33
+ *
34
+ * Paths 2 and 3 read one routing step (routeFor) and one table per path
35
+ * keyed by provider, so a key or endpoint reaches the same place on both.
36
+ * routeFor and the contract table live in lib/models/adapterResolver.ts,
37
+ * which imports no ADK; `melchizedek-agents/model` exports its resolver,
38
+ * which gives a Gemini id GeminiAdapter (ADR 0068).
21
39
  *
22
40
  * Register BEFORE constructing any agent: the LLMRegistry caches model→class
23
41
  * resolution (LRU), so late registration can be masked by stale cache hits.
24
42
  */
25
- import { Gemini } from '@google/adk';
26
- import type { BaseLlm, GeminiParams, LlmRequest, LlmResponse } from '@google/adk';
43
+ import type { BaseLlm } from '@google/adk';
27
44
  import type { ProviderEndpoint } from './endpoints.ts';
45
+ import type { ModelAdapter } from './contract.ts';
46
+ import type { GeminiAdapterChoice, ResolveAdapterOptions } from './adapterResolver.ts';
47
+ import type { FallbackAdapterOptions } from './fallbackAdapter.ts';
48
+ import { TracedGemini } from './tracedGemini.ts';
28
49
  import { GatewayLlm } from './gatewayLlm.ts';
29
50
  import { PROVIDERS, providerForModel, providerKeyPresent } from './providerMap.ts';
30
51
  import type { ProviderId } from './providerMap.ts';
@@ -32,30 +53,12 @@ export { providerForModel, providerKeyPresent, PROVIDERS };
32
53
  export { endpointFromEnv, endpointLabel, endpointProblems, PLATFORMS_FOR, platformFromEnv, providerReady, } from './endpoints.ts';
33
54
  export type { Platform, ProviderEndpoint } from './endpoints.ts';
34
55
  export type { ProviderId };
56
+ export type { GeminiAdapterChoice, ResolveAdapterOptions };
35
57
  export { gatewayConfig, gatewayProblem, gatewayUsable, planTransport, GATEWAYS } from './gateway.ts';
36
58
  export type { GatewayId, GatewayInfo, TransportPlan } from './gateway.ts';
37
59
  export { describeCapabilities, capabilitySummary } from './capabilities.ts';
38
60
  export type { CapabilityReport } from './capabilities.ts';
39
- export { GatewayLlm };
40
- export declare class TracedGemini extends Gemini {
41
- static readonly supportedModels: Array<string | RegExp>;
42
- /**
43
- * The Gemini platform (ADR 0023) applies to every construction, the
44
- * LLMRegistry's included: on Vertex AI the client authenticates with
45
- * Google Application Default Credentials for the configured project and
46
- * location, and an AI Studio key (the environment's or a caller's) is not
47
- * sent. `endpoint` overrides the environment's (the credentials plug point).
48
- */
49
- constructor(params?: GeminiParams & {
50
- endpoint?: ProviderEndpoint;
51
- });
52
- generateContentAsync(llmRequest: LlmRequest, stream?: boolean, abortSignal?: AbortSignal): AsyncGenerator<LlmResponse, void>;
53
- /** Tags the llm.request span (web_search = Gemini grounding), then
54
- * delegates to ADK's Gemini. Runs inside the span context. The abort
55
- * signal is forwarded so a canceled turn stops the request in flight
56
- * (ADK's Gemini puts it on the genai request config). */
57
- private tagAndGenerate;
58
- }
61
+ export { GatewayLlm, TracedGemini };
59
62
  export interface ProviderStatus {
60
63
  provider: ProviderId;
61
64
  label: string;
@@ -89,7 +92,7 @@ export interface ResolveModelOptions {
89
92
  /**
90
93
  * DEPRECATED — the A2A X-Provider header. Only consulted when `model` is
91
94
  * undefined, to pick that provider's default model. A model id in the
92
- * YAML always wins.
95
+ * YAML always wins. It also names the provider `apiKey` belongs to.
93
96
  */
94
97
  defaultProvider?: string;
95
98
  /**
@@ -100,9 +103,29 @@ export interface ResolveModelOptions {
100
103
  endpoint?: Partial<ProviderEndpoint>;
101
104
  }
102
105
  /**
103
- * Resolves a model id (from YAML) to a provider adapter INSTANCE, injecting
104
- * a per-request apiKey where the provider accepts one. When `model` is
105
- * undefined, falls back to the default model of `defaultProvider` (or
106
- * Gemini).
106
+ * Resolves a model id (from YAML) to a provider adapter INSTANCE for the ADK
107
+ * runtime, injecting a per-request apiKey where the provider accepts one.
108
+ * When `model` is undefined, falls back to the default model of
109
+ * `defaultProvider` (or Gemini).
107
110
  */
108
111
  export declare function resolveModel(model: string | undefined, options?: ResolveModelOptions): BaseLlm;
112
+ /** GEMINI_ADAPTER (`adk`, the default here, or `engine`). Any other value is a configuration error. */
113
+ export declare function geminiAdapterChoice(env?: NodeJS.ProcessEnv): GeminiAdapterChoice;
114
+ /**
115
+ * Resolves a model id to the engine's own ModelAdapter (ADR 0048), from the
116
+ * same prefix table and transport rule as resolveModel, with no ADK
117
+ * LLMRegistry: the provider's adapter when its key (env, BYOK or endpoint)
118
+ * is present, the gateway's when it is absent and MODEL_GATEWAY is set.
119
+ * The adapter opens no span and charges nothing: its caller does (ADR 0053).
120
+ */
121
+ export declare function resolveAdapter(modelId: string, options?: ResolveAdapterOptions): ModelAdapter;
122
+ /**
123
+ * An agent's model and its `fallback_model:` on the contract path: a
124
+ * FallbackAdapter (ADR 0044) around resolveAdapter's two adapters, or the
125
+ * primary alone when there is no fallback. The caller's key stays with its
126
+ * own provider: unless `keyProvider` says otherwise it belongs to the
127
+ * primary's, so a fallback on another provider resolves from server env.
128
+ * Nothing calls this yet; the ADK path's pair stays
129
+ * FallbackLlm(shim(primary), shim(fallback)) (ADR 0053).
130
+ */
131
+ export declare function resolveAdapterWithFallback(modelId: string, fallbackId: string | undefined, options?: ResolveAdapterOptions, fallbackOptions?: FallbackAdapterOptions): ModelAdapter;
@@ -3,105 +3,62 @@
3
3
  * optionality: an agent's YAML declares `model`, and this module makes sure
4
4
  * that string reaches the right provider adapter.
5
5
  *
6
- * TWO RESOLUTION PATHS, ONE PREFIX TABLE (lib/models/providerMap.ts):
6
+ * THREE RESOLUTION PATHS, ONE PREFIX TABLE (lib/models/providerMap.ts):
7
7
  *
8
8
  * 1. registerAvailableProviders() — for entrypoints that pass `model` as a
9
9
  * STRING to LlmAgent (scripts/syndicate_chat.ts). Registers every
10
- * adapter whose credentials exist into the ADK LLMRegistry; the
11
- * registry then string-matches supportedModels patterns:
10
+ * provider's own ADK class whose credentials exist into the ADK
11
+ * LLMRegistry; the registry then string-matches supportedModels patterns:
12
12
  * claude-* → ClaudeLlm gpt-* / o<digit>* → GptLlm
13
13
  * grok-* → GrokLlm ollama/<model> → OllamaLlm
14
14
  * kimi-* → KimiLlm gemini-* → TracedGemini (ADK's Gemini + llm.request spans)
15
+ * Each non-Gemini class is the ADK shim around its contract adapter,
16
+ * with the provider's own toLlmResponse (ADR 0056, ADR 0057); never a
17
+ * bare adkShimClass, which would lose it.
15
18
  *
16
- * 2. resolveModel() — instance factory for BYOK paths (scripts/
17
- * a2a_server.ts), where a per-request API key from an HTTP header must
18
- * be injected into the adapter. Same prefix table; the YAML model
19
- * string always wins over the X-Provider header (which only selects a
20
- * DEFAULT model when the YAML omits `model` — a deprecated affordance).
19
+ * 2. resolveModel() — the ADK BaseLlm INSTANCE for one id, for BYOK paths
20
+ * (lib/a2a/app.ts), where a per-request API key or endpoint must be
21
+ * injected. The same classes. The YAML model string always wins over
22
+ * the X-Provider header (which only selects a DEFAULT model when the
23
+ * YAML omits `model` — a deprecated affordance).
24
+ *
25
+ * 3. resolveAdapter() — the engine's own ModelAdapter (lib/models/
26
+ * contract.ts, ADR 0048) for one id, with no ADK LLMRegistry, for the
27
+ * native loop (ADR 0045). The same transport rule (the gateway when the
28
+ * direct key is absent), the same BYOK and endpoint injection. Gemini
29
+ * ids get the temporary AdkGeminiAdapter until gate G3, or the engine's
30
+ * GeminiAdapter when GEMINI_ADAPTER=engine or `{ gemini: 'engine' }`
31
+ * asks for it (ADR 0060). resolveAdapterWithFallback() wraps a pair in a
32
+ * FallbackAdapter; the ADK path keeps FallbackLlm(shim, shim) (ADR 0053).
33
+ *
34
+ * Paths 2 and 3 read one routing step (routeFor) and one table per path
35
+ * keyed by provider, so a key or endpoint reaches the same place on both.
36
+ * routeFor and the contract table live in lib/models/adapterResolver.ts,
37
+ * which imports no ADK; `melchizedek-agents/model` exports its resolver,
38
+ * which gives a Gemini id GeminiAdapter (ADR 0068).
21
39
  *
22
40
  * Register BEFORE constructing any agent: the LLMRegistry caches model→class
23
41
  * resolution (LRU), so late registration can be masked by stale cache hits.
24
42
  */
25
43
  import { Gemini, LLMRegistry } from '@google/adk';
26
- import { endpointFromEnv, endpointProblems, mergeEndpoint, platformModel, providerReady } from './endpoints.js';
27
- import { currentTurnSignal } from '../runtime/turnControl.js';
28
- import { errorStatus, retryUntilFirstYield } from './retry.js';
44
+ import { endpointFromEnv, endpointProblems, providerReady } from './endpoints.js';
29
45
  import { DEFAULT_CLAUDE_MODEL, DEFAULT_GEMINI_MODEL, DEFAULT_GPT_MODEL, DEFAULT_GROK_MODEL, DEFAULT_KIMI_MODEL, DEFAULT_OLLAMA_MODEL, } from '../config.js';
30
- import { traceLlmGeneration, setLlmSpanAttribute, } from '../observability/tracer.js';
46
+ import { AdkGeminiAdapter } from './adkGeminiAdapter.js';
47
+ import { adapterResolver, geminiAdapterSetting, normalizeProvider, routeFor, scopedKey } from './adapterResolver.js';
48
+ import { TracedGemini } from './tracedGemini.js';
31
49
  import { ClaudeLlm, registerClaudeLlm } from './claudeLlm.js';
32
50
  import { GptLlm, registerGptLlm } from './gptLlm.js';
33
51
  import { GrokLlm, registerGrokLlm } from './grokLlm.js';
34
52
  import { KimiLlm, registerKimiLlm } from './kimiLlm.js';
35
53
  import { OllamaLlm, registerOllamaLlm } from './ollamaLlm.js';
36
54
  import { GatewayLlm, registerGatewayLlm } from './gatewayLlm.js';
37
- import { gatewayConfig, gatewayProblem, gatewayUsable, planTransport, } from './gateway.js';
55
+ import { gatewayConfig, gatewayProblem, gatewayUsable } from './gateway.js';
38
56
  import { PROVIDERS, providerForModel, providerKeyPresent, } from './providerMap.js';
39
57
  export { providerForModel, providerKeyPresent, PROVIDERS };
40
58
  export { endpointFromEnv, endpointLabel, endpointProblems, PLATFORMS_FOR, platformFromEnv, providerReady, } from './endpoints.js';
41
59
  export { gatewayConfig, gatewayProblem, gatewayUsable, planTransport, GATEWAYS } from './gateway.js';
42
60
  export { describeCapabilities, capabilitySummary } from './capabilities.js';
43
- export { GatewayLlm };
44
- // ── TracedGemini ─────────────────────────────────────────────────────────────
45
- // ADK's built-in Gemini adapter, wrapped so Gemini calls emit the same
46
- // per-request llm.request spans (tokens, latency) as every other provider,
47
- // and get the shared transient-failure retries (lib/models/retry.ts).
48
- export class TracedGemini extends Gemini {
49
- // CRITICAL: reuse Gemini's exact regex instances. The LLMRegistry dict is
50
- // keyed by the regex OBJECT — registering the same instances REPLACES the
51
- // built-in Gemini entries instead of adding shadowed duplicates.
52
- static supportedModels = Gemini.supportedModels;
53
- /**
54
- * The Gemini platform (ADR 0023) applies to every construction, the
55
- * LLMRegistry's included: on Vertex AI the client authenticates with
56
- * Google Application Default Credentials for the configured project and
57
- * location, and an AI Studio key (the environment's or a caller's) is not
58
- * sent. `endpoint` overrides the environment's (the credentials plug point).
59
- */
60
- constructor(params = {}) {
61
- const { endpoint: given, ...rest } = params;
62
- const e = given ?? endpointFromEnv('gemini');
63
- const model = rest.model ? platformModel(e, rest.model) : rest.model;
64
- super(e.platform === 'vertex'
65
- ? { ...rest, model, apiKey: e.apiKey, vertexai: true, project: e.project, location: e.location }
66
- : { ...rest, model, ...(e.apiKey && !rest.apiKey ? { apiKey: e.apiKey } : {}) });
67
- }
68
- async *generateContentAsync(llmRequest, stream, abortSignal) {
69
- yield* traceLlmGeneration({ provider: 'gemini', model: this.model, llmRequest }, this.tagAndGenerate(llmRequest, stream, abortSignal ?? currentTurnSignal()));
70
- }
71
- /** Tags the llm.request span (web_search = Gemini grounding), then
72
- * delegates to ADK's Gemini. Runs inside the span context. The abort
73
- * signal is forwarded so a canceled turn stops the request in flight
74
- * (ADK's Gemini puts it on the genai request config). */
75
- async *tagAndGenerate(llmRequest, stream, abortSignal) {
76
- const hasGrounding = (llmRequest.config?.tools ?? []).some((t) => t && (t.googleSearch || t.googleSearchRetrieval));
77
- if (hasGrounding)
78
- setLlmSpanAttribute('llm.web_search.native', true);
79
- // Retries live here, not in genai's own httpOptions.retryOptions: that
80
- // hook (p-retry 4, client-level only) ignores the abort signal — it
81
- // sleeps and re-sends after a canceled turn — honours no Retry-After,
82
- // does not retry Node's "fetch failed" resets, and replaces a 4xx's
83
- // error body (e.g. "API key not valid") with a bare statusText. Wrapping
84
- // the call keeps genai's ApiError intact and applies the same policy as
85
- // every other adapter. A retry is only made while nothing has been
86
- // yielded, so a stream that fails mid-reply is surfaced, not replayed.
87
- // ADK's request preprocessing is idempotent, so re-sending the same
88
- // llmRequest is safe. Both the registry class and resolveModel()'s
89
- // per-request instances are TracedGemini, so both get this.
90
- try {
91
- yield* retryUntilFirstYield(() => super.generateContentAsync(llmRequest, stream, abortSignal), {
92
- signal: abortSignal,
93
- onRetry: ({ retries }) => setLlmSpanAttribute('llm.retries', retries),
94
- });
95
- }
96
- catch (err) {
97
- // genai's ApiError carries the status; put it where the ledger reads.
98
- const status = errorStatus(err);
99
- if (status !== undefined)
100
- setLlmSpanAttribute('llm.http_status', status);
101
- throw err;
102
- }
103
- }
104
- }
61
+ export { GatewayLlm, TracedGemini };
105
62
  /** Availability report without side effects (used by demos and key gates). */
106
63
  export function providerStatuses() {
107
64
  const gw = gatewayUsable() ? gatewayConfig() : null;
@@ -229,50 +186,64 @@ const DEFAULT_MODEL_FOR = {
229
186
  ollama: DEFAULT_OLLAMA_MODEL,
230
187
  };
231
188
  /**
232
- * Resolves a model id (from YAML) to a provider adapter INSTANCE, injecting
233
- * a per-request apiKey where the provider accepts one. When `model` is
234
- * undefined, falls back to the default model of `defaultProvider` (or
235
- * Gemini).
189
+ * Each provider's ADK class for a direct route: the provider's own exported
190
+ * class, so GptLlm's and the chat-completions shims' toLlmResponse keep the
191
+ * ledger's usage meaning (ADR 0056, ADR 0057). Grok has no platforms, so it
192
+ * takes no endpoint; Kimi takes its base URL; Ollama is local and takes
193
+ * neither.
194
+ */
195
+ const ADK_LLM = {
196
+ ollama: (r) => new OllamaLlm({ model: r.model }),
197
+ anthropic: (r) => new ClaudeLlm({ model: r.model, apiKey: r.apiKey, endpoint: r.endpoint }),
198
+ openai: (r) => new GptLlm({ model: r.model, apiKey: r.apiKey, endpoint: r.endpoint }),
199
+ xai: (r) => new GrokLlm({ model: r.model, apiKey: r.apiKey }),
200
+ moonshot: (r) => new KimiLlm({ model: r.model, apiKey: r.apiKey, baseUrl: r.endpoint?.baseURL }),
201
+ gemini: (r) => new TracedGemini({ model: r.model, apiKey: r.apiKey, endpoint: r.endpoint }),
202
+ };
203
+ /**
204
+ * Resolves a model id (from YAML) to a provider adapter INSTANCE for the ADK
205
+ * runtime, injecting a per-request apiKey where the provider accepts one.
206
+ * When `model` is undefined, falls back to the default model of
207
+ * `defaultProvider` (or Gemini).
236
208
  */
237
209
  export function resolveModel(model, options = {}) {
238
- const resolved = model ??
239
- DEFAULT_MODEL_FOR[normalizeProvider(options.defaultProvider)];
240
- // BYOK is scoped to the CALLER'S provider: the X-API-Key a client sends
241
- // authenticates that client's own provider (typically Gemini). Passing it
242
- // to a different provider's adapter would override the server's env key
243
- // (adapters prefer a passed key) and fail auth — e.g. a Gemini key sent to
244
- // xAI. Cross-provider agents therefore resolve keys from server env.
245
- const apiKey = providerForModel(model ?? DEFAULT_MODEL_FOR[normalizeProvider(options.defaultProvider)]) === normalizeProvider(options.defaultProvider)
246
- ? options.apiKey
247
- : undefined;
248
- // The fallback rule (lib/models/gateway.ts): the direct adapter whenever
249
- // the provider's key — from env, or the caller's own BYOK key — is
250
- // present; the gateway stand-in only when it is absent and a gateway is
251
- // configured. The gateway key is server env only, never a request header.
252
- const provider = providerForModel(resolved);
253
- const endpoint = options.endpoint ? mergeEndpoint(provider, options.endpoint) : undefined;
254
- if (planTransport(resolved, { callerKey: !!apiKey || !!endpoint }).transport === 'gateway') {
255
- return new GatewayLlm({ model: resolved });
256
- }
257
- switch (provider) {
258
- case 'ollama':
259
- return new OllamaLlm({ model: resolved });
260
- case 'anthropic':
261
- return new ClaudeLlm({ model: resolved, apiKey, endpoint });
262
- case 'openai':
263
- return new GptLlm({ model: resolved, apiKey, endpoint });
264
- case 'xai':
265
- return new GrokLlm({ model: resolved, apiKey });
266
- case 'moonshot':
267
- return new KimiLlm({ model: resolved, apiKey, baseUrl: endpoint?.baseURL });
268
- case 'gemini':
269
- return new TracedGemini({ model: resolved, apiKey, endpoint });
270
- }
210
+ const keyProvider = normalizeProvider(options.defaultProvider);
211
+ const resolved = model ?? DEFAULT_MODEL_FOR[keyProvider];
212
+ const route = routeFor(resolved, scopedKey(resolved, options.apiKey, keyProvider), options.endpoint);
213
+ return route.transport === 'gateway' ? new GatewayLlm({ model: resolved }) : ADK_LLM[route.provider](route);
271
214
  }
272
- function normalizeProvider(provider) {
273
- const p = provider?.toLowerCase();
274
- if (p === 'ollama' || p === 'anthropic' || p === 'openai' || p === 'xai' || p === 'moonshot') {
275
- return p;
276
- }
277
- return 'gemini';
215
+ // ── Contract adapters (the native runtime) ───────────────────────────────────
216
+ /** GEMINI_ADAPTER (`adk`, the default here, or `engine`). Any other value is a configuration error. */
217
+ export function geminiAdapterChoice(env = process.env) {
218
+ return geminiAdapterSetting(env) ?? 'adk';
219
+ }
220
+ /**
221
+ * The contract resolver with the temporary AdkGeminiAdapter (ADR 0060): a
222
+ * Gemini id gets it until gate G3, or the engine's GeminiAdapter when
223
+ * GEMINI_ADAPTER=engine or `{ gemini: 'engine' }` asks for it. The
224
+ * ADK-free resolver in lib/models/adapterResolver.ts, which
225
+ * `melchizedek-agents/model` exports, defaults to GeminiAdapter (ADR 0068).
226
+ */
227
+ const WITH_ADK_GEMINI = adapterResolver((r) => new AdkGeminiAdapter(r));
228
+ /**
229
+ * Resolves a model id to the engine's own ModelAdapter (ADR 0048), from the
230
+ * same prefix table and transport rule as resolveModel, with no ADK
231
+ * LLMRegistry: the provider's adapter when its key (env, BYOK or endpoint)
232
+ * is present, the gateway's when it is absent and MODEL_GATEWAY is set.
233
+ * The adapter opens no span and charges nothing: its caller does (ADR 0053).
234
+ */
235
+ export function resolveAdapter(modelId, options = {}) {
236
+ return WITH_ADK_GEMINI.resolveAdapter(modelId, options);
237
+ }
238
+ /**
239
+ * An agent's model and its `fallback_model:` on the contract path: a
240
+ * FallbackAdapter (ADR 0044) around resolveAdapter's two adapters, or the
241
+ * primary alone when there is no fallback. The caller's key stays with its
242
+ * own provider: unless `keyProvider` says otherwise it belongs to the
243
+ * primary's, so a fallback on another provider resolves from server env.
244
+ * Nothing calls this yet; the ADK path's pair stays
245
+ * FallbackLlm(shim(primary), shim(fallback)) (ADR 0053).
246
+ */
247
+ export function resolveAdapterWithFallback(modelId, fallbackId, options = {}, fallbackOptions = {}) {
248
+ return WITH_ADK_GEMINI.resolveAdapterWithFallback(modelId, fallbackId, options, fallbackOptions);
278
249
  }
@@ -14,7 +14,8 @@
14
14
  * THE POLICY:
15
15
  * - Bounded: MODEL_RETRY_MAX_ATTEMPTS total attempts (default 3, clamped
16
16
  * 1..10; 1 disables retries). Matches the vendor SDKs' 1 + 2 retries.
17
- * - Retried: HTTP 408/409/425/429/500/502/503/504, and connection-level
17
+ * - Retried: HTTP 408/409/425/429/500/502/503/504/529 (Anthropic's
18
+ * "overloaded"), and connection-level
18
19
  * failures that say nothing about the request (ECONNRESET, ETIMEDOUT,
19
20
  * EPIPE, ECONNABORTED, EAI_AGAIN, undici socket/connect-timeout). Every
20
21
  * other 4xx is the request's own fault and is never repeated.
@@ -14,7 +14,8 @@
14
14
  * THE POLICY:
15
15
  * - Bounded: MODEL_RETRY_MAX_ATTEMPTS total attempts (default 3, clamped
16
16
  * 1..10; 1 disables retries). Matches the vendor SDKs' 1 + 2 retries.
17
- * - Retried: HTTP 408/409/425/429/500/502/503/504, and connection-level
17
+ * - Retried: HTTP 408/409/425/429/500/502/503/504/529 (Anthropic's
18
+ * "overloaded"), and connection-level
18
19
  * failures that say nothing about the request (ECONNRESET, ETIMEDOUT,
19
20
  * EPIPE, ECONNABORTED, EAI_AGAIN, undici socket/connect-timeout). Every
20
21
  * other 4xx is the request's own fault and is never repeated.
@@ -51,7 +52,7 @@
51
52
  * setLlmSpanAttribute).
52
53
  */
53
54
  export const RETRYABLE_STATUSES = new Set([
54
- 408, 409, 425, 429, 500, 502, 503, 504,
55
+ 408, 409, 425, 429, 500, 502, 503, 504, 529,
55
56
  ]);
56
57
  export const RETRYABLE_NETWORK_CODES = new Set([
57
58
  'ECONNRESET',