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
|
@@ -43,8 +43,25 @@
|
|
|
43
43
|
* error; a run that ends with one and no output returns it as the
|
|
44
44
|
* run's `error`, and the scheduler fails the attempt with
|
|
45
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
|
|
47
|
-
*
|
|
46
|
+
* ADK's does, and reported once (by the node's own event). A run the turn stopped throws. A run that pauses on
|
|
47
|
+
* an ask_user tool call is refused by name.
|
|
48
|
+
* 8. APPROVALS (ADR 0098). A run that pauses on approval requests (a tool
|
|
49
|
+
* in the agent's `require_approval`) resolves with their ids as the
|
|
50
|
+
* node's interrupts: the node waits and the walk ends paused, as an
|
|
51
|
+
* ask_user node's does. The resumed walk reruns the node with
|
|
52
|
+
* `resumedInterruptIds`: until every request has a decision among the
|
|
53
|
+
* answers (a confirmation, never a plain-text message) it waits again
|
|
54
|
+
* without running, its open requests raised again on one event of the
|
|
55
|
+
* new run (`waitAgain`), so the run after still resumes them; then the
|
|
56
|
+
* agent's run continues instead of starting afresh, unless it already
|
|
57
|
+
* did on an earlier resume, whose stored output is then the node's
|
|
58
|
+
* (`outputAfter`). No input turn is stored, so the person's answer stays the
|
|
59
|
+
* latest user event, and the loop's approval resume
|
|
60
|
+
* (lib/runtime/native/interrupts.ts, ADR 0077) runs or refuses the
|
|
61
|
+
* pinned call before the next model step, which reads the node's turn
|
|
62
|
+
* from its input on. ADK's runLlmAgentAsNode stores the input again and
|
|
63
|
+
* starts the agent afresh, so the pinned call never runs there; ADK
|
|
64
|
+
* turns refuse gates on workflow nodes instead.
|
|
48
65
|
*
|
|
49
66
|
* `agentNodeRuntime` puts it together for the scheduler: a `runNode` for
|
|
50
67
|
* agent nodes and map items, and an `onEvent` that stores the event ADK
|
|
@@ -52,10 +69,11 @@
|
|
|
52
69
|
* (lib/workflow/nodeEvents.ts), so a session the native walk writes holds
|
|
53
70
|
* what ADK's holds, in the same order.
|
|
54
71
|
*
|
|
55
|
-
* NOT HERE:
|
|
72
|
+
* NOT HERE: an ask_user tool call inside a node, a pause inside a map item,
|
|
56
73
|
* tool nodes (lib/workflow/toolNode.ts) and ask_user nodes
|
|
57
74
|
* (lib/workflow/pause.ts). It imports nothing from ADK.
|
|
58
75
|
*/
|
|
76
|
+
import { APPROVAL_REQUEST } from '../runtime/approvals.js';
|
|
59
77
|
import { createTurnEvent, getFunctionCalls } from '../runtime/events.js';
|
|
60
78
|
import { runAgentLoop } from '../runtime/native/agentLoop.js';
|
|
61
79
|
import { predecessorOutputs } from '../runtime/native/request.js';
|
|
@@ -130,12 +148,71 @@ function nodeStamp(agent, run, invocationId, state) {
|
|
|
130
148
|
}
|
|
131
149
|
}
|
|
132
150
|
enrichNodeEvent(event, run, { invocationId });
|
|
151
|
+
// ADK's node runner (consume): an event that raises an interrupt records the node's input for the resume.
|
|
152
|
+
if (event.longRunningToolIds?.length)
|
|
153
|
+
event.actions = { ...event.actions, agentState: { ...(event.actions?.agentState ?? {}), input: run.input } };
|
|
133
154
|
if (event.output !== undefined)
|
|
134
155
|
state.output = event.output;
|
|
135
156
|
if (event.errorCode !== undefined)
|
|
136
157
|
state.reported = { errorCode: event.errorCode, ...(event.errorMessage !== undefined ? { errorMessage: event.errorMessage } : {}) };
|
|
137
158
|
};
|
|
138
159
|
}
|
|
160
|
+
/** Whether `event` carries the approval request `id` (an `adk_request_confirmation` call). */
|
|
161
|
+
function isApprovalRequest(event, id) {
|
|
162
|
+
return !!event && getFunctionCalls(event).some((call) => call.id === id && call.name === APPROVAL_REQUEST);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Whether a resumed walk's answer to an approval request is a decision: a
|
|
166
|
+
* ToolConfirmation (`{ confirmed }`), or ADK's `{ response: <json> }` form.
|
|
167
|
+
* A plain-text message the resume read as the answer is not one, and the
|
|
168
|
+
* node keeps waiting.
|
|
169
|
+
*/
|
|
170
|
+
function isApprovalAnswer(value) {
|
|
171
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value))
|
|
172
|
+
return false;
|
|
173
|
+
const answer = value;
|
|
174
|
+
return typeof answer.confirmed === 'boolean' || typeof answer.response === 'string';
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Rule 8, a node whose decided requests an earlier resume already acted on
|
|
178
|
+
* (another node's approval was the one answered since): the output its run
|
|
179
|
+
* stored after the last of those requests, else undefined. The node does
|
|
180
|
+
* not run again.
|
|
181
|
+
*/
|
|
182
|
+
function outputAfter(events, path, ids) {
|
|
183
|
+
const open = new Set(ids);
|
|
184
|
+
let start = -1;
|
|
185
|
+
events.forEach((event, i) => {
|
|
186
|
+
if (getFunctionCalls(event).some((call) => call.name === APPROVAL_REQUEST && call.id !== undefined && open.has(call.id)))
|
|
187
|
+
start = i;
|
|
188
|
+
});
|
|
189
|
+
if (start === -1)
|
|
190
|
+
return undefined;
|
|
191
|
+
for (let i = events.length - 1; i > start; i--) {
|
|
192
|
+
const event = events[i];
|
|
193
|
+
if (event.nodeInfo?.path === path && event.output !== undefined && !event.partial)
|
|
194
|
+
return event.output;
|
|
195
|
+
}
|
|
196
|
+
return undefined;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Rule 8, a node still waiting: its open requests raised again, as one event
|
|
200
|
+
* of this run (a copy of each request call, stamped as the node's), so the
|
|
201
|
+
* next message's resume finds the walk paused in this invocation as in the
|
|
202
|
+
* one before; nothing runs. Resolves with the ids it waits on.
|
|
203
|
+
*/
|
|
204
|
+
async function waitAgain(agent, run, ctx, waiting) {
|
|
205
|
+
const open = new Set(waiting);
|
|
206
|
+
const calls = ctx.session.events.flatMap((event) => getFunctionCalls(event).filter((call) => call.name === APPROVAL_REQUEST && call.id !== undefined && open.has(call.id)));
|
|
207
|
+
const seen = new Set();
|
|
208
|
+
const parts = calls.filter((call) => !seen.has(call.id) && seen.add(call.id)).map((call) => ({ functionCall: structuredClone(call) }));
|
|
209
|
+
const event = createTurnEvent({ author: agent.name, invocationId: ctx.invocationId, content: { role: 'model', parts } });
|
|
210
|
+
event.longRunningToolIds = [...seen];
|
|
211
|
+
nodeStamp(agent, run, ctx.invocationId, { output: undefined })(event);
|
|
212
|
+
const stored = await (ctx.appendInput ?? ((e) => ctx.sessions.append(ctx.session, e)))(event);
|
|
213
|
+
ctx.onEvent?.(stored);
|
|
214
|
+
return { interruptIds: [...seen] };
|
|
215
|
+
}
|
|
139
216
|
/**
|
|
140
217
|
* Runs `agent` as the node `run` names, on the native loop, and resolves
|
|
141
218
|
* with the node's output, or with the error it reported when it ended on
|
|
@@ -146,7 +223,17 @@ export async function runAgentNode(agent, run, ctx) {
|
|
|
146
223
|
const taskMode = agent.mode === 'task';
|
|
147
224
|
const nodeAgent = asNodeAgent(agent);
|
|
148
225
|
const { session, sessions, invocationId } = ctx;
|
|
149
|
-
|
|
226
|
+
// Rule 8: a node that waited on an approval resumes its own run once every request it raised is answered.
|
|
227
|
+
const resumed = run.resumedInterruptIds ?? [];
|
|
228
|
+
if (resumed.length > 0) {
|
|
229
|
+
const waiting = resumed.filter((id) => !isApprovalAnswer(run.resumeInputs?.[id]));
|
|
230
|
+
if (waiting.length > 0)
|
|
231
|
+
return waitAgain(agent, run, ctx, waiting);
|
|
232
|
+
const finished = outputAfter(ctx.session.events, run.path, resumed);
|
|
233
|
+
if (finished !== undefined)
|
|
234
|
+
return { output: finished };
|
|
235
|
+
}
|
|
236
|
+
if (resumed.length === 0 && !taskMode && run.input !== undefined && run.input !== null) {
|
|
150
237
|
const userEvent = createTurnEvent({ author: 'user', invocationId, branch: run.branch, content: nodeInputContent(run.input) });
|
|
151
238
|
const stored = await (ctx.appendInput ?? ((e) => sessions.append(session, e)))(userEvent);
|
|
152
239
|
ctx.onEvent?.(stored);
|
|
@@ -179,7 +266,11 @@ export async function runAgentNode(agent, run, ctx) {
|
|
|
179
266
|
ctx.onEvent?.(next.value);
|
|
180
267
|
}
|
|
181
268
|
if (end.reason === 'paused') {
|
|
182
|
-
|
|
269
|
+
// Rule 8: an approval request pauses the node, and the walk with it; any other pause (an ask_user call) is refused.
|
|
270
|
+
const pending = end.pending ?? [];
|
|
271
|
+
if (pending.length > 0 && pending.every((id) => isApprovalRequest(end.lastEvent, id)))
|
|
272
|
+
return { interruptIds: [...pending] };
|
|
273
|
+
throw new Error(`Node '${agent.name}' paused on ${pending.join(', ')}: a pause inside an agent node other than an approval does not run on the native runtime yet.`);
|
|
183
274
|
}
|
|
184
275
|
if (end.reason === 'stopped')
|
|
185
276
|
throw new NodeStoppedError(agent.name, end.stop);
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
* 1. The block's cross-field rules — every name an agent or a declared
|
|
20
20
|
* node, `START` opening a chain, a routing map after the node it
|
|
21
21
|
* routes, a declared node exactly one kind, the reserved `__route`
|
|
22
|
-
* suffix, `workflow` without `dispatch`, and
|
|
23
|
-
* node cannot carry yet. Same paths and messages as the schema's
|
|
22
|
+
* suffix, `workflow` without `dispatch`, `retry` and `timeout` refused on
|
|
23
|
+
* a map entry, and the pauses and remotes a node cannot carry yet. Same paths and messages as the schema's
|
|
24
24
|
* (lib/syndicateSchema.ts, `workflowProblems`), thrown together as a
|
|
25
25
|
* `WorkflowGraphError`.
|
|
26
26
|
* 2. The graph's own rules, on the built edges — no empty routing map,
|
|
@@ -74,8 +74,9 @@ export interface MapNode {
|
|
|
74
74
|
/** Concurrency of the map; absent means the runtime's default (8). */
|
|
75
75
|
maxParallel?: number;
|
|
76
76
|
/**
|
|
77
|
-
* The map entry's own modifiers
|
|
78
|
-
*
|
|
77
|
+
* The map entry's own modifiers: always empty, since the schema refuses
|
|
78
|
+
* `retry` and `timeout` on a map entry (ADR 0103). ADK's compile hands
|
|
79
|
+
* neither to its ParallelWorker.
|
|
79
80
|
*/
|
|
80
81
|
settings: GraphNodeSettings;
|
|
81
82
|
/** The mapped agent's own node modifiers (`nodes.<agent>`), which ADK applies to each item's run. */
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
* 1. The block's cross-field rules — every name an agent or a declared
|
|
20
20
|
* node, `START` opening a chain, a routing map after the node it
|
|
21
21
|
* routes, a declared node exactly one kind, the reserved `__route`
|
|
22
|
-
* suffix, `workflow` without `dispatch`, and
|
|
23
|
-
* node cannot carry yet. Same paths and messages as the schema's
|
|
22
|
+
* suffix, `workflow` without `dispatch`, `retry` and `timeout` refused on
|
|
23
|
+
* a map entry, and the pauses and remotes a node cannot carry yet. Same paths and messages as the schema's
|
|
24
24
|
* (lib/syndicateSchema.ts, `workflowProblems`), thrown together as a
|
|
25
25
|
* `WorkflowGraphError`.
|
|
26
26
|
* 2. The graph's own rules, on the built edges — no empty routing map,
|
|
@@ -254,6 +254,15 @@ export function workflowConfigProblems(raw, subs) {
|
|
|
254
254
|
if (kind !== 'map' && entry.max_parallel !== undefined) {
|
|
255
255
|
out.push({ path: ['workflow', 'nodes', name, 'max_parallel'], message: 'max_parallel applies to map only' });
|
|
256
256
|
}
|
|
257
|
+
// A map item runs under its agent's own modifiers, as on ADK (ADR 0089, ADR 0103): the map entry's would be applied by neither runtime.
|
|
258
|
+
if (kind === 'map') {
|
|
259
|
+
for (const key of ['retry', 'timeout']) {
|
|
260
|
+
if (entry[key] === undefined)
|
|
261
|
+
continue;
|
|
262
|
+
const target = entry.map;
|
|
263
|
+
out.push({ path: ['workflow', 'nodes', name, key], message: `${key} on a map node is not applied: each item runs under its agent's own ${key}; set it on nodes.${target}` });
|
|
264
|
+
}
|
|
265
|
+
}
|
|
257
266
|
}
|
|
258
267
|
for (const name of agentNames) {
|
|
259
268
|
if (name.endsWith(ROUTE_STEP_SUFFIX))
|
|
@@ -324,8 +333,9 @@ export function workflowConfigProblems(raw, subs) {
|
|
|
324
333
|
for (const [path, agent] of agents) {
|
|
325
334
|
if (!isObj(agent))
|
|
326
335
|
continue;
|
|
327
|
-
|
|
328
|
-
|
|
336
|
+
// A map item cannot pause: the walk resumes a paused agent node, not an item of a map (ADR 0094, ADR 0098).
|
|
337
|
+
if (typeof agent.name === 'string' && mapped.has(agent.name) && Array.isArray(agent.require_approval) && agent.require_approval.length) {
|
|
338
|
+
out.push({ path: [...path, 'require_approval'], message: 'approval gates are not supported on an agent a map node runs: a map item cannot pause the walk' });
|
|
329
339
|
}
|
|
330
340
|
if (isObj(agent.skills) && agent.skills.scripts === 'local') {
|
|
331
341
|
out.push({ path: [...path, 'skills', 'scripts'], message: 'skill scripts (an approval pause) are not supported inside a workflow yet' });
|
|
@@ -119,13 +119,13 @@ export declare function workflowNodeInput(content: TurnContent | undefined): unk
|
|
|
119
119
|
*/
|
|
120
120
|
export declare function resumeInputsFromPlainText(content: TurnContent | undefined, events: readonly StoredEvent[], invocationId: string): Record<string, unknown>;
|
|
121
121
|
/**
|
|
122
|
-
* A pause the native walk cannot resume: one raised inside an agent node
|
|
123
|
-
* `ask_user` tool call,
|
|
124
|
-
* item. ADK resumes those inside the node (the agent's own
|
|
125
|
-
* ParallelWorker's item); the native agent node
|
|
126
|
-
* (lib/workflow/agentNode.ts), so it cannot pick
|
|
127
|
-
* walk anyway would run the node again from its
|
|
128
|
-
* resume refuses by name instead.
|
|
122
|
+
* A pause the native walk cannot resume: one raised inside an agent node
|
|
123
|
+
* other than an approval (an `ask_user` tool call, a credential request) or
|
|
124
|
+
* inside a map item. ADK resumes those inside the node (the agent's own
|
|
125
|
+
* history, the ParallelWorker's item); the native agent node pauses only on
|
|
126
|
+
* an approval (lib/workflow/agentNode.ts, ADR 0098), so it cannot pick the
|
|
127
|
+
* others up. Resuming the walk anyway would run the node again from its
|
|
128
|
+
* input and ask again, so the resume refuses by name instead.
|
|
129
129
|
*/
|
|
130
130
|
export declare class UnsupportedWorkflowResumeError extends Error {
|
|
131
131
|
/** The node path the pause was raised at. */
|
|
@@ -134,8 +134,9 @@ export declare class UnsupportedWorkflowResumeError extends Error {
|
|
|
134
134
|
}
|
|
135
135
|
/**
|
|
136
136
|
* Throws UnsupportedWorkflowResumeError for the first interrupt in the run's
|
|
137
|
-
* events that is
|
|
138
|
-
* the workflow (the workflow's
|
|
137
|
+
* events that is neither an ask_user node's input request nor an agent
|
|
138
|
+
* node's approval request at a direct child of the workflow (the workflow's
|
|
139
|
+
* own record aside).
|
|
139
140
|
*/
|
|
140
141
|
export declare function assertResumable(runEvents: readonly StoredEvent[], workflowPath: string): void;
|
|
141
142
|
export interface WorkflowResumeRequest {
|
|
@@ -384,27 +384,28 @@ export function resumeInputsFromPlainText(content, events, invocationId) {
|
|
|
384
384
|
}
|
|
385
385
|
// ── What the native walk cannot resume yet ───────────────────────────────────
|
|
386
386
|
/**
|
|
387
|
-
* A pause the native walk cannot resume: one raised inside an agent node
|
|
388
|
-
* `ask_user` tool call,
|
|
389
|
-
* item. ADK resumes those inside the node (the agent's own
|
|
390
|
-
* ParallelWorker's item); the native agent node
|
|
391
|
-
* (lib/workflow/agentNode.ts), so it cannot pick
|
|
392
|
-
* walk anyway would run the node again from its
|
|
393
|
-
* resume refuses by name instead.
|
|
387
|
+
* A pause the native walk cannot resume: one raised inside an agent node
|
|
388
|
+
* other than an approval (an `ask_user` tool call, a credential request) or
|
|
389
|
+
* inside a map item. ADK resumes those inside the node (the agent's own
|
|
390
|
+
* history, the ParallelWorker's item); the native agent node pauses only on
|
|
391
|
+
* an approval (lib/workflow/agentNode.ts, ADR 0098), so it cannot pick the
|
|
392
|
+
* others up. Resuming the walk anyway would run the node again from its
|
|
393
|
+
* input and ask again, so the resume refuses by name instead.
|
|
394
394
|
*/
|
|
395
395
|
export class UnsupportedWorkflowResumeError extends Error {
|
|
396
396
|
/** The node path the pause was raised at. */
|
|
397
397
|
nodePath;
|
|
398
398
|
constructor(nodePath, why) {
|
|
399
|
-
super(`Cannot resume the workflow on the native runtime: the pause at '${nodePath}' was raised ${why}, which only an ask_user node's pause supports here.`);
|
|
399
|
+
super(`Cannot resume the workflow on the native runtime: the pause at '${nodePath}' was raised ${why}, which only an ask_user node's pause or an agent node's approval supports here.`);
|
|
400
400
|
this.name = 'UnsupportedWorkflowResumeError';
|
|
401
401
|
this.nodePath = nodePath;
|
|
402
402
|
}
|
|
403
403
|
}
|
|
404
404
|
/**
|
|
405
405
|
* Throws UnsupportedWorkflowResumeError for the first interrupt in the run's
|
|
406
|
-
* events that is
|
|
407
|
-
* the workflow (the workflow's
|
|
406
|
+
* events that is neither an ask_user node's input request nor an agent
|
|
407
|
+
* node's approval request at a direct child of the workflow (the workflow's
|
|
408
|
+
* own record aside).
|
|
408
409
|
*/
|
|
409
410
|
export function assertResumable(runEvents, workflowPath) {
|
|
410
411
|
for (const event of runEvents) {
|
|
@@ -415,8 +416,8 @@ export function assertResumable(runEvents, workflowPath) {
|
|
|
415
416
|
continue;
|
|
416
417
|
if (directChildName(path, workflowPath) === undefined)
|
|
417
418
|
throw new UnsupportedWorkflowResumeError(path || String(event.author ?? ''), 'inside a nested node (a map item)');
|
|
418
|
-
const
|
|
419
|
-
if (!
|
|
419
|
+
const resumable = partsOf(event).some((p) => p.functionCall?.name === INPUT_REQUEST || p.functionCall?.name === APPROVAL_REQUEST);
|
|
420
|
+
if (!resumable)
|
|
420
421
|
throw new UnsupportedWorkflowResumeError(path, 'inside an agent node');
|
|
421
422
|
}
|
|
422
423
|
}
|
|
@@ -147,6 +147,12 @@ export interface NodeRun {
|
|
|
147
147
|
* Absent in a walk that is not a resume.
|
|
148
148
|
*/
|
|
149
149
|
resumeInputs?: Readonly<Record<string, unknown>>;
|
|
150
|
+
/**
|
|
151
|
+
* The interrupts this node's prior run paused on, when this run resumes it
|
|
152
|
+
* (a resumed walk's first activation of a node that waited). An agent node
|
|
153
|
+
* resumes its own run on them instead of starting afresh (ADR 0098).
|
|
154
|
+
*/
|
|
155
|
+
resumedInterruptIds?: readonly string[];
|
|
150
156
|
}
|
|
151
157
|
/** An error a node reports instead of throwing, as an ADK event's errorCode and errorMessage. */
|
|
152
158
|
export interface ReportedNodeError {
|
|
@@ -361,14 +367,11 @@ export declare const RETRY_DEFAULTS: {
|
|
|
361
367
|
readonly jitter: 1;
|
|
362
368
|
};
|
|
363
369
|
/**
|
|
364
|
-
* A node's retry
|
|
365
|
-
*
|
|
366
|
-
*
|
|
370
|
+
* A node's retry, as the YAML spells it: ADK's fields, `exceptions` (the
|
|
371
|
+
* error names that may be retried, all when absent) and `jitter` (the
|
|
372
|
+
* random spread, default 1) included.
|
|
367
373
|
*/
|
|
368
|
-
export type RetrySettings = RetryYaml
|
|
369
|
-
exceptions?: string[];
|
|
370
|
-
jitter?: number;
|
|
371
|
-
};
|
|
374
|
+
export type RetrySettings = RetryYaml;
|
|
372
375
|
/** The names an error answers to: its class's and its `name`, as ADK matches `exceptions`. */
|
|
373
376
|
export declare function errorNames(error: unknown): string[];
|
|
374
377
|
/** ADK's errorType: the class name, or the assigned name of a plain Error. */
|
|
@@ -292,7 +292,12 @@ export async function runWorkflowGraph(graph, options) {
|
|
|
292
292
|
}
|
|
293
293
|
}
|
|
294
294
|
const resuming = prior !== undefined && prior.interruptIds.size > 0 && prior.input !== undefined;
|
|
295
|
-
|
|
295
|
+
const waited = prior !== undefined && prior.interruptIds.size > 0 && !repeat;
|
|
296
|
+
return {
|
|
297
|
+
...(resuming ? { input: prior.input } : {}),
|
|
298
|
+
resumeInputs: repeat ? {} : resume.resumeInputs,
|
|
299
|
+
...(waited ? { resumedInterruptIds: [...prior.interruptIds] } : {}),
|
|
300
|
+
};
|
|
296
301
|
};
|
|
297
302
|
// Seed: one trigger per START edge, each on its own branch when there are several.
|
|
298
303
|
const startEdges = graph.edges.filter((e) => e.from === START_NODE);
|
|
@@ -329,7 +334,15 @@ export async function runWorkflowGraph(graph, options) {
|
|
|
329
334
|
const path = `${workflowPath}.${name}`;
|
|
330
335
|
const input = start.input !== undefined ? start.input : trigger.input;
|
|
331
336
|
emit({ type: 'node_start', node: name, kind: node.kind, runId, path, branch, input });
|
|
332
|
-
const ctx = {
|
|
337
|
+
const ctx = {
|
|
338
|
+
input,
|
|
339
|
+
runId,
|
|
340
|
+
path,
|
|
341
|
+
branch,
|
|
342
|
+
signal: controller.signal,
|
|
343
|
+
...(start.resumeInputs ? { resumeInputs: start.resumeInputs } : {}),
|
|
344
|
+
...(start.resumedInterruptIds ? { resumedInterruptIds: start.resumedInterruptIds } : {}),
|
|
345
|
+
};
|
|
333
346
|
const traced = { name, kind: node.kind, path, runId, attempts: state.attempts };
|
|
334
347
|
const run = walk.traceNode(traced, () => executeNode(node, ctx, walk, state.attempts)).then((result) => ({ name, result: { ...result, branch } }), (error) => ({ name, error }));
|
|
335
348
|
pending.set(name, run);
|
package/dist/lib/workflow.d.ts
CHANGED
|
@@ -41,18 +41,32 @@
|
|
|
41
41
|
* the wiki), including a `map` node, which ADK would otherwise name after
|
|
42
42
|
* the agent it wraps.
|
|
43
43
|
*
|
|
44
|
+
* ── As a subagent (ADR 0098) ─────────────────────────────────────────────
|
|
45
|
+
* A delegated `yaml_reference` to a workflow syndicate is the whole graph:
|
|
46
|
+
* `assembleWorkflow` builds its Workflow under the subagent entry's name
|
|
47
|
+
* and description, and lib/compileAdk.ts wraps it in ADK's AgentTool, whose
|
|
48
|
+
* answer is the graph's last event's text. A nested workflow with an
|
|
49
|
+
* `ask_user` node is refused by name (lib/compile.ts compileWorkflowSpec): a
|
|
50
|
+
* pause inside a tool call cannot reach the caller (ADR 0028). As a dispatch
|
|
51
|
+
* route or a workflow node, a workflow syndicate is still its orchestrator
|
|
52
|
+
* alone.
|
|
53
|
+
*
|
|
54
|
+
* ── Approval gates (ADR 0098) ────────────────────────────────────────────
|
|
55
|
+
* A tool in a node agent's `require_approval` pauses the node on ADK's
|
|
56
|
+
* `adk_request_confirmation`, and the walk with it. Only the native walk
|
|
57
|
+
* resumes it (lib/workflow/agentNode.ts): ADK's runLlmAgentAsNode reruns the
|
|
58
|
+
* node from its input and never runs the pinned call, so runSyndicateTurn
|
|
59
|
+
* refuses a gated workflow on ADK. The schema refuses a gate on an agent a
|
|
60
|
+
* map runs (an item cannot pause the walk).
|
|
61
|
+
*
|
|
44
62
|
* ── Not in this version ───────────────────────────────────────────────────
|
|
45
|
-
*
|
|
46
|
-
* `a2a_agent_url` subagents are refused inside a workflow by the schema
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* Both are open for a later record. A `Workflow` cannot yet be another
|
|
50
|
-
* agent's subagent (an ADK limit), so `yaml_reference` to a workflow
|
|
51
|
-
* syndicate compiles its orchestrator alone.
|
|
63
|
+
* Skill scripts (`skills.scripts: local`, an approval pause) and remote
|
|
64
|
+
* `a2a_agent_url` subagents are refused inside a workflow by the schema; a
|
|
65
|
+
* remote agent is reachable only as a tool. Both are open for a later
|
|
66
|
+
* record.
|
|
52
67
|
*/
|
|
53
|
-
import { Workflow } from '@google/adk';
|
|
54
|
-
import type {
|
|
55
|
-
import type { CompileOptions } from './compile.ts';
|
|
68
|
+
import type { BaseNode, LlmAgent, Workflow } from '@google/adk';
|
|
69
|
+
import type { CompileOptions, WorkflowSpec } from './compile.ts';
|
|
56
70
|
import type { SyndicateYamlConfig } from './loadSyndicate.ts';
|
|
57
71
|
export * from './workflowConfig.ts';
|
|
58
72
|
export interface CompiledWorkflow {
|
|
@@ -63,10 +77,18 @@ export interface CompiledWorkflow {
|
|
|
63
77
|
nodes: Map<string, BaseNode>;
|
|
64
78
|
}
|
|
65
79
|
/**
|
|
66
|
-
* Compile a workflow syndicate: every agent through `
|
|
80
|
+
* Compile a workflow syndicate: every agent through `compileSubagentSpec` (its
|
|
67
81
|
* tools, skills and MCP server as in any mode), the declared nodes, the
|
|
68
82
|
* hidden route steps, and the edge chains, into one ADK `Workflow` named
|
|
69
83
|
* after the syndicate. Throws on a name the schema let through, a tool that
|
|
70
84
|
* is not registered, or a graph ADK rejects (unreachable node, cycle).
|
|
71
85
|
*/
|
|
72
86
|
export declare function compileWorkflow(config: SyndicateYamlConfig, opts?: CompileOptions, transformAgent?: (agent: LlmAgent) => LlmAgent): Promise<CompiledWorkflow>;
|
|
87
|
+
/**
|
|
88
|
+
* ADK's Workflow from a compiled workflow spec, synchronously: each agent
|
|
89
|
+
* built by compileAdk with its node modifiers (retry, timeout) at
|
|
90
|
+
* construction, then the declared nodes, route steps and edges. A nested
|
|
91
|
+
* workflow (ADR 0098) is this Workflow under its subagent entry's name and
|
|
92
|
+
* description, which lib/compileAdk.ts wraps in ADK's AgentTool.
|
|
93
|
+
*/
|
|
94
|
+
export declare function assembleWorkflow(spec: WorkflowSpec, opts?: CompileOptions, transformAgent?: (agent: LlmAgent) => LlmAgent): CompiledWorkflow;
|
package/dist/lib/workflow.js
CHANGED
|
@@ -41,22 +41,37 @@
|
|
|
41
41
|
* the wiki), including a `map` node, which ADK would otherwise name after
|
|
42
42
|
* the agent it wraps.
|
|
43
43
|
*
|
|
44
|
+
* ── As a subagent (ADR 0098) ─────────────────────────────────────────────
|
|
45
|
+
* A delegated `yaml_reference` to a workflow syndicate is the whole graph:
|
|
46
|
+
* `assembleWorkflow` builds its Workflow under the subagent entry's name
|
|
47
|
+
* and description, and lib/compileAdk.ts wraps it in ADK's AgentTool, whose
|
|
48
|
+
* answer is the graph's last event's text. A nested workflow with an
|
|
49
|
+
* `ask_user` node is refused by name (lib/compile.ts compileWorkflowSpec): a
|
|
50
|
+
* pause inside a tool call cannot reach the caller (ADR 0028). As a dispatch
|
|
51
|
+
* route or a workflow node, a workflow syndicate is still its orchestrator
|
|
52
|
+
* alone.
|
|
53
|
+
*
|
|
54
|
+
* ── Approval gates (ADR 0098) ────────────────────────────────────────────
|
|
55
|
+
* A tool in a node agent's `require_approval` pauses the node on ADK's
|
|
56
|
+
* `adk_request_confirmation`, and the walk with it. Only the native walk
|
|
57
|
+
* resumes it (lib/workflow/agentNode.ts): ADK's runLlmAgentAsNode reruns the
|
|
58
|
+
* node from its input and never runs the pinned call, so runSyndicateTurn
|
|
59
|
+
* refuses a gated workflow on ADK. The schema refuses a gate on an agent a
|
|
60
|
+
* map runs (an item cannot pause the walk).
|
|
61
|
+
*
|
|
44
62
|
* ── Not in this version ───────────────────────────────────────────────────
|
|
45
|
-
*
|
|
46
|
-
* `a2a_agent_url` subagents are refused inside a workflow by the schema
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* Both are open for a later record. A `Workflow` cannot yet be another
|
|
50
|
-
* agent's subagent (an ADK limit), so `yaml_reference` to a workflow
|
|
51
|
-
* syndicate compiles its orchestrator alone.
|
|
63
|
+
* Skill scripts (`skills.scripts: local`, an approval pause) and remote
|
|
64
|
+
* `a2a_agent_url` subagents are refused inside a workflow by the schema; a
|
|
65
|
+
* remote agent is reachable only as a tool. Both are open for a later
|
|
66
|
+
* record.
|
|
52
67
|
*/
|
|
53
|
-
import {
|
|
54
|
-
import {
|
|
55
|
-
import {
|
|
68
|
+
import { requireAdk } from './adkPeer.js';
|
|
69
|
+
import { compileWorkflowSpec } from './compile.js';
|
|
70
|
+
import { compileAdk } from './compileAdk.js';
|
|
56
71
|
import { DEFAULT_ROUTE_KEY, ROUTE_STEP_SUFFIX, START_NAME, isWorkflowSyndicate, nodeKind, nodeSettings, routeOf } from './workflowConfig.js';
|
|
57
72
|
export * from './workflowConfig.js';
|
|
58
73
|
/**
|
|
59
|
-
* Compile a workflow syndicate: every agent through `
|
|
74
|
+
* Compile a workflow syndicate: every agent through `compileSubagentSpec` (its
|
|
60
75
|
* tools, skills and MCP server as in any mode), the declared nodes, the
|
|
61
76
|
* hidden route steps, and the edge chains, into one ADK `Workflow` named
|
|
62
77
|
* after the syndicate. Throws on a name the schema let through, a tool that
|
|
@@ -65,23 +80,29 @@ export * from './workflowConfig.js';
|
|
|
65
80
|
export async function compileWorkflow(config, opts = {}, transformAgent = (a) => a) {
|
|
66
81
|
if (!isWorkflowSyndicate(config))
|
|
67
82
|
throw new Error(`${config.syndicate_name}: no workflow block`);
|
|
83
|
+
return assembleWorkflow(await compileWorkflowSpec(config, opts), opts, transformAgent);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* ADK's Workflow from a compiled workflow spec, synchronously: each agent
|
|
87
|
+
* built by compileAdk with its node modifiers (retry, timeout) at
|
|
88
|
+
* construction, then the declared nodes, route steps and edges. A nested
|
|
89
|
+
* workflow (ADR 0098) is this Workflow under its subagent entry's name and
|
|
90
|
+
* description, which lib/compileAdk.ts wraps in ADK's AgentTool.
|
|
91
|
+
*/
|
|
92
|
+
export function assembleWorkflow(spec, opts = {}, transformAgent = (a) => a) {
|
|
93
|
+
const config = spec.config;
|
|
94
|
+
if (!isWorkflowSyndicate(config))
|
|
95
|
+
throw new Error(`${config.syndicate_name}: no workflow block`);
|
|
96
|
+
// ADK's Workflow is the adk runtime's; the native walk (lib/workflow/turn.ts) needs none of this (ADR 0102).
|
|
97
|
+
const { DEFAULT_ROUTE, FunctionNode, JoinNode, ParallelWorker, RequestInput, ToolNode, Workflow, createEvent } = requireAdk("ADK's Workflow (a workflow syndicate on the adk runtime, compileWorkflow)");
|
|
68
98
|
const wf = config.workflow;
|
|
69
99
|
const nodeYaml = wf.nodes ?? {};
|
|
70
|
-
|
|
71
|
-
agentConfigs.set(config.orchestrator.name, { description: '', ...config.orchestrator });
|
|
72
|
-
for (const sub of config.subagents ?? [])
|
|
73
|
-
agentConfigs.set(sub.name, sub);
|
|
74
|
-
// Agents, with their node modifiers (retry, timeout) at construction.
|
|
75
|
-
const compileOpts = {
|
|
76
|
-
...opts,
|
|
77
|
-
nodeConfig: (name) => {
|
|
78
|
-
const settings = nodeSettings(nodeYaml[name]);
|
|
79
|
-
return Object.keys(settings).length ? settings : undefined;
|
|
80
|
-
},
|
|
81
|
-
};
|
|
100
|
+
// Agents, with their node modifiers (retry, timeout) at construction; not on a nested syndicate's orchestrator.
|
|
82
101
|
const agents = new Map();
|
|
83
|
-
for (const
|
|
84
|
-
|
|
102
|
+
for (const { yaml, spec: agentSpec } of spec.agents) {
|
|
103
|
+
const settings = yaml.yaml_reference ? {} : nodeSettings(nodeYaml[yaml.name]);
|
|
104
|
+
agents.set(yaml.name, transformAgent(compileAdk(agentSpec, opts, settings)));
|
|
105
|
+
}
|
|
85
106
|
// Declared nodes.
|
|
86
107
|
const nodes = new Map(agents);
|
|
87
108
|
for (const [name, entry] of Object.entries(nodeYaml)) {
|
|
@@ -118,7 +139,7 @@ export async function compileWorkflow(config, opts = {}, transformAgent = (a) =>
|
|
|
118
139
|
nodes.set(name, worker);
|
|
119
140
|
}
|
|
120
141
|
else if (kind === 'tool') {
|
|
121
|
-
const
|
|
142
|
+
const tool = spec.resolveTool(entry.tool);
|
|
122
143
|
if (!tool)
|
|
123
144
|
throw new Error(`workflow node '${name}': tool '${entry.tool}' is not registered`);
|
|
124
145
|
nodes.set(name, new ToolNode(tool, { name, ...settings }));
|
|
@@ -172,7 +193,8 @@ export async function compileWorkflow(config, opts = {}, transformAgent = (a) =>
|
|
|
172
193
|
return out;
|
|
173
194
|
});
|
|
174
195
|
const workflow = new Workflow({
|
|
175
|
-
name:
|
|
196
|
+
name: spec.name,
|
|
197
|
+
...(spec.description ? { description: spec.description } : {}),
|
|
176
198
|
edges,
|
|
177
199
|
...(wf.max_concurrency !== undefined ? { maxConcurrency: wf.max_concurrency } : {}),
|
|
178
200
|
});
|
|
@@ -20,6 +20,10 @@ export interface RetryYaml {
|
|
|
20
20
|
initial_delay?: number;
|
|
21
21
|
max_delay?: number;
|
|
22
22
|
backoff_factor?: number;
|
|
23
|
+
/** Randomness of the backoff: 0 none, default 1 (ADK's). */
|
|
24
|
+
jitter?: number;
|
|
25
|
+
/** Error names a failure is retried on (its class's or its `name`); every error when absent. */
|
|
26
|
+
exceptions?: string[];
|
|
23
27
|
}
|
|
24
28
|
/** Per-node settings. A node is an agent (modifiers only) or exactly one of the kinds. */
|
|
25
29
|
export interface WorkflowNodeYaml {
|
|
@@ -42,6 +42,10 @@ export function toRetryConfig(retry) {
|
|
|
42
42
|
out.maxDelay = retry.max_delay;
|
|
43
43
|
if (retry.backoff_factor !== undefined)
|
|
44
44
|
out.backoffFactor = retry.backoff_factor;
|
|
45
|
+
if (retry.jitter !== undefined)
|
|
46
|
+
out.jitter = retry.jitter;
|
|
47
|
+
if (retry.exceptions !== undefined)
|
|
48
|
+
out.exceptions = [...retry.exceptions];
|
|
45
49
|
return out;
|
|
46
50
|
}
|
|
47
51
|
/** The BaseNode fields a node entry's modifiers map to. */
|
package/dist/scripts/doctor.d.ts
CHANGED
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
* examples/), resolves each agent's model to its provider under the current
|
|
7
7
|
* .env, and prints: the provider, whether that path is funded (direct key,
|
|
8
8
|
* gateway stand-in, or local), which declared server-side tools it keeps or
|
|
9
|
-
* drops, and one verdict per syndicate.
|
|
9
|
+
* drops, and one verdict per syndicate. Says first which runtime a turn runs
|
|
10
|
+
* on (MELCHIZEDEK_RUNTIME, else native) and whether @google/adk, needed only
|
|
11
|
+
* for the adk runtime, is installed. Closes with the env vars that would
|
|
10
12
|
* unlock the most, where to get each, and the first command to try.
|
|
11
13
|
*
|
|
12
14
|
* Read-only: never edits .env, never sends a request, never prints a key
|
package/dist/scripts/doctor.js
CHANGED
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
* examples/), resolves each agent's model to its provider under the current
|
|
7
7
|
* .env, and prints: the provider, whether that path is funded (direct key,
|
|
8
8
|
* gateway stand-in, or local), which declared server-side tools it keeps or
|
|
9
|
-
* drops, and one verdict per syndicate.
|
|
9
|
+
* drops, and one verdict per syndicate. Says first which runtime a turn runs
|
|
10
|
+
* on (MELCHIZEDEK_RUNTIME, else native) and whether @google/adk, needed only
|
|
11
|
+
* for the adk runtime, is installed. Closes with the env vars that would
|
|
10
12
|
* unlock the most, where to get each, and the first command to try.
|
|
11
13
|
*
|
|
12
14
|
* Read-only: never edits .env, never sends a request, never prints a key
|
|
@@ -86,5 +88,5 @@ if (json) {
|
|
|
86
88
|
else {
|
|
87
89
|
console.log(renderDoctor(result, { color: !noColor }));
|
|
88
90
|
}
|
|
89
|
-
if (check && result.counts.blocked > 0)
|
|
91
|
+
if (check && (result.counts.blocked > 0 || result.runtime.problem))
|
|
90
92
|
process.exit(1);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "melchizedek-agents",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "A multi-model, multi-agent orchestration framework on Google ADK
|
|
3
|
+
"version": "0.20.0",
|
|
4
|
+
"description": "A multi-model, multi-agent orchestration framework — YAML-defined syndicates on the engine's own agent loop (Google ADK optional until 1.0), Supabase session persistence, pgvector long-term memory. Companion repo to the lyceumagents.com curriculum.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"bugs": {
|
|
13
13
|
"url": "https://github.com/jhwadman/melch-ai/issues"
|
|
14
14
|
},
|
|
15
|
-
"//": "adk + genai are pinned exact in dev: newer genai minors change response part shapes and silently break the chat printer. Bump deliberately, verify a live run, then update the pin. adk itself is
|
|
15
|
+
"//": "adk + genai are pinned exact in dev: newer genai minors change response part shapes and silently break the chat printer. Bump deliberately, verify a live run, then update the pin. adk itself is an OPTIONAL PEER dependency since 0.20.0 (ADR 0102): the native runtime, the default, needs none of it; a consumer on MELCHIZEDEK_RUNTIME=adk installs it, and their app owns the ADK instance so the model registry is a singleton. lib/adkPeer.ts is the one module that loads it. The adk peer range is capped to the tested minor (~2.2.0): a new adk minor can pull a second genai copy, so the range widens only after a release is tested against it.",
|
|
16
16
|
"engines": {
|
|
17
17
|
"node": ">=22.6.0"
|
|
18
18
|
},
|
|
@@ -168,6 +168,9 @@
|
|
|
168
168
|
"@anthropic-ai/bedrock-sdk": {
|
|
169
169
|
"optional": true
|
|
170
170
|
},
|
|
171
|
+
"@google/adk": {
|
|
172
|
+
"optional": true
|
|
173
|
+
},
|
|
171
174
|
"@anthropic-ai/vertex-sdk": {
|
|
172
175
|
"optional": true
|
|
173
176
|
},
|