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
@@ -25,10 +25,31 @@
25
25
  * subagents, nested syndicates), an optional deadline bounds wall-clock
26
26
  * time, and an outer AbortSignal cancels it. All three abort the provider
27
27
  * request in flight, not just the loop around it.
28
+ *
29
+ * ── Runtimes (ADR 0045, ADR 0073) ─────────────────────────────────────────
30
+ * Each agent of a turn runs on ADK's Runner (the default) or on the
31
+ * engine's own agent loop: the turn's `runtime` option, else
32
+ * MELCHIZEDEK_RUNTIME. Both compile the same AgentSpec (lib/compile.ts),
33
+ * store the same events and drain through drainAgentStream, so everything
34
+ * else here is shared. What native does not run yet fails before any model
35
+ * call, naming the feature (lib/runtime/nativeTurn.ts).
28
36
  */
29
37
  import { InMemorySessionService, ReflectAndRetryModelPlugin, ReflectAndRetryToolPlugin, Runner, StreamingMode, getFunctionCalls, getFunctionResponses } from '@google/adk';
30
38
  import { DEFAULT_MAX_STEPS } from '../config.js';
31
- import { agentGates, compileGraph, compileSubagent } from '../compile.js';
39
+ import { agentGates, compileGraph, compileSpec, compileSubagent, compileSubagentSpec } from '../compile.js';
40
+ import { compileNative, nativeAdapterFor } from '../compileNative.js';
41
+ import { nativeMemory, refuseOnNative, runNativeAgent } from './nativeTurn.js';
42
+ import { asSessionService } from './adkSessionBridge.js';
43
+ import { resolveTools } from '../toolRegistry.js';
44
+ import { buildWorkflowGraph } from '../workflow/graph.js';
45
+ import { UnsupportedWorkflowResumeError } from '../workflow/resume.js';
46
+ import { refuseUnrunnableNodes, runNativeWorkflow } from '../workflow/turn.js';
47
+ import { SelfCorrection } from './native/selfCorrection.js';
48
+ import { UnsupportedOnRuntimeError, chooseRuntime } from './runtimeFlag.js';
49
+ import { pinnedCredentialStore } from '../tools/auth.js';
50
+ import { credentialResponsePart, describeConsent, pendingConsent } from './credentials.js';
51
+ export { CREDENTIAL_REQUEST, credentialResponsePart, describeConsent, pendingConsent } from './credentials.js';
52
+ export { chooseRuntime, runtimeSetting, DEFAULT_RUNTIME, RUNTIMES, UnsupportedOnRuntimeError } from './runtimeFlag.js';
32
53
  import { ROUTE_STEP_SUFFIX, compileWorkflow, describeInput, inputRequestFrom, isWorkflowSyndicate } from '../workflow.js';
33
54
  export { describeInput } from '../workflow.js';
34
55
  import { isDispatchSyndicate, matchRouteOverride, resolveRoute } from '../dispatch.js';
@@ -44,13 +65,14 @@ export { ASK_USER, pendingQuestion, questionAnswerPart } from './questions.js';
44
65
  export { approvalResponsePart, describeApproval, pendingApproval } from './approvals.js';
45
66
  import { RemoteA2AAgent, remoteContextId, remoteToolOutput } from '../a2a/remoteAgent.js';
46
67
  import { createTurnControl, runWithTurnControl, stopCode, stopMessage } from './turnControl.js';
68
+ import { DEFAULT_MODEL_ERROR_RETRIES, DEFAULT_TOOL_ERROR_RETRIES } from './native/selfCorrection.js';
47
69
  const THOUGHTS_PREVIEW_CHARS = 600;
48
70
  const CLASSIFIER_PREAMBLE = `RECENT CONVERSATION, oldest first — context for your classification only. `
49
71
  + `Never answer it, and never route on it alone; it is here so you can tell a `
50
72
  + `follow-up, a redo request, or a challenge to a previous answer apart from small talk.\n`;
51
73
  // ── Self-correction (ADR 0034) ───────────────────────────────────────────────
52
- export const DEFAULT_MODEL_ERROR_RETRIES = 2;
53
- export const DEFAULT_TOOL_ERROR_RETRIES = 3;
74
+ // The defaults live with the native loop's self-correction, so both runtimes read one pair.
75
+ export { DEFAULT_MODEL_ERROR_RETRIES, DEFAULT_TOOL_ERROR_RETRIES } from './native/selfCorrection.js';
54
76
  /**
55
77
  * ADK's reflect-and-retry plugins, on by default. The model plugin turns a
56
78
  * reply ADK marks malformed (MALFORMED_FUNCTION_CALL) into a retry with
@@ -263,6 +285,7 @@ export async function runSyndicateTurn(opts) {
263
285
  // the framework's adapters registered there, Gemini would be ADK's own
264
286
  // class, which bypasses traceLlmGeneration: no max_steps, no cancel. A
265
287
  // caller that resolves models itself (the A2A server) is left alone.
288
+ const runtime = chooseRuntime(opts.runtime);
266
289
  if (!opts.compile?.resolveModel)
267
290
  registerAvailableProviders();
268
291
  const control = createTurnControl({
@@ -271,13 +294,34 @@ export async function runSyndicateTurn(opts) {
271
294
  signal: opts.signal,
272
295
  });
273
296
  try {
274
- return await runWithTurnControl(control, () => runTurnInner(opts, control));
297
+ return await runWithTurnControl(control, () => runTurnInner(opts, control, runtime));
275
298
  }
276
299
  finally {
277
300
  control.dispose();
278
301
  }
279
302
  }
280
- async function runTurnInner(opts, control) {
303
+ /**
304
+ * A workflow syndicate for the native runtime: its graph, every agent
305
+ * compiled for native from the same specs ADK's compileWorkflow builds its
306
+ * agents from, one adapter lookup that knows every agent's models, and the
307
+ * registry's lookup for tool nodes. A tool node ADK's compile refuses (an
308
+ * unregistered or long-running tool) is refused here, before any model
309
+ * call, with ADK's message.
310
+ */
311
+ async function compileNativeWorkflow(config, opts) {
312
+ const graph = buildWorkflowGraph(config);
313
+ const specs = [];
314
+ const agents = new Map();
315
+ for (const sub of [{ description: '', ...config.orchestrator }, ...(config.subagents ?? [])]) {
316
+ const spec = await compileSubagentSpec(sub, opts);
317
+ specs.push(spec);
318
+ agents.set(sub.name, compileNative(spec));
319
+ }
320
+ const resolveTool = (name) => resolveTools([name], opts.onUnknownTool)[0];
321
+ refuseUnrunnableNodes(graph, resolveTool);
322
+ return { runtime: 'native-workflow', graph, agents, adapterFor: nativeAdapterFor(opts, specs), resolveTool };
323
+ }
324
+ async function runTurnInner(opts, control, runtime) {
281
325
  const { config, appName, userId, sessionId, sessionService } = opts;
282
326
  const ev = opts.events ?? {};
283
327
  // Nested references load from the definition's bundle when it has one
@@ -288,6 +332,17 @@ async function runTurnInner(opts, control) {
288
332
  const trace = opts.trace === false ? undefined : opts.trace ?? {};
289
333
  let parts = opts.parts.map((p) => (typeof p === 'string' ? { text: p } : p));
290
334
  const messageText = parts.map((p) => (typeof p.text === 'string' ? p.text : '')).join('\n');
335
+ const native = runtime === 'native';
336
+ // What native does not run yet fails here, before the session is touched.
337
+ if (native)
338
+ refuseOnNative(config, { isWorkflow: isWorkflowSyndicate(config), transformAgent: opts.transformAgent });
339
+ const nativeOf = (spec) => ({ runtime: 'native', agent: compileNative(spec), adapterFor: nativeAdapterFor(compileOpts, spec) });
340
+ /** The orchestrator (a DELEGATE root, or a dispatch classifier) for the turn's runtime. */
341
+ const compileRoot = async () => native ? nativeOf(await compileSpec(config, compileOpts)) : { runtime: 'adk', agent: transform(await compileGraph(config, compileOpts)) };
342
+ /** A dispatch route for the turn's runtime. */
343
+ const compileRoute = async (routeCfg) => native ? nativeOf(await compileSubagentSpec(routeCfg, compileOpts)) : { runtime: 'adk', agent: transform(await compileSubagent(routeCfg, compileOpts)) };
344
+ // Native self-correction (ADR 0075): one per turn, from the YAML's retries:, as the ADK path installs retryPlugins.
345
+ const selfCorrection = native ? new SelfCorrection(config.retries) : undefined;
291
346
  const result = {
292
347
  status: 'completed',
293
348
  text: '',
@@ -338,12 +393,54 @@ async function runTurnInner(opts, control) {
338
393
  // The log names the call, not its arguments: they are user content.
339
394
  ev.log?.(`✓ Approval ${decision.approved ? 'granted' : 'refused'}: ${resuming.agent} → ${resuming.tool}`);
340
395
  }
396
+ // ── Consent (lib/runtime/credentials.ts, ADR 0085) ────────────────────────
397
+ // While a call waits for an OAuth grant, the next message resumes it once
398
+ // the callback has stored the grant; until then it repeats the request and
399
+ // runs nothing. Only the native loop resumes it: ADK's auth preprocessor
400
+ // would exchange a code carried in the message, which this engine never
401
+ // puts there.
402
+ const credentialStore = opts.toolCredentials ? pinnedCredentialStore(opts.toolCredentials.store, appName) : undefined;
403
+ const consentPause = (pending) => {
404
+ result.status = 'input-required';
405
+ result.consent = pending;
406
+ result.text = `Authorization needed: ${describeConsent(pending)}. Open the authorization link, then send any message to continue.`;
407
+ ev.log?.(`⏸ Authorization needed: ${pending.agent} → ${pending.provider}`);
408
+ return finish();
409
+ };
410
+ let granting;
411
+ if (!decision && !isWorkflowSyndicate(config)) {
412
+ const open = pendingConsent(existing?.events ?? []);
413
+ if (open) {
414
+ if (!native) {
415
+ throw new UnsupportedOnRuntimeError('resuming an OAuth consent (adk_request_credential)', 'adk', config.syndicate_name || open.agent || 'syndicate');
416
+ }
417
+ if (!credentialStore) {
418
+ result.status = 'failed';
419
+ result.error = { code: 'CONSENT_UNAVAILABLE', message: `A call waits for a ${open.provider} authorization, but this turn has no credential store.` };
420
+ return finish();
421
+ }
422
+ let granted = false;
423
+ try {
424
+ granted = !!open.provider && !!(await credentialStore.get({ appName, userId, provider: open.provider }));
425
+ }
426
+ catch {
427
+ // Expired or unreadable: not granted. The request stands.
428
+ }
429
+ if (!granted)
430
+ return consentPause(open);
431
+ granting = open;
432
+ parts = [credentialResponsePart(open.id, open.provider)];
433
+ ev.log?.(`✓ Authorization granted: ${open.agent} → ${open.provider}`);
434
+ }
435
+ }
341
436
  // ── Questions (lib/runtime/questions.ts) ───────────────────────────────────
342
437
  // While an agent's `ask_user` call is open, a plain-text message is its
343
438
  // answer: it becomes that call's response, and the agent that asked
344
- // resumes its own tool loop. A workflow's pauses are ADK's own business.
439
+ // resumes its own tool loop, on either runtime (the native loop reads the
440
+ // response from its history, as ADK's content processor does; ADR 0079).
441
+ // A workflow's pauses are ADK's own business.
345
442
  let answering;
346
- if (!decision && !isWorkflowSyndicate(config)) {
443
+ if (!decision && !granting && !isWorkflowSyndicate(config)) {
347
444
  const question = pendingQuestion(existing?.events ?? []);
348
445
  const plainText = parts.length > 0 && parts.every((p) => typeof p.text === 'string');
349
446
  if (question && plainText) {
@@ -353,7 +450,21 @@ async function runTurnInner(opts, control) {
353
450
  }
354
451
  }
355
452
  /** The agent a dispatch turn must resume, and the call its interrupted turn holds. */
356
- const resumeTarget = resuming ? { agent: resuming.agent, id: resuming.id, why: 'resuming an approval' } : answering ? { ...answering, why: 'answering its question' } : undefined;
453
+ const resumeTarget = resuming
454
+ ? { agent: resuming.agent, id: resuming.id, why: 'resuming an approval' }
455
+ : granting
456
+ ? { agent: granting.agent, id: granting.id, why: 'resuming after an authorization' }
457
+ : answering
458
+ ? { ...answering, why: 'answering its question' }
459
+ : undefined;
460
+ /** After the answering run: is a call now waiting for a grant? */
461
+ const awaitingConsent = async (agentName) => {
462
+ if (!opts.toolCredentials?.consent || !native)
463
+ return undefined;
464
+ const after = await sessionService.getSession({ appName, userId, sessionId });
465
+ const pending = pendingConsent(after?.events ?? []);
466
+ return pending && pending.agent === agentName ? pending : undefined;
467
+ };
357
468
  /** After the answering run: is a gated call now waiting? */
358
469
  const awaitingApproval = async (agentName) => {
359
470
  const after = await sessionService.getSession({ appName, userId, sessionId });
@@ -380,20 +491,64 @@ async function runTurnInner(opts, control) {
380
491
  };
381
492
  /** Run ONE agent against ONE session, under the turn's controls. */
382
493
  const runAgent = async (params) => {
383
- const runner = new Runner({
384
- agent: params.agent,
385
- appName,
386
- sessionService: params.sessions,
387
- plugins: retryPlugins(config.retries),
388
- ...(opts.memoryService ? { memoryService: opts.memoryService } : {}),
389
- });
390
- let stream = runner.runAsync({
391
- userId,
392
- sessionId: params.sid,
393
- newMessage: { role: 'user', parts: params.userParts },
394
- abortSignal: control.signal,
395
- ...(opts.streaming ? { runConfig: { streamingMode: StreamingMode.SSE } } : {}),
396
- });
494
+ let stream;
495
+ if (params.agent.runtime === 'native-workflow') {
496
+ // The engine's scheduler walks the graph (lib/workflow/turn.ts): the same events, the same drain.
497
+ stream = runNativeWorkflow({
498
+ graph: params.agent.graph,
499
+ agents: params.agent.agents,
500
+ adapterFor: params.agent.adapterFor,
501
+ resolveTool: params.agent.resolveTool,
502
+ sessions: asSessionService(params.sessions),
503
+ appName,
504
+ userId,
505
+ sessionId: params.sid,
506
+ userParts: params.userParts,
507
+ signal: control.signal,
508
+ stream: opts.streaming === true,
509
+ memory: nativeMemory(opts.memoryService),
510
+ ...(selfCorrection ? { selfCorrection } : {}),
511
+ ...(credentialStore ? { credentials: credentialStore } : {}),
512
+ ...(compileOpts.log ? { log: compileOpts.log } : {}),
513
+ });
514
+ }
515
+ else if (params.agent.runtime === 'native') {
516
+ // The engine's own loop (lib/runtime/nativeTurn.ts): the same events, the same drain.
517
+ stream = runNativeAgent({
518
+ agent: params.agent.agent,
519
+ adapterFor: params.agent.adapterFor,
520
+ sessions: params.sessions,
521
+ appName,
522
+ userId,
523
+ sessionId: params.sid,
524
+ userParts: params.userParts,
525
+ signal: control.signal,
526
+ stream: opts.streaming === true,
527
+ memory: nativeMemory(opts.memoryService),
528
+ ...(selfCorrection ? { selfCorrection } : {}),
529
+ // Tool credentials and the consent step (ADR 0072, ADR 0085); the classifier's lane lists no tools.
530
+ ...(credentialStore ? { credentials: credentialStore } : {}),
531
+ ...(opts.toolCredentials?.consent && params.stage !== 'classify' ? { consent: opts.toolCredentials.consent } : {}),
532
+ // The fallback's notice goes where compile's FallbackLlm sends it on ADK.
533
+ ...(compileOpts.log ? { log: compileOpts.log } : {}),
534
+ });
535
+ }
536
+ else {
537
+ const runner = new Runner({
538
+ agent: params.agent.agent,
539
+ appName,
540
+ sessionService: params.sessions,
541
+ plugins: retryPlugins(config.retries),
542
+ ...(opts.memoryService ? { memoryService: opts.memoryService } : {}),
543
+ });
544
+ stream = runner.runAsync({
545
+ userId,
546
+ sessionId: params.sid,
547
+ newMessage: { role: 'user', parts: params.userParts },
548
+ abortSignal: control.signal,
549
+ ...(opts.streaming ? { runConfig: { streamingMode: StreamingMode.SSE } } : {}),
550
+ });
551
+ }
397
552
  if (trace) {
398
553
  stream = traceAgentRun(stream, {
399
554
  syndicateName: trace.syndicateName ?? config.syndicate_name ?? appName,
@@ -450,7 +605,7 @@ async function runTurnInner(opts, control) {
450
605
  throw new Error(`Call ${resumeTarget.id} was raised by '${resumeTarget.agent}', which is not a route of this syndicate.`);
451
606
  }
452
607
  resolution = { route: resumeTarget.agent, reason: resumeTarget.why, fellBack: false, fallbackReason: '', viaOverride: false };
453
- decidedBy = resuming ? 'approval' : 'answer';
608
+ decidedBy = resuming ? 'approval' : granting ? 'consent' : 'answer';
454
609
  }
455
610
  else if (resolution) {
456
611
  ev.log?.(`⇄ Route pinned by override: ${resolution.route}`);
@@ -467,7 +622,7 @@ async function runTurnInner(opts, control) {
467
622
  // The classifier reads the SHARED transcript as an input digest and runs
468
623
  // in a throwaway in-memory lane, so its JSON verdicts never enter the
469
624
  // conversation the next specialist reads.
470
- const routerAgent = transform(await compileGraph(config, compileOpts));
625
+ const routerAgent = await compileRoot();
471
626
  const routerSid = `${sessionId}::route`;
472
627
  const routerSessions = new InMemorySessionService();
473
628
  await routerSessions.createSession({ appName, userId, sessionId: routerSid });
@@ -514,7 +669,7 @@ async function runTurnInner(opts, control) {
514
669
  // The route answers directly in the SHARED session, read through a
515
670
  // projection: ADK would otherwise render other agents' turns as user
516
671
  // speech mixed with their tool payloads (lib/session/transcript.ts).
517
- const routeAgent = transform(await compileSubagent(routeCfg, compileOpts));
672
+ const routeAgent = await compileRoute(routeCfg);
518
673
  answer = await runAgent({
519
674
  agent: routeAgent,
520
675
  sid: sessionId,
@@ -525,7 +680,9 @@ async function runTurnInner(opts, control) {
525
680
  ? { rawFrom: (events) => interruptedTurnStart(events, resuming.id) }
526
681
  : answering
527
682
  ? { rawFrom: (events) => turnStartOfCall(events, answering.id) }
528
- : {}),
683
+ : granting
684
+ ? { rawFrom: (events) => turnStartOfCall(events, granting.id) }
685
+ : {}),
529
686
  stage: 'dispatch',
530
687
  route: resolution,
531
688
  publishToolStatus: true,
@@ -543,6 +700,11 @@ async function runTurnInner(opts, control) {
543
700
  if (pending)
544
701
  return pause(pending);
545
702
  }
703
+ if (!routeCfg.a2a_agent_url) {
704
+ const consent = await awaitingConsent(routeCfg.name);
705
+ if (consent)
706
+ return consentPause(consent);
707
+ }
546
708
  const askedRoute = asked(answer);
547
709
  if (askedRoute)
548
710
  return askedRoute;
@@ -558,14 +720,18 @@ async function runTurnInner(opts, control) {
558
720
  else if (isWorkflowSyndicate(config)) {
559
721
  // ══ WORKFLOW ═════════════════════════════════════════════════════════
560
722
  // The syndicate is a graph (lib/workflow.ts): every agent a node, run
561
- // by ADK's Workflow in the shared session. A node agent sees only its
562
- // input unless its YAML says otherwise, so no projection is needed. An
723
+ // in the shared session by ADK's Workflow, or on native by the engine's
724
+ // scheduler (lib/workflow/turn.ts, ADR 0095); both store the same events
725
+ // and drain through the same reader. A node agent sees only its input
726
+ // unless its YAML says otherwise, so no projection is needed. An
563
727
  // `ask_user` node ends the turn input-required; the next message
564
728
  // resumes the graph where it waited.
565
- const compiled = await compileWorkflow(config, compileOpts, transform);
729
+ const workflowAgent = native
730
+ ? await compileNativeWorkflow(config, compileOpts)
731
+ : { runtime: 'adk', agent: (await compileWorkflow(config, compileOpts, transform)).workflow };
566
732
  try {
567
733
  answer = await runAgent({
568
- agent: compiled.workflow,
734
+ agent: workflowAgent,
569
735
  sid: sessionId,
570
736
  userParts: parts,
571
737
  sessions: sessionService,
@@ -582,7 +748,8 @@ async function runTurnInner(opts, control) {
582
748
  throw err;
583
749
  result.status = 'failed';
584
750
  result.failedStage = 'workflow';
585
- result.error = { code: 'NODE_FAILED', message: last.message };
751
+ // A pause only ADK can resume fails the turn on native rather than walking afresh (ADR 0094, ADR 0095).
752
+ result.error = { code: last instanceof UnsupportedWorkflowResumeError ? 'RESUME_UNSUPPORTED' : 'NODE_FAILED', message: last.message };
586
753
  return finish();
587
754
  }
588
755
  result.answer = answer;
@@ -612,7 +779,7 @@ async function runTurnInner(opts, control) {
612
779
  else {
613
780
  // ══ DELEGATE ═════════════════════════════════════════════════════════
614
781
  // Subagents are AgentTools; the orchestrator relays the answer it got.
615
- const orchestrator = transform(await compileGraph(config, compileOpts));
782
+ const orchestrator = await compileRoot();
616
783
  let drained;
617
784
  answer = await runAgent({
618
785
  agent: orchestrator,
@@ -636,6 +803,9 @@ async function runTurnInner(opts, control) {
636
803
  if (pending)
637
804
  return pause(pending);
638
805
  }
806
+ const consent = await awaitingConsent(config.orchestrator.name);
807
+ if (consent)
808
+ return consentPause(consent);
639
809
  const askedOrchestrator = asked(answer);
640
810
  if (askedOrchestrator)
641
811
  return askedOrchestrator;
@@ -1,26 +1,73 @@
1
+ /**
2
+ * lib/session/supabaseSessionService.ts — sessions through supabase-js
3
+ * (the REST path ADR 0021 keeps for a transition period), for either
4
+ * runtime (ADR 0052, ADR 0058).
5
+ *
6
+ * One row per conversation in adk_sessions, its events as one JSON array
7
+ * that every append rewrites whole (the Postgres adapter keeps a row per
8
+ * event instead, lib/storage/postgres/sessionService.ts). Each event in the
9
+ * row is passed through trimEventForStorage (lib/session/transcript.ts).
10
+ *
11
+ * TWO FACES, ONE STORE:
12
+ * The class is the engine's SessionService (create, get, list, delete,
13
+ * append) and ADK's BaseSessionService (createSession, getSession, …), so
14
+ * the ADK runtime and the native one read and write the same rows. The ADK
15
+ * methods call the engine's, except appendEvent, which applies the event
16
+ * to the runner's session through ADK's base service (its write-order
17
+ * check included), where append uses applyEvent. Both write the row the
18
+ * same way. The rules are lib/runtime/sessions.ts's:
19
+ * - a create of an existing id returns the conversation unchanged, where
20
+ * an upsert would reset it to no events;
21
+ * - a list without a user id lists every user's sessions of the app, as
22
+ * the Postgres adapter and ADK's own stores do;
23
+ * - `afterTimestamp` is strict and filters before `numRecentEvents`
24
+ * counts (selectEvents);
25
+ * - lastUpdateTime is the appended event's timestamp, which is the clock
26
+ * of the process that made the event, just before the append.
27
+ */
1
28
  import { BaseSessionService } from '@google/adk';
2
- import type { CreateSessionRequest, GetSessionRequest, ListSessionsRequest, ListSessionsResponse, DeleteSessionRequest, Session, Event } from '@google/adk';
29
+ import type { CreateSessionRequest as AdkCreateSessionRequest, DeleteSessionRequest as AdkDeleteSessionRequest, Event as AdkEvent, GetSessionRequest as AdkGetSessionRequest, ListSessionsRequest as AdkListSessionsRequest, ListSessionsResponse as AdkListSessionsResponse, Session as AdkSession } from '@google/adk';
3
30
  import type { SupabaseClient } from '@supabase/supabase-js';
4
- export declare class SupabaseSessionService extends BaseSessionService {
31
+ import type { TurnEvent } from '../runtime/events.ts';
32
+ import type { CreateSessionRequest, GetSessionOptions, ListSessionsRequest, ListSessionsResult, Session, SessionKey, SessionService } from '../runtime/sessions.ts';
33
+ export declare class SupabaseSessionService extends BaseSessionService implements SessionService {
5
34
  private supabase;
6
35
  constructor(supabaseClient: SupabaseClient);
7
36
  private getDbId;
8
- createSession(request: CreateSessionRequest): Promise<Session>;
9
- getSession(request: GetSessionRequest): Promise<Session | undefined>;
37
+ private expireAt;
38
+ create(request: CreateSessionRequest): Promise<Session>;
39
+ get(key: SessionKey, options?: GetSessionOptions): Promise<Session | undefined>;
10
40
  /**
11
- * ADK's ListSessions contract carries paging: `limit` with either `page`
12
- * (1-based, wins) or `offset` (0-based), plus an optional sort by last
13
- * update, and the response must report where in the set the caller is.
14
- * The window is pushed down to Postgres via .range(), and `count:
15
- * 'exact'` returns the TOTAL matching rows alongside the page — so
16
- * totalItems is the real total, not the slice length. With no `limit`,
17
- * the whole set is one page, which is what the ADK's own docs specify
18
- * ("Page size used. Equals `totalItems` when no limit was requested").
41
+ * Paging as listWindow and listPage state it. The window is pushed down
42
+ * to Postgres via .range(), and `count: 'exact'` returns the TOTAL
43
+ * matching rows alongside the page, so totalItems is the real total, not
44
+ * the slice length. Every user's sessions when `userId` is absent. By
45
+ * last update, ties by id, when an order is asked for; in the order the
46
+ * rows were created otherwise, so a page never depends on how Postgres
47
+ * happens to scan.
19
48
  */
20
- listSessions(request: ListSessionsRequest): Promise<ListSessionsResponse>;
21
- deleteSession(request: DeleteSessionRequest): Promise<void>;
49
+ list(request: ListSessionsRequest): Promise<ListSessionsResult>;
50
+ delete(key: SessionKey): Promise<void>;
51
+ append(session: Session, event: TurnEvent): Promise<TurnEvent>;
52
+ /**
53
+ * The caller's session, as it stands after the event, becomes the row.
54
+ *
55
+ * Trim on the SERIALIZED COPY only. The live session keeps thought
56
+ * signatures and real tool payloads — the agent's own tool loop reads
57
+ * them back mid-turn — but nothing reads them from the ROW: the
58
+ * projection drops both on the way into a prompt, and the memory service
59
+ * walks `part.text` alone. Across 128 live sessions they were ~90% of
60
+ * every byte stored (73% of it Gemini's `thoughtSignature`), and this
61
+ * re-uploads the whole array on every event, so those bytes were paid for
62
+ * again on each one. See trimEventForStorage.
63
+ */
64
+ private write;
65
+ createSession(request: AdkCreateSessionRequest): Promise<AdkSession>;
66
+ getSession(request: AdkGetSessionRequest): Promise<AdkSession | undefined>;
67
+ listSessions(request: AdkListSessionsRequest): Promise<AdkListSessionsResponse>;
68
+ deleteSession(request: AdkDeleteSessionRequest): Promise<void>;
22
69
  appendEvent(request: {
23
- session: Session;
24
- event: Event;
25
- }): Promise<Event>;
70
+ session: AdkSession;
71
+ event: AdkEvent;
72
+ }): Promise<AdkEvent>;
26
73
  }