melchizedek-agents 0.19.0 → 0.20.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.
- package/CHANGELOG.md +252 -76
- package/DOCUMENTATION.md +44 -15
- package/QUICKSTART.md +9 -6
- package/README.md +6 -9
- package/config/agents/syndicateSchema.yaml +3 -0
- package/dist/lib/adkPeer.d.ts +63 -0
- package/dist/lib/adkPeer.js +240 -0
- package/dist/lib/compile.d.ts +40 -2
- package/dist/lib/compile.js +80 -12
- package/dist/lib/compileAdk.d.ts +7 -4
- package/dist/lib/compileAdk.js +22 -12
- package/dist/lib/compileNative.d.ts +28 -2
- package/dist/lib/compileNative.js +60 -4
- package/dist/lib/doctor.d.ts +28 -1
- package/dist/lib/doctor.js +63 -2
- package/dist/lib/index.d.ts +4 -0
- package/dist/lib/index.js +5 -0
- package/dist/lib/models/adapterResolver.d.ts +13 -11
- package/dist/lib/models/adapterResolver.js +11 -10
- package/dist/lib/models/adkGeminiAdapter.js +2 -0
- package/dist/lib/models/adkShim.d.ts +1 -1
- package/dist/lib/models/adkShim.js +1 -1
- package/dist/lib/models/capabilities.js +13 -10
- package/dist/lib/models/claudeLlm.js +2 -2
- package/dist/lib/models/fallback.d.ts +1 -1
- package/dist/lib/models/fallback.js +1 -1
- package/dist/lib/models/gatewayLlm.js +2 -2
- package/dist/lib/models/geminiAdapter.d.ts +6 -4
- package/dist/lib/models/geminiAdapter.js +28 -5
- package/dist/lib/models/geminiState.d.ts +21 -0
- package/dist/lib/models/geminiState.js +26 -0
- package/dist/lib/models/genaiMapping.d.ts +24 -4
- package/dist/lib/models/genaiMapping.js +109 -6
- package/dist/lib/models/gptLlm.js +2 -2
- package/dist/lib/models/grokLlm.js +2 -2
- package/dist/lib/models/kimiLlm.js +2 -2
- package/dist/lib/models/ollamaLlm.js +2 -2
- package/dist/lib/models/registry.d.ts +5 -1
- package/dist/lib/models/registry.js +17 -12
- package/dist/lib/models/tracedGemini.d.ts +1 -1
- package/dist/lib/models/tracedGemini.js +1 -1
- package/dist/lib/runtime/adkSessionBridge.d.ts +1 -1
- package/dist/lib/runtime/adkSessionBridge.js +1 -1
- package/dist/lib/runtime/approvals.d.ts +5 -0
- package/dist/lib/runtime/approvals.js +39 -8
- package/dist/lib/runtime/credentials.d.ts +3 -1
- package/dist/lib/runtime/credentials.js +6 -1
- package/dist/lib/runtime/native/agentLoop.d.ts +7 -1
- package/dist/lib/runtime/native/agentLoop.js +31 -13
- package/dist/lib/runtime/native/delegate.d.ts +53 -0
- package/dist/lib/runtime/native/delegate.js +91 -8
- package/dist/lib/runtime/native/interrupts.d.ts +6 -3
- package/dist/lib/runtime/native/interrupts.js +23 -4
- package/dist/lib/runtime/native/request.d.ts +1 -1
- package/dist/lib/runtime/native/request.js +1 -1
- package/dist/lib/runtime/native/selfCorrection.d.ts +64 -6
- package/dist/lib/runtime/native/selfCorrection.js +82 -8
- package/dist/lib/runtime/native/step.d.ts +14 -6
- package/dist/lib/runtime/native/step.js +34 -10
- package/dist/lib/runtime/runtimeFlag.d.ts +13 -5
- package/dist/lib/runtime/runtimeFlag.js +14 -6
- package/dist/lib/runtime/syndicateTurn.d.ts +15 -10
- package/dist/lib/runtime/syndicateTurn.js +59 -32
- package/dist/lib/runtime/valueDepth.d.ts +23 -0
- package/dist/lib/runtime/valueDepth.js +41 -0
- package/dist/lib/session/supabaseSessionService.d.ts +1 -1
- package/dist/lib/session/supabaseSessionService.js +1 -1
- package/dist/lib/session/transcript.d.ts +1 -1
- package/dist/lib/session/transcript.js +5 -3
- package/dist/lib/storage/postgres/sessionService.d.ts +1 -1
- package/dist/lib/storage/postgres/sessionService.js +1 -1
- package/dist/lib/syndicateSchema.d.ts +2 -0
- package/dist/lib/syndicateSchema.js +27 -6
- package/dist/lib/toolRegistry.d.ts +12 -1
- package/dist/lib/toolRegistry.js +42 -2
- package/dist/lib/tools/adkTool.d.ts +1 -1
- package/dist/lib/tools/adkTool.js +1 -1
- package/dist/lib/tools/collectionsSearchTool.d.ts +1 -1
- package/dist/lib/tools/collectionsSearchTool.js +1 -1
- package/dist/lib/tools/generateImageTool.d.ts +1 -1
- package/dist/lib/tools/inspectImageTool.d.ts +1 -1
- package/dist/lib/tools/urlContextTool.d.ts +1 -1
- package/dist/lib/tools/urlContextTool.js +1 -1
- package/dist/lib/tools/webExtractTool.d.ts +1 -1
- package/dist/lib/tools/webSearchTool.d.ts +1 -1
- package/dist/lib/tools/webSearchTool.js +1 -1
- package/dist/lib/tools/xApiSearchTool.d.ts +1 -1
- package/dist/lib/tools/xSearchTool.d.ts +1 -1
- package/dist/lib/tools/xSearchTool.js +1 -1
- package/dist/lib/wiki/agentRun.d.ts +1 -1
- package/dist/lib/wiki/agentRun.js +2 -1
- package/dist/lib/workflow/agentNode.d.ts +21 -4
- package/dist/lib/workflow/agentNode.js +96 -5
- package/dist/lib/workflow/graph.d.ts +5 -4
- package/dist/lib/workflow/graph.js +14 -4
- package/dist/lib/workflow/resume.d.ts +10 -9
- package/dist/lib/workflow/resume.js +13 -12
- package/dist/lib/workflow/scheduler.d.ts +10 -7
- package/dist/lib/workflow/scheduler.js +15 -2
- package/dist/lib/workflow.d.ts +33 -11
- package/dist/lib/workflow.js +49 -27
- package/dist/lib/workflowConfig.d.ts +4 -0
- package/dist/lib/workflowConfig.js +4 -0
- package/dist/scripts/doctor.d.ts +3 -1
- package/dist/scripts/doctor.js +4 -2
- package/package.json +6 -3
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/adkPeer.ts — @google/adk as an optional peer (ADR 0102).
|
|
3
|
+
*
|
|
4
|
+
* WHY this file exists:
|
|
5
|
+
* From 0.20.0 the native runtime is the default, and @google/adk is needed
|
|
6
|
+
* only for MELCHIZEDEK_RUNTIME=adk and the features only ADK runs. Until
|
|
7
|
+
* 1.0.0 removes ADK (ADR 0045), the engine's objects still carry an ADK
|
|
8
|
+
* face: the tool registry holds FunctionTools that carry their own Tool,
|
|
9
|
+
* the model shims are BaseLlm classes that carry their contract adapter,
|
|
10
|
+
* and the durable session stores are ADK BaseSessionServices as well as
|
|
11
|
+
* the engine's SessionService. Those classes extend ADK's at load time.
|
|
12
|
+
*
|
|
13
|
+
* This module is the one place the package loads ADK. It tries once, when
|
|
14
|
+
* it is first imported, and every other module takes ADK's values from
|
|
15
|
+
* here, never from '@google/adk' directly (a type-only import is fine):
|
|
16
|
+
* - When ADK is installed, each export below IS ADK's own value, so the
|
|
17
|
+
* ADK runtime, `instanceof` and ADK's registry behave exactly as before.
|
|
18
|
+
* - When it is not, the base classes are stand-ins: they construct as
|
|
19
|
+
* ADK's do (a tool's name, a model's id, a toolset's filter) and carry
|
|
20
|
+
* ADK's own Symbol.for marks, so the engine reads them as it reads ADK's,
|
|
21
|
+
* and every method only ADK calls throws AdkNotInstalledError, which
|
|
22
|
+
* names the package. Everything else (`Runner`, `LlmAgent`, the plugins)
|
|
23
|
+
* is reached through requireAdk(feature), which throws the same error.
|
|
24
|
+
*
|
|
25
|
+
* A package that is installed but fails to load for another reason (a
|
|
26
|
+
* missing dependency of its own, a syntax error) is not "absent": that
|
|
27
|
+
* error is rethrown, so nothing hides a broken install.
|
|
28
|
+
*
|
|
29
|
+
* The load is a top-level await of a dynamic import: an ES module cannot
|
|
30
|
+
* load another synchronously, and the exported classes must exist before
|
|
31
|
+
* any subclass is defined.
|
|
32
|
+
*/
|
|
33
|
+
/** The package this module loads. */
|
|
34
|
+
export const ADK_PACKAGE = '@google/adk';
|
|
35
|
+
/** Whether `err` says the package itself could not be found (and not a module it imports). */
|
|
36
|
+
function isMissingPackage(err) {
|
|
37
|
+
const e = err;
|
|
38
|
+
if (!e || typeof e !== 'object')
|
|
39
|
+
return false;
|
|
40
|
+
if (e.code !== 'ERR_MODULE_NOT_FOUND' && e.code !== 'MODULE_NOT_FOUND')
|
|
41
|
+
return false;
|
|
42
|
+
return typeof e.message === 'string' && e.message.includes(`'${ADK_PACKAGE}'`);
|
|
43
|
+
}
|
|
44
|
+
let loaded;
|
|
45
|
+
try {
|
|
46
|
+
loaded = await import('@google/adk');
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
if (!isMissingPackage(err))
|
|
50
|
+
throw err;
|
|
51
|
+
}
|
|
52
|
+
/** ADK's module when it is installed, else undefined. */
|
|
53
|
+
export const adk = loaded;
|
|
54
|
+
/** Whether @google/adk is installed and loaded. */
|
|
55
|
+
export function adkInstalled() {
|
|
56
|
+
return loaded !== undefined;
|
|
57
|
+
}
|
|
58
|
+
/** The installed @google/adk version, read from its package.json, or undefined when it is not installed. */
|
|
59
|
+
export async function adkVersion() {
|
|
60
|
+
if (!loaded)
|
|
61
|
+
return undefined;
|
|
62
|
+
try {
|
|
63
|
+
const { createRequire } = await import('node:module');
|
|
64
|
+
const require = createRequire(import.meta.url);
|
|
65
|
+
const fs = await import('node:fs');
|
|
66
|
+
const path = await import('node:path');
|
|
67
|
+
// The package's exports map hides package.json, so walk up from its entry.
|
|
68
|
+
let dir = path.dirname(require.resolve(ADK_PACKAGE));
|
|
69
|
+
for (let i = 0; i < 6; i++) {
|
|
70
|
+
const file = path.join(dir, 'package.json');
|
|
71
|
+
if (fs.existsSync(file)) {
|
|
72
|
+
const pkg = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
73
|
+
if (pkg.name === ADK_PACKAGE)
|
|
74
|
+
return pkg.version;
|
|
75
|
+
}
|
|
76
|
+
dir = path.dirname(dir);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
// Unreadable: the version is unknown, not the package absent.
|
|
81
|
+
}
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
/** A feature only ADK runs was used without @google/adk installed. */
|
|
85
|
+
export class AdkNotInstalledError extends Error {
|
|
86
|
+
feature;
|
|
87
|
+
constructor(feature) {
|
|
88
|
+
super(`${feature} needs ${ADK_PACKAGE}, which is not installed. ` +
|
|
89
|
+
`Install it beside melchizedek-agents (npm install ${ADK_PACKAGE}@~2.2.0), ` +
|
|
90
|
+
`or run on the native runtime (the default; unset MELCHIZEDEK_RUNTIME or set it to native).`);
|
|
91
|
+
this.name = 'AdkNotInstalledError';
|
|
92
|
+
this.feature = feature;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/** ADK's module, or AdkNotInstalledError naming `feature` when it is not installed. */
|
|
96
|
+
export function requireAdk(feature) {
|
|
97
|
+
if (!loaded)
|
|
98
|
+
throw new AdkNotInstalledError(feature);
|
|
99
|
+
return loaded;
|
|
100
|
+
}
|
|
101
|
+
// ── Stand-ins for ADK's base classes ─────────────────────────────────────────
|
|
102
|
+
//
|
|
103
|
+
// Each matches the ADK constructor's effect on the instance and ADK's
|
|
104
|
+
// Symbol.for mark, nothing more. They exist only when ADK is not installed.
|
|
105
|
+
const BASE_TOOL = Symbol.for('google.adk.baseTool');
|
|
106
|
+
const IN_MODEL_TOOL = Symbol.for('google.adk.inModelTool');
|
|
107
|
+
const FUNCTION_TOOL = Symbol.for('google.adk.functionTool');
|
|
108
|
+
const BASE_TOOLSET = Symbol.for('google.adk.baseToolset');
|
|
109
|
+
const BASE_MODEL = Symbol.for('google.adk.baseModel');
|
|
110
|
+
const GEMINI_MODEL = Symbol.for('google.adk.geminiModel');
|
|
111
|
+
function adkOnly(what) {
|
|
112
|
+
throw new AdkNotInstalledError(what);
|
|
113
|
+
}
|
|
114
|
+
class MissingBaseTool {
|
|
115
|
+
[BASE_TOOL] = true;
|
|
116
|
+
name;
|
|
117
|
+
description;
|
|
118
|
+
isLongRunning;
|
|
119
|
+
constructor(params) {
|
|
120
|
+
this.name = params.name;
|
|
121
|
+
this.description = params.description;
|
|
122
|
+
this.isLongRunning = params.isLongRunning ?? false;
|
|
123
|
+
}
|
|
124
|
+
_getDeclaration() {
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
async checkRequireConfirmation() {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
async processLlmRequest(_request) {
|
|
131
|
+
adkOnly(`The ADK face of the tool '${this.name}'`);
|
|
132
|
+
}
|
|
133
|
+
async runAsync(_request) {
|
|
134
|
+
return adkOnly(`The ADK face of the tool '${this.name}'`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
class MissingFunctionTool extends MissingBaseTool {
|
|
138
|
+
[FUNCTION_TOOL] = true;
|
|
139
|
+
execute;
|
|
140
|
+
parameters;
|
|
141
|
+
requireConfirmation;
|
|
142
|
+
constructor(options) {
|
|
143
|
+
const name = options.name ?? options.execute.name;
|
|
144
|
+
if (!name)
|
|
145
|
+
throw new Error('Tool name cannot be empty. Either name the `execute` function or provide a `name`.');
|
|
146
|
+
super({ name, description: options.description, isLongRunning: options.isLongRunning });
|
|
147
|
+
this.execute = options.execute;
|
|
148
|
+
this.parameters = options.parameters;
|
|
149
|
+
this.requireConfirmation = options.requireConfirmation ?? false;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
class MissingBaseToolset {
|
|
153
|
+
[BASE_TOOLSET] = true;
|
|
154
|
+
toolFilter;
|
|
155
|
+
prefix;
|
|
156
|
+
constructor(toolFilter, prefix) {
|
|
157
|
+
this.toolFilter = toolFilter;
|
|
158
|
+
this.prefix = prefix;
|
|
159
|
+
}
|
|
160
|
+
async getTools() {
|
|
161
|
+
return adkOnly('An ADK toolset');
|
|
162
|
+
}
|
|
163
|
+
async close() { }
|
|
164
|
+
}
|
|
165
|
+
class MissingBaseLlm {
|
|
166
|
+
[BASE_MODEL] = true;
|
|
167
|
+
model;
|
|
168
|
+
static supportedModels = [];
|
|
169
|
+
constructor({ model }) {
|
|
170
|
+
this.model = model;
|
|
171
|
+
}
|
|
172
|
+
generateContentAsync() {
|
|
173
|
+
return adkOnly(`The ADK face of the model '${this.model}'`);
|
|
174
|
+
}
|
|
175
|
+
async connect() {
|
|
176
|
+
return adkOnly(`The ADK face of the model '${this.model}'`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* ADK's Gemini, absent: it holds what a caller gave it (the model, a key,
|
|
181
|
+
* Vertex AI's settings), as ADK's does, so the native runtime reads it as it
|
|
182
|
+
* reads TracedGemini (lib/compileNative.ts). Calling it throws.
|
|
183
|
+
*/
|
|
184
|
+
class MissingGemini extends MissingBaseLlm {
|
|
185
|
+
[GEMINI_MODEL] = true;
|
|
186
|
+
apiKey;
|
|
187
|
+
vertexai;
|
|
188
|
+
project;
|
|
189
|
+
location;
|
|
190
|
+
headers;
|
|
191
|
+
constructor(params) {
|
|
192
|
+
super({ model: params.model ?? 'gemini-2.5-flash' });
|
|
193
|
+
if (params.apiKey !== undefined)
|
|
194
|
+
this.apiKey = params.apiKey;
|
|
195
|
+
if (params.vertexai !== undefined)
|
|
196
|
+
this.vertexai = params.vertexai;
|
|
197
|
+
if (params.project !== undefined)
|
|
198
|
+
this.project = params.project;
|
|
199
|
+
if (params.location !== undefined)
|
|
200
|
+
this.location = params.location;
|
|
201
|
+
if (params.headers !== undefined)
|
|
202
|
+
this.headers = params.headers;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* ADK's session service base, absent. A store that extends it is still the
|
|
207
|
+
* engine's SessionService; only the ADK face (the base's appendEvent, which
|
|
208
|
+
* ADK's Runner reaches) needs ADK.
|
|
209
|
+
*/
|
|
210
|
+
class MissingBaseSessionService {
|
|
211
|
+
async appendEvent(_request) {
|
|
212
|
+
return adkOnly('The ADK face of a session store');
|
|
213
|
+
}
|
|
214
|
+
/** ADK's own: the session when it exists, else a new one, through the store's methods. */
|
|
215
|
+
async getOrCreateSession(request) {
|
|
216
|
+
const self = this;
|
|
217
|
+
if (!request.sessionId)
|
|
218
|
+
return self.createSession(request);
|
|
219
|
+
const session = await self.getSession({ appName: request.appName, userId: request.userId, sessionId: request.sessionId });
|
|
220
|
+
return session ?? self.createSession(request);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
/** ADK's GOOGLE_SEARCH, absent: an in-model tool named google_search, which the engine reads by ADK's mark. */
|
|
224
|
+
class MissingGoogleSearchTool extends MissingBaseTool {
|
|
225
|
+
[IN_MODEL_TOOL] = true;
|
|
226
|
+
constructor() {
|
|
227
|
+
super({ name: 'google_search', description: 'Google Search Tool' });
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
// ── The values every other module imports ────────────────────────────────────
|
|
231
|
+
//
|
|
232
|
+
// A type of the same name sits beside each value, so `import { BaseTool }`
|
|
233
|
+
// from here serves as both, as it did from '@google/adk'.
|
|
234
|
+
export const BaseTool = loaded?.BaseTool ?? MissingBaseTool;
|
|
235
|
+
export const FunctionTool = loaded?.FunctionTool ?? MissingFunctionTool;
|
|
236
|
+
export const BaseToolset = loaded?.BaseToolset ?? MissingBaseToolset;
|
|
237
|
+
export const BaseLlm = loaded?.BaseLlm ?? MissingBaseLlm;
|
|
238
|
+
export const Gemini = loaded?.Gemini ?? MissingGemini;
|
|
239
|
+
export const BaseSessionService = loaded?.BaseSessionService ?? MissingBaseSessionService;
|
|
240
|
+
export const GOOGLE_SEARCH = loaded?.GOOGLE_SEARCH ?? new MissingGoogleSearchTool();
|
package/dist/lib/compile.d.ts
CHANGED
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
* the native loop's NativeAgent (ADR 0045). runSyndicateTurn picks one by
|
|
38
38
|
* MELCHIZEDEK_RUNTIME or its `runtime` option.
|
|
39
39
|
*/
|
|
40
|
-
import { BaseLlm, FunctionTool } from '
|
|
40
|
+
import { BaseLlm, FunctionTool } from './adkPeer.ts';
|
|
41
41
|
import type { BaseTool, LlmAgent } from '@google/adk';
|
|
42
42
|
import type { ReasoningSetting, SubagentYamlConfig, SyndicateYamlConfig } from './loadSyndicate.ts';
|
|
43
43
|
import type { ExampleConfig } from './tools/examples.ts';
|
|
@@ -122,7 +122,9 @@ export declare function agentGates(agent: {
|
|
|
122
122
|
* period an ADK object that carries its own Tool or InstructionTool
|
|
123
123
|
* (lib/tools/adkTool.ts), an MCP tool or the skills toolset, gated by
|
|
124
124
|
* require_approval where the YAML says so. `agent` is a delegated subagent
|
|
125
|
-
* (DELEGATE mode), `remote` a subagent served over A2A
|
|
125
|
+
* (DELEGATE mode), `remote` a subagent served over A2A, `workflow` a
|
|
126
|
+
* `yaml_reference` to a workflow syndicate, whose whole graph is the tool
|
|
127
|
+
* (ADR 0098).
|
|
126
128
|
*/
|
|
127
129
|
export type SpecTool = {
|
|
128
130
|
kind: 'tool';
|
|
@@ -135,7 +137,32 @@ export type SpecTool = {
|
|
|
135
137
|
name: string;
|
|
136
138
|
description: string;
|
|
137
139
|
url: string;
|
|
140
|
+
} | {
|
|
141
|
+
kind: 'workflow';
|
|
142
|
+
workflow: WorkflowSpec;
|
|
138
143
|
};
|
|
144
|
+
/**
|
|
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.
|
|
150
|
+
*/
|
|
151
|
+
export interface WorkflowSpec {
|
|
152
|
+
/** The workflow's name: the syndicate's, or the subagent entry's when nested. */
|
|
153
|
+
name: string;
|
|
154
|
+
/** The tool's description when nested; '' at the root. */
|
|
155
|
+
description: string;
|
|
156
|
+
/** The syndicate, its `syndicate_name` set to `name`. */
|
|
157
|
+
config: SyndicateYamlConfig;
|
|
158
|
+
/** Every agent of the graph, the orchestrator first, as compileSubagentSpec builds it, with its YAML entry. */
|
|
159
|
+
agents: Array<{
|
|
160
|
+
yaml: SubagentYamlConfig;
|
|
161
|
+
spec: AgentSpec;
|
|
162
|
+
}>;
|
|
163
|
+
/** The registry entry for a tool node's tool name, or undefined (CompileOptions.onUnknownTool applies). */
|
|
164
|
+
resolveTool: (name: string) => unknown;
|
|
165
|
+
}
|
|
139
166
|
/**
|
|
140
167
|
* One YAML agent, compiled, for either runtime: what lib/compileAdk.ts
|
|
141
168
|
* turns into ADK's LlmAgent and lib/compileNative.ts into the native loop's
|
|
@@ -174,6 +201,17 @@ export interface AgentSpec {
|
|
|
174
201
|
/** `mode: task`. */
|
|
175
202
|
mode?: 'task';
|
|
176
203
|
}
|
|
204
|
+
/**
|
|
205
|
+
* The spec of a workflow syndicate: every agent through compileSubagentSpec
|
|
206
|
+
* (the orchestrator first, as a node like any other), and the registry's
|
|
207
|
+
* lookup for its tool nodes. `name` and `description` name a nested one
|
|
208
|
+
* after its subagent entry (ADR 0098); `ref` is the file it came from.
|
|
209
|
+
*
|
|
210
|
+
* A nested workflow runs inside its caller's tool call, so a pause inside it
|
|
211
|
+
* 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.
|
|
213
|
+
*/
|
|
214
|
+
export declare function compileWorkflowSpec(config: SyndicateYamlConfig, opts?: CompileOptions, name?: string, description?: string, ref?: string): Promise<WorkflowSpec>;
|
|
177
215
|
/**
|
|
178
216
|
* The spec of ONE agent from a subagent entry. A `yaml_reference` entry is
|
|
179
217
|
* the nested syndicate's whole graph under this entry's name and
|
package/dist/lib/compile.js
CHANGED
|
@@ -37,10 +37,11 @@
|
|
|
37
37
|
* the native loop's NativeAgent (ADR 0045). runSyndicateTurn picks one by
|
|
38
38
|
* MELCHIZEDEK_RUNTIME or its `runtime` option.
|
|
39
39
|
*/
|
|
40
|
-
import { BaseLlm, FunctionTool } from '
|
|
40
|
+
import { BaseLlm, FunctionTool } from './adkPeer.js';
|
|
41
41
|
import { relative } from 'node:path';
|
|
42
42
|
import { compileAdk } from './compileAdk.js';
|
|
43
43
|
import { isDispatchSyndicate } from './dispatch.js';
|
|
44
|
+
import { isWorkflowSyndicate, nodeKind } from './workflowConfig.js';
|
|
44
45
|
import { loadSyndicate, nestedLoader } from './loadSyndicate.js';
|
|
45
46
|
import { REASONING_OLDER_SPELLING } from './syndicateSchema.js';
|
|
46
47
|
import { reasoningConfig } from './models/reasoning.js';
|
|
@@ -278,6 +279,71 @@ function specOf(yaml, name, description, instruction, tools, opts) {
|
|
|
278
279
|
return spec;
|
|
279
280
|
}
|
|
280
281
|
const asTools = (tools) => tools.map((tool) => ({ kind: 'tool', tool }));
|
|
282
|
+
/**
|
|
283
|
+
* A nested `yaml_reference:` syndicate, loaded. A nested syndicate runs
|
|
284
|
+
* inside a tool call (or as a route whose own subagents do): a pause there
|
|
285
|
+
* cannot reach the caller (ADR 0028), so one that declares approval gates is
|
|
286
|
+
* refused.
|
|
287
|
+
*/
|
|
288
|
+
/** Where the yaml_reference chain a compile is inside is kept: an own symbol on the options, so a spread copy keeps it. */
|
|
289
|
+
const NESTING = Symbol('melchizedek.compile.nesting');
|
|
290
|
+
/** The deepest a yaml_reference chain may go: well past any syndicate the engine ships, short of the stack. */
|
|
291
|
+
const MAX_NESTING_DEPTH = 16;
|
|
292
|
+
/**
|
|
293
|
+
* The options a nested `ref` compiles with: `opts` and the chain of
|
|
294
|
+
* references above it. A reference already on the chain (a syndicate that
|
|
295
|
+
* reaches itself) or a chain past MAX_NESTING_DEPTH is refused by name (WS5-5,
|
|
296
|
+
* ADR 0101): the compile would otherwise recurse until the stack gave out,
|
|
297
|
+
* which took the process with it.
|
|
298
|
+
*/
|
|
299
|
+
function nestedOptions(ref, opts) {
|
|
300
|
+
const chain = (opts[NESTING] ?? []);
|
|
301
|
+
if (chain.includes(ref))
|
|
302
|
+
throw new Error(`${ref}: a nested syndicate reaches itself (${[...chain, ref].join(' → ')}); a yaml_reference chain must end.`);
|
|
303
|
+
if (chain.length >= MAX_NESTING_DEPTH)
|
|
304
|
+
throw new Error(`${ref}: nested syndicates go deeper than ${MAX_NESTING_DEPTH} levels (${[...chain, ref].join(' → ')}).`);
|
|
305
|
+
return { ...opts, [NESTING]: [...chain, ref] };
|
|
306
|
+
}
|
|
307
|
+
function loadNestedSyndicate(ref, opts) {
|
|
308
|
+
opts.log?.(`Loading nested syndicate: ${ref}`);
|
|
309
|
+
const nested = (opts.loadNested ?? loadSyndicate)(ref);
|
|
310
|
+
if (declaresApprovals(nested)) {
|
|
311
|
+
throw new Error(`${ref}: approval gates (require_approval) are not supported inside a nested syndicate.`);
|
|
312
|
+
}
|
|
313
|
+
return nested;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* The spec of a workflow syndicate: every agent through compileSubagentSpec
|
|
317
|
+
* (the orchestrator first, as a node like any other), and the registry's
|
|
318
|
+
* lookup for its tool nodes. `name` and `description` name a nested one
|
|
319
|
+
* after its subagent entry (ADR 0098); `ref` is the file it came from.
|
|
320
|
+
*
|
|
321
|
+
* A nested workflow runs inside its caller's tool call, so a pause inside it
|
|
322
|
+
* 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.
|
|
324
|
+
*/
|
|
325
|
+
export async function compileWorkflowSpec(config, opts = {}, name, description, ref) {
|
|
326
|
+
if (!isWorkflowSyndicate(config))
|
|
327
|
+
throw new Error(`${config.syndicate_name}: no workflow block`);
|
|
328
|
+
if (name) {
|
|
329
|
+
const asking = Object.entries(config.workflow.nodes ?? {}).find(([, node]) => nodeKind(node) === 'ask_user');
|
|
330
|
+
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.`);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
const workflowName = name || config.syndicate_name;
|
|
335
|
+
const agents = [];
|
|
336
|
+
for (const yaml of [{ description: '', ...config.orchestrator }, ...(config.subagents ?? [])]) {
|
|
337
|
+
agents.push({ yaml, spec: await compileSubagentSpec(yaml, opts) });
|
|
338
|
+
}
|
|
339
|
+
return {
|
|
340
|
+
name: workflowName,
|
|
341
|
+
description: description ?? '',
|
|
342
|
+
config: { ...config, syndicate_name: workflowName },
|
|
343
|
+
agents,
|
|
344
|
+
resolveTool: (tool) => resolveNamedTools([tool], opts.onUnknownTool)[0],
|
|
345
|
+
};
|
|
346
|
+
}
|
|
281
347
|
/**
|
|
282
348
|
* The spec of ONE agent from a subagent entry. A `yaml_reference` entry is
|
|
283
349
|
* the nested syndicate's whole graph under this entry's name and
|
|
@@ -291,14 +357,8 @@ export async function compileSubagentSpec(subCfg, opts = {}) {
|
|
|
291
357
|
throw new Error(`'${subCfg.name}' is a remote A2A agent (a2a_agent_url) and has no local agent to compile.`);
|
|
292
358
|
}
|
|
293
359
|
if (subCfg.yaml_reference) {
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
if (declaresApprovals(nested)) {
|
|
297
|
-
// A nested syndicate runs inside a tool call (or as a route whose
|
|
298
|
-
// own subagents do): a pause there cannot reach the caller (ADR 0028).
|
|
299
|
-
throw new Error(`${subCfg.yaml_reference}: approval gates (require_approval) are not supported inside a nested syndicate.`);
|
|
300
|
-
}
|
|
301
|
-
return compileSpec(nested, opts, subCfg.name, subCfg.description);
|
|
360
|
+
const nestedOpts = nestedOptions(subCfg.yaml_reference, opts);
|
|
361
|
+
return compileSpec(loadNestedSyndicate(subCfg.yaml_reference, nestedOpts), nestedOpts, subCfg.name, subCfg.description);
|
|
302
362
|
}
|
|
303
363
|
const gated = gateTools(await resolveAgentTools(subCfg.tools, subCfg.mcp_server_url, opts, subCfg.openapi, subCfg.examples, subCfg.mcp_tools), subCfg.require_approval, subCfg.name);
|
|
304
364
|
const { instruction, tools } = await withSkills(subCfg.instruction ?? '', gated, subCfg.skills, subCfg.name, opts);
|
|
@@ -317,13 +377,14 @@ export async function compileSpec(config, opts = {}, overrideName, overrideDescr
|
|
|
317
377
|
if (config.bundled_references && !opts.loadNested)
|
|
318
378
|
opts = { ...opts, loadNested: nestedLoader(config) };
|
|
319
379
|
// A graph has no orchestrator-with-tools shape to build: its agents are
|
|
320
|
-
// nodes (lib/workflow.ts).
|
|
321
|
-
//
|
|
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.
|
|
322
383
|
if (config.workflow && !overrideName) {
|
|
323
384
|
throw new Error(`${config.syndicate_name}: a workflow syndicate is compiled with compileWorkflow (lib/workflow.ts), not compileGraph`);
|
|
324
385
|
}
|
|
325
386
|
if (config.workflow)
|
|
326
|
-
opts.log?.(`${config.syndicate_name}:
|
|
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)`);
|
|
327
388
|
const delegated = isDispatchSyndicate(config)
|
|
328
389
|
? []
|
|
329
390
|
: await Promise.all((config.subagents ?? []).map(async (subCfg) => {
|
|
@@ -331,6 +392,13 @@ export async function compileSpec(config, opts = {}, overrideName, overrideDescr
|
|
|
331
392
|
opts.log?.(`Remote A2A agent: ${subCfg.name} → ${subCfg.a2a_agent_url}`);
|
|
332
393
|
return { kind: 'remote', name: subCfg.name, description: subCfg.description, url: subCfg.a2a_agent_url };
|
|
333
394
|
}
|
|
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
|
+
}
|
|
334
402
|
return { kind: 'agent', agent: await compileSubagentSpec(subCfg, opts) };
|
|
335
403
|
}));
|
|
336
404
|
const name = overrideName || config.orchestrator.name;
|
package/dist/lib/compileAdk.d.ts
CHANGED
|
@@ -8,16 +8,19 @@
|
|
|
8
8
|
* model resolved once and its generateContentConfig built for that model.
|
|
9
9
|
* This file adds what only ADK's LlmAgent takes: the model wrapped in a
|
|
10
10
|
* FallbackLlm for `fallback_model:`, each delegated subagent as an
|
|
11
|
-
* AgentTool (a
|
|
11
|
+
* AgentTool (a nested workflow's whole Workflow too; a remote one as its
|
|
12
|
+
* A2A tool), Gemini's code executor, the
|
|
12
13
|
* context compactor, task mode and a workflow node's settings. Every field
|
|
13
14
|
* reaches LlmAgent as compileGraph and compileSubagent always passed it, so
|
|
14
15
|
* the ADK runtime runs the agent it ran before the split.
|
|
15
16
|
* lib/compileNative.ts builds the native loop's agent from the same spec.
|
|
16
17
|
*
|
|
17
|
-
* Imports from lib/compile.ts are types only
|
|
18
|
-
*
|
|
18
|
+
* Imports from lib/compile.ts are types only. A nested workflow's Workflow
|
|
19
|
+
* comes from lib/workflow.ts (assembleWorkflow, ADR 0098), which imports
|
|
20
|
+
* lib/compile.ts; every use of either is inside a function, so the modules
|
|
21
|
+
* load in any order.
|
|
19
22
|
*/
|
|
20
|
-
import { LlmAgent } from '@google/adk';
|
|
23
|
+
import type { LlmAgent } from '@google/adk';
|
|
21
24
|
import type { AgentSpec, CompileOptions } from './compile.ts';
|
|
22
25
|
import { DEFAULT_KEEP_RECENT_EVENTS } from './runtime/native/compaction.ts';
|
|
23
26
|
/** Events kept verbatim after a compaction summary when `context:` names none: the native compactor's default. */
|
package/dist/lib/compileAdk.js
CHANGED
|
@@ -8,17 +8,21 @@
|
|
|
8
8
|
* model resolved once and its generateContentConfig built for that model.
|
|
9
9
|
* This file adds what only ADK's LlmAgent takes: the model wrapped in a
|
|
10
10
|
* FallbackLlm for `fallback_model:`, each delegated subagent as an
|
|
11
|
-
* AgentTool (a
|
|
11
|
+
* AgentTool (a nested workflow's whole Workflow too; a remote one as its
|
|
12
|
+
* A2A tool), Gemini's code executor, the
|
|
12
13
|
* context compactor, task mode and a workflow node's settings. Every field
|
|
13
14
|
* reaches LlmAgent as compileGraph and compileSubagent always passed it, so
|
|
14
15
|
* the ADK runtime runs the agent it ran before the split.
|
|
15
16
|
* lib/compileNative.ts builds the native loop's agent from the same spec.
|
|
16
17
|
*
|
|
17
|
-
* Imports from lib/compile.ts are types only
|
|
18
|
-
*
|
|
18
|
+
* Imports from lib/compile.ts are types only. A nested workflow's Workflow
|
|
19
|
+
* comes from lib/workflow.ts (assembleWorkflow, ADR 0098), which imports
|
|
20
|
+
* lib/compile.ts; every use of either is inside a function, so the modules
|
|
21
|
+
* load in any order.
|
|
19
22
|
*/
|
|
20
|
-
import {
|
|
23
|
+
import { BaseLlm, adk, requireAdk } from './adkPeer.js';
|
|
21
24
|
import { remoteAgentTool } from './a2a/remoteAgent.js';
|
|
25
|
+
import { assembleWorkflow } from './workflow.js';
|
|
22
26
|
import { FallbackLlm } from './models/fallback.js';
|
|
23
27
|
import { resolveModel as resolveRegistryModel } from './models/registry.js';
|
|
24
28
|
import { onLogLevel } from './runtime/logging.js';
|
|
@@ -27,13 +31,13 @@ import { DEFAULT_KEEP_RECENT_EVENTS } from './runtime/native/compaction.js';
|
|
|
27
31
|
* ADK's logger follows the engine's level (lib/runtime/logging.ts, ADR
|
|
28
32
|
* 0080), so a surface sets one level and never names ADK to quiet it.
|
|
29
33
|
*/
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
info:
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
if (adk) {
|
|
35
|
+
const { LogLevel: Level, setLogLevel } = adk;
|
|
36
|
+
const levels = { debug: Level.DEBUG, info: Level.INFO, warn: Level.WARN, error: Level.ERROR };
|
|
37
|
+
onLogLevel((level) => setLogLevel(levels[level]));
|
|
38
|
+
}
|
|
39
|
+
/** What compileAdk builds needs @google/adk; without it, this names the package (ADR 0102). */
|
|
40
|
+
const FEATURE = 'Compiling an agent for the ADK runtime (MELCHIZEDEK_RUNTIME=adk, compileGraph, compileSubagent)';
|
|
37
41
|
/** Events kept verbatim after a compaction summary when `context:` names none: the native compactor's default. */
|
|
38
42
|
export { DEFAULT_KEEP_RECENT_EVENTS };
|
|
39
43
|
/**
|
|
@@ -66,6 +70,7 @@ function passthroughFields(spec) {
|
|
|
66
70
|
* node, its arguments become the node's output).
|
|
67
71
|
*/
|
|
68
72
|
function executionFields(cfg, opts) {
|
|
73
|
+
const { BuiltInCodeExecutor, LLMRegistry, LlmSummarizer, TokenBasedContextCompactor } = requireAdk(FEATURE);
|
|
69
74
|
const out = {};
|
|
70
75
|
if (cfg.codeExecution === 'gemini')
|
|
71
76
|
out.codeExecutor = new BuiltInCodeExecutor();
|
|
@@ -98,8 +103,9 @@ function withFallback(primary, fallbackId, opts) {
|
|
|
98
103
|
const asLlm = (m) => (m instanceof BaseLlm ? m : resolveRegistryModel(String(m)));
|
|
99
104
|
return new FallbackLlm(asLlm(primary), asLlm(resolve(fallbackId)), opts.log ?? ((m) => console.warn(m)));
|
|
100
105
|
}
|
|
101
|
-
/** The spec's tools as LlmAgent takes them: a delegated subagent as an AgentTool, a remote one as its A2A tool. */
|
|
106
|
+
/** The spec's tools as LlmAgent takes them: a delegated subagent (a nested workflow's Workflow included) as an AgentTool, a remote one as its A2A tool. */
|
|
102
107
|
function adkTools(spec, opts) {
|
|
108
|
+
const { AgentTool } = requireAdk(FEATURE);
|
|
103
109
|
return spec.tools.map((entry) => {
|
|
104
110
|
switch (entry.kind) {
|
|
105
111
|
case 'tool':
|
|
@@ -108,6 +114,9 @@ function adkTools(spec, opts) {
|
|
|
108
114
|
return new AgentTool({ agent: compileAdk(entry.agent, opts) });
|
|
109
115
|
case 'remote':
|
|
110
116
|
return remoteAgentTool({ name: entry.name, description: entry.description, url: entry.url });
|
|
117
|
+
case 'workflow':
|
|
118
|
+
// ADK's AgentTool runs any node its Runner takes, a Workflow included: the whole graph, its last event's text the answer (ADR 0098).
|
|
119
|
+
return new AgentTool({ agent: assembleWorkflow(entry.workflow, opts).workflow });
|
|
111
120
|
}
|
|
112
121
|
});
|
|
113
122
|
}
|
|
@@ -116,6 +125,7 @@ function adkTools(spec, opts) {
|
|
|
116
125
|
* settings (CompileOptions.nodeConfig), which compileSubagent passes.
|
|
117
126
|
*/
|
|
118
127
|
export function compileAdk(spec, opts = {}, extra = {}) {
|
|
128
|
+
const { LlmAgent } = requireAdk(FEATURE);
|
|
119
129
|
const tools = adkTools(spec, opts);
|
|
120
130
|
return new LlmAgent({
|
|
121
131
|
name: spec.name,
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
* runs by shape during the dual period (ADR 0071). A delegated subagent
|
|
17
17
|
* becomes a subagentTool holding its own NativeAgent, which the loop runs as
|
|
18
18
|
* a child loop (lib/runtime/native/delegate.ts, ADR 0074), a nested
|
|
19
|
-
* syndicate as its orchestrator's agent
|
|
19
|
+
* syndicate as its orchestrator's agent, a nested workflow syndicate as a
|
|
20
|
+
* workflowSubagentTool whose call walks the whole graph (ADR 0098); a remote A2A subagent is the own
|
|
20
21
|
* Tool the ADK runtime's FunctionTool wraps (lib/a2a/remoteAgent.ts).
|
|
21
22
|
*
|
|
22
23
|
* EVERY AGENT KEY COMPILES for the native loop: `context:` is handed to
|
|
@@ -38,11 +39,13 @@
|
|
|
38
39
|
* ADK classes are told apart by ADK's own Symbol.for marks, so this file
|
|
39
40
|
* imports nothing from ADK.
|
|
40
41
|
*/
|
|
41
|
-
import type { AgentSpec, CompileOptions } from './compile.ts';
|
|
42
|
+
import type { AgentSpec, CompileOptions, WorkflowSpec } from './compile.ts';
|
|
42
43
|
import type { SubagentYamlConfig, SyndicateYamlConfig } from './loadSyndicate.ts';
|
|
43
44
|
import type { ModelAdapter } from './models/contract.ts';
|
|
45
|
+
import type { WorkflowSubagent } from './runtime/native/delegate.ts';
|
|
44
46
|
import type { NativeAgent } from './runtime/native/request.ts';
|
|
45
47
|
export { UnsupportedOnRuntimeError, unsupportedOnNative } from './runtime/runtimeFlag.ts';
|
|
48
|
+
import type { WorkflowGraph } from './workflow/graph.ts';
|
|
46
49
|
/**
|
|
47
50
|
* The class name of an ADK model the native runtime cannot run, else
|
|
48
51
|
* undefined: an ADK BaseLlm that is neither ADK's Gemini (TracedGemini
|
|
@@ -66,6 +69,29 @@ export declare function compileNative(spec: AgentSpec): NativeAgent;
|
|
|
66
69
|
export declare function wireModelOf(spec: Pick<AgentSpec, 'modelId' | 'resolvedModel'>): string | undefined;
|
|
67
70
|
/** A syndicate's orchestrator for the native loop: compileSpec, then compileNative. */
|
|
68
71
|
export declare function compileNativeGraph(config: SyndicateYamlConfig, opts?: CompileOptions): Promise<NativeAgent>;
|
|
72
|
+
/** A workflow syndicate for the native walk (lib/workflow/turn.ts): its graph, every agent by YAML name, and the tool nodes' lookup. */
|
|
73
|
+
export interface NativeWorkflow {
|
|
74
|
+
name: string;
|
|
75
|
+
description: string;
|
|
76
|
+
graph: WorkflowGraph;
|
|
77
|
+
agents: Map<string, NativeAgent>;
|
|
78
|
+
resolveTool: (name: string) => unknown;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* A workflow spec for the native walk: the graph, every agent compiled for
|
|
82
|
+
* native from the same specs ADK's assembleWorkflow builds its agents from,
|
|
83
|
+
* and the registry's lookup for tool nodes. A tool node ADK's compile
|
|
84
|
+
* refuses (an unregistered or long-running tool) is refused here, before
|
|
85
|
+
* any model call, with ADK's message.
|
|
86
|
+
*/
|
|
87
|
+
export declare function compileNativeWorkflow(spec: WorkflowSpec): NativeWorkflow;
|
|
88
|
+
/**
|
|
89
|
+
* A nested workflow as the delegated subagent the native loop calls (ADR
|
|
90
|
+
* 0098): one call walks the whole graph with runNativeWorkflow on the child
|
|
91
|
+
* session lib/runtime/native/delegate.ts opened, as ADK's AgentTool runs a
|
|
92
|
+
* Workflow on its own Runner.
|
|
93
|
+
*/
|
|
94
|
+
export declare function workflowSubagentOf(workflow: NativeWorkflow): WorkflowSubagent;
|
|
69
95
|
/** One subagent entry (a dispatch route) for the native loop: compileSubagentSpec, then compileNative. */
|
|
70
96
|
export declare function compileNativeSubagent(subCfg: SubagentYamlConfig, opts?: CompileOptions): Promise<NativeAgent>;
|
|
71
97
|
/** What nativeAdapterFor reads from a spec: its model resolution, the other ids it calls, and its delegated subagents. */
|