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
@@ -31,7 +31,7 @@
31
31
  * private one, so any public slice of this graph is closed by
32
32
  * construction.
33
33
  */
34
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
34
+ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
35
35
  import { dirname, join } from 'node:path';
36
36
  import { z } from 'zod';
37
37
  import { isPrivatePath } from './format.js';
@@ -604,11 +604,53 @@ export function relationEdges(records) {
604
604
  ...(r.at ? { at: r.at } : {}),
605
605
  }));
606
606
  }
607
+ /**
608
+ * Replace the whole store with `records`, in the order given. The store's
609
+ * order is the order of assertion; nothing sorts it.
610
+ */
607
611
  export function saveRelations(wikiRoot, records) {
608
612
  const file = relationsPath(wikiRoot);
609
613
  mkdirSync(dirname(file), { recursive: true });
610
- const sorted = [...records].sort((a, b) => a.from.localeCompare(b.from) || a.rel.localeCompare(b.rel) || a.to.localeCompare(b.to));
611
- writeFileSync(file, `${JSON.stringify({ version: 1, relations: sorted }, null, 2)}\n`, 'utf-8');
614
+ writeFileSync(file, `${JSON.stringify({ version: 1, relations: records }, null, 2)}\n`, 'utf-8');
615
+ }
616
+ /**
617
+ * Add one assertion at the end of the store. Every record already there
618
+ * keeps its place and its bytes, so two branches that each assert something
619
+ * merge by keeping both sides. Returns false, writing nothing, when the edge
620
+ * is already asserted. Throws when the store does not parse rather than
621
+ * write over it.
622
+ */
623
+ export function appendRelation(wikiRoot, record) {
624
+ const next = relationRecordSchema.parse(record);
625
+ const file = relationsPath(wikiRoot);
626
+ let store = { version: 1, relations: [] };
627
+ // Read once, with no existence check first: a check and then a read can
628
+ // see two different files (CodeQL js/file-system-race).
629
+ let text;
630
+ try {
631
+ text = readFileSync(file, 'utf-8');
632
+ }
633
+ catch (err) {
634
+ if (err.code !== 'ENOENT')
635
+ throw err;
636
+ }
637
+ if (text !== undefined) {
638
+ const raw = JSON.parse(text);
639
+ const parsed = relationStoreSchema.safeParse(raw);
640
+ if (!parsed.success)
641
+ throw new Error(`relations.json is not a relation store: ${parsed.error.issues[0]?.message ?? 'invalid'}`);
642
+ store = raw;
643
+ store.relations ??= [];
644
+ if (parsed.data.relations.some((r) => edgeKey(r) === edgeKey(next)))
645
+ return false;
646
+ }
647
+ store.relations.push(next);
648
+ mkdirSync(dirname(file), { recursive: true });
649
+ // Replace the store in one step, so a reader never sees half a file.
650
+ const tmp = `${file}.${process.pid}.tmp`;
651
+ writeFileSync(tmp, `${JSON.stringify(store, null, 2)}\n`, 'utf-8');
652
+ renameSync(tmp, file);
653
+ return true;
612
654
  }
613
655
  export function writeSnapshot(wikiRoot, graph, generated) {
614
656
  const file = snapshotPath(wikiRoot);
@@ -0,0 +1,136 @@
1
+ /**
2
+ * lib/workflow/agentNode.ts — an agent as a workflow node on the native
3
+ * runtime, as ADK 2.2 runs an LlmAgent node (ADR 0030, ADR 0090).
4
+ *
5
+ * ADK runs an agent node through `runLlmAgentAsNode`
6
+ * (workflow/run_llm_agent_as_node.js) inside its node runner
7
+ * (workflow/node_runner.js). This module is the same run on the native
8
+ * agent loop (lib/runtime/native/agentLoop.ts), rule for rule:
9
+ *
10
+ * 1. THE INPUT IS THE USER TURN. The previous node's output is stored as a
11
+ * user event on the node's branch before the agent runs: a Content as
12
+ * it is (role `user`), a string as one text part, anything else as its
13
+ * JSON. An undefined or null input stores nothing. The event carries no
14
+ * node path, as ADK appends it straight to the session.
15
+ * 2. THE includeContents RULE. An agent whose YAML does not set
16
+ * `includeContents` runs with `none`: it sees the current turn, which
17
+ * is its input, and nothing else of the session. One that sets it keeps
18
+ * what it set. ADK sets this on the agent itself; here the node runs a
19
+ * copy, so the compiled agent is unchanged.
20
+ * 3. TASK MODE. A `mode: task` agent gets no user turn and keeps its
21
+ * includeContents; the loop runs it as a task node (`taskNode`), which
22
+ * ends on finish_task's successful answer and writes the output on that
23
+ * event (lib/runtime/native/taskMode.ts, ADR 0081).
24
+ * 4. THE OUTPUT. Outside task mode, each stored model event with content
25
+ * and no function call carries the node's output: its text (thought
26
+ * parts left out), or, with an output schema, the text parsed as JSON
27
+ * when it parses; and `nodeInfo.messageAsOutput` (ADK's maybeSetOutput).
28
+ * The node's output is the last output an event carried.
29
+ * 5. THE STAMP. Every event the loop stores gets `nodeInfo.path` (the
30
+ * node's path, `<workflow>.<node>`, or `<workflow>.<map>.<agent>@<i>`
31
+ * for a map item), `nodeInfo.outputFor` on an event with an output,
32
+ * and the node's branch when it has none (ADK's enrichEvent, the one
33
+ * port in lib/workflow/toolNode.ts, enrichNodeEvent). The loop
34
+ * calls the stamp before it stores each event (`nodeStamp`), after the
35
+ * outputKey and task hooks, the order ADK applies them in.
36
+ * 6. THE INSTRUCTION SCOPE. The run carries ADK's workflow instruction
37
+ * scope (`workflowScope`): the node's input, and the output every event
38
+ * of the invocation stored before the node ran, by node name
39
+ * (predecessorOutputs, ADK's collectPredecessorOutputs). The request
40
+ * fills `{x.field}` and `<x.field from Node>` from it
41
+ * (lib/runtime/native/request.ts, injectSessionState).
42
+ * 7. FAILURE. An event carrying an error code is the node's reported
43
+ * error; a run that ends with one and no output returns it as the
44
+ * run's `error`, and the scheduler fails the attempt with
45
+ * NodeReportedError, ADK's message, retried or stopping the walk as
46
+ * ADK's does, and reported once (by the node's own event). A run the turn stopped throws. A run that pauses on a person
47
+ * (an ask_user tool, an approval) is an interrupt, not run here yet.
48
+ *
49
+ * `agentNodeRuntime` puts it together for the scheduler: a `runNode` for
50
+ * agent nodes and map items, and an `onEvent` that stores the event ADK
51
+ * stores for each route step (lib/workflow/route.ts), join and map
52
+ * (lib/workflow/nodeEvents.ts), so a session the native walk writes holds
53
+ * what ADK's holds, in the same order.
54
+ *
55
+ * NOT HERE: interrupts inside a node (an ask_user tool call, an approval),
56
+ * tool nodes (lib/workflow/toolNode.ts) and ask_user nodes
57
+ * (lib/workflow/pause.ts). It imports nothing from ADK.
58
+ */
59
+ import type { TurnContent, TurnEvent } from '../runtime/events.ts';
60
+ import type { AgentLoopContext } from '../runtime/native/agentLoop.ts';
61
+ import type { NativeAgent } from '../runtime/native/request.ts';
62
+ import type { Session, SessionService } from '../runtime/sessions.ts';
63
+ import type { NodeResult, NodeRun, NodeRunner, SchedulerEvent } from './scheduler.ts';
64
+ /** A node whose run ended on an error event and produced no output: the scheduler's, which fails the attempt (rule 7). */
65
+ export { NodeReportedError } from './scheduler.ts';
66
+ /** A node run the turn stopped (cancel, deadline, max_steps): the stop's code and message. */
67
+ export declare class NodeStoppedError extends Error {
68
+ readonly code: string;
69
+ readonly nodeName: string;
70
+ constructor(nodeName: string, stop: {
71
+ code: string;
72
+ message: string;
73
+ } | undefined);
74
+ }
75
+ /** The user turn a node input becomes (ADK's toUserContent). */
76
+ export declare function nodeInputContent(input: unknown): TurnContent;
77
+ /** The agent a node runs: outside task mode, `includeContents: none` unless the agent set it. A copy; the compiled agent is unchanged. */
78
+ export declare function asNodeAgent(agent: NativeAgent): NativeAgent;
79
+ /** ADK's maybeSetOutput: the output a stored model event carries outside task mode, or undefined when it carries none. */
80
+ export declare function eventOutput(agent: Pick<NativeAgent, 'outputSchema'>, event: TurnEvent): unknown;
81
+ /** The loop options a node run takes from its caller; the node sets the rest. */
82
+ export type AgentNodeLoopOptions = Omit<AgentLoopContext, 'session' | 'sessions' | 'invocationId' | 'userContent' | 'branch' | 'signal' | 'taskNode' | 'nodeStamp' | 'workflowScope'>;
83
+ export interface AgentNodeContext {
84
+ session: Session;
85
+ sessions: SessionService;
86
+ /** The workflow run's invocation id: every event of every node carries it. */
87
+ invocationId: string;
88
+ /** The message that started the turn (the invocation's user content). */
89
+ userContent?: TurnContent;
90
+ /** Loop options for every node: adapters, self-correction, memory, streaming. */
91
+ loop?: AgentNodeLoopOptions;
92
+ /** Each event as it is stored, in order. */
93
+ onEvent?: (event: TurnEvent) => void;
94
+ /** Each partial (streamed, never stored) event the node's loop yields, as it yields it. */
95
+ onPartial?: (event: TurnEvent) => void;
96
+ /** Stores the node's user turn; default `sessions.append`. agentNodeRuntime passes its queue. Called synchronously, before the run's first await. */
97
+ appendInput?: (event: TurnEvent) => Promise<TurnEvent>;
98
+ }
99
+ /**
100
+ * Runs `agent` as the node `run` names, on the native loop, and resolves
101
+ * with the node's output, or with the error it reported when it ended on
102
+ * one with no output. Throws NodeStoppedError when the turn stopped it, and
103
+ * an Error when it paused on a person.
104
+ */
105
+ export declare function runAgentNode(agent: NativeAgent, run: Pick<NodeRun, 'input' | 'path' | 'branch' | 'signal'>, ctx: AgentNodeContext): Promise<NodeResult>;
106
+ export interface AgentNodeRuntimeOptions extends Omit<AgentNodeContext, 'appendInput'> {
107
+ /** Every agent of the syndicate, compiled for native, by YAML name. */
108
+ agents: ReadonlyMap<string, NativeAgent>;
109
+ /**
110
+ * Runs every run that is not an agent node or a map item (tool, ask_user),
111
+ * as toolNodeRunner(context, next) hands on what it does not run, so the
112
+ * runners chain. Default: refuses them by name.
113
+ */
114
+ next?: NodeRunner;
115
+ }
116
+ export interface AgentNodeRuntime {
117
+ /** The scheduler's runNode: agent nodes and map items run here; every other run goes to `next`. */
118
+ runNode: NodeRunner;
119
+ /** The scheduler's onEvent: stores the event ADK stores for each route step, join and map. */
120
+ onEvent: (event: SchedulerEvent) => void;
121
+ /**
122
+ * Stores an event another runner of the chain made (a tool node's, through
123
+ * its context's onEvent) on the same queue, in walk order, and hands it to
124
+ * the `onEvent` option once stored.
125
+ */
126
+ store(event: TurnEvent): Promise<TurnEvent>;
127
+ /** Resolves once every event queued for storage is stored; rejects with the first store error. */
128
+ settled(): Promise<void>;
129
+ }
130
+ /**
131
+ * The scheduler's node runner for a syndicate's agents, and the store for
132
+ * its route steps' events. Node user turns and route events are stored in
133
+ * the order the walk reaches them, through one queue, so a route step's
134
+ * event lands before its successor's input as on ADK.
135
+ */
136
+ export declare function agentNodeRuntime(options: AgentNodeRuntimeOptions): AgentNodeRuntime;
@@ -0,0 +1,274 @@
1
+ /**
2
+ * lib/workflow/agentNode.ts — an agent as a workflow node on the native
3
+ * runtime, as ADK 2.2 runs an LlmAgent node (ADR 0030, ADR 0090).
4
+ *
5
+ * ADK runs an agent node through `runLlmAgentAsNode`
6
+ * (workflow/run_llm_agent_as_node.js) inside its node runner
7
+ * (workflow/node_runner.js). This module is the same run on the native
8
+ * agent loop (lib/runtime/native/agentLoop.ts), rule for rule:
9
+ *
10
+ * 1. THE INPUT IS THE USER TURN. The previous node's output is stored as a
11
+ * user event on the node's branch before the agent runs: a Content as
12
+ * it is (role `user`), a string as one text part, anything else as its
13
+ * JSON. An undefined or null input stores nothing. The event carries no
14
+ * node path, as ADK appends it straight to the session.
15
+ * 2. THE includeContents RULE. An agent whose YAML does not set
16
+ * `includeContents` runs with `none`: it sees the current turn, which
17
+ * is its input, and nothing else of the session. One that sets it keeps
18
+ * what it set. ADK sets this on the agent itself; here the node runs a
19
+ * copy, so the compiled agent is unchanged.
20
+ * 3. TASK MODE. A `mode: task` agent gets no user turn and keeps its
21
+ * includeContents; the loop runs it as a task node (`taskNode`), which
22
+ * ends on finish_task's successful answer and writes the output on that
23
+ * event (lib/runtime/native/taskMode.ts, ADR 0081).
24
+ * 4. THE OUTPUT. Outside task mode, each stored model event with content
25
+ * and no function call carries the node's output: its text (thought
26
+ * parts left out), or, with an output schema, the text parsed as JSON
27
+ * when it parses; and `nodeInfo.messageAsOutput` (ADK's maybeSetOutput).
28
+ * The node's output is the last output an event carried.
29
+ * 5. THE STAMP. Every event the loop stores gets `nodeInfo.path` (the
30
+ * node's path, `<workflow>.<node>`, or `<workflow>.<map>.<agent>@<i>`
31
+ * for a map item), `nodeInfo.outputFor` on an event with an output,
32
+ * and the node's branch when it has none (ADK's enrichEvent, the one
33
+ * port in lib/workflow/toolNode.ts, enrichNodeEvent). The loop
34
+ * calls the stamp before it stores each event (`nodeStamp`), after the
35
+ * outputKey and task hooks, the order ADK applies them in.
36
+ * 6. THE INSTRUCTION SCOPE. The run carries ADK's workflow instruction
37
+ * scope (`workflowScope`): the node's input, and the output every event
38
+ * of the invocation stored before the node ran, by node name
39
+ * (predecessorOutputs, ADK's collectPredecessorOutputs). The request
40
+ * fills `{x.field}` and `<x.field from Node>` from it
41
+ * (lib/runtime/native/request.ts, injectSessionState).
42
+ * 7. FAILURE. An event carrying an error code is the node's reported
43
+ * error; a run that ends with one and no output returns it as the
44
+ * run's `error`, and the scheduler fails the attempt with
45
+ * NodeReportedError, ADK's message, retried or stopping the walk as
46
+ * ADK's does, and reported once (by the node's own event). A run the turn stopped throws. A run that pauses on a person
47
+ * (an ask_user tool, an approval) is an interrupt, not run here yet.
48
+ *
49
+ * `agentNodeRuntime` puts it together for the scheduler: a `runNode` for
50
+ * agent nodes and map items, and an `onEvent` that stores the event ADK
51
+ * stores for each route step (lib/workflow/route.ts), join and map
52
+ * (lib/workflow/nodeEvents.ts), so a session the native walk writes holds
53
+ * what ADK's holds, in the same order.
54
+ *
55
+ * NOT HERE: interrupts inside a node (an ask_user tool call, an approval),
56
+ * tool nodes (lib/workflow/toolNode.ts) and ask_user nodes
57
+ * (lib/workflow/pause.ts). It imports nothing from ADK.
58
+ */
59
+ import { createTurnEvent, getFunctionCalls } from '../runtime/events.js';
60
+ import { runAgentLoop } from '../runtime/native/agentLoop.js';
61
+ import { predecessorOutputs } from '../runtime/native/request.js';
62
+ import { joinNodeEvent, mapNodeEvent } from './nodeEvents.js';
63
+ import { routeStepEvent } from './route.js';
64
+ import { enrichNodeEvent } from './toolNode.js';
65
+ // ── Errors, as ADK names them ────────────────────────────────────────────────
66
+ /** A node whose run ended on an error event and produced no output: the scheduler's, which fails the attempt (rule 7). */
67
+ export { NodeReportedError } from './scheduler.js';
68
+ /** A node run the turn stopped (cancel, deadline, max_steps): the stop's code and message. */
69
+ export class NodeStoppedError extends Error {
70
+ code;
71
+ nodeName;
72
+ constructor(nodeName, stop) {
73
+ super(`Node '${nodeName}' stopped: ${stop ? `${stop.code}: ${stop.message}` : 'the turn stopped it'}`);
74
+ this.name = 'NodeStoppedError';
75
+ this.code = stop?.code ?? 'STOPPED';
76
+ this.nodeName = nodeName;
77
+ }
78
+ }
79
+ // ── The rules, one function each ─────────────────────────────────────────────
80
+ /** ADK's isContent: an object with a `parts` array. */
81
+ function isContent(value) {
82
+ return typeof value === 'object' && value !== null && Array.isArray(value.parts);
83
+ }
84
+ /** The user turn a node input becomes (ADK's toUserContent). */
85
+ export function nodeInputContent(input) {
86
+ if (isContent(input))
87
+ return { ...input, role: 'user' };
88
+ if (typeof input === 'string')
89
+ return { role: 'user', parts: [{ text: input }] };
90
+ return { role: 'user', parts: [{ text: JSON.stringify(input) }] };
91
+ }
92
+ /** The agent a node runs: outside task mode, `includeContents: none` unless the agent set it. A copy; the compiled agent is unchanged. */
93
+ export function asNodeAgent(agent) {
94
+ if (agent.mode === 'task' || agent.includeContents !== undefined)
95
+ return agent;
96
+ return { ...agent, includeContents: 'none' };
97
+ }
98
+ /** ADK's maybeSetOutput: the output a stored model event carries outside task mode, or undefined when it carries none. */
99
+ export function eventOutput(agent, event) {
100
+ if (event.partial)
101
+ return undefined;
102
+ if (getFunctionCalls(event).length > 0)
103
+ return undefined;
104
+ const content = event.content;
105
+ if (!content || content.role !== 'model' || !content.parts)
106
+ return undefined;
107
+ const text = content.parts
108
+ .filter((p) => p.text && !p.thought)
109
+ .map((p) => p.text)
110
+ .join('');
111
+ if (agent.outputSchema && text.trim()) {
112
+ try {
113
+ return JSON.parse(text);
114
+ }
115
+ catch {
116
+ return text;
117
+ }
118
+ }
119
+ return text;
120
+ }
121
+ /** The stamp the loop applies to each event before it stores it (rules 4 and 5). */
122
+ function nodeStamp(agent, run, invocationId, state) {
123
+ const taskMode = agent.mode === 'task';
124
+ return (event) => {
125
+ if (!taskMode) {
126
+ const output = eventOutput(agent, event);
127
+ if (output !== undefined) {
128
+ event.output = output;
129
+ event.nodeInfo = { ...(event.nodeInfo ?? {}), messageAsOutput: true };
130
+ }
131
+ }
132
+ enrichNodeEvent(event, run, { invocationId });
133
+ if (event.output !== undefined)
134
+ state.output = event.output;
135
+ if (event.errorCode !== undefined)
136
+ state.reported = { errorCode: event.errorCode, ...(event.errorMessage !== undefined ? { errorMessage: event.errorMessage } : {}) };
137
+ };
138
+ }
139
+ /**
140
+ * Runs `agent` as the node `run` names, on the native loop, and resolves
141
+ * with the node's output, or with the error it reported when it ended on
142
+ * one with no output. Throws NodeStoppedError when the turn stopped it, and
143
+ * an Error when it paused on a person.
144
+ */
145
+ export async function runAgentNode(agent, run, ctx) {
146
+ const taskMode = agent.mode === 'task';
147
+ const nodeAgent = asNodeAgent(agent);
148
+ const { session, sessions, invocationId } = ctx;
149
+ if (!taskMode && run.input !== undefined && run.input !== null) {
150
+ const userEvent = createTurnEvent({ author: 'user', invocationId, branch: run.branch, content: nodeInputContent(run.input) });
151
+ const stored = await (ctx.appendInput ?? ((e) => sessions.append(session, e)))(userEvent);
152
+ ctx.onEvent?.(stored);
153
+ }
154
+ // ADK's withWorkflowInstructionScope: the input, and the outputs stored before the node runs.
155
+ const workflowScope = { input: run.input, outputsByNode: predecessorOutputs(session.events, invocationId) };
156
+ const state = { output: undefined };
157
+ const loop = runAgentLoop(nodeAgent, {
158
+ ...(ctx.loop ?? {}),
159
+ session,
160
+ sessions,
161
+ invocationId,
162
+ ...(ctx.userContent ? { userContent: ctx.userContent } : {}),
163
+ ...(run.branch !== undefined ? { branch: run.branch } : {}),
164
+ signal: run.signal,
165
+ taskNode: taskMode,
166
+ nodeStamp: nodeStamp(agent, run, invocationId, state),
167
+ workflowScope,
168
+ });
169
+ let end;
170
+ for (;;) {
171
+ const next = await loop.next();
172
+ if (next.done) {
173
+ end = next.value;
174
+ break;
175
+ }
176
+ if (next.value.partial)
177
+ ctx.onPartial?.(next.value);
178
+ else
179
+ ctx.onEvent?.(next.value);
180
+ }
181
+ if (end.reason === 'paused') {
182
+ throw new Error(`Node '${agent.name}' paused on ${(end.pending ?? []).join(', ')}: a pause inside an agent node does not run on the native runtime yet.`);
183
+ }
184
+ if (end.reason === 'stopped')
185
+ throw new NodeStoppedError(agent.name, end.stop);
186
+ // ADK's failIfNodeReportedError: an error with an output is not the node's failure. Without one the error is
187
+ // returned, not thrown: the scheduler fails the attempt with its own NodeReportedError (this class's message), which
188
+ // it knows the node reported, so it writes no node-error event of its own, as ADK writes none (ADR 0095).
189
+ if (state.reported && state.output === undefined) {
190
+ const code = state.reported.errorCode ?? 'UNKNOWN_ERROR';
191
+ return { error: { code, message: state.reported.errorMessage ?? code } };
192
+ }
193
+ return state.output === undefined ? {} : { output: state.output };
194
+ }
195
+ /**
196
+ * The scheduler's node runner for a syndicate's agents, and the store for
197
+ * its route steps' events. Node user turns and route events are stored in
198
+ * the order the walk reaches them, through one queue, so a route step's
199
+ * event lands before its successor's input as on ADK.
200
+ */
201
+ export function agentNodeRuntime(options) {
202
+ const { agents, session, sessions, invocationId } = options;
203
+ let tail = Promise.resolve();
204
+ let failure;
205
+ const enqueue = (event, onStored) => {
206
+ const stored = tail.then(async () => {
207
+ const appended = await sessions.append(session, event);
208
+ onStored?.(appended);
209
+ return appended;
210
+ });
211
+ tail = stored.then(() => undefined, (error) => {
212
+ failure ??= { error };
213
+ });
214
+ return stored;
215
+ };
216
+ const ctx = {
217
+ session,
218
+ sessions,
219
+ invocationId,
220
+ ...(options.userContent ? { userContent: options.userContent } : {}),
221
+ ...(options.loop ? { loop: options.loop } : {}),
222
+ ...(options.onEvent ? { onEvent: options.onEvent } : {}),
223
+ ...(options.onPartial ? { onPartial: options.onPartial } : {}),
224
+ // An event queued before the input that failed to store stops the node before its agent runs.
225
+ appendInput: async (event) => {
226
+ const stored = await enqueue(event);
227
+ if (failure)
228
+ throw failure.error;
229
+ return stored;
230
+ },
231
+ };
232
+ const agentNamed = (name) => {
233
+ const agent = agents.get(name);
234
+ if (!agent)
235
+ throw new Error(`workflow: '${name}' is not a compiled agent of this syndicate`);
236
+ return agent;
237
+ };
238
+ // A node's user turn is queued as the node starts, in the same synchronous pass, as ADK's runLlmAgentAsNode appends it
239
+ // straight to the session; so it lands after every event queued before it (a route step's, a predecessor's) and
240
+ // before the events other runners hand over in that pass (`store`, below).
241
+ const runNode = async (run) => {
242
+ if (failure)
243
+ throw failure.error;
244
+ const target = run.target;
245
+ if (target.kind === 'agent')
246
+ return runAgentNode(agentNamed(target.name), run, ctx);
247
+ if (target.kind === 'map_item')
248
+ return runAgentNode(agentNamed(target.agent), run, ctx);
249
+ if (options.next)
250
+ return options.next(run);
251
+ throw new Error(`agentNodeRunner runs agent nodes and map items only; ${target.name} is a ${target.kind} run`);
252
+ };
253
+ const onEvent = (event) => {
254
+ if (event.type !== 'node_end')
255
+ return;
256
+ const run = { name: event.node, path: event.path, branch: event.branch, invocationId, output: event.output };
257
+ // The events ADK stores for the nodes the scheduler runs itself: a route step's, a join's, a map's.
258
+ const stored = event.kind === 'route' ? routeStepEvent({ ...run, route: event.route }) : event.kind === 'join' ? joinNodeEvent(run) : event.kind === 'map' ? mapNodeEvent(run) : undefined;
259
+ if (stored)
260
+ enqueue(stored, options.onEvent).catch(() => { }); // surfaced by runNode and settled()
261
+ };
262
+ return {
263
+ runNode,
264
+ onEvent,
265
+ // ADK's Runner stores what a node yields a few ticks after it is yielded, behind the user turns of nodes started in
266
+ // the same pass: queued one microtask later, which is still before the walk starts the node's successors.
267
+ store: (event) => Promise.resolve().then(() => enqueue(event, options.onEvent)),
268
+ async settled() {
269
+ await tail;
270
+ if (failure)
271
+ throw failure.error;
272
+ },
273
+ };
274
+ }
@@ -0,0 +1,177 @@
1
+ /**
2
+ * lib/workflow/graph.ts — the `workflow:` block as an engine-owned graph.
3
+ *
4
+ * The YAML (lib/workflowConfig.ts) says what runs after what in chains of
5
+ * names; this module turns those chains into the graph a scheduler runs:
6
+ * typed nodes (`start`, `agent`, `join`, `map`, `tool`, `ask_user`, and the
7
+ * hidden `route` step after a node a routing map follows), directed edges
8
+ * that are unconditional, keyed to a route, or the `default` route, and the
9
+ * workflow's `max_concurrency`. It imports nothing from ADK.
10
+ *
11
+ * It is the same graph `compileWorkflow` (lib/workflow.ts) hands ADK's
12
+ * `Workflow`: the same node names in the same order, the same edges in the
13
+ * same order with the same routes (tests/workflowGraph.test.ts holds the
14
+ * two together on every workflow fixture). The engine's own scheduler,
15
+ * lib/workflow/scheduler.ts, runs it (ADR 0087).
16
+ *
17
+ * ── Validation ────────────────────────────────────────────────────────────
18
+ * Two passes, each raising the message today's path raises:
19
+ * 1. The block's cross-field rules — every name an agent or a declared
20
+ * node, `START` opening a chain, a routing map after the node it
21
+ * routes, a declared node exactly one kind, the reserved `__route`
22
+ * suffix, `workflow` without `dispatch`, and the pauses and remotes a
23
+ * node cannot carry yet. Same paths and messages as the schema's
24
+ * (lib/syndicateSchema.ts, `workflowProblems`), thrown together as a
25
+ * `WorkflowGraphError`.
26
+ * 2. The graph's own rules, on the built edges — no empty routing map,
27
+ * `START` present, without routes and without incoming edges, every
28
+ * node reachable from `START`, no duplicate edge, one `default` per
29
+ * node, no unconditional cycle. Same messages ADK's graph validation
30
+ * throws when `compileWorkflow` builds the `Workflow`, first problem
31
+ * only, as ADK does.
32
+ * The schema's type checks (an edge chain of at least two elements, a name
33
+ * that is a non-empty string) are not repeated: the input is a syndicate
34
+ * that has passed `validateSyndicateConfig`, or one shaped like it. Whether
35
+ * a `tool` node's tool is registered is a compile-time question (the
36
+ * registry), not a graph one.
37
+ */
38
+ import type { SyndicateYamlConfig } from '../loadSyndicate.ts';
39
+ import type { RetryYaml } from '../workflowConfig.ts';
40
+ /**
41
+ * The entry node's name in the graph. The YAML writes it `START`; the graph
42
+ * names it as the ADK compile does, so a node path read from an ADK-written
43
+ * workflow event names the same node here.
44
+ */
45
+ export declare const START_NODE = "__START__";
46
+ /** What a node is. `route` is the hidden step after a node a routing map follows. */
47
+ export type GraphNodeKind = 'start' | 'agent' | 'join' | 'map' | 'tool' | 'ask_user' | 'route';
48
+ /** The modifiers a node entry carries (`retry`, `timeout`), in the YAML spelling. */
49
+ export interface GraphNodeSettings {
50
+ retry?: RetryYaml;
51
+ /** Seconds this node may run before it fails. */
52
+ timeout?: number;
53
+ }
54
+ export interface StartNode {
55
+ kind: 'start';
56
+ name: typeof START_NODE;
57
+ }
58
+ export interface AgentNode {
59
+ kind: 'agent';
60
+ /** The agent's YAML name: the orchestrator or a subagent. */
61
+ name: string;
62
+ settings: GraphNodeSettings;
63
+ }
64
+ export interface JoinNode {
65
+ kind: 'join';
66
+ name: string;
67
+ settings: GraphNodeSettings;
68
+ }
69
+ export interface MapNode {
70
+ kind: 'map';
71
+ name: string;
72
+ /** The agent run once per item of the list input. It is not itself a graph node. */
73
+ agent: string;
74
+ /** Concurrency of the map; absent means the runtime's default (8). */
75
+ maxParallel?: number;
76
+ /**
77
+ * The map entry's own modifiers. ADK's compile does not hand them to its
78
+ * ParallelWorker, so neither runtime applies them; they are kept as written.
79
+ */
80
+ settings: GraphNodeSettings;
81
+ /** The mapped agent's own node modifiers (`nodes.<agent>`), which ADK applies to each item's run. */
82
+ agentSettings: GraphNodeSettings;
83
+ }
84
+ export interface ToolNode {
85
+ kind: 'tool';
86
+ name: string;
87
+ /** The registry tool run with the node input as its arguments. */
88
+ tool: string;
89
+ settings: GraphNodeSettings;
90
+ }
91
+ export interface AskUserNode {
92
+ kind: 'ask_user';
93
+ name: string;
94
+ /** The question. */
95
+ message: string;
96
+ /** JSON Schema a structured reply must satisfy. */
97
+ schema?: Record<string, unknown>;
98
+ settings: GraphNodeSettings;
99
+ }
100
+ export interface RouteNode {
101
+ kind: 'route';
102
+ /** `<source>__route`. */
103
+ name: string;
104
+ /** The node whose output this step reads the route from. */
105
+ source: string;
106
+ /** Property of a JSON output holding the route (`route_key`, default "route"); else the trimmed text. */
107
+ routeKey: string;
108
+ }
109
+ export type GraphNode = StartNode | AgentNode | JoinNode | MapNode | ToolNode | AskUserNode | RouteNode;
110
+ /**
111
+ * When an edge fires: always (`always`), when the source's route is `key`
112
+ * (`key`, the YAML routing-map key verbatim), or when no keyed edge from the
113
+ * same source matched (`default`).
114
+ */
115
+ export type EdgeRoute = {
116
+ kind: 'always';
117
+ } | {
118
+ kind: 'key';
119
+ key: string;
120
+ } | {
121
+ kind: 'default';
122
+ };
123
+ export interface GraphEdge {
124
+ from: string;
125
+ to: string;
126
+ route: EdgeRoute;
127
+ }
128
+ export interface WorkflowGraph {
129
+ /** The syndicate's name, which names the workflow. */
130
+ name: string;
131
+ /** Every node, by name, in order of first appearance in `edges` (`START_NODE` first). */
132
+ nodes: Map<string, GraphNode>;
133
+ /** Every edge, chain by chain, element pair by element pair. */
134
+ edges: GraphEdge[];
135
+ /** Nodes that may run at once; absent means unbounded. */
136
+ maxConcurrency?: number;
137
+ /** Nodes with no outgoing edge: the workflow's output is theirs. */
138
+ terminals: string[];
139
+ /** Every agent the syndicate declares (orchestrator first), including one reached only through a map. */
140
+ agents: string[];
141
+ }
142
+ /** One problem the block's rules found, with the key path the schema reports it at. */
143
+ export interface GraphProblem {
144
+ path: readonly PropertyKey[];
145
+ message: string;
146
+ }
147
+ /**
148
+ * Thrown by `buildWorkflowGraph`. For the block's rules, `problems` holds one
149
+ * `<key.path> — <what>` line per problem and the message reads as
150
+ * `SyndicateValidationError`'s does without a file; for a graph rule, it
151
+ * holds the one message, which is the error's message.
152
+ */
153
+ export declare class WorkflowGraphError extends Error {
154
+ readonly problems: string[];
155
+ constructor(problems: string[], message?: string);
156
+ }
157
+ /**
158
+ * The graph a workflow syndicate declares. Throws `WorkflowGraphError` on a
159
+ * rule the block breaks, and an `Error` when the syndicate has no
160
+ * `workflow:` block, with `compileWorkflow`'s message.
161
+ */
162
+ export declare function buildWorkflowGraph(config: SyndicateYamlConfig): WorkflowGraph;
163
+ /**
164
+ * The cross-field rules of a `workflow:` block, with the paths and messages
165
+ * `validateSyndicateConfig` reports for them, in the same order. Empty for a
166
+ * block that keeps them all.
167
+ */
168
+ export declare function workflowConfigProblems(raw: Record<string, unknown>, subs: unknown[]): GraphProblem[];
169
+ /**
170
+ * A routing-map key as the ADK compile stores it and prints it: an integer
171
+ * spelling becomes a number and `true`/`false` a boolean, compared as
172
+ * strings, so `01` and `1` name the same route there. Used for the
173
+ * duplicate-edge rule and its message, and by the scheduler
174
+ * (lib/workflow/scheduler.ts) to match an emitted route as ADK matches it
175
+ * (ADR 0087); the graph keeps the key verbatim.
176
+ */
177
+ export declare function adkRouteString(route: EdgeRoute): string | null;