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
@@ -12,9 +12,14 @@
12
12
  * read differently on the other:
13
13
  *
14
14
  * THE MODEL (`retries.model_errors`, default 2; 0 off):
15
- * - Every request declares the reflection tool, `adk_handle_model_error`,
16
- * after the agent's own tools (the plugin's beforeModelCallback adds it
17
- * to the toolsDict last).
15
+ * - The reflection tool, `adk_handle_model_error`, is one of every step's
16
+ * tools, after the agent's own: the plugin's beforeModelCallback adds it
17
+ * to the request's toolsDict last, and never to its config. Whether the
18
+ * model is told of it depends on the model class ADK hands the request
19
+ * to (ADR 0097): the ADK shim and the engine's own ADK classes declare
20
+ * the toolsDict, so the tool is declared; ADK's own Gemini sends the
21
+ * config alone, so a Gemini model is never told of it. The step asks
22
+ * `declaresReflectionTool` and runs the tool either way.
18
23
  * - Each response is checked (afterModelCallback), partials included. A
19
24
  * response that calls the reflection tool itself, or whose finish reason
20
25
  * is MALFORMED_FUNCTION_CALL, is replaced by a call to the reflection
@@ -22,6 +27,13 @@
22
27
  * the retry's number counted per agent in the run. The loop runs that
23
28
  * call like any other, and the tool answers with reflection guidance.
24
29
  * Any other response resets the agent's count.
30
+ * - ON A GEMINI MODEL the stored reflection call is signed (ADR 0103), where
31
+ * ADK's plugin stores it unsigned: it carries the replaced response's
32
+ * thoughtSignature, or on Gemini 3 Gemini's documented placeholder when
33
+ * the response had none (a MALFORMED_FUNCTION_CALL has no parts). Gemini 3
34
+ * rejects the next request with an unsigned current-turn call (400,
35
+ * "missing a thought_signature"); ADK's runtime still does. This is the
36
+ * one place the native loop stores what ADK would not (reflectionSigning).
25
37
  * - Past the limit the step ends on ADK's error event for a callback that
26
38
  * threw: UNKNOWN_ERROR, and the plugin manager's message.
27
39
  *
@@ -46,6 +58,7 @@
46
58
  * reads responses as.
47
59
  */
48
60
  import { randomUUID } from 'node:crypto';
61
+ import { GEMINI_PROVIDER, PLACEHOLDER_THOUGHT_SIGNATURE } from '../../models/geminiState.js';
49
62
  export const DEFAULT_MODEL_ERROR_RETRIES = 2;
50
63
  export const DEFAULT_TOOL_ERROR_RETRIES = 3;
51
64
  export const ADK_HANDLE_MODEL_ERROR = 'adk_handle_model_error';
@@ -54,6 +67,63 @@ const RESERVED_TOOL_CALL = 'RESERVED_TOOL_CALL';
54
67
  /** The finish reasons the model plugin retries (its onModelErrors default). */
55
68
  const MODEL_ERRORS = ['MALFORMED_FUNCTION_CALL'];
56
69
  const MODEL_PLUGIN = 'reflect_retry_model_plugin';
70
+ // ── Where ADK declares the reflection tool ──────────────────────────────────
71
+ /** Gemini adapters a caller handed over as a contract adapter or behind the ADK shim: on ADK the shim declares the toolsDict. */
72
+ const SHIMMED_GEMINI = new WeakSet();
73
+ /**
74
+ * Marks `adapter` as one the ADK runtime would call through the ADK shim
75
+ * (a resolver's shim or contract adapter, lib/compileNative.ts), not through
76
+ * ADK's own Gemini. Returns it.
77
+ */
78
+ export function servedThroughShim(adapter) {
79
+ SHIMMED_GEMINI.add(adapter);
80
+ return adapter;
81
+ }
82
+ /**
83
+ * Whether the ADK runtime would tell this adapter's model of the reflection
84
+ * tool (ADR 0097). The plugin puts the tool in the toolsDict alone. Every
85
+ * model class the engine hands ADK declares the toolsDict, but ADK's own
86
+ * Gemini (and TracedGemini over it) sends only the request's config, which
87
+ * never holds it. A Gemini adapter stands for ADK's Gemini unless a caller
88
+ * handed it over behind the shim (servedThroughShim).
89
+ */
90
+ export function declaresReflectionTool(adapter) {
91
+ return !standsForAdkGemini(adapter);
92
+ }
93
+ /**
94
+ * Whether this adapter stands, on the native runtime, for ADK's own Gemini
95
+ * (TracedGemini) on the ADK runtime: a Gemini adapter no caller handed over
96
+ * behind the shim. The step declares no reflection tool to it (ADR 0097) and
97
+ * stores no `turnComplete` on its events, as ADK's Gemini writes none
98
+ * (ADR 0100).
99
+ */
100
+ export function standsForAdkGemini(adapter) {
101
+ return adapter.provider === GEMINI_PROVIDER && !SHIMMED_GEMINI.has(adapter);
102
+ }
103
+ /**
104
+ * How self-correction signs the reflection call it stores in place of this
105
+ * adapter's response, or undefined to store it unsigned, as ADK's plugin
106
+ * does. A Gemini adapter's call carries the replaced response's signature;
107
+ * on a Gemini 3 model, whose API rejects an unsigned current-turn call, the
108
+ * placeholder stands in when there was none.
109
+ */
110
+ export function reflectionSigning(adapter, model) {
111
+ if (adapter.provider !== GEMINI_PROVIDER)
112
+ return undefined;
113
+ return isGemini3(model) ? { placeholder: PLACEHOLDER_THOUGHT_SIGNATURE } : {};
114
+ }
115
+ /** A Gemini 3 model id, bare or under a resource path (`models/…`, `publishers/google/models/…`). */
116
+ function isGemini3(model) {
117
+ if (!model)
118
+ return false;
119
+ return model.slice(model.lastIndexOf('/') + 1).startsWith('gemini-3');
120
+ }
121
+ /** The signature the replaced response carried: its first call's, else its first signed part's. */
122
+ function signatureOf(response) {
123
+ const parts = response.content?.parts ?? [];
124
+ const signed = (p) => typeof p.thoughtSignature === 'string' && p.thoughtSignature.length > 0;
125
+ return (parts.find((p) => p.functionCall && signed(p)) ?? parts.find(signed))?.thoughtSignature;
126
+ }
57
127
  // ── Counting, per run ────────────────────────────────────────────────────────
58
128
  /** ADK's ScopedFailureTracker: failures per name, within one run (invocation scope). */
59
129
  class FailureTracker {
@@ -100,7 +170,7 @@ export class SelfCorrection {
100
170
  const max = this.modelErrors;
101
171
  const tracker = this.#models;
102
172
  const name = agentName || 'default_model';
103
- const retry = (errorType, errorDetails, finishReason) => {
173
+ const retry = (errorType, errorDetails, finishReason, signature) => {
104
174
  const count = tracker.increment(invocationId, name);
105
175
  if (count > max) {
106
176
  const thrown = `The model has failed consecutively ${max} times and the retry limit has been exceeded.`;
@@ -108,18 +178,22 @@ export class SelfCorrection {
108
178
  }
109
179
  const args = { response_type: REFLECT_AND_RETRY_RESPONSE_TYPE, error_type: errorType, error_details: errorDetails, finish_reason: finishReason, retry_count: count };
110
180
  const response = {
111
- content: { role: 'model', parts: [{ functionCall: { id: `${ADK_HANDLE_MODEL_ERROR}_${randomUUID()}`, name: ADK_HANDLE_MODEL_ERROR, args } }] },
181
+ content: {
182
+ role: 'model',
183
+ parts: [{ functionCall: { id: `${ADK_HANDLE_MODEL_ERROR}_${randomUUID()}`, name: ADK_HANDLE_MODEL_ERROR, args }, ...(signature ? { thoughtSignature: signature } : {}) }],
184
+ },
112
185
  };
113
186
  return { response, replaced: true };
114
187
  };
115
188
  return {
116
189
  tools: [reflectionTool(max)],
117
- afterModel(response) {
190
+ afterModel(response, signing) {
191
+ const signature = () => (signing ? (signatureOf(response) ?? signing.placeholder) : undefined);
118
192
  if (response.content?.parts?.some((p) => p.functionCall?.name === ADK_HANDLE_MODEL_ERROR)) {
119
- return retry(RESERVED_TOOL_CALL, `Model attempted to call reserved tool ${ADK_HANDLE_MODEL_ERROR} directly. This tool is reserved for framework use only. Do not call it.`, 'OTHER');
193
+ return retry(RESERVED_TOOL_CALL, `Model attempted to call reserved tool ${ADK_HANDLE_MODEL_ERROR} directly. This tool is reserved for framework use only. Do not call it.`, 'OTHER', signature());
120
194
  }
121
195
  if (response.finishReason && MODEL_ERRORS.includes(response.finishReason)) {
122
- return retry(response.errorCode ?? 'MODEL_ERROR', response.errorMessage ?? 'Model error encountered.', response.finishReason);
196
+ return retry(response.errorCode ?? 'MODEL_ERROR', response.errorMessage ?? 'Model error encountered.', response.finishReason, signature());
123
197
  }
124
198
  tracker.reset(invocationId, name);
125
199
  return { response, replaced: false };
@@ -23,16 +23,24 @@
23
23
  * - THE EVENT. Each response becomes ADK's event for it: created before
24
24
  * the call with the run's id, the agent as author and the branch, and
25
25
  * merged with the response as the shim maps it (modelResponseToLlmResponse),
26
- * a fresh id for every response after the first. A tool call with no id
26
+ * a fresh id for every response after the first. For a Gemini adapter
27
+ * that stands for ADK's own Gemini (standsForAdkGemini), the event has no
28
+ * turnComplete, since ADK's Gemini writes none (ADR 0100). A tool call with no id
27
29
  * gets ADK's `adk-<uuid>`; a call to a long-running tool is listed in
28
30
  * longRunningToolIds; a set_model_response call becomes its arguments as
29
31
  * JSON text, ending the step (skipSummarization). An answer with no
30
32
  * parts, no error and no usage makes no event.
31
33
  * - SELF-CORRECTION (ADR 0075). With the caller's `correction`, the
32
- * request declares the reflection tool after the agent's tools, and each
33
- * response passes through it first, as ADK's reflect-and-retry model
34
- * plugin sees it: a retry may stand in its place, or the step may end on
35
- * the plugin's UNKNOWN_ERROR event (lib/runtime/native/selfCorrection.ts).
34
+ * reflection tool is one of the step's tools, after the agent's, and
35
+ * each response passes through it first, as ADK's reflect-and-retry
36
+ * model plugin sees it: a retry may stand in its place, or the step may
37
+ * end on the plugin's UNKNOWN_ERROR event (lib/runtime/native/
38
+ * selfCorrection.ts). The request declares the tool only where ADK's
39
+ * model class would (declaresReflectionTool): never to a Gemini model
40
+ * ADK's own Gemini would serve, which sends no toolsDict (ADR 0097).
41
+ * On a Gemini adapter the reflection call stored in a response's place
42
+ * carries its signature, or Gemini 3's placeholder (reflectionSigning,
43
+ * ADR 0103), where ADK stores it unsigned.
36
44
  * - A THROWN FAILURE. The contract forbids an adapter to throw, but a
37
45
  * leaf that does (an ADK-era model class) is read as ADK reads it. With
38
46
  * a `redirect`, a provider-side failure (errorDecision, lib/models/
@@ -132,7 +140,7 @@ export interface ModelStepResult {
132
140
  stopped?: StepStop;
133
141
  /** The failure `redirect` took: nothing was stored for it. */
134
142
  redirected?: ModelError;
135
- /** The client-side tools the request declared, by name: what runs the answer's calls. */
143
+ /** The client-side tools the request declared, and the reflection tool when it was not declared, by name: what runs the answer's calls. */
136
144
  tools: Map<string, unknown>;
137
145
  }
138
146
  export declare function eitherSignal(...candidates: Array<AbortSignal | undefined>): AbortSignal | undefined;
@@ -23,16 +23,24 @@
23
23
  * - THE EVENT. Each response becomes ADK's event for it: created before
24
24
  * the call with the run's id, the agent as author and the branch, and
25
25
  * merged with the response as the shim maps it (modelResponseToLlmResponse),
26
- * a fresh id for every response after the first. A tool call with no id
26
+ * a fresh id for every response after the first. For a Gemini adapter
27
+ * that stands for ADK's own Gemini (standsForAdkGemini), the event has no
28
+ * turnComplete, since ADK's Gemini writes none (ADR 0100). A tool call with no id
27
29
  * gets ADK's `adk-<uuid>`; a call to a long-running tool is listed in
28
30
  * longRunningToolIds; a set_model_response call becomes its arguments as
29
31
  * JSON text, ending the step (skipSummarization). An answer with no
30
32
  * parts, no error and no usage makes no event.
31
33
  * - SELF-CORRECTION (ADR 0075). With the caller's `correction`, the
32
- * request declares the reflection tool after the agent's tools, and each
33
- * response passes through it first, as ADK's reflect-and-retry model
34
- * plugin sees it: a retry may stand in its place, or the step may end on
35
- * the plugin's UNKNOWN_ERROR event (lib/runtime/native/selfCorrection.ts).
34
+ * reflection tool is one of the step's tools, after the agent's, and
35
+ * each response passes through it first, as ADK's reflect-and-retry
36
+ * model plugin sees it: a retry may stand in its place, or the step may
37
+ * end on the plugin's UNKNOWN_ERROR event (lib/runtime/native/
38
+ * selfCorrection.ts). The request declares the tool only where ADK's
39
+ * model class would (declaresReflectionTool): never to a Gemini model
40
+ * ADK's own Gemini would serve, which sends no toolsDict (ADR 0097).
41
+ * On a Gemini adapter the reflection call stored in a response's place
42
+ * carries its signature, or Gemini 3's placeholder (reflectionSigning,
43
+ * ADR 0103), where ADK stores it unsigned.
36
44
  * - A THROWN FAILURE. The contract forbids an adapter to throw, but a
37
45
  * leaf that does (an ADK-era model class) is read as ADK reads it. With
38
46
  * a `redirect`, a provider-side failure (errorDecision, lib/models/
@@ -53,7 +61,7 @@
53
61
  */
54
62
  import { randomUUID } from 'node:crypto';
55
63
  import { errorDecision, errorText } from '../../models/errorResponse.js';
56
- import { modelResponseToLlmResponse } from '../../models/genaiMapping.js';
64
+ import { contractModelResponse, modelResponseToLlmResponse } from '../../models/genaiMapping.js';
57
65
  import { resolveAdapter } from '../../models/registry.js';
58
66
  import { traceLlmGeneration } from '../../observability/tracer.js';
59
67
  import { createTurnEvent, getFunctionCalls, newEventId } from '../events.js';
@@ -61,6 +69,7 @@ import { currentTurnControl, currentTurnSignal, stopCode, stopMessage } from '..
61
69
  import { toolOf } from '../../tools/tool.js';
62
70
  import { ADK_CALL_ID_PREFIX } from './history.js';
63
71
  import { SET_MODEL_RESPONSE, buildModelRequest } from './request.js';
72
+ import { declaresReflectionTool, reflectionSigning, standsForAdkGemini } from './selfCorrection.js';
64
73
  export function eitherSignal(...candidates) {
65
74
  const signals = [...new Set(candidates.filter((s) => s !== undefined))];
66
75
  return signals.length <= 1 ? signals[0] : AbortSignal.any(signals);
@@ -108,6 +117,10 @@ function thrownModelError(err) {
108
117
  export async function runModelStep(options) {
109
118
  const { agent, session, sessions } = options;
110
119
  const signal = eitherSignal(options.signal, currentTurnSignal());
120
+ const adapter = options.adapter ?? resolveAdapter(agent.model);
121
+ // ADK's plugin puts the reflection tool in the toolsDict alone: declared where the model class reads it, run either way.
122
+ const correctionTools = options.correction?.tools ?? [];
123
+ const declareCorrection = correctionTools.length > 0 && declaresReflectionTool(adapter);
111
124
  const { request, tools } = await buildModelRequest(agent, {
112
125
  session,
113
126
  invocationId: options.invocationId,
@@ -119,15 +132,17 @@ export async function runModelStep(options) {
119
132
  ...(options.stateOverlay ? { stateOverlay: options.stateOverlay } : {}),
120
133
  stream: options.stream ?? false,
121
134
  ...(signal ? { signal } : {}),
122
- ...(options.correction ? { extraTools: options.correction.tools } : {}),
135
+ ...(declareCorrection ? { extraTools: correctionTools } : {}),
123
136
  ...(options.workflowScope ? { workflowScope: options.workflowScope } : {}),
124
137
  });
138
+ if (!declareCorrection)
139
+ for (const tool of correctionTools)
140
+ tools.set(tool.name, tool);
125
141
  if (options.model)
126
142
  request.model = options.model;
127
143
  const result = { request, text: '', thinking: '', toolCalls: [], longRunningToolIds: [], tools };
128
144
  if (signal?.aborted)
129
145
  return { ...result, stopped: stopOf() };
130
- const adapter = options.adapter ?? resolveAdapter(agent.model);
131
146
  // The event ADK creates before the call; each response after the first gets a fresh id and time.
132
147
  const base = createTurnEvent({ invocationId: options.invocationId, author: agent.name, branch: options.branch });
133
148
  let next = { id: base.id, timestamp: base.timestamp };
@@ -135,10 +150,18 @@ export async function runModelStep(options) {
135
150
  const sources = new WeakMap();
136
151
  // What the adapter itself threw, as opposed to the store or a callback.
137
152
  let thrown;
153
+ // ADK's own Gemini writes no turnComplete, so its stand-in's events carry none (ADR 0100).
154
+ const adkGemini = standsForAdkGemini(adapter);
155
+ // How a reflection call stored in this adapter's place is signed (ADR 0103).
156
+ const signing = reflectionSigning(adapter, request.model);
138
157
  async function* inner() {
139
158
  try {
140
- for await (const response of adapter.generate(request)) {
159
+ for await (const unchecked of adapter.generate(request)) {
160
+ // The answer held to the contract, as the shim's mapping holds it (contractModelResponse): the step reads and stores the same parts.
161
+ const response = contractModelResponse(unchecked);
141
162
  const mapped = modelResponseToLlmResponse(response);
163
+ if (adkGemini)
164
+ delete mapped.turnComplete;
142
165
  sources.set(mapped, response);
143
166
  yield mapped;
144
167
  }
@@ -186,7 +209,8 @@ export async function runModelStep(options) {
186
209
  return { ...result, response: source, redirected: source.error };
187
210
  produced = true;
188
211
  // Self-correction sees the response as ADK's afterModelCallback does: it may stand a retry in its place, or end the step.
189
- const corrected = options.correction?.afterModel(traced) ?? { response: traced, replaced: false };
212
+ // On Gemini the reflection call it stores is signed, so the next request does not 400 (ADR 0103).
213
+ const corrected = options.correction?.afterModel(traced, signing) ?? { response: traced, replaced: false };
190
214
  if ('failed' in corrected) {
191
215
  // ADK's runAndHandleError: a callback that threw ends the step on an error event of its own.
192
216
  const { code, message } = corrected.failed;
@@ -2,10 +2,11 @@
2
2
  * lib/runtime/runtimeFlag.ts — which runtime runs a turn: MELCHIZEDEK_RUNTIME
3
3
  * and the turn's `runtime` option (ADR 0045, ADR 0073).
4
4
  *
5
- * `adk` runs each agent on Google ADK's Runner, `native` on the engine's own
6
- * agent loop (lib/runtime/native/agentLoop.ts). The default is `adk` until
7
- * the release that makes native the default (ADR 0045). A feature the native
8
- * runtime does not run yet fails before any model call with
5
+ * `native` runs each agent on the engine's own agent loop
6
+ * (lib/runtime/native/agentLoop.ts), `adk` on Google ADK's Runner. `native`
7
+ * is the default since 0.20.0 (ADR 0045, ADR 0102); `adk` needs the optional
8
+ * peer @google/adk installed, and leaves the package at 1.0.0. A feature the
9
+ * native runtime does not run yet fails before any model call with
9
10
  * UnsupportedOnRuntimeError, which names the feature and the runtime.
10
11
  *
11
12
  * A leaf module: it imports nothing, so every caller (the compiler, the
@@ -18,7 +19,7 @@ export declare const RUNTIMES: readonly RuntimeName[];
18
19
  export declare const DEFAULT_RUNTIME: RuntimeName;
19
20
  /** MELCHIZEDEK_RUNTIME as set, or undefined when unset or blank. Any other value is a configuration error. */
20
21
  export declare function runtimeSetting(env?: NodeJS.ProcessEnv): RuntimeName | undefined;
21
- /** The runtime to use: the caller's option, else MELCHIZEDEK_RUNTIME, else adk. */
22
+ /** The runtime to use: the caller's option, else MELCHIZEDEK_RUNTIME, else native. */
22
23
  export declare function chooseRuntime(option?: string, env?: NodeJS.ProcessEnv): RuntimeName;
23
24
  /** A feature the chosen runtime does not run yet. Thrown before any model call. */
24
25
  export declare class UnsupportedOnRuntimeError extends Error {
@@ -28,3 +29,10 @@ export declare class UnsupportedOnRuntimeError extends Error {
28
29
  }
29
30
  /** The error for a feature the native runtime does not run yet; `where` names the agent or syndicate. */
30
31
  export declare function unsupportedOnNative(feature: string, where: string): UnsupportedOnRuntimeError;
32
+ /** Where the runtime in use came from: the caller's option, MELCHIZEDEK_RUNTIME, or the default. */
33
+ export type RuntimeSource = 'option' | 'MELCHIZEDEK_RUNTIME' | 'default';
34
+ /** The runtime chooseRuntime picks, and where it came from (the doctor prints both). */
35
+ export declare function describeRuntime(option?: string, env?: NodeJS.ProcessEnv): {
36
+ runtime: RuntimeName;
37
+ source: RuntimeSource;
38
+ };
@@ -2,10 +2,11 @@
2
2
  * lib/runtime/runtimeFlag.ts — which runtime runs a turn: MELCHIZEDEK_RUNTIME
3
3
  * and the turn's `runtime` option (ADR 0045, ADR 0073).
4
4
  *
5
- * `adk` runs each agent on Google ADK's Runner, `native` on the engine's own
6
- * agent loop (lib/runtime/native/agentLoop.ts). The default is `adk` until
7
- * the release that makes native the default (ADR 0045). A feature the native
8
- * runtime does not run yet fails before any model call with
5
+ * `native` runs each agent on the engine's own agent loop
6
+ * (lib/runtime/native/agentLoop.ts), `adk` on Google ADK's Runner. `native`
7
+ * is the default since 0.20.0 (ADR 0045, ADR 0102); `adk` needs the optional
8
+ * peer @google/adk installed, and leaves the package at 1.0.0. A feature the
9
+ * native runtime does not run yet fails before any model call with
9
10
  * UnsupportedOnRuntimeError, which names the feature and the runtime.
10
11
  *
11
12
  * A leaf module: it imports nothing, so every caller (the compiler, the
@@ -13,7 +14,7 @@
13
14
  */
14
15
  export const RUNTIMES = ['adk', 'native'];
15
16
  /** The runtime when neither the turn nor MELCHIZEDEK_RUNTIME names one. */
16
- export const DEFAULT_RUNTIME = 'adk';
17
+ export const DEFAULT_RUNTIME = 'native';
17
18
  function asRuntime(raw, source) {
18
19
  const value = raw.trim().toLowerCase();
19
20
  if (value === 'adk' || value === 'native')
@@ -27,7 +28,7 @@ export function runtimeSetting(env = process.env) {
27
28
  return undefined;
28
29
  return asRuntime(raw, 'MELCHIZEDEK_RUNTIME');
29
30
  }
30
- /** The runtime to use: the caller's option, else MELCHIZEDEK_RUNTIME, else adk. */
31
+ /** The runtime to use: the caller's option, else MELCHIZEDEK_RUNTIME, else native. */
31
32
  export function chooseRuntime(option, env = process.env) {
32
33
  if (option !== undefined)
33
34
  return asRuntime(option, 'The runtime option');
@@ -48,3 +49,10 @@ export class UnsupportedOnRuntimeError extends Error {
48
49
  export function unsupportedOnNative(feature, where) {
49
50
  return new UnsupportedOnRuntimeError(feature, 'native', where);
50
51
  }
52
+ /** The runtime chooseRuntime picks, and where it came from (the doctor prints both). */
53
+ export function describeRuntime(option, env = process.env) {
54
+ if (option !== undefined)
55
+ return { runtime: asRuntime(option, 'The runtime option'), source: 'option' };
56
+ const set = runtimeSetting(env);
57
+ return set ? { runtime: set, source: 'MELCHIZEDEK_RUNTIME' } : { runtime: DEFAULT_RUNTIME, source: 'default' };
58
+ }
@@ -26,13 +26,15 @@
26
26
  * time, and an outer AbortSignal cancels it. All three abort the provider
27
27
  * request in flight, not just the loop around it.
28
28
  *
29
- * ── Runtimes (ADR 0045, ADR 0073) ─────────────────────────────────────────
30
- * Each agent of a turn runs on ADK's Runner (the default) or on the
31
- * engine's own agent loop: the turn's `runtime` option, else
29
+ * ── Runtimes (ADR 0045, ADR 0073, ADR 0102) ───────────────────────────────
30
+ * Each agent of a turn runs on the engine's own agent loop (the default
31
+ * since 0.20.0) or on ADK's Runner: the turn's `runtime` option, else
32
32
  * MELCHIZEDEK_RUNTIME. Both compile the same AgentSpec (lib/compile.ts),
33
33
  * store the same events and drain through drainAgentStream, so everything
34
34
  * else here is shared. What native does not run yet fails before any model
35
- * call, naming the feature (lib/runtime/nativeTurn.ts).
35
+ * call, naming the feature (lib/runtime/nativeTurn.ts). The adk runtime
36
+ * needs @google/adk installed; without it, a turn asked to run there fails
37
+ * before the session is touched, naming the package (lib/adkPeer.ts).
36
38
  */
37
39
  import type { BasePlugin } from '@google/adk';
38
40
  import type { BaseMemoryService, BaseSessionService, Event, LlmAgent } from '@google/adk';
@@ -42,8 +44,11 @@ import type { PendingConsent } from './credentials.ts';
42
44
  export { CREDENTIAL_REQUEST, credentialResponsePart, describeConsent, pendingConsent } from './credentials.ts';
43
45
  export type { PendingConsent } from './credentials.ts';
44
46
  export type { ToolCredentials } from '../tools/oauthConsent.ts';
45
- export { chooseRuntime, runtimeSetting, DEFAULT_RUNTIME, RUNTIMES, UnsupportedOnRuntimeError } from './runtimeFlag.ts';
46
- export type { RuntimeName } from './runtimeFlag.ts';
47
+ export { chooseRuntime, describeRuntime, runtimeSetting, DEFAULT_RUNTIME, RUNTIMES, UnsupportedOnRuntimeError } from './runtimeFlag.ts';
48
+ export type { RuntimeName, RuntimeSource } from './runtimeFlag.ts';
49
+ export { AdkNotInstalledError, adkInstalled } from '../adkPeer.ts';
50
+ export { InProcessSessionService } from './sessions.ts';
51
+ export { asAdkSessionService, asSessionService } from './adkSessionBridge.ts';
47
52
  import type { PendingInput } from '../workflow.ts';
48
53
  export { describeInput } from '../workflow.ts';
49
54
  export type { PendingInput } from '../workflow.ts';
@@ -112,10 +117,10 @@ export interface SyndicateTurnOptions {
112
117
  /** Applied to every compiled agent before it runs (eval tool replay). ADK runtime only. */
113
118
  transformAgent?: (agent: LlmAgent) => LlmAgent;
114
119
  /**
115
- * The runtime that runs the turn's agents: `adk` (Google ADK's Runner) or
116
- * `native` (the engine's own loop). Default: MELCHIZEDEK_RUNTIME, else
117
- * `adk`. A feature native does not run yet throws UnsupportedOnRuntimeError
118
- * before any model call.
120
+ * The runtime that runs the turn's agents: `native` (the engine's own
121
+ * loop) or `adk` (Google ADK's Runner, which needs @google/adk installed).
122
+ * Default: MELCHIZEDEK_RUNTIME, else `native`. A feature native does not
123
+ * run yet throws UnsupportedOnRuntimeError before any model call.
119
124
  */
120
125
  runtime?: RuntimeName;
121
126
  /** Plan-dispatch only: skip the classifier and run this route. Overrides
@@ -26,30 +26,36 @@
26
26
  * time, and an outer AbortSignal cancels it. All three abort the provider
27
27
  * request in flight, not just the loop around it.
28
28
  *
29
- * ── Runtimes (ADR 0045, ADR 0073) ─────────────────────────────────────────
30
- * Each agent of a turn runs on ADK's Runner (the default) or on the
31
- * engine's own agent loop: the turn's `runtime` option, else
29
+ * ── Runtimes (ADR 0045, ADR 0073, ADR 0102) ───────────────────────────────
30
+ * Each agent of a turn runs on the engine's own agent loop (the default
31
+ * since 0.20.0) or on ADK's Runner: the turn's `runtime` option, else
32
32
  * MELCHIZEDEK_RUNTIME. Both compile the same AgentSpec (lib/compile.ts),
33
33
  * store the same events and drain through drainAgentStream, so everything
34
34
  * else here is shared. What native does not run yet fails before any model
35
- * call, naming the feature (lib/runtime/nativeTurn.ts).
35
+ * call, naming the feature (lib/runtime/nativeTurn.ts). The adk runtime
36
+ * needs @google/adk installed; without it, a turn asked to run there fails
37
+ * before the session is touched, naming the package (lib/adkPeer.ts).
36
38
  */
37
- import { InMemorySessionService, ReflectAndRetryModelPlugin, ReflectAndRetryToolPlugin, Runner, StreamingMode, getFunctionCalls, getFunctionResponses } from '@google/adk';
38
39
  import { DEFAULT_MAX_STEPS } from '../config.js';
39
- import { agentGates, compileGraph, compileSpec, compileSubagent, compileSubagentSpec } from '../compile.js';
40
- import { compileNative, nativeAdapterFor } from '../compileNative.js';
40
+ import { agentGates, compileGraph, compileSpec, compileSubagent, compileSubagentSpec, compileWorkflowSpec, declaresApprovals } from '../compile.js';
41
+ import { compileNative, compileNativeWorkflow, nativeAdapterFor } from '../compileNative.js';
41
42
  import { nativeMemory, refuseOnNative, runNativeAgent } from './nativeTurn.js';
42
- import { asSessionService } from './adkSessionBridge.js';
43
- import { resolveTools } from '../toolRegistry.js';
44
- import { buildWorkflowGraph } from '../workflow/graph.js';
43
+ import { asAdkSessionService, asSessionService } from './adkSessionBridge.js';
44
+ import { requireAdk } from '../adkPeer.js';
45
+ import { getFunctionCalls, getFunctionResponses } from './events.js';
46
+ import { InProcessSessionService } from './sessions.js';
45
47
  import { UnsupportedWorkflowResumeError } from '../workflow/resume.js';
46
- import { refuseUnrunnableNodes, runNativeWorkflow } from '../workflow/turn.js';
48
+ import { runNativeWorkflow } from '../workflow/turn.js';
47
49
  import { SelfCorrection } from './native/selfCorrection.js';
48
50
  import { UnsupportedOnRuntimeError, chooseRuntime } from './runtimeFlag.js';
49
51
  import { pinnedCredentialStore } from '../tools/auth.js';
50
52
  import { credentialResponsePart, describeConsent, pendingConsent } from './credentials.js';
51
53
  export { CREDENTIAL_REQUEST, credentialResponsePart, describeConsent, pendingConsent } from './credentials.js';
52
- export { chooseRuntime, runtimeSetting, DEFAULT_RUNTIME, RUNTIMES, UnsupportedOnRuntimeError } from './runtimeFlag.js';
54
+ export { chooseRuntime, describeRuntime, runtimeSetting, DEFAULT_RUNTIME, RUNTIMES, UnsupportedOnRuntimeError } from './runtimeFlag.js';
55
+ export { AdkNotInstalledError, adkInstalled } from '../adkPeer.js';
56
+ // A turn's session store with no ADK: runSyndicateTurn takes it as asAdkSessionService(new InProcessSessionService()) (ADR 0102).
57
+ export { InProcessSessionService } from './sessions.js';
58
+ export { asAdkSessionService, asSessionService } from './adkSessionBridge.js';
53
59
  import { ROUTE_STEP_SUFFIX, compileWorkflow, describeInput, inputRequestFrom, isWorkflowSyndicate } from '../workflow.js';
54
60
  export { describeInput } from '../workflow.js';
55
61
  import { isDispatchSyndicate, matchRouteOverride, resolveRoute } from '../dispatch.js';
@@ -85,6 +91,9 @@ export function retryPlugins(retries) {
85
91
  const model = retries?.model_errors ?? DEFAULT_MODEL_ERROR_RETRIES;
86
92
  const tool = retries?.tool_errors ?? DEFAULT_TOOL_ERROR_RETRIES;
87
93
  const plugins = [];
94
+ if (model <= 0 && tool <= 0)
95
+ return plugins;
96
+ const { ReflectAndRetryModelPlugin, ReflectAndRetryToolPlugin } = requireAdk("ADK's retry plugins (retryPlugins)");
88
97
  if (model > 0)
89
98
  plugins.push(new ReflectAndRetryModelPlugin({ maxRetries: model }));
90
99
  if (tool > 0)
@@ -173,7 +182,7 @@ export async function drainAgentStream(stream, opts = {}) {
173
182
  d.tokens.output += e.usageMetadata.candidatesTokenCount ?? 0;
174
183
  d.tokens.thinking += e.usageMetadata.thoughtsTokenCount ?? 0;
175
184
  }
176
- const calls = getFunctionCalls(event) ?? [];
185
+ const calls = getFunctionCalls(event);
177
186
  // Text streamed before a tool call was narration, not the answer.
178
187
  if (streamed && calls.length) {
179
188
  ev.onTextReset?.();
@@ -207,7 +216,7 @@ export async function drainAgentStream(stream, opts = {}) {
207
216
  if (opts.publishToolStatus)
208
217
  ev.onProgress?.(`Invoking tool: ${name}`);
209
218
  }
210
- for (const resp of getFunctionResponses(event) ?? []) {
219
+ for (const resp of getFunctionResponses(event)) {
211
220
  const r = resp;
212
221
  const name = r.name ?? r.functionResponse?.name ?? '';
213
222
  const content = r.response ?? r.functionResponse?.response ?? {};
@@ -286,6 +295,9 @@ export async function runSyndicateTurn(opts) {
286
295
  // class, which bypasses traceLlmGeneration: no max_steps, no cancel. A
287
296
  // caller that resolves models itself (the A2A server) is left alone.
288
297
  const runtime = chooseRuntime(opts.runtime);
298
+ // The adk runtime without @google/adk installed fails here, naming the package (ADR 0102).
299
+ if (runtime === 'adk')
300
+ requireAdk("The adk runtime (MELCHIZEDEK_RUNTIME=adk, or the turn's runtime option)");
289
301
  if (!opts.compile?.resolveModel)
290
302
  registerAvailableProviders();
291
303
  const control = createTurnControl({
@@ -303,23 +315,15 @@ export async function runSyndicateTurn(opts) {
303
315
  /**
304
316
  * A workflow syndicate for the native runtime: its graph, every agent
305
317
  * compiled for native from the same specs ADK's compileWorkflow builds its
306
- * agents from, one adapter lookup that knows every agent's models, and the
307
- * registry's lookup for tool nodes. A tool node ADK's compile refuses (an
308
- * unregistered or long-running tool) is refused here, before any model
309
- * call, with ADK's message.
318
+ * agents from (compileWorkflowSpec, then compileNativeWorkflow), one adapter
319
+ * lookup that knows every agent's models, and the registry's lookup for tool
320
+ * nodes. A tool node ADK's compile refuses (an unregistered or long-running
321
+ * tool) is refused here, before any model call, with ADK's message.
310
322
  */
311
- async function compileNativeWorkflow(config, opts) {
312
- const graph = buildWorkflowGraph(config);
313
- const specs = [];
314
- const agents = new Map();
315
- for (const sub of [{ description: '', ...config.orchestrator }, ...(config.subagents ?? [])]) {
316
- const spec = await compileSubagentSpec(sub, opts);
317
- specs.push(spec);
318
- agents.set(sub.name, compileNative(spec));
319
- }
320
- const resolveTool = (name) => resolveTools([name], opts.onUnknownTool)[0];
321
- refuseUnrunnableNodes(graph, resolveTool);
322
- return { runtime: 'native-workflow', graph, agents, adapterFor: nativeAdapterFor(opts, specs), resolveTool };
323
+ async function compileNativeWorkflowAgent(config, opts) {
324
+ const spec = await compileWorkflowSpec(config, opts);
325
+ const { graph, agents, resolveTool } = compileNativeWorkflow(spec);
326
+ return { runtime: 'native-workflow', graph, agents, adapterFor: nativeAdapterFor(opts, spec.agents.map((a) => a.spec)), resolveTool };
323
327
  }
324
328
  async function runTurnInner(opts, control, runtime) {
325
329
  const { config, appName, userId, sessionId, sessionService } = opts;
@@ -336,6 +340,11 @@ async function runTurnInner(opts, control, runtime) {
336
340
  // What native does not run yet fails here, before the session is touched.
337
341
  if (native)
338
342
  refuseOnNative(config, { isWorkflow: isWorkflowSyndicate(config), transformAgent: opts.transformAgent });
343
+ // ADK pauses a gated call in a workflow node, but its resume reruns the node from its input, so the
344
+ // pinned call never runs: approvals on workflow nodes run on native only (ADR 0098).
345
+ if (!native && isWorkflowSyndicate(config) && declaresApprovals(config)) {
346
+ throw new UnsupportedOnRuntimeError('an approval gate (require_approval) on a workflow node', 'adk', config.syndicate_name || 'syndicate');
347
+ }
339
348
  const nativeOf = (spec) => ({ runtime: 'native', agent: compileNative(spec), adapterFor: nativeAdapterFor(compileOpts, spec) });
340
349
  /** The orchestrator (a DELEGATE root, or a dispatch classifier) for the turn's runtime. */
341
350
  const compileRoot = async () => native ? nativeOf(await compileSpec(config, compileOpts)) : { runtime: 'adk', agent: transform(await compileGraph(config, compileOpts)) };
@@ -534,6 +543,7 @@ async function runTurnInner(opts, control, runtime) {
534
543
  });
535
544
  }
536
545
  else {
546
+ const { Runner, StreamingMode } = requireAdk('The adk runtime');
537
547
  const runner = new Runner({
538
548
  agent: params.agent.agent,
539
549
  appName,
@@ -624,7 +634,10 @@ async function runTurnInner(opts, control, runtime) {
624
634
  // conversation the next specialist reads.
625
635
  const routerAgent = await compileRoot();
626
636
  const routerSid = `${sessionId}::route`;
627
- const routerSessions = new InMemorySessionService();
637
+ // ADK's in-memory store on adk; the engine's on native, which needs no ADK.
638
+ const routerSessions = native
639
+ ? asAdkSessionService(new InProcessSessionService())
640
+ : new (requireAdk('The adk runtime').InMemorySessionService)();
628
641
  await routerSessions.createSession({ appName, userId, sessionId: routerSid });
629
642
  const shared = await sessionService.getSession({ appName, userId, sessionId });
630
643
  const digest = renderTranscriptDigest(shared?.events ?? []);
@@ -726,8 +739,15 @@ async function runTurnInner(opts, control, runtime) {
726
739
  // unless its YAML says otherwise, so no projection is needed. An
727
740
  // `ask_user` node ends the turn input-required; the next message
728
741
  // resumes the graph where it waited.
742
+ // While a gated call waits, a message that is not its decision repeats the request: the walk cannot move past
743
+ // the waiting node, so nothing is stored and nothing runs, as the A2A server answers it (ADR 0098).
744
+ if (!decision && declaresApprovals(config)) {
745
+ const open = pendingApproval(existing?.events ?? []);
746
+ if (open)
747
+ return pause(open);
748
+ }
729
749
  const workflowAgent = native
730
- ? await compileNativeWorkflow(config, compileOpts)
750
+ ? await compileNativeWorkflowAgent(config, compileOpts)
731
751
  : { runtime: 'adk', agent: (await compileWorkflow(config, compileOpts, transform)).workflow };
732
752
  try {
733
753
  answer = await runAgent({
@@ -759,6 +779,13 @@ async function runTurnInner(opts, control, runtime) {
759
779
  result.error = answer.error;
760
780
  return finish();
761
781
  }
782
+ // A gated call paused its node, and the walk with it (ADR 0098): the next message answers it.
783
+ if (declaresApprovals(config)) {
784
+ const after = await sessionService.getSession({ appName, userId, sessionId });
785
+ const pending = pendingApproval(after?.events ?? []);
786
+ if (pending)
787
+ return pause(pending);
788
+ }
762
789
  if (answer.inputRequests.length) {
763
790
  const input = answer.inputRequests[answer.inputRequests.length - 1];
764
791
  result.status = 'input-required';
@@ -0,0 +1,23 @@
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 declare 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 declare function nestedDeeperThan(value: unknown, max?: number): boolean;