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.
Files changed (106) hide show
  1. package/CHANGELOG.md +252 -76
  2. package/DOCUMENTATION.md +44 -15
  3. package/QUICKSTART.md +9 -6
  4. package/README.md +6 -9
  5. package/config/agents/syndicateSchema.yaml +3 -0
  6. package/dist/lib/adkPeer.d.ts +63 -0
  7. package/dist/lib/adkPeer.js +240 -0
  8. package/dist/lib/compile.d.ts +40 -2
  9. package/dist/lib/compile.js +80 -12
  10. package/dist/lib/compileAdk.d.ts +7 -4
  11. package/dist/lib/compileAdk.js +22 -12
  12. package/dist/lib/compileNative.d.ts +28 -2
  13. package/dist/lib/compileNative.js +60 -4
  14. package/dist/lib/doctor.d.ts +28 -1
  15. package/dist/lib/doctor.js +63 -2
  16. package/dist/lib/index.d.ts +4 -0
  17. package/dist/lib/index.js +5 -0
  18. package/dist/lib/models/adapterResolver.d.ts +13 -11
  19. package/dist/lib/models/adapterResolver.js +11 -10
  20. package/dist/lib/models/adkGeminiAdapter.js +2 -0
  21. package/dist/lib/models/adkShim.d.ts +1 -1
  22. package/dist/lib/models/adkShim.js +1 -1
  23. package/dist/lib/models/capabilities.js +13 -10
  24. package/dist/lib/models/claudeLlm.js +2 -2
  25. package/dist/lib/models/fallback.d.ts +1 -1
  26. package/dist/lib/models/fallback.js +1 -1
  27. package/dist/lib/models/gatewayLlm.js +2 -2
  28. package/dist/lib/models/geminiAdapter.d.ts +6 -4
  29. package/dist/lib/models/geminiAdapter.js +28 -5
  30. package/dist/lib/models/geminiState.d.ts +21 -0
  31. package/dist/lib/models/geminiState.js +26 -0
  32. package/dist/lib/models/genaiMapping.d.ts +24 -4
  33. package/dist/lib/models/genaiMapping.js +109 -6
  34. package/dist/lib/models/gptLlm.js +2 -2
  35. package/dist/lib/models/grokLlm.js +2 -2
  36. package/dist/lib/models/kimiLlm.js +2 -2
  37. package/dist/lib/models/ollamaLlm.js +2 -2
  38. package/dist/lib/models/registry.d.ts +5 -1
  39. package/dist/lib/models/registry.js +17 -12
  40. package/dist/lib/models/tracedGemini.d.ts +1 -1
  41. package/dist/lib/models/tracedGemini.js +1 -1
  42. package/dist/lib/runtime/adkSessionBridge.d.ts +1 -1
  43. package/dist/lib/runtime/adkSessionBridge.js +1 -1
  44. package/dist/lib/runtime/approvals.d.ts +5 -0
  45. package/dist/lib/runtime/approvals.js +39 -8
  46. package/dist/lib/runtime/credentials.d.ts +3 -1
  47. package/dist/lib/runtime/credentials.js +6 -1
  48. package/dist/lib/runtime/native/agentLoop.d.ts +7 -1
  49. package/dist/lib/runtime/native/agentLoop.js +31 -13
  50. package/dist/lib/runtime/native/delegate.d.ts +53 -0
  51. package/dist/lib/runtime/native/delegate.js +91 -8
  52. package/dist/lib/runtime/native/interrupts.d.ts +6 -3
  53. package/dist/lib/runtime/native/interrupts.js +23 -4
  54. package/dist/lib/runtime/native/request.d.ts +1 -1
  55. package/dist/lib/runtime/native/request.js +1 -1
  56. package/dist/lib/runtime/native/selfCorrection.d.ts +64 -6
  57. package/dist/lib/runtime/native/selfCorrection.js +82 -8
  58. package/dist/lib/runtime/native/step.d.ts +14 -6
  59. package/dist/lib/runtime/native/step.js +34 -10
  60. package/dist/lib/runtime/runtimeFlag.d.ts +13 -5
  61. package/dist/lib/runtime/runtimeFlag.js +14 -6
  62. package/dist/lib/runtime/syndicateTurn.d.ts +15 -10
  63. package/dist/lib/runtime/syndicateTurn.js +59 -32
  64. package/dist/lib/runtime/valueDepth.d.ts +23 -0
  65. package/dist/lib/runtime/valueDepth.js +41 -0
  66. package/dist/lib/session/supabaseSessionService.d.ts +1 -1
  67. package/dist/lib/session/supabaseSessionService.js +1 -1
  68. package/dist/lib/session/transcript.d.ts +1 -1
  69. package/dist/lib/session/transcript.js +5 -3
  70. package/dist/lib/storage/postgres/sessionService.d.ts +1 -1
  71. package/dist/lib/storage/postgres/sessionService.js +1 -1
  72. package/dist/lib/syndicateSchema.d.ts +2 -0
  73. package/dist/lib/syndicateSchema.js +27 -6
  74. package/dist/lib/toolRegistry.d.ts +12 -1
  75. package/dist/lib/toolRegistry.js +42 -2
  76. package/dist/lib/tools/adkTool.d.ts +1 -1
  77. package/dist/lib/tools/adkTool.js +1 -1
  78. package/dist/lib/tools/collectionsSearchTool.d.ts +1 -1
  79. package/dist/lib/tools/collectionsSearchTool.js +1 -1
  80. package/dist/lib/tools/generateImageTool.d.ts +1 -1
  81. package/dist/lib/tools/inspectImageTool.d.ts +1 -1
  82. package/dist/lib/tools/urlContextTool.d.ts +1 -1
  83. package/dist/lib/tools/urlContextTool.js +1 -1
  84. package/dist/lib/tools/webExtractTool.d.ts +1 -1
  85. package/dist/lib/tools/webSearchTool.d.ts +1 -1
  86. package/dist/lib/tools/webSearchTool.js +1 -1
  87. package/dist/lib/tools/xApiSearchTool.d.ts +1 -1
  88. package/dist/lib/tools/xSearchTool.d.ts +1 -1
  89. package/dist/lib/tools/xSearchTool.js +1 -1
  90. package/dist/lib/wiki/agentRun.d.ts +1 -1
  91. package/dist/lib/wiki/agentRun.js +2 -1
  92. package/dist/lib/workflow/agentNode.d.ts +21 -4
  93. package/dist/lib/workflow/agentNode.js +96 -5
  94. package/dist/lib/workflow/graph.d.ts +5 -4
  95. package/dist/lib/workflow/graph.js +14 -4
  96. package/dist/lib/workflow/resume.d.ts +10 -9
  97. package/dist/lib/workflow/resume.js +13 -12
  98. package/dist/lib/workflow/scheduler.d.ts +10 -7
  99. package/dist/lib/workflow/scheduler.js +15 -2
  100. package/dist/lib/workflow.d.ts +33 -11
  101. package/dist/lib/workflow.js +49 -27
  102. package/dist/lib/workflowConfig.d.ts +4 -0
  103. package/dist/lib/workflowConfig.js +4 -0
  104. package/dist/scripts/doctor.d.ts +3 -1
  105. package/dist/scripts/doctor.js +4 -2
  106. package/package.json +6 -3
@@ -0,0 +1,41 @@
1
+ /**
2
+ * lib/runtime/valueDepth.ts — how deeply a JSON value nests, read without
3
+ * recursion (WS5-5, ADR 0101).
4
+ *
5
+ * WHY this file exists:
6
+ * A tool call's arguments come from a model, and a tool's result can come
7
+ * from a remote server (an MCP tool, a fetched API). Both are stored in the
8
+ * session and read again on every later step: cloned for the history,
9
+ * serialized for a durable store and a span. Those readers recurse, so a
10
+ * value nested a few thousand levels deep overflows the stack in each of
11
+ * them, on this turn and on every turn after it: the session stops
12
+ * working. No tool schema the engine knows nests anywhere near
13
+ * MAX_VALUE_DEPTH, so a value past it is malformed, and the runtime keeps
14
+ * a short note in its place (lib/models/genaiMapping.ts contractOutputPart for
15
+ * arguments, lib/runtime/native/agentLoop.ts for results).
16
+ *
17
+ * The check itself walks with an explicit stack, so the value it guards
18
+ * against cannot overflow it.
19
+ */
20
+ /** The deepest a tool call's arguments or a tool's result may nest, in levels of objects and arrays (the value itself is level 1). */
21
+ export const MAX_VALUE_DEPTH = 64;
22
+ /** True when `value` nests objects or arrays more than `max` levels deep. Iterative; a value seen twice (a cycle) is walked once. */
23
+ export function nestedDeeperThan(value, max = MAX_VALUE_DEPTH) {
24
+ if (typeof value !== 'object' || value === null)
25
+ return false;
26
+ const stack = [{ node: value, level: 1 }];
27
+ const seen = new Set();
28
+ while (stack.length > 0) {
29
+ const { node, level } = stack.pop();
30
+ if (level > max)
31
+ return true;
32
+ if (seen.has(node))
33
+ continue;
34
+ seen.add(node);
35
+ for (const child of Object.values(node)) {
36
+ if (typeof child === 'object' && child !== null)
37
+ stack.push({ node: child, level: level + 1 });
38
+ }
39
+ }
40
+ return false;
41
+ }
@@ -25,7 +25,7 @@
25
25
  * - lastUpdateTime is the appended event's timestamp, which is the clock
26
26
  * of the process that made the event, just before the append.
27
27
  */
28
- import { BaseSessionService } from '@google/adk';
28
+ import { BaseSessionService } from '../adkPeer.ts';
29
29
  import type { CreateSessionRequest as AdkCreateSessionRequest, DeleteSessionRequest as AdkDeleteSessionRequest, Event as AdkEvent, GetSessionRequest as AdkGetSessionRequest, ListSessionsRequest as AdkListSessionsRequest, ListSessionsResponse as AdkListSessionsResponse, Session as AdkSession } from '@google/adk';
30
30
  import type { SupabaseClient } from '@supabase/supabase-js';
31
31
  import type { TurnEvent } from '../runtime/events.ts';
@@ -25,7 +25,7 @@
25
25
  * - lastUpdateTime is the appended event's timestamp, which is the clock
26
26
  * of the process that made the event, just before the append.
27
27
  */
28
- import { BaseSessionService } from '@google/adk';
28
+ import { BaseSessionService } from '../adkPeer.js';
29
29
  import { randomUUID } from 'crypto';
30
30
  import { applyEvent, listPage, listWindow, selectEvents, withoutTempKeys } from '../runtime/sessions.js';
31
31
  import { trimEventForStorage } from './transcript.js';
@@ -40,7 +40,7 @@
40
40
  * adapter keeps every event verbatim. Both keep the text whole, which is all
41
41
  * long-term memory ingestion reads.
42
42
  */
43
- import { BaseSessionService } from '@google/adk';
43
+ import { BaseSessionService } from '../adkPeer.ts';
44
44
  import type { CreateSessionRequest, GetSessionRequest, ListSessionsRequest, ListSessionsResponse, DeleteSessionRequest, Session, Event } from '@google/adk';
45
45
  import type { TurnEvent } from '../runtime/events.ts';
46
46
  import type { CreateSessionRequest as EngineCreateSessionRequest, GetSessionOptions, ListSessionsRequest as EngineListSessionsRequest, ListSessionsResult, Session as EngineSession, SessionKey, SessionService } from '../runtime/sessions.ts';
@@ -40,8 +40,8 @@
40
40
  * adapter keeps every event verbatim. Both keep the text whole, which is all
41
41
  * long-term memory ingestion reads.
42
42
  */
43
- import { BaseSessionService } from '@google/adk';
44
- import { AdkSessionServiceForEngine, asAdkSessionService, isAdkSessionService, isSessionService } from '../runtime/adkSessionBridge.js';
43
+ import { BaseSessionService } from '../adkPeer.js';
44
+ import { asAdkSessionService, asSessionService, isAdkSessionService, isSessionService } from '../runtime/adkSessionBridge.js';
45
45
  import { applyEvent } from '../runtime/sessions.js';
46
46
  const DEFAULT_MAX_HISTORY_CHARS = 40_000;
47
47
  const DEFAULT_MAX_HISTORY_TURNS = 16;
@@ -313,7 +313,9 @@ export class ProjectedSessionService extends BaseSessionService {
313
313
  // always was, so the ADK face reaches the same object it did.
314
314
  const engineOnly = isSessionService(inner) && !isAdkSessionService(inner);
315
315
  this.inner = engineOnly ? asAdkSessionService(inner) : inner;
316
- this.own = isSessionService(inner) ? inner : new AdkSessionServiceForEngine(inner);
316
+ // A bridge is unwrapped to the store it wraps, so the engine face of an
317
+ // engine store never goes through ADK's base service (ADR 0102).
318
+ this.own = asSessionService(inner);
317
319
  this.forAgent = forAgent;
318
320
  this.options = options;
319
321
  }
@@ -32,7 +32,7 @@
32
32
  * '<appName>:<userId>:<sessionId>'), so erase and the session prune cover
33
33
  * both. Tables: db/migrations/0001_base.sql and 0003_postgres_storage.sql.
34
34
  */
35
- import { BaseSessionService } from '@google/adk';
35
+ import { BaseSessionService } from '../../adkPeer.ts';
36
36
  import type { CreateSessionRequest as AdkCreateSessionRequest, DeleteSessionRequest as AdkDeleteSessionRequest, Event as AdkEvent, GetSessionRequest as AdkGetSessionRequest, ListSessionsRequest as AdkListSessionsRequest, ListSessionsResponse as AdkListSessionsResponse, Session as AdkSession } from '@google/adk';
37
37
  import type { Pool } from 'pg';
38
38
  import type { TurnEvent } from '../../runtime/events.ts';
@@ -33,7 +33,7 @@
33
33
  * both. Tables: db/migrations/0001_base.sql and 0003_postgres_storage.sql.
34
34
  */
35
35
  import { randomUUID } from 'node:crypto';
36
- import { BaseSessionService } from '@google/adk';
36
+ import { BaseSessionService } from '../../adkPeer.js';
37
37
  import { applyEvent, listPage, listWindow, withoutTempKeys } from '../../runtime/sessions.js';
38
38
  function dbId(appName, userId, sessionId) {
39
39
  return `${appName}:${userId}:${sessionId}`;
@@ -440,6 +440,8 @@ export declare const syndicateSchema: z.ZodObject<{
440
440
  initial_delay: z.ZodOptional<z.ZodNumber>;
441
441
  max_delay: z.ZodOptional<z.ZodNumber>;
442
442
  backoff_factor: z.ZodOptional<z.ZodNumber>;
443
+ jitter: z.ZodOptional<z.ZodNumber>;
444
+ exceptions: z.ZodOptional<z.ZodArray<z.ZodString>>;
443
445
  }, z.core.$strict>>;
444
446
  timeout: z.ZodOptional<z.ZodNumber>;
445
447
  }, z.core.$strict>>>;
@@ -296,12 +296,20 @@ const edgeElement = z.union([
296
296
  .record(z.string().min(1), edgeTargets)
297
297
  .describe('A routing map after a node: `{ <route>: <node or nodes>, default: <node> }`, matched against that node\'s output.'),
298
298
  ]);
299
+ /** An error class name, as ADK matches `exceptions` against one: an identifier. */
300
+ const ERROR_NAME = /^[A-Za-z_$][\w$]*$/;
299
301
  const retrySchema = z
300
302
  .strictObject({
301
303
  max_attempts: z.number().int().positive().optional().describe('Attempts including the first; 1 = no retry. ADK default 5.'),
302
304
  initial_delay: z.number().nonnegative().optional().describe('Seconds before the first retry.'),
303
305
  max_delay: z.number().nonnegative().optional(),
304
306
  backoff_factor: z.number().positive().optional(),
307
+ jitter: z.number().nonnegative().optional().describe('Randomness of the backoff; 0 = none. ADK default 1.'),
308
+ exceptions: z
309
+ .array(z.string().regex(ERROR_NAME, 'an error name, such as TypeError or NodeTimeoutError'))
310
+ .min(1)
311
+ .optional()
312
+ .describe('Error names to retry on (the error\'s class or its `name`); every error when absent.'),
305
313
  })
306
314
  .describe('Retry a node on failure (lib/workflow.ts).');
307
315
  const workflowNodeSchema = z
@@ -313,8 +321,8 @@ const workflowNodeSchema = z
313
321
  max_parallel: z.number().int().positive().optional().describe('Concurrency of map. Default 8.'),
314
322
  tool: z.string().min(1).optional().describe('Run this registry tool with the node input as its arguments.'),
315
323
  route_key: z.string().min(1).optional().describe('Property of a JSON output holding the route. Default "route".'),
316
- retry: retrySchema.optional(),
317
- timeout: z.number().positive().optional().describe('Seconds this node may run before it fails.'),
324
+ retry: retrySchema.optional().describe('Retry this node on failure. Not on a map node: each item runs under its agent\'s own retry.'),
325
+ timeout: z.number().positive().optional().describe('Seconds this node may run before it fails. Not on a map node: each item runs under its agent\'s own timeout.'),
318
326
  })
319
327
  .describe('A declared node (exactly one of ask_user, join, map, tool) or modifiers for an agent node (retry, timeout, route_key).');
320
328
  const workflowSchema = z
@@ -663,11 +671,14 @@ function crossFieldProblems(raw) {
663
671
  questionProblems(raw.orchestrator, ['orchestrator'], true);
664
672
  }
665
673
  const dispatching = isObj(raw.dispatch);
674
+ // A workflow's subagents are its nodes, not delegated tools: a gated call pauses its node, and
675
+ // the walk resumes it (ADR 0098). Skill scripts stay refused inside a workflow (workflowProblems).
676
+ const pausing = dispatching || isObj(raw.workflow);
666
677
  subs.forEach((sub, i) => {
667
678
  if (!isObj(sub))
668
679
  return;
669
- gateProblems(sub, ['subagents', i], dispatching);
670
- skillProblems(sub, ['subagents', i], dispatching);
680
+ gateProblems(sub, ['subagents', i], pausing);
681
+ skillProblems(sub, ['subagents', i], pausing);
671
682
  questionProblems(sub, ['subagents', i], dispatching);
672
683
  const hasRef = typeof sub.yaml_reference === 'string';
673
684
  const hasRemote = typeof sub.a2a_agent_url === 'string';
@@ -783,6 +794,15 @@ function workflowProblems(raw, subs) {
783
794
  if (kind !== 'map' && entry.max_parallel !== undefined) {
784
795
  out.push({ path: ['workflow', 'nodes', name, 'max_parallel'], message: 'max_parallel applies to map only' });
785
796
  }
797
+ // 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.
798
+ if (kind === 'map') {
799
+ for (const key of ['retry', 'timeout']) {
800
+ if (entry[key] === undefined)
801
+ continue;
802
+ const target = entry.map;
803
+ 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}` });
804
+ }
805
+ }
786
806
  }
787
807
  for (const name of agentNames) {
788
808
  if (name.endsWith(ROUTE_STEP_SUFFIX))
@@ -854,8 +874,9 @@ function workflowProblems(raw, subs) {
854
874
  for (const [path, agent] of agents) {
855
875
  if (!isObj(agent))
856
876
  continue;
857
- if (Array.isArray(agent.require_approval) && agent.require_approval.length) {
858
- out.push({ path: [...path, 'require_approval'], message: 'approval gates are not supported inside a workflow yet' });
877
+ // A map item cannot pause: the walk resumes a paused agent node, not an item of a map (ADR 0094, ADR 0098).
878
+ if (typeof agent.name === 'string' && mapped.has(agent.name) && Array.isArray(agent.require_approval) && agent.require_approval.length) {
879
+ 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' });
859
880
  }
860
881
  if (isObj(agent.skills) && agent.skills.scripts === 'local') {
861
882
  out.push({ path: [...path, 'skills', 'scripts'], message: 'skill scripts (an approval pause) are not supported inside a workflow yet' });
@@ -22,6 +22,15 @@
22
22
  * callers can log in their own format.
23
23
  */
24
24
  export declare function resolveTools(toolNames?: string[], onUnknown?: (name: string) => void): any[];
25
+ /**
26
+ * Names the framework itself declares, calls or reads on the wire: the
27
+ * approval, credential and input interrupts, the reflection tool, delegation,
28
+ * structured output and task mode. A consumer's tool under one of them would
29
+ * be mistaken for the framework's own (a forged approval request, a fake
30
+ * transfer), so registerTool refuses them. `ask_user` is the framework's
31
+ * question tool; only that tool may be registered under it.
32
+ */
33
+ export declare const RESERVED_TOOL_NAMES: readonly string[];
25
34
  /**
26
35
  * Make a tool resolvable by name from a syndicate YAML's `tools:` list.
27
36
  *
@@ -34,7 +43,9 @@ export declare function resolveTools(toolNames?: string[], onUnknown?: (name: st
34
43
  * a ready ADK tool. A contract or Tool reaches the ADK runtime through
35
44
  * toFunctionTool, an InstructionTool through toAdkInstructionTool, a
36
45
  * NativeToolMarker as its sentinel (toAdkTool, lib/tools/adkTool.ts).
37
- * Replacing a built-in requires `{ override: true }`.
46
+ * Replacing a built-in requires `{ override: true }`. A reserved framework
47
+ * name (RESERVED_TOOL_NAMES), as the registry name or the tool's own, is
48
+ * refused whatever the options say.
38
49
  */
39
50
  export declare function registerTool(name: string, tool: unknown, options?: {
40
51
  override?: boolean;
@@ -21,7 +21,7 @@ import { inspectImageTool } from './tools/inspectImageTool.js';
21
21
  import { toAdkInstructionTool, toAdkTool, toFunctionTool } from './tools/adkTool.js';
22
22
  import { loadMemoryTool, preloadMemoryTool } from './tools/memoryTools.js';
23
23
  import { COLLECTIONS_SEARCH_MARKER, GOOGLE_SEARCH_MARKER, URL_CONTEXT_MARKER, WEB_SEARCH_MARKER, X_SEARCH_MARKER, } from './tools/nativeTools.js';
24
- import { isInstructionTool, isNativeToolMarker, isTool } from './tools/tool.js';
24
+ import { isInstructionTool, isNativeToolMarker, isTool, toolOf } from './tools/tool.js';
25
25
  import { webExtractTool } from './tools/webExtractTool.js';
26
26
  import { WIKI_AGENT_TOOL_CONTRACTS } from './tools/wikiTools.js';
27
27
  import { SCIENCE_TOOL_CONTRACTS } from './tools/scienceTools.js';
@@ -104,6 +104,40 @@ export function resolveTools(toolNames = [], onUnknown) {
104
104
  })
105
105
  .filter(Boolean);
106
106
  }
107
+ /**
108
+ * Names the framework itself declares, calls or reads on the wire: the
109
+ * approval, credential and input interrupts, the reflection tool, delegation,
110
+ * structured output and task mode. A consumer's tool under one of them would
111
+ * be mistaken for the framework's own (a forged approval request, a fake
112
+ * transfer), so registerTool refuses them. `ask_user` is the framework's
113
+ * question tool; only that tool may be registered under it.
114
+ */
115
+ export const RESERVED_TOOL_NAMES = [
116
+ 'adk_request_confirmation',
117
+ 'adk_request_credential',
118
+ 'adk_request_input',
119
+ 'ask_user',
120
+ 'adk_handle_model_error',
121
+ 'transfer_to_agent',
122
+ 'set_model_response',
123
+ 'finish_task',
124
+ ];
125
+ /** Whether `tool` is the framework's own ask_user (the own Tool, or the registry's wrapper of it). */
126
+ function isFrameworkAskUser(tool) {
127
+ return tool === askUserTool || tool === TOOL_MAP.ask_user || (!!tool && typeof tool === 'object' && toolOf(tool) === askUserTool);
128
+ }
129
+ /** The reserved name `name` or `tool` would take, if any. */
130
+ function reservedNameOf(name, tool) {
131
+ const own = tool && typeof tool === 'object' ? tool.name : undefined;
132
+ for (const candidate of [name, typeof own === 'string' ? own : undefined]) {
133
+ if (!candidate || !RESERVED_TOOL_NAMES.includes(candidate))
134
+ continue;
135
+ if (candidate === 'ask_user' && isFrameworkAskUser(tool))
136
+ continue;
137
+ return candidate;
138
+ }
139
+ return undefined;
140
+ }
107
141
  /**
108
142
  * Make a tool resolvable by name from a syndicate YAML's `tools:` list.
109
143
  *
@@ -116,12 +150,18 @@ export function resolveTools(toolNames = [], onUnknown) {
116
150
  * a ready ADK tool. A contract or Tool reaches the ADK runtime through
117
151
  * toFunctionTool, an InstructionTool through toAdkInstructionTool, a
118
152
  * NativeToolMarker as its sentinel (toAdkTool, lib/tools/adkTool.ts).
119
- * Replacing a built-in requires `{ override: true }`.
153
+ * Replacing a built-in requires `{ override: true }`. A reserved framework
154
+ * name (RESERVED_TOOL_NAMES), as the registry name or the tool's own, is
155
+ * refused whatever the options say.
120
156
  */
121
157
  export function registerTool(name, tool, options = {}) {
122
158
  if (!/^[A-Za-z_][A-Za-z0-9_]{0,63}$/.test(name)) {
123
159
  throw new Error(`registerTool: '${name}' is not a valid tool name`);
124
160
  }
161
+ const reserved = reservedNameOf(name, tool);
162
+ if (reserved) {
163
+ throw new Error(`registerTool: '${reserved}' is reserved by the framework (${RESERVED_TOOL_NAMES.join(', ')}); register the tool under another name`);
164
+ }
125
165
  if (Object.prototype.hasOwnProperty.call(TOOL_MAP, name) && !options.override) {
126
166
  throw new Error(`registerTool: '${name}' is already registered (pass { override: true } to replace it)`);
127
167
  }
@@ -38,7 +38,7 @@
38
38
  *
39
39
  * toAdkTool takes any of these and picks the wrapper.
40
40
  */
41
- import { BaseTool, BaseToolset, FunctionTool } from '@google/adk';
41
+ import { BaseTool, BaseToolset, FunctionTool } from '../adkPeer.ts';
42
42
  import type { InstructionTool, NativeToolMarker, Tool, ToolContext, Toolset } from './tool.ts';
43
43
  import type { ToolContract } from './toolContract.ts';
44
44
  /** The ToolContext for one ADK call; a standalone one outside a run. */
@@ -38,7 +38,7 @@
38
38
  *
39
39
  * toAdkTool takes any of these and picks the wrapper.
40
40
  */
41
- import { BaseTool, BaseToolset, FunctionTool, GOOGLE_SEARCH } from '@google/adk';
41
+ import { BaseTool, BaseToolset, FunctionTool, GOOGLE_SEARCH } from '../adkPeer.js';
42
42
  import { currentTurnSignal } from '../runtime/turnControl.js';
43
43
  import { COLLECTIONS_SEARCH } from './collectionsSearchTool.js';
44
44
  import { OWN_TOOL, createToolContext, isInstructionTool, isNativeToolMarker, isOwnToolset, nativeToolMarkerOf } from './tool.js';
@@ -30,7 +30,7 @@
30
30
  * silent no-op everywhere else (same non-throwing routing contract as
31
31
  * web_search / x_search).
32
32
  */
33
- import { BaseTool } from '@google/adk';
33
+ import { BaseTool } from '../adkPeer.ts';
34
34
  import type { LlmRequest } from '@google/adk';
35
35
  import { NATIVE_TOOL } from './tool.ts';
36
36
  export declare const COLLECTIONS_SEARCH_TOOL_NAME = "collections_search";
@@ -30,7 +30,7 @@
30
30
  * silent no-op everywhere else (same non-throwing routing contract as
31
31
  * web_search / x_search).
32
32
  */
33
- import { BaseTool } from '@google/adk';
33
+ import { BaseTool } from '../adkPeer.js';
34
34
  import { providerForModel } from '../models/providerMap.js';
35
35
  import { COLLECTIONS_SEARCH_MARKER } from './nativeTools.js';
36
36
  import { NATIVE_TOOL, nativeToolMarkerOf } from './tool.js';
@@ -22,4 +22,4 @@ export declare const generateImageContract: import("./toolContract.ts").DefinedT
22
22
  color_palette: z.ZodOptional<z.ZodString>;
23
23
  }, z.core.$strip>, string>;
24
24
  /** ADK surface, ready for the registry. */
25
- export declare const generateImageTool: import("@google/adk").FunctionTool<undefined>;
25
+ export declare const generateImageTool: import("../adkPeer.ts").FunctionTool;
@@ -21,4 +21,4 @@ export declare const inspectImageContract: import("./toolContract.ts").DefinedTo
21
21
  image_path: z.ZodString;
22
22
  }, z.core.$strip>, string>;
23
23
  /** ADK surface, ready for the registry. */
24
- export declare const inspectImageTool: import("@google/adk").FunctionTool<undefined>;
24
+ export declare const inspectImageTool: import("../adkPeer.ts").FunctionTool;
@@ -14,7 +14,7 @@
14
14
  * deployment's network is reachable through it. Page text arrives as model
15
15
  * input; treat it as data, as any fetched page.
16
16
  */
17
- import { BaseTool } from '@google/adk';
17
+ import { BaseTool } from '../adkPeer.ts';
18
18
  import type { LlmRequest } from '@google/adk';
19
19
  import { NATIVE_TOOL } from './tool.ts';
20
20
  export declare const URL_CONTEXT_TOOL_NAME = "url_context";
@@ -14,7 +14,7 @@
14
14
  * deployment's network is reachable through it. Page text arrives as model
15
15
  * input; treat it as data, as any fetched page.
16
16
  */
17
- import { BaseTool } from '@google/adk';
17
+ import { BaseTool } from '../adkPeer.js';
18
18
  import { providerForModel } from '../models/providerMap.js';
19
19
  import { URL_CONTEXT_MARKER } from './nativeTools.js';
20
20
  import { NATIVE_TOOL } from './tool.js';
@@ -70,4 +70,4 @@ export declare const webExtractContract: import("./toolContract.ts").DefinedTool
70
70
  offset: z.ZodOptional<z.ZodNumber>;
71
71
  }, z.core.$strip>, string>;
72
72
  /** ADK surface, ready for the registry. */
73
- export declare const webExtractTool: import("@google/adk").FunctionTool<undefined>;
73
+ export declare const webExtractTool: import("../adkPeer.ts").FunctionTool;
@@ -26,7 +26,7 @@
26
26
  * `google_search` remains available as the Gemini-only ADK tool for
27
27
  * backward compatibility; new YAMLs should declare `web_search`.
28
28
  */
29
- import { BaseTool } from '@google/adk';
29
+ import { BaseTool } from '../adkPeer.ts';
30
30
  import type { LlmRequest } from '@google/adk';
31
31
  import { NATIVE_TOOL } from './tool.ts';
32
32
  export declare const WEB_SEARCH_TOOL_NAME = "web_search";
@@ -26,7 +26,7 @@
26
26
  * `google_search` remains available as the Gemini-only ADK tool for
27
27
  * backward compatibility; new YAMLs should declare `web_search`.
28
28
  */
29
- import { BaseTool } from '@google/adk';
29
+ import { BaseTool } from '../adkPeer.js';
30
30
  import { providerForModel } from '../models/providerMap.js';
31
31
  import { WEB_SEARCH_MARKER } from './nativeTools.js';
32
32
  import { NATIVE_TOOL, nativeToolMarkerOf } from './tool.js';
@@ -191,4 +191,4 @@ export declare const xApiSearchContract: import("./toolContract.ts").DefinedTool
191
191
  read_images: z.ZodOptional<z.ZodBoolean>;
192
192
  }, z.core.$strip>, string>;
193
193
  /** ADK surface, registered under its contract name in lib/toolRegistry.ts. */
194
- export declare const xApiSearchTool: import("@google/adk").FunctionTool<undefined>;
194
+ export declare const xApiSearchTool: import("../adkPeer.ts").FunctionTool;
@@ -33,7 +33,7 @@
33
33
  * malformed dates are dropped, oversize handle lists truncate, and when
34
34
  * both lists are set the allowlist wins.
35
35
  */
36
- import { BaseTool } from '@google/adk';
36
+ import { BaseTool } from '../adkPeer.ts';
37
37
  import type { LlmRequest } from '@google/adk';
38
38
  import { NATIVE_TOOL } from './tool.ts';
39
39
  export declare const X_SEARCH_TOOL_NAME = "x_search";
@@ -33,7 +33,7 @@
33
33
  * malformed dates are dropped, oversize handle lists truncate, and when
34
34
  * both lists are set the allowlist wins.
35
35
  */
36
- import { BaseTool } from '@google/adk';
36
+ import { BaseTool } from '../adkPeer.js';
37
37
  import { providerForModel } from '../models/providerMap.js';
38
38
  import { X_SEARCH_MARKER } from './nativeTools.js';
39
39
  import { NATIVE_TOOL, nativeToolMarkerOf } from './tool.js';
@@ -34,7 +34,7 @@ export interface WikiAgentRun {
34
34
  tools?: FunctionTool[];
35
35
  temperature?: number;
36
36
  maxOutputTokens?: number;
37
- /** The runtime that runs the agent. Default: MELCHIZEDEK_RUNTIME, else adk. */
37
+ /** The runtime that runs the agent. Default: MELCHIZEDEK_RUNTIME, else native. */
38
38
  runtime?: RuntimeName;
39
39
  /** Native runtime only: the leaf adapter for a model id. Default resolveAdapter (lib/models/registry.ts). */
40
40
  adapterFor?: (model: string) => ModelAdapter;
@@ -23,7 +23,7 @@
23
23
  * read the same way.
24
24
  */
25
25
  import { randomUUID } from 'node:crypto';
26
- import { InMemorySessionService, LlmAgent, Runner } from '@google/adk';
26
+ import { requireAdk } from '../adkPeer.js';
27
27
  import { providerForModel, providerKeyPresent, registerAvailableProviders, resolveAdapter, } from '../models/registry.js';
28
28
  import { SelfCorrection } from '../runtime/native/selfCorrection.js';
29
29
  import { runNativeAgent } from '../runtime/nativeTurn.js';
@@ -101,6 +101,7 @@ export async function runWikiAgent(run) {
101
101
  selfCorrection: new SelfCorrection({ model_errors: 0, tool_errors: 0 }),
102
102
  }));
103
103
  }
104
+ const { InMemorySessionService, LlmAgent, Runner } = requireAdk('A wiki agent on the adk runtime (MELCHIZEDEK_RUNTIME=adk)');
104
105
  registerAvailableProviders();
105
106
  const agent = new LlmAgent({
106
107
  name: run.name,
@@ -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 a person
47
- * (an ask_user tool, an approval) is an interrupt, not run here yet.
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,7 +69,7 @@
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: interrupts inside a node (an ask_user tool call, an approval),
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
  */
@@ -102,7 +119,7 @@ export interface AgentNodeContext {
102
119
  * one with no output. Throws NodeStoppedError when the turn stopped it, and
103
120
  * an Error when it paused on a person.
104
121
  */
105
- export declare function runAgentNode(agent: NativeAgent, run: Pick<NodeRun, 'input' | 'path' | 'branch' | 'signal'>, ctx: AgentNodeContext): Promise<NodeResult>;
122
+ export declare function runAgentNode(agent: NativeAgent, run: Pick<NodeRun, 'input' | 'path' | 'branch' | 'signal' | 'resumeInputs' | 'resumedInterruptIds'>, ctx: AgentNodeContext): Promise<NodeResult>;
106
123
  export interface AgentNodeRuntimeOptions extends Omit<AgentNodeContext, 'appendInput'> {
107
124
  /** Every agent of the syndicate, compiled for native, by YAML name. */
108
125
  agents: ReadonlyMap<string, NativeAgent>;