melchizedek-agents 0.20.0 → 1.0.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 (207) hide show
  1. package/.env.example +4 -5
  2. package/AGENT_SETUP.md +3 -3
  3. package/CHANGELOG.md +240 -0
  4. package/DOCUMENTATION.md +142 -150
  5. package/QUICKSTART.md +12 -11
  6. package/README.md +11 -11
  7. package/config/agents/examples/image_production.yaml +2 -2
  8. package/config/agents/syndicateSchema.yaml +52 -26
  9. package/dist/lib/a2a/app.d.ts +17 -12
  10. package/dist/lib/a2a/app.js +16 -6
  11. package/dist/lib/a2a/executor.d.ts +10 -14
  12. package/dist/lib/a2a/executor.js +10 -18
  13. package/dist/lib/a2a/remoteAgent.d.ts +5 -12
  14. package/dist/lib/a2a/remoteAgent.js +5 -12
  15. package/dist/lib/compile.d.ts +76 -86
  16. package/dist/lib/compile.js +100 -116
  17. package/dist/lib/compileNative.d.ts +44 -56
  18. package/dist/lib/compileNative.js +91 -89
  19. package/dist/lib/config.d.ts +6 -6
  20. package/dist/lib/config.js +6 -6
  21. package/dist/lib/doctor.d.ts +8 -14
  22. package/dist/lib/doctor.js +10 -46
  23. package/dist/lib/index.d.ts +12 -9
  24. package/dist/lib/index.js +10 -11
  25. package/dist/lib/loadSyndicate.d.ts +3 -3
  26. package/dist/lib/loadSyndicate.js +2 -2
  27. package/dist/lib/memory/erase.d.ts +1 -1
  28. package/dist/lib/memory/erase.js +1 -1
  29. package/dist/lib/memory/namespace.d.ts +12 -14
  30. package/dist/lib/memory/namespace.js +13 -14
  31. package/dist/lib/memory/providers.d.ts +4 -5
  32. package/dist/lib/memory/providers.js +12 -6
  33. package/dist/lib/memory/supabaseMemoryService.d.ts +9 -30
  34. package/dist/lib/memory/supabaseMemoryService.js +8 -30
  35. package/dist/lib/model.d.ts +6 -12
  36. package/dist/lib/model.js +6 -12
  37. package/dist/lib/models/adapterResolver.d.ts +21 -40
  38. package/dist/lib/models/adapterResolver.js +32 -40
  39. package/dist/lib/models/chatCompletionsAdapter.d.ts +12 -33
  40. package/dist/lib/models/chatCompletionsAdapter.js +13 -18
  41. package/dist/lib/models/circuitBreaker.d.ts +5 -5
  42. package/dist/lib/models/circuitBreaker.js +5 -5
  43. package/dist/lib/models/claudeAdapter.d.ts +9 -26
  44. package/dist/lib/models/claudeAdapter.js +11 -15
  45. package/dist/lib/models/claudeModels.d.ts +4 -4
  46. package/dist/lib/models/claudeModels.js +4 -4
  47. package/dist/lib/models/contract.d.ts +11 -11
  48. package/dist/lib/models/contract.js +6 -6
  49. package/dist/lib/models/errorResponse.d.ts +13 -20
  50. package/dist/lib/models/errorResponse.js +0 -12
  51. package/dist/lib/models/fallbackAdapter.d.ts +7 -8
  52. package/dist/lib/models/gatewayAdapter.d.ts +1 -1
  53. package/dist/lib/models/gatewayAdapter.js +1 -1
  54. package/dist/lib/models/geminiAdapter.d.ts +5 -6
  55. package/dist/lib/models/geminiAdapter.js +9 -10
  56. package/dist/lib/models/geminiState.d.ts +8 -8
  57. package/dist/lib/models/geminiState.js +8 -8
  58. package/dist/lib/models/genaiMapping.d.ts +82 -36
  59. package/dist/lib/models/genaiMapping.js +41 -41
  60. package/dist/lib/models/gptAdapter.d.ts +11 -11
  61. package/dist/lib/models/gptAdapter.js +13 -13
  62. package/dist/lib/models/kimiAdapter.d.ts +6 -7
  63. package/dist/lib/models/kimiAdapter.js +6 -9
  64. package/dist/lib/models/ollamaAdapter.d.ts +3 -3
  65. package/dist/lib/models/ollamaAdapter.js +3 -3
  66. package/dist/lib/models/providerMap.d.ts +6 -5
  67. package/dist/lib/models/providerMap.js +6 -5
  68. package/dist/lib/models/providerState.d.ts +3 -2
  69. package/dist/lib/models/providerState.js +3 -2
  70. package/dist/lib/models/reasoning.d.ts +1 -1
  71. package/dist/lib/models/registry.d.ts +26 -73
  72. package/dist/lib/models/registry.js +31 -144
  73. package/dist/lib/models/retry.d.ts +2 -2
  74. package/dist/lib/models/retry.js +2 -2
  75. package/dist/lib/models/schemaNormalize.d.ts +25 -55
  76. package/dist/lib/models/schemaNormalize.js +30 -100
  77. package/dist/lib/observability/lineage.d.ts +3 -3
  78. package/dist/lib/observability/lineage.js +10 -10
  79. package/dist/lib/observability/supabaseSpanExporter.js +1 -1
  80. package/dist/lib/observability/tracer.d.ts +25 -23
  81. package/dist/lib/observability/tracer.js +26 -63
  82. package/dist/lib/persistence/supabaseProvider.d.ts +4 -3
  83. package/dist/lib/runtime/approvals.d.ts +1 -1
  84. package/dist/lib/runtime/credentials.d.ts +1 -1
  85. package/dist/lib/runtime/events.d.ts +3 -4
  86. package/dist/lib/runtime/events.js +3 -4
  87. package/dist/lib/runtime/logging.d.ts +3 -8
  88. package/dist/lib/runtime/logging.js +3 -8
  89. package/dist/lib/runtime/memoryService.d.ts +4 -6
  90. package/dist/lib/runtime/memoryService.js +3 -5
  91. package/dist/lib/runtime/native/agentLoop.d.ts +18 -16
  92. package/dist/lib/runtime/native/agentLoop.js +38 -26
  93. package/dist/lib/runtime/native/compaction.d.ts +10 -11
  94. package/dist/lib/runtime/native/compaction.js +10 -11
  95. package/dist/lib/runtime/native/delegate.d.ts +13 -14
  96. package/dist/lib/runtime/native/delegate.js +11 -18
  97. package/dist/lib/runtime/native/history.d.ts +5 -6
  98. package/dist/lib/runtime/native/history.js +5 -6
  99. package/dist/lib/runtime/native/interrupts.d.ts +6 -6
  100. package/dist/lib/runtime/native/interrupts.js +6 -6
  101. package/dist/lib/runtime/native/request.d.ts +24 -24
  102. package/dist/lib/runtime/native/request.js +35 -24
  103. package/dist/lib/runtime/native/selfCorrection.d.ts +32 -32
  104. package/dist/lib/runtime/native/selfCorrection.js +34 -34
  105. package/dist/lib/runtime/native/step.d.ts +23 -23
  106. package/dist/lib/runtime/native/step.js +49 -27
  107. package/dist/lib/runtime/native/taskMode.d.ts +8 -8
  108. package/dist/lib/runtime/native/taskMode.js +8 -8
  109. package/dist/lib/runtime/native/telemetry.d.ts +11 -11
  110. package/dist/lib/runtime/native/telemetry.js +11 -11
  111. package/dist/lib/runtime/native/tempState.d.ts +4 -4
  112. package/dist/lib/runtime/native/tempState.js +4 -4
  113. package/dist/lib/runtime/nativeTurn.d.ts +29 -32
  114. package/dist/lib/runtime/nativeTurn.js +30 -41
  115. package/dist/lib/runtime/questions.d.ts +8 -9
  116. package/dist/lib/runtime/questions.js +1 -2
  117. package/dist/lib/runtime/runtimeFlag.d.ts +28 -14
  118. package/dist/lib/runtime/runtimeFlag.js +38 -16
  119. package/dist/lib/runtime/sessions.d.ts +10 -12
  120. package/dist/lib/runtime/sessions.js +10 -12
  121. package/dist/lib/runtime/syndicateTurn.d.ts +44 -45
  122. package/dist/lib/runtime/syndicateTurn.js +163 -158
  123. package/dist/lib/runtime/turnControl.d.ts +8 -8
  124. package/dist/lib/runtime/turnControl.js +8 -8
  125. package/dist/lib/session/supabaseSessionService.d.ts +7 -21
  126. package/dist/lib/session/supabaseSessionService.js +7 -43
  127. package/dist/lib/session/transcript.d.ts +16 -26
  128. package/dist/lib/session/transcript.js +17 -57
  129. package/dist/lib/storage/postgres/sessionService.d.ts +6 -20
  130. package/dist/lib/storage/postgres/sessionService.js +6 -39
  131. package/dist/lib/syndicateSchema.js +7 -6
  132. package/dist/lib/toolRegistry.d.ts +9 -14
  133. package/dist/lib/toolRegistry.js +36 -33
  134. package/dist/lib/tools/auth.d.ts +1 -1
  135. package/dist/lib/tools/auth.js +1 -1
  136. package/dist/lib/tools/examples.d.ts +2 -4
  137. package/dist/lib/tools/examples.js +2 -4
  138. package/dist/lib/tools/generateImageTool.d.ts +3 -3
  139. package/dist/lib/tools/generateImageTool.js +4 -5
  140. package/dist/lib/tools/inspectImageTool.d.ts +2 -2
  141. package/dist/lib/tools/inspectImageTool.js +3 -4
  142. package/dist/lib/tools/mcpToolFactory.d.ts +4 -24
  143. package/dist/lib/tools/mcpToolFactory.js +19 -9
  144. package/dist/lib/tools/memoryTools.d.ts +5 -6
  145. package/dist/lib/tools/memoryTools.js +5 -6
  146. package/dist/lib/tools/nativeTools.d.ts +9 -14
  147. package/dist/lib/tools/nativeTools.js +9 -14
  148. package/dist/lib/tools/openapiTools.d.ts +5 -7
  149. package/dist/lib/tools/openapiTools.js +6 -13
  150. package/dist/lib/tools/scienceTools.d.ts +3 -3
  151. package/dist/lib/tools/scienceTools.js +8 -10
  152. package/dist/lib/tools/skillToolset.d.ts +1 -2
  153. package/dist/lib/tools/skillToolset.js +1 -2
  154. package/dist/lib/tools/skills/executor.d.ts +1 -1
  155. package/dist/lib/tools/skills/executor.js +1 -1
  156. package/dist/lib/tools/skills/frontmatter.d.ts +2 -2
  157. package/dist/lib/tools/skills/frontmatter.js +2 -2
  158. package/dist/lib/tools/skills/tools.d.ts +8 -10
  159. package/dist/lib/tools/skills/tools.js +9 -11
  160. package/dist/lib/tools/tool.d.ts +24 -40
  161. package/dist/lib/tools/tool.js +24 -56
  162. package/dist/lib/tools/toolContract.d.ts +8 -13
  163. package/dist/lib/tools/toolContract.js +6 -17
  164. package/dist/lib/tools/webExtractTool.d.ts +2 -2
  165. package/dist/lib/tools/webExtractTool.js +3 -4
  166. package/dist/lib/tools/wikiTools.d.ts +2 -2
  167. package/dist/lib/tools/wikiTools.js +5 -6
  168. package/dist/lib/tools/xApiSearchTool.d.ts +2 -2
  169. package/dist/lib/tools/xApiSearchTool.js +3 -4
  170. package/dist/lib/tools/xaiSearchParams.d.ts +2 -5
  171. package/dist/lib/tools/xaiSearchParams.js +2 -5
  172. package/dist/lib/wiki/agentRun.d.ts +10 -11
  173. package/dist/lib/wiki/agentRun.js +24 -42
  174. package/dist/lib/workflow/agentNode.d.ts +10 -1
  175. package/dist/lib/workflow/agentNode.js +5 -3
  176. package/dist/lib/workflow/graph.d.ts +8 -9
  177. package/dist/lib/workflow/graph.js +12 -12
  178. package/dist/lib/workflow/nodeEvents.d.ts +5 -5
  179. package/dist/lib/workflow/nodeEvents.js +5 -5
  180. package/dist/lib/workflow/pause.d.ts +5 -4
  181. package/dist/lib/workflow/pause.js +5 -4
  182. package/dist/lib/workflow/resume.d.ts +4 -4
  183. package/dist/lib/workflow/resume.js +4 -4
  184. package/dist/lib/workflow/route.d.ts +7 -7
  185. package/dist/lib/workflow/route.js +8 -8
  186. package/dist/lib/workflow/scheduler.d.ts +44 -2
  187. package/dist/lib/workflow/scheduler.js +60 -6
  188. package/dist/lib/workflow/toolNode.d.ts +18 -29
  189. package/dist/lib/workflow/toolNode.js +29 -35
  190. package/dist/lib/workflow/turn.d.ts +29 -20
  191. package/dist/lib/workflow/turn.js +111 -24
  192. package/dist/lib/workflow.d.ts +34 -60
  193. package/dist/lib/workflow.js +34 -168
  194. package/dist/lib/workflowConfig.d.ts +2 -10
  195. package/dist/lib/workflowConfig.js +2 -31
  196. package/dist/scripts/a2a_server.js +1 -2
  197. package/dist/scripts/assistant_worker.d.ts +2 -2
  198. package/dist/scripts/assistant_worker.js +8 -7
  199. package/dist/scripts/doctor.d.ts +2 -2
  200. package/dist/scripts/doctor.js +2 -2
  201. package/dist/scripts/syndicate_chat.js +14 -24
  202. package/package.json +3 -9
  203. package/skills/briefs/_shared.md +2 -2
  204. package/skills/briefs/melchizedek-author.md +2 -2
  205. package/skills/briefs/melchizedek-models.md +6 -6
  206. package/skills/melchizedek-author/SKILL.md +2 -2
  207. package/skills/melchizedek-models/SKILL.md +5 -5
@@ -1,6 +1,6 @@
1
1
  /**
2
- * lib/compile.ts — the one YAML → agent compiler: a runtime-neutral
3
- * AgentSpec, and the ADK agent graph built from it.
2
+ * lib/compile.ts — the one YAML → agent compiler: an AgentSpec per agent,
3
+ * which lib/compileNative.ts turns into what the runtime runs.
4
4
  *
5
5
  * WHY this file exists:
6
6
  * The A2A server carried this logic as two closures inside its executor,
@@ -12,44 +12,40 @@
12
12
  * So the compiler moved here and both callers import it.
13
13
  *
14
14
  * What it does NOT own: model resolution and nested-config loading. Both are
15
- * injected, because the two callers differ precisely there:
16
- * - the A2A server resolves `model` to a provider INSTANCE carrying the
15
+ * injected, because the callers differ precisely there:
16
+ * - the A2A server resolves `model` to a ModelAdapter carrying the
17
17
  * caller's BYOK key (lib/models/registry.ts resolveModel);
18
- * - the observatory passes the model id through as a string (the
19
- * LLMRegistry routes it) and loads nested syndicates with its
20
- * per-variant overrides already applied.
18
+ * - the observatory passes the model id through as a string (the loop
19
+ * resolves it, lib/models/registry.ts resolveAdapter) and loads nested
20
+ * syndicates with its per-variant overrides already applied.
21
21
  *
22
22
  * ── Two orchestration methods, one compiler ───────────────────────────────
23
- * DELEGATE (no `dispatch:` block): every subagent becomes an AgentTool on
24
- * the orchestrator. PLAN-DISPATCH (`dispatch:` present): the orchestrator
23
+ * DELEGATE (no `dispatch:` block): every subagent becomes a delegation tool
24
+ * on the orchestrator. PLAN-DISPATCH (`dispatch:` present): the orchestrator
25
25
  * is compiled WITHOUT subagent tools — it is a pure classifier — and the
26
- * caller runs `compileSubagent(route)` directly for the chosen route. Both
27
- * paths build subagents through the same function, so the agent a route
28
- * dispatches to is identical to the one DELEGATE would have wrapped.
26
+ * turn runner compiles the chosen route's own spec. Both paths build
27
+ * subagents through the same function, so the agent a route dispatches to
28
+ * is identical to the one DELEGATE would have delegated to.
29
29
  * Contract and rationale: lib/dispatch.ts.
30
30
  *
31
- * ── One spec, two runtimes (ADR 0073) ─────────────────────────────────────
32
- * compileSpec and compileSubagentSpec do the work every runtime shares:
33
- * resolve and gate the tools, append the skills index, resolve the model
34
- * once, build the generateContentConfig. The result is an AgentSpec.
35
- * lib/compileAdk.ts builds ADK's LlmAgent from it (compileGraph and
36
- * compileSubagent are spec + compileAdk), and lib/compileNative.ts builds
37
- * the native loop's NativeAgent (ADR 0045). runSyndicateTurn picks one by
38
- * MELCHIZEDEK_RUNTIME or its `runtime` option.
31
+ * ── The spec (ADR 0073, ADR 0107) ─────────────────────────────────────────
32
+ * compileSpec and compileSubagentSpec resolve and gate the tools, append the
33
+ * skills index, resolve the model once and build the generateContentConfig.
34
+ * The result is an AgentSpec; lib/compileNative.ts builds the loop's
35
+ * NativeAgent from it.
39
36
  */
40
- import { BaseLlm, FunctionTool } from './adkPeer.ts';
41
- import type { BaseTool, LlmAgent } from '@google/adk';
42
37
  import type { ReasoningSetting, SubagentYamlConfig, SyndicateYamlConfig } from './loadSyndicate.ts';
38
+ import type { ModelAdapter } from './models/contract.ts';
43
39
  import type { ExampleConfig } from './tools/examples.ts';
44
40
  import type { SkillsConfig } from './tools/skillToolset.ts';
45
41
  export interface CompileOptions {
46
42
  /**
47
- * Turns the YAML `model` string into what LlmAgent receives. Default:
48
- * identity — the string goes straight to ADK's LLMRegistry, which needs
49
- * `registerAvailableProviders()` to have run (lib/models/registry.ts).
50
- * The A2A server substitutes a BYOK instance factory here.
43
+ * Turns the YAML `model` string into what the agent runs on: a model id,
44
+ * or a ModelAdapter (lib/models/contract.ts). Default: identity — the id
45
+ * resolves through lib/models/registry.ts resolveAdapter when the agent
46
+ * first calls it. The A2A server substitutes a BYOK adapter factory here.
51
47
  */
52
- resolveModel?: (model: string | undefined) => string | BaseLlm | undefined;
48
+ resolveModel?: (model: string | undefined) => string | ModelAdapter | undefined;
53
49
  /**
54
50
  * Loads a nested `yaml_reference:` syndicate. Default: `loadSyndicate(ref)`
55
51
  * with no bindings — the same call the server makes. The observatory wraps
@@ -60,12 +56,6 @@ export interface CompileOptions {
60
56
  onUnknownTool?: (name: string) => void;
61
57
  /** Progress/diagnostic line sink (nested loads, MCP discovery). */
62
58
  log?: (message: string) => void;
63
- /**
64
- * Node settings for an agent compiled as a workflow node (lib/workflow.ts):
65
- * ADK's `retryConfig` and `timeout`, which an LlmAgent takes only at
66
- * construction. Called with the agent's name; undefined means none.
67
- */
68
- nodeConfig?: (agentName: string) => Record<string, unknown> | undefined;
69
59
  }
70
60
  export { REASONING_BUDGETS, reasoningConfig } from './models/reasoning.ts';
71
61
  /**
@@ -79,36 +69,17 @@ export declare function withReasoning(agent: {
79
69
  reasoning?: ReasoningSetting;
80
70
  generateContentConfig?: object;
81
71
  }, model: string | undefined): Record<string, unknown> | undefined;
82
- /** An agent's `context:` block and its default, owned by the native compactor (ADR 0033); compileAdk hands the same values to ADK's. */
72
+ /** An agent's `context:` block and its default, owned by the compactor (ADR 0033). */
83
73
  export type { ContextConfig } from './runtime/native/compaction.ts';
84
74
  import type { ContextConfig } from './runtime/native/compaction.ts';
85
75
  export { DEFAULT_KEEP_RECENT_EVENTS } from './runtime/native/compaction.ts';
86
- /**
87
- * A copy of a FunctionTool that runs only after a person approves the call
88
- * (ADR 0028). ADK's own gate does the work: the call raises an
89
- * `adk_request_confirmation` interrupt pinning the call and its arguments,
90
- * and only an approval bound to that exact call runs it. The original stays
91
- * ungated for every other agent that lists the same tool.
92
- */
93
- export declare function requireApprovalOn(tool: FunctionTool): FunctionTool;
94
- /**
95
- * A copy of an ADK BaseTool that runs only after a person approves the
96
- * call: the same confirmation interrupt FunctionTool's own gate raises, so
97
- * the turn pauses and resumes exactly as ADR 0028 says. The engine no
98
- * longer uses it: an OpenAPI operation is a FunctionTool over an own Tool
99
- * (ADR 0067) and takes requireApprovalOn like every registry tool.
100
- * @deprecated Gate a FunctionTool with requireApprovalOn, or an own Tool
101
- * with requireApproval (lib/tools/tool.ts).
102
- */
103
- export declare function requireApprovalOnBaseTool<T extends BaseTool>(tool: T): T;
104
76
  /** True when any agent of a syndicate may pause for approval: a gated tool, or skill scripts. */
105
77
  export declare function declaresApprovals(config: SyndicateYamlConfig): boolean;
106
78
  export type { ExampleConfig };
107
79
  /**
108
- * An agent's `examples:` as the ADK tool for their InstructionTool
109
- * (lib/tools/examples.ts): never called by the model, it adds the exchanges
110
- * to every request's instruction as few-shot examples, in the words ADK's
111
- * ExampleTool used.
80
+ * An agent's `examples:` as their InstructionTool (lib/tools/examples.ts):
81
+ * never called by the model, it adds the exchanges to every request's
82
+ * instruction as few-shot examples, in the words ADK's ExampleTool used.
112
83
  */
113
84
  export declare function examplesTool(examples: ExampleConfig[] | undefined): unknown[];
114
85
  /** True when a turn running this agent directly may pause for a person (ADR 0028). */
@@ -118,10 +89,9 @@ export declare function agentGates(agent: {
118
89
  } | undefined): boolean;
119
90
  /**
120
91
  * One entry of an agent's tool list, in the order the model sees it.
121
- * `tool` is a resolved tool as the registry gives it: during the dual
122
- * period an ADK object that carries its own Tool or InstructionTool
123
- * (lib/tools/adkTool.ts), an MCP tool or the skills toolset, gated by
124
- * require_approval where the YAML says so. `agent` is a delegated subagent
92
+ * `tool` is a resolved tool as the registry gives it: an own Tool,
93
+ * InstructionTool, NativeToolMarker or Toolset (lib/tools/tool.ts), gated
94
+ * by require_approval where the YAML says so. `agent` is a delegated subagent
125
95
  * (DELEGATE mode), `remote` a subagent served over A2A, `workflow` a
126
96
  * `yaml_reference` to a workflow syndicate, whose whole graph is the tool
127
97
  * (ADR 0098).
@@ -142,11 +112,10 @@ export type SpecTool = {
142
112
  workflow: WorkflowSpec;
143
113
  };
144
114
  /**
145
- * A workflow syndicate, compiled for either runtime: lib/workflow.ts builds
146
- * ADK's Workflow from it, lib/compileNative.ts the native walk's graph and
147
- * agents. Nested as a subagent (a `yaml_reference` in DELEGATE mode), the
148
- * graph runs under the entry's name and description, and that name is the
149
- * root of every node path, as ADK names a Workflow's nodes after it.
115
+ * A workflow syndicate, compiled: lib/compileNative.ts builds the walk's
116
+ * graph and agents from it. Nested as a subagent (a `yaml_reference` in
117
+ * DELEGATE mode), the graph runs under the entry's name and description,
118
+ * and that name is the root of every node path.
150
119
  */
151
120
  export interface WorkflowSpec {
152
121
  /** The workflow's name: the syndicate's, or the subagent entry's when nested. */
@@ -160,12 +129,20 @@ export interface WorkflowSpec {
160
129
  yaml: SubagentYamlConfig;
161
130
  spec: AgentSpec;
162
131
  }>;
132
+ /**
133
+ * Every node that is a `yaml_reference` to a workflow syndicate, with its
134
+ * YAML entry: the nested graph under the entry's name (ADR 0106). The
135
+ * walk runs it as the node, on its own child session.
136
+ */
137
+ workflows: Array<{
138
+ yaml: SubagentYamlConfig;
139
+ workflow: WorkflowSpec;
140
+ }>;
163
141
  /** The registry entry for a tool node's tool name, or undefined (CompileOptions.onUnknownTool applies). */
164
142
  resolveTool: (name: string) => unknown;
165
143
  }
166
144
  /**
167
- * One YAML agent, compiled, for either runtime: what lib/compileAdk.ts
168
- * turns into ADK's LlmAgent and lib/compileNative.ts into the native loop's
145
+ * One YAML agent, compiled: what lib/compileNative.ts turns into the loop's
169
146
  * NativeAgent. Built once per agent by compileSpec and compileSubagentSpec:
170
147
  * the tools resolved (OpenAPI operations built, MCP tools listed) and
171
148
  * gated, the skills index appended to the instruction, the model resolved
@@ -181,14 +158,14 @@ export interface AgentSpec {
181
158
  resolvedModel?: unknown;
182
159
  /** The id the agent runs on: the YAML's, else the resolved adapter's. */
183
160
  modelId?: string;
184
- /** `fallback_model:`, unresolved: each runtime resolves it where it calls it. */
161
+ /** `fallback_model:`, unresolved: the loop resolves it where it calls it. */
185
162
  fallbackModel?: string;
186
163
  /** The YAML instruction, with the skills index appended when the agent has `skills:`. */
187
164
  instruction: string;
188
165
  globalInstruction?: string;
189
166
  tools: SpecTool[];
190
167
  outputSchema?: Record<string, unknown>;
191
- /** The YAML's config with `reasoning:` mapped in and server-side tool invocations on, as both runtimes send it. */
168
+ /** The YAML's config with `reasoning:` mapped in and server-side tool invocations on. */
192
169
  generateContentConfig: Record<string, unknown>;
193
170
  includeContents?: 'default' | 'none';
194
171
  outputKey?: string;
@@ -209,33 +186,46 @@ export interface AgentSpec {
209
186
  *
210
187
  * A nested workflow runs inside its caller's tool call, so a pause inside it
211
188
  * could not reach the caller (ADR 0028, as for any nested syndicate): an
212
- * `ask_user` node is refused by name here, on both runtimes.
189
+ * `ask_user` node is refused by name here.
213
190
  */
214
191
  export declare function compileWorkflowSpec(config: SyndicateYamlConfig, opts?: CompileOptions, name?: string, description?: string, ref?: string): Promise<WorkflowSpec>;
192
+ /** Every agent spec a workflow runs, its nested workflow nodes' agents included, for one adapter lookup (nativeAdapterFor). */
193
+ export declare function workflowAgentSpecs(spec: WorkflowSpec): AgentSpec[];
194
+ /** A subagent entry, compiled: one agent, or a nested workflow syndicate's whole graph (ADR 0098, ADR 0106). */
195
+ export type EntrySpec = {
196
+ kind: 'agent';
197
+ spec: AgentSpec;
198
+ } | {
199
+ kind: 'workflow';
200
+ workflow: WorkflowSpec;
201
+ };
202
+ /**
203
+ * A subagent entry as what it runs: an inline agent or a nested syndicate's
204
+ * orchestrator as one agent, or a `yaml_reference` to a workflow syndicate
205
+ * as its whole graph under the entry's name and description. A delegated
206
+ * subagent, a dispatch route and a workflow node all compile through here,
207
+ * so the graph a file describes is the graph that runs (ADR 0106).
208
+ */
209
+ export declare function compileEntrySpec(subCfg: SubagentYamlConfig, opts?: CompileOptions): Promise<EntrySpec>;
210
+ /**
211
+ * The names of a syndicate's subagent entries that are `yaml_reference`s to
212
+ * a workflow syndicate. Loads each reference once and compiles nothing, so a
213
+ * runtime can refuse what it cannot run before the session is touched.
214
+ */
215
+ export declare function workflowEntryNames(config: SyndicateYamlConfig, opts?: CompileOptions): string[];
215
216
  /**
216
217
  * The spec of ONE agent from a subagent entry. A `yaml_reference` entry is
217
- * the nested syndicate's whole graph under this entry's name and
218
- * description, so the parent sees one tool (or one route) either way.
218
+ * the nested syndicate's orchestrator under this entry's name and
219
+ * description, its own subagents delegated to as in any DELEGATE graph. A
220
+ * `yaml_reference` to a workflow syndicate has no one agent to build: it
221
+ * runs as its whole graph (compileEntrySpec), and is refused here by name.
219
222
  */
220
223
  export declare function compileSubagentSpec(subCfg: SubagentYamlConfig, opts?: CompileOptions): Promise<AgentSpec>;
221
224
  /**
222
225
  * The spec of a syndicate's orchestrator. In DELEGATE mode its subagents
223
226
  * come first among its tools, as delegations; in PLAN-DISPATCH mode it gets
224
- * none (ADK refuses outputSchema + AgentTool on one agent — see
227
+ * none (a classifier answers with its outputSchema — see
225
228
  * config/agents/critic.yaml), and the caller dispatches to a route's own
226
229
  * spec itself.
227
230
  */
228
231
  export declare function compileSpec(config: SyndicateYamlConfig, opts?: CompileOptions, overrideName?: string, overrideDescription?: string): Promise<AgentSpec>;
229
- /**
230
- * Builds ONE runnable ADK agent from a subagent entry: its spec, as
231
- * lib/compileAdk.ts builds it. A workflow node's settings
232
- * (CompileOptions.nodeConfig) apply to a local agent, not to a nested
233
- * syndicate's orchestrator.
234
- */
235
- export declare function compileSubagent(subCfg: SubagentYamlConfig, opts?: CompileOptions): Promise<LlmAgent>;
236
- /**
237
- * Compiles a syndicate's orchestrator for the ADK runtime. In DELEGATE mode
238
- * its subagents are attached as AgentTools; in PLAN-DISPATCH mode it gets
239
- * none, and the caller dispatches to `compileSubagent(route)` itself.
240
- */
241
- export declare function compileGraph(config: SyndicateYamlConfig, opts?: CompileOptions, overrideName?: string, overrideDescription?: string): Promise<LlmAgent>;
@@ -1,6 +1,6 @@
1
1
  /**
2
- * lib/compile.ts — the one YAML → agent compiler: a runtime-neutral
3
- * AgentSpec, and the ADK agent graph built from it.
2
+ * lib/compile.ts — the one YAML → agent compiler: an AgentSpec per agent,
3
+ * which lib/compileNative.ts turns into what the runtime runs.
4
4
  *
5
5
  * WHY this file exists:
6
6
  * The A2A server carried this logic as two closures inside its executor,
@@ -12,34 +12,29 @@
12
12
  * So the compiler moved here and both callers import it.
13
13
  *
14
14
  * What it does NOT own: model resolution and nested-config loading. Both are
15
- * injected, because the two callers differ precisely there:
16
- * - the A2A server resolves `model` to a provider INSTANCE carrying the
15
+ * injected, because the callers differ precisely there:
16
+ * - the A2A server resolves `model` to a ModelAdapter carrying the
17
17
  * caller's BYOK key (lib/models/registry.ts resolveModel);
18
- * - the observatory passes the model id through as a string (the
19
- * LLMRegistry routes it) and loads nested syndicates with its
20
- * per-variant overrides already applied.
18
+ * - the observatory passes the model id through as a string (the loop
19
+ * resolves it, lib/models/registry.ts resolveAdapter) and loads nested
20
+ * syndicates with its per-variant overrides already applied.
21
21
  *
22
22
  * ── Two orchestration methods, one compiler ───────────────────────────────
23
- * DELEGATE (no `dispatch:` block): every subagent becomes an AgentTool on
24
- * the orchestrator. PLAN-DISPATCH (`dispatch:` present): the orchestrator
23
+ * DELEGATE (no `dispatch:` block): every subagent becomes a delegation tool
24
+ * on the orchestrator. PLAN-DISPATCH (`dispatch:` present): the orchestrator
25
25
  * is compiled WITHOUT subagent tools — it is a pure classifier — and the
26
- * caller runs `compileSubagent(route)` directly for the chosen route. Both
27
- * paths build subagents through the same function, so the agent a route
28
- * dispatches to is identical to the one DELEGATE would have wrapped.
26
+ * turn runner compiles the chosen route's own spec. Both paths build
27
+ * subagents through the same function, so the agent a route dispatches to
28
+ * is identical to the one DELEGATE would have delegated to.
29
29
  * Contract and rationale: lib/dispatch.ts.
30
30
  *
31
- * ── One spec, two runtimes (ADR 0073) ─────────────────────────────────────
32
- * compileSpec and compileSubagentSpec do the work every runtime shares:
33
- * resolve and gate the tools, append the skills index, resolve the model
34
- * once, build the generateContentConfig. The result is an AgentSpec.
35
- * lib/compileAdk.ts builds ADK's LlmAgent from it (compileGraph and
36
- * compileSubagent are spec + compileAdk), and lib/compileNative.ts builds
37
- * the native loop's NativeAgent (ADR 0045). runSyndicateTurn picks one by
38
- * MELCHIZEDEK_RUNTIME or its `runtime` option.
31
+ * ── The spec (ADR 0073, ADR 0107) ─────────────────────────────────────────
32
+ * compileSpec and compileSubagentSpec resolve and gate the tools, append the
33
+ * skills index, resolve the model once and build the generateContentConfig.
34
+ * The result is an AgentSpec; lib/compileNative.ts builds the loop's
35
+ * NativeAgent from it.
39
36
  */
40
- import { BaseLlm, FunctionTool } from './adkPeer.js';
41
37
  import { relative } from 'node:path';
42
- import { compileAdk } from './compileAdk.js';
43
38
  import { isDispatchSyndicate } from './dispatch.js';
44
39
  import { isWorkflowSyndicate, nodeKind } from './workflowConfig.js';
45
40
  import { loadSyndicate, nestedLoader } from './loadSyndicate.js';
@@ -47,12 +42,12 @@ import { REASONING_OLDER_SPELLING } from './syndicateSchema.js';
47
42
  import { reasoningConfig } from './models/reasoning.js';
48
43
  import { resolveTools as resolveNamedTools } from './toolRegistry.js';
49
44
  import { createMcpTools } from './tools/mcpToolFactory.js';
50
- import { toAdkInstructionTool, toAdkToolset } from './tools/adkTool.js';
45
+ import { requireApproval, toolOf } from './tools/tool.js';
51
46
  import { examplesInstructionTool } from './tools/examples.js';
52
47
  import { capabilitySummary, describeCapabilities } from './models/capabilities.js';
53
48
  import { buildSkillHarness } from './tools/skillToolset.js';
54
49
  import { buildOpenApiTools, namesTool, openApiOperationId } from './tools/openapiTools.js';
55
- /** generateContentConfig as every entrypoint has always sent it to ADK. */
50
+ /** generateContentConfig as every entrypoint sends it: server-side tool invocations on. */
56
51
  function withServerSideToolInvocations(generateContentConfig) {
57
52
  const cfg = (generateContentConfig ?? {});
58
53
  return {
@@ -65,7 +60,7 @@ function withServerSideToolInvocations(generateContentConfig) {
65
60
  }
66
61
  // ── Reasoning (ADR 0047) ─────────────────────────────────────────────────────
67
62
  // REASONING_BUDGETS and reasoningConfig live in lib/models/reasoning.ts, so a
68
- // model adapter can map `reasoning:` without importing the compiler (and ADK).
63
+ // model adapter can map `reasoning:` without importing the compiler.
69
64
  export { REASONING_BUDGETS, reasoningConfig } from './models/reasoning.js';
70
65
  /**
71
66
  * An agent's generateContentConfig with its `reasoning:` key mapped in for
@@ -85,7 +80,12 @@ export function withReasoning(agent, model) {
85
80
  }
86
81
  /** The model id an agent runs on, from its YAML or its resolved adapter. */
87
82
  function modelIdOf(yamlModel, resolved) {
88
- return yamlModel ?? (typeof resolved === 'string' ? resolved : resolved instanceof BaseLlm ? resolved.model : undefined);
83
+ if (yamlModel !== undefined)
84
+ return yamlModel;
85
+ if (typeof resolved === 'string')
86
+ return resolved;
87
+ const own = resolved && typeof resolved === 'object' ? resolved.model : undefined;
88
+ return typeof own === 'string' ? own : undefined;
89
89
  }
90
90
  export { DEFAULT_KEEP_RECENT_EVENTS } from './runtime/native/compaction.js';
91
91
  /**
@@ -103,44 +103,6 @@ function logCapabilities(opts, agentName, model, tools) {
103
103
  if (line)
104
104
  opts.log(`capability · ${line}`);
105
105
  }
106
- /**
107
- * A copy of a FunctionTool that runs only after a person approves the call
108
- * (ADR 0028). ADK's own gate does the work: the call raises an
109
- * `adk_request_confirmation` interrupt pinning the call and its arguments,
110
- * and only an approval bound to that exact call runs it. The original stays
111
- * ungated for every other agent that lists the same tool.
112
- */
113
- export function requireApprovalOn(tool) {
114
- const gated = Object.create(tool);
115
- Object.defineProperty(gated, 'requireConfirmation', { value: true, enumerable: false });
116
- return gated;
117
- }
118
- /**
119
- * A copy of an ADK BaseTool that runs only after a person approves the
120
- * call: the same confirmation interrupt FunctionTool's own gate raises, so
121
- * the turn pauses and resumes exactly as ADR 0028 says. The engine no
122
- * longer uses it: an OpenAPI operation is a FunctionTool over an own Tool
123
- * (ADR 0067) and takes requireApprovalOn like every registry tool.
124
- * @deprecated Gate a FunctionTool with requireApprovalOn, or an own Tool
125
- * with requireApproval (lib/tools/tool.ts).
126
- */
127
- export function requireApprovalOnBaseTool(tool) {
128
- const gated = Object.create(tool);
129
- Object.defineProperty(gated, 'runAsync', {
130
- value: async (request) => {
131
- const ctx = request.toolContext;
132
- if (!ctx.toolConfirmation) {
133
- ctx.requestConfirmation({ hint: `Approval is required before ${tool.name} runs.`, payload: request.args });
134
- ctx.actions.skipSummarization = true;
135
- return { error: 'This call requires approval, please approve or reject.' };
136
- }
137
- if (!ctx.toolConfirmation.confirmed)
138
- return { error: 'This call was rejected.' };
139
- return tool.runAsync(request);
140
- },
141
- });
142
- return gated;
143
- }
144
106
  function gateTools(tools, names, agentName) {
145
107
  if (!names?.length)
146
108
  return tools;
@@ -155,11 +117,12 @@ function gateTools(tools, names, agentName) {
155
117
  if (!match)
156
118
  return t;
157
119
  wanted.delete(match);
158
- // An OpenAPI operation is a FunctionTool over an own Tool (ADR 0067): one gate for both.
159
- if (!(t instanceof FunctionTool)) {
160
- throw new Error(`${agentName}: '${name}' cannot require approval — only function tools from the registry and OpenAPI operations can be gated (ADR 0028).`);
120
+ // A registry tool, an OpenAPI operation and an MCP tool are own Tools (ADR 0067): one gate for all.
121
+ const own = toolOf(t);
122
+ if (!own) {
123
+ throw new Error(`${agentName}: '${name}' cannot require approval — only function tools from the registry, OpenAPI operations and MCP tools can be gated (ADR 0028).`);
161
124
  }
162
- return requireApprovalOn(t);
125
+ return requireApproval(own);
163
126
  });
164
127
  if (wanted.size) {
165
128
  // Fail closed: a gate on a tool that did not resolve must not leave an
@@ -173,14 +136,13 @@ export function declaresApprovals(config) {
173
136
  return agentGates(config.orchestrator) || (config.subagents ?? []).some((s) => agentGates(s));
174
137
  }
175
138
  /**
176
- * An agent's `examples:` as the ADK tool for their InstructionTool
177
- * (lib/tools/examples.ts): never called by the model, it adds the exchanges
178
- * to every request's instruction as few-shot examples, in the words ADK's
179
- * ExampleTool used.
139
+ * An agent's `examples:` as their InstructionTool (lib/tools/examples.ts):
140
+ * never called by the model, it adds the exchanges to every request's
141
+ * instruction as few-shot examples, in the words ADK's ExampleTool used.
180
142
  */
181
143
  export function examplesTool(examples) {
182
144
  const tool = examplesInstructionTool(examples);
183
- return tool ? [toAdkInstructionTool(tool)] : [];
145
+ return tool ? [tool] : [];
184
146
  }
185
147
  async function resolveAgentTools(toolNames, mcpServerUrl, opts, openapi, examples, mcpAllowed) {
186
148
  const tools = [...resolveNamedTools(toolNames, opts.onUnknownTool), ...examplesTool(examples)];
@@ -233,8 +195,7 @@ async function withSkills(instruction, tools, skills, agentName, opts) {
233
195
  opts.log?.(`skills · ${agentName}: ${count} skill${count === 1 ? '' : 's'} from ${skills.dir}${skills.scripts === 'local' ? ' · scripts run after approval' : ''}`);
234
196
  for (const problem of harness.problems)
235
197
  opts.log?.(`⚠ skills · ${skills.dir}: not loaded — ${problem}`);
236
- // The ADK face of the engine's own toolset; compileNative reads the toolset back (toolsetOf).
237
- return { instruction: `${instruction.trimEnd()}\n\n${harness.instruction}`, tools: [...tools, toAdkToolset(harness.toolset)] };
198
+ return { instruction: `${instruction.trimEnd()}\n\n${harness.instruction}`, tools: [...tools, harness.toolset] };
238
199
  }
239
200
  /** True when a turn running this agent directly may pause for a person (ADR 0028). */
240
201
  export function agentGates(agent) {
@@ -320,7 +281,7 @@ function loadNestedSyndicate(ref, opts) {
320
281
  *
321
282
  * A nested workflow runs inside its caller's tool call, so a pause inside it
322
283
  * could not reach the caller (ADR 0028, as for any nested syndicate): an
323
- * `ask_user` node is refused by name here, on both runtimes.
284
+ * `ask_user` node is refused by name here.
324
285
  */
325
286
  export async function compileWorkflowSpec(config, opts = {}, name, description, ref) {
326
287
  if (!isWorkflowSyndicate(config))
@@ -328,26 +289,72 @@ export async function compileWorkflowSpec(config, opts = {}, name, description,
328
289
  if (name) {
329
290
  const asking = Object.entries(config.workflow.nodes ?? {}).find(([, node]) => nodeKind(node) === 'ask_user');
330
291
  if (asking) {
331
- throw new Error(`${ref ?? config.syndicate_name}: the ask_user node '${asking[0]}' pauses for a person, which a workflow nested as a subagent (${name}) cannot carry to its caller; run the workflow as its own syndicate, or remove the node.`);
292
+ throw new Error(`${ref ?? config.syndicate_name}: the ask_user node '${asking[0]}' pauses for a person, which a workflow nested in another syndicate (${name}) cannot carry to its caller; run the workflow as its own syndicate, or remove the node.`);
332
293
  }
333
294
  }
334
295
  const workflowName = name || config.syndicate_name;
335
296
  const agents = [];
297
+ const workflows = [];
336
298
  for (const yaml of [{ description: '', ...config.orchestrator }, ...(config.subagents ?? [])]) {
337
- agents.push({ yaml, spec: await compileSubagentSpec(yaml, opts) });
299
+ const entry = await compileEntrySpec(yaml, opts);
300
+ if (entry.kind === 'workflow')
301
+ workflows.push({ yaml, workflow: entry.workflow });
302
+ else
303
+ agents.push({ yaml, spec: entry.spec });
304
+ }
305
+ // A map runs one agent per item; a nested graph is not an agent a map item can be (ADR 0106).
306
+ for (const [node, entry] of Object.entries(config.workflow.nodes ?? {})) {
307
+ const mapped = nodeKind(entry) === 'map' ? workflows.find((w) => w.yaml.name === entry.map) : undefined;
308
+ if (mapped) {
309
+ throw new Error(`${ref ?? config.syndicate_name}: the map node '${node}' runs '${mapped.yaml.name}', a workflow syndicate (${mapped.yaml.yaml_reference}); a map runs one agent per item, so make the workflow a node of its own.`);
310
+ }
338
311
  }
339
312
  return {
340
313
  name: workflowName,
341
314
  description: description ?? '',
342
315
  config: { ...config, syndicate_name: workflowName },
343
316
  agents,
317
+ workflows,
344
318
  resolveTool: (tool) => resolveNamedTools([tool], opts.onUnknownTool)[0],
345
319
  };
346
320
  }
321
+ /** Every agent spec a workflow runs, its nested workflow nodes' agents included, for one adapter lookup (nativeAdapterFor). */
322
+ export function workflowAgentSpecs(spec) {
323
+ return [...spec.agents.map((a) => a.spec), ...spec.workflows.flatMap((w) => workflowAgentSpecs(w.workflow))];
324
+ }
325
+ /**
326
+ * A subagent entry as what it runs: an inline agent or a nested syndicate's
327
+ * orchestrator as one agent, or a `yaml_reference` to a workflow syndicate
328
+ * as its whole graph under the entry's name and description. A delegated
329
+ * subagent, a dispatch route and a workflow node all compile through here,
330
+ * so the graph a file describes is the graph that runs (ADR 0106).
331
+ */
332
+ export async function compileEntrySpec(subCfg, opts = {}) {
333
+ if (subCfg.yaml_reference && !subCfg.a2a_agent_url) {
334
+ const nestedOpts = nestedOptions(subCfg.yaml_reference, opts);
335
+ const nested = loadNestedSyndicate(subCfg.yaml_reference, nestedOpts);
336
+ if (isWorkflowSyndicate(nested)) {
337
+ return { kind: 'workflow', workflow: await compileWorkflowSpec(nested, nestedOpts, subCfg.name, subCfg.description, subCfg.yaml_reference) };
338
+ }
339
+ return { kind: 'agent', spec: await compileSpec(nested, nestedOpts, subCfg.name, subCfg.description) };
340
+ }
341
+ return { kind: 'agent', spec: await compileSubagentSpec(subCfg, opts) };
342
+ }
343
+ /**
344
+ * The names of a syndicate's subagent entries that are `yaml_reference`s to
345
+ * a workflow syndicate. Loads each reference once and compiles nothing, so a
346
+ * runtime can refuse what it cannot run before the session is touched.
347
+ */
348
+ export function workflowEntryNames(config, opts = {}) {
349
+ const load = opts.loadNested ?? (config.bundled_references ? nestedLoader(config) : loadSyndicate);
350
+ return (config.subagents ?? []).filter((s) => !!s.yaml_reference && !s.a2a_agent_url && isWorkflowSyndicate(load(s.yaml_reference))).map((s) => s.name);
351
+ }
347
352
  /**
348
353
  * The spec of ONE agent from a subagent entry. A `yaml_reference` entry is
349
- * the nested syndicate's whole graph under this entry's name and
350
- * description, so the parent sees one tool (or one route) either way.
354
+ * the nested syndicate's orchestrator under this entry's name and
355
+ * description, its own subagents delegated to as in any DELEGATE graph. A
356
+ * `yaml_reference` to a workflow syndicate has no one agent to build: it
357
+ * runs as its whole graph (compileEntrySpec), and is refused here by name.
351
358
  */
352
359
  export async function compileSubagentSpec(subCfg, opts = {}) {
353
360
  if (subCfg.a2a_agent_url) {
@@ -358,7 +365,11 @@ export async function compileSubagentSpec(subCfg, opts = {}) {
358
365
  }
359
366
  if (subCfg.yaml_reference) {
360
367
  const nestedOpts = nestedOptions(subCfg.yaml_reference, opts);
361
- return compileSpec(loadNestedSyndicate(subCfg.yaml_reference, nestedOpts), nestedOpts, subCfg.name, subCfg.description);
368
+ const nested = loadNestedSyndicate(subCfg.yaml_reference, nestedOpts);
369
+ if (isWorkflowSyndicate(nested)) {
370
+ throw new Error(`${subCfg.yaml_reference}: '${subCfg.name}' is a workflow syndicate, which runs as its whole graph, not as one agent; compile the entry with compileEntrySpec (ADR 0106).`);
371
+ }
372
+ return compileSpec(nested, nestedOpts, subCfg.name, subCfg.description);
362
373
  }
363
374
  const gated = gateTools(await resolveAgentTools(subCfg.tools, subCfg.mcp_server_url, opts, subCfg.openapi, subCfg.examples, subCfg.mcp_tools), subCfg.require_approval, subCfg.name);
364
375
  const { instruction, tools } = await withSkills(subCfg.instruction ?? '', gated, subCfg.skills, subCfg.name, opts);
@@ -368,7 +379,7 @@ export async function compileSubagentSpec(subCfg, opts = {}) {
368
379
  /**
369
380
  * The spec of a syndicate's orchestrator. In DELEGATE mode its subagents
370
381
  * come first among its tools, as delegations; in PLAN-DISPATCH mode it gets
371
- * none (ADK refuses outputSchema + AgentTool on one agent — see
382
+ * none (a classifier answers with its outputSchema — see
372
383
  * config/agents/critic.yaml), and the caller dispatches to a route's own
373
384
  * spec itself.
374
385
  */
@@ -377,14 +388,12 @@ export async function compileSpec(config, opts = {}, overrideName, overrideDescr
377
388
  if (config.bundled_references && !opts.loadNested)
378
389
  opts = { ...opts, loadNested: nestedLoader(config) };
379
390
  // A graph has no orchestrator-with-tools shape to build: its agents are
380
- // nodes (lib/workflow.ts). A delegated yaml_reference to one runs the whole
381
- // graph as the tool (nestedWorkflowSpec, ADR 0098); as a dispatch route or
382
- // a workflow node it is still its orchestrator alone.
383
- if (config.workflow && !overrideName) {
384
- throw new Error(`${config.syndicate_name}: a workflow syndicate is compiled with compileWorkflow (lib/workflow.ts), not compileGraph`);
391
+ // nodes (lib/workflow.ts). A yaml_reference to one runs the whole graph, as
392
+ // a delegated tool (ADR 0098), a dispatch route or a workflow node (ADR
393
+ // 0106), through compileEntrySpec, which never compiles one here.
394
+ if (config.workflow) {
395
+ throw new Error(`${config.syndicate_name}: a workflow syndicate is compiled with compileWorkflowSpec, not compileSpec`);
385
396
  }
386
- if (config.workflow)
387
- opts.log?.(`${config.syndicate_name}: a dispatch route or a workflow node, so only its orchestrator runs (a delegated subagent runs the whole graph)`);
388
397
  const delegated = isDispatchSyndicate(config)
389
398
  ? []
390
399
  : await Promise.all((config.subagents ?? []).map(async (subCfg) => {
@@ -392,14 +401,8 @@ export async function compileSpec(config, opts = {}, overrideName, overrideDescr
392
401
  opts.log?.(`Remote A2A agent: ${subCfg.name} → ${subCfg.a2a_agent_url}`);
393
402
  return { kind: 'remote', name: subCfg.name, description: subCfg.description, url: subCfg.a2a_agent_url };
394
403
  }
395
- if (subCfg.yaml_reference) {
396
- const nestedOpts = nestedOptions(subCfg.yaml_reference, opts);
397
- const nested = loadNestedSyndicate(subCfg.yaml_reference, nestedOpts);
398
- if (isWorkflowSyndicate(nested))
399
- return { kind: 'workflow', workflow: await compileWorkflowSpec(nested, nestedOpts, subCfg.name, subCfg.description, subCfg.yaml_reference) };
400
- return { kind: 'agent', agent: await compileSpec(nested, nestedOpts, subCfg.name, subCfg.description) };
401
- }
402
- return { kind: 'agent', agent: await compileSubagentSpec(subCfg, opts) };
404
+ const entry = await compileEntrySpec(subCfg, opts);
405
+ return entry.kind === 'workflow' ? entry : { kind: 'agent', agent: entry.spec };
403
406
  }));
404
407
  const name = overrideName || config.orchestrator.name;
405
408
  // Orchestrator tools are registry names only — no entrypoint has ever
@@ -411,22 +414,3 @@ export async function compileSpec(config, opts = {}, overrideName, overrideDescr
411
414
  logCapabilities(opts, name, config.orchestrator.model, config.orchestrator.tools);
412
415
  return specOf(config.orchestrator, name, overrideDescription || config.orchestrator.description, instruction, [...delegated, ...asTools(tools)], opts);
413
416
  }
414
- // ── The ADK runtime's agents (lib/compileAdk.ts) ─────────────────────────────
415
- /**
416
- * Builds ONE runnable ADK agent from a subagent entry: its spec, as
417
- * lib/compileAdk.ts builds it. A workflow node's settings
418
- * (CompileOptions.nodeConfig) apply to a local agent, not to a nested
419
- * syndicate's orchestrator.
420
- */
421
- export async function compileSubagent(subCfg, opts = {}) {
422
- const spec = await compileSubagentSpec(subCfg, opts);
423
- return compileAdk(spec, opts, subCfg.yaml_reference ? {} : (opts.nodeConfig?.(subCfg.name) ?? {}));
424
- }
425
- /**
426
- * Compiles a syndicate's orchestrator for the ADK runtime. In DELEGATE mode
427
- * its subagents are attached as AgentTools; in PLAN-DISPATCH mode it gets
428
- * none, and the caller dispatches to `compileSubagent(route)` itself.
429
- */
430
- export async function compileGraph(config, opts = {}, overrideName, overrideDescription) {
431
- return compileAdk(await compileSpec(config, opts, overrideName, overrideDescription), opts);
432
- }