@google/adk 2.2.0 → 2.2.1

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 (32) hide show
  1. package/dist/cjs/a2a/event_converter_utils.js +5 -1
  2. package/dist/cjs/a2a/metadata_converter_utils.js +2 -1
  3. package/dist/cjs/common.js +18 -0
  4. package/dist/cjs/events/abort_events.js +135 -0
  5. package/dist/cjs/events/internal_metadata.js +131 -0
  6. package/dist/cjs/models/gemini_continuation.js +232 -0
  7. package/dist/cjs/plugins/debug_logging_plugin.js +653 -0
  8. package/dist/cjs/plugins/plugin_manager.js +1 -1
  9. package/dist/cjs/plugins/tool_call_integrity_plugin.js +364 -0
  10. package/dist/cjs/runner/runner.js +17 -3
  11. package/dist/cjs/version.js +1 -1
  12. package/dist/esm/a2a/event_converter_utils.js +5 -1
  13. package/dist/esm/a2a/metadata_converter_utils.js +2 -1
  14. package/dist/esm/common.js +20 -0
  15. package/dist/esm/events/abort_events.js +110 -0
  16. package/dist/esm/events/internal_metadata.js +97 -0
  17. package/dist/esm/models/gemini_continuation.js +205 -0
  18. package/dist/esm/plugins/debug_logging_plugin.js +615 -0
  19. package/dist/esm/plugins/plugin_manager.js +1 -1
  20. package/dist/esm/plugins/tool_call_integrity_plugin.js +339 -0
  21. package/dist/esm/runner/runner.js +20 -3
  22. package/dist/esm/version.js +1 -1
  23. package/dist/types/common.d.ts +3 -0
  24. package/dist/types/events/abort_events.d.ts +43 -0
  25. package/dist/types/events/internal_metadata.d.ts +78 -0
  26. package/dist/types/models/gemini_continuation.d.ts +59 -0
  27. package/dist/types/plugins/debug_logging_plugin.d.ts +157 -0
  28. package/dist/types/plugins/tool_call_integrity_plugin.d.ts +116 -0
  29. package/dist/types/version.d.ts +1 -1
  30. package/dist/web/index_web.js +59 -59
  31. package/dist/web/index_web.js.map +4 -4
  32. package/package.json +1 -1
@@ -0,0 +1,339 @@
1
+ import {createRequire as topLevelCreateRequire} from 'module';
2
+ const require = topLevelCreateRequire(import.meta.url);
3
+ var __defProp = Object.defineProperty;
4
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
5
+ /**
6
+ * @license
7
+ * Copyright 2026 Google LLC
8
+ * SPDX-License-Identifier: Apache-2.0
9
+ */
10
+ import { createEvent, getFunctionCalls } from "../events/event.js";
11
+ import {
12
+ INTERNAL_METADATA_PREFIX,
13
+ markRestored,
14
+ RESTORED_EVENT_KEY
15
+ } from "../events/internal_metadata.js";
16
+ import { logger } from "../utils/logger.js";
17
+ import { BasePlugin } from "./base_plugin.js";
18
+ const TOOL_CALL_HMAC_METADATA_KEY = `${INTERNAL_METADATA_PREFIX}fc_hmac`;
19
+ const STAMP_PREFIX = "v1:";
20
+ const _ToolCallIntegrityError = class _ToolCallIntegrityError extends Error {
21
+ constructor(message) {
22
+ super(message);
23
+ this.name = "ToolCallIntegrityError";
24
+ }
25
+ };
26
+ __name(_ToolCallIntegrityError, "ToolCallIntegrityError");
27
+ let ToolCallIntegrityError = _ToolCallIntegrityError;
28
+ function jsonForm(value) {
29
+ const json = JSON.stringify(value);
30
+ return json === void 0 ? null : JSON.parse(json);
31
+ }
32
+ __name(jsonForm, "jsonForm");
33
+ function canonicalJson(value) {
34
+ if (Array.isArray(value)) {
35
+ return `[${value.map((item) => canonicalJson(item)).join(",")}]`;
36
+ }
37
+ if (value !== null && typeof value === "object") {
38
+ const object = value;
39
+ const entries = Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson(object[key])}`);
40
+ return `{${entries.join(",")}}`;
41
+ }
42
+ return JSON.stringify(value);
43
+ }
44
+ __name(canonicalJson, "canonicalJson");
45
+ function jsonArgs(args) {
46
+ const json = jsonForm(args != null ? args : {});
47
+ return json != null ? json : {};
48
+ }
49
+ __name(jsonArgs, "jsonArgs");
50
+ function canonicalPayload(session, event, functionCall) {
51
+ var _a, _b, _c, _d, _e;
52
+ return new TextEncoder().encode(
53
+ canonicalJson({
54
+ app_name: session.appName,
55
+ user_id: session.userId,
56
+ session_id: session.id,
57
+ invocation_id: (_a = event.invocationId) != null ? _a : null,
58
+ branch: (_b = event.branch) != null ? _b : null,
59
+ author: (_c = event.author) != null ? _c : null,
60
+ name: (_d = functionCall.name) != null ? _d : null,
61
+ id: (_e = functionCall.id) != null ? _e : null,
62
+ args: jsonArgs(functionCall.args)
63
+ })
64
+ );
65
+ }
66
+ __name(canonicalPayload, "canonicalPayload");
67
+ function isStampMap(value) {
68
+ return value !== null && typeof value === "object" && !Array.isArray(value) && Object.values(value).every(
69
+ // eslint-disable-next-line no-control-regex
70
+ (stamp) => typeof stamp === "string" && /^[\x00-\x7f]*$/.test(stamp)
71
+ );
72
+ }
73
+ __name(isStampMap, "isStampMap");
74
+ function isRestored(event) {
75
+ var _a;
76
+ return Boolean((_a = event.customMetadata) == null ? void 0 : _a[RESTORED_EVENT_KEY]);
77
+ }
78
+ __name(isRestored, "isRestored");
79
+ function getStamps(event) {
80
+ var _a;
81
+ const stamps = (_a = event.customMetadata) == null ? void 0 : _a[TOOL_CALL_HMAC_METADATA_KEY];
82
+ if (stamps === void 0 || stamps === null) {
83
+ return {};
84
+ }
85
+ if (!isStampMap(stamps)) {
86
+ throw new ToolCallIntegrityError(
87
+ `Event '${event.id}' has a malformed integrity stamp.`
88
+ );
89
+ }
90
+ return stamps;
91
+ }
92
+ __name(getStamps, "getStamps");
93
+ function hasStamp(stamps, callId) {
94
+ return Object.hasOwn(stamps, callId);
95
+ }
96
+ __name(hasStamp, "hasStamp");
97
+ function toHex(bytes) {
98
+ return Array.from(
99
+ new Uint8Array(bytes),
100
+ (b) => b.toString(16).padStart(2, "0")
101
+ ).join("");
102
+ }
103
+ __name(toHex, "toHex");
104
+ function fromHex(hex) {
105
+ if (!/^[0-9a-f]{64}$/.test(hex)) {
106
+ return void 0;
107
+ }
108
+ const bytes = new Uint8Array(hex.length / 2);
109
+ for (let i = 0; i < bytes.length; i++) {
110
+ bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
111
+ }
112
+ return bytes;
113
+ }
114
+ __name(fromHex, "fromHex");
115
+ function getSubtleCrypto() {
116
+ var _a;
117
+ const subtle = (_a = globalThis.crypto) == null ? void 0 : _a.subtle;
118
+ if (!subtle) {
119
+ throw new Error(
120
+ "ToolCallIntegrityPlugin requires the Web Crypto API (globalThis.crypto.subtle), which is not available in this environment."
121
+ );
122
+ }
123
+ return subtle;
124
+ }
125
+ __name(getSubtleCrypto, "getSubtleCrypto");
126
+ const _ToolCallIntegrityPlugin = class _ToolCallIntegrityPlugin extends BasePlugin {
127
+ /**
128
+ * @throws {Error} If `secretKey` is empty or contains a key that is not
129
+ * non-empty bytes.
130
+ */
131
+ constructor(options) {
132
+ var _a, _b;
133
+ super((_a = options.name) != null ? _a : "tool_call_integrity");
134
+ const secretKey = options.secretKey;
135
+ const rawKeys = secretKey instanceof Uint8Array ? [secretKey] : Array.isArray(secretKey) ? [...secretKey] : [];
136
+ if (rawKeys.length === 0 || !rawKeys.every((key) => key instanceof Uint8Array && key.length > 0)) {
137
+ throw new Error(
138
+ "secretKey must be non-empty bytes or a non-empty list of them."
139
+ );
140
+ }
141
+ this.keys = rawKeys.map((key) => new Uint8Array(key));
142
+ this.allowUnstampedCalls = (_b = options.allowUnstampedCalls) != null ? _b : false;
143
+ }
144
+ /**
145
+ * Returns a copy with internal metadata removed and marked as restored.
146
+ *
147
+ * Use it on events that your code copies into another session, so that the
148
+ * history passes the integrity check. The copy only keeps the history: its
149
+ * function calls are never executed.
150
+ *
151
+ * @param event The event to copy. It is not modified.
152
+ * @returns The marked copy, ready to append to the new session.
153
+ */
154
+ static prepareRestoredEvent(event) {
155
+ return markRestored(createEvent(structuredClone(event)));
156
+ }
157
+ getCryptoKeys() {
158
+ if (!this.cryptoKeys) {
159
+ const subtle = getSubtleCrypto();
160
+ this.cryptoKeys = Promise.all(
161
+ this.keys.map(
162
+ (key) => subtle.importKey("raw", key, { name: "HMAC", hash: "SHA-256" }, false, [
163
+ "sign",
164
+ "verify"
165
+ ])
166
+ )
167
+ );
168
+ }
169
+ return this.cryptoKeys;
170
+ }
171
+ async sign(payload) {
172
+ const [primary] = await this.getCryptoKeys();
173
+ const digest = await getSubtleCrypto().sign("HMAC", primary, payload);
174
+ return STAMP_PREFIX + toHex(digest);
175
+ }
176
+ /** `subtle.verify` compares in constant time. */
177
+ async verify(payload, stamp) {
178
+ if (!stamp.startsWith(STAMP_PREFIX)) {
179
+ return false;
180
+ }
181
+ const signature = fromHex(stamp.slice(STAMP_PREFIX.length));
182
+ if (!signature) {
183
+ return false;
184
+ }
185
+ const subtle = getSubtleCrypto();
186
+ for (const key of await this.getCryptoKeys()) {
187
+ if (await subtle.verify("HMAC", key, signature, payload)) {
188
+ return true;
189
+ }
190
+ }
191
+ return false;
192
+ }
193
+ unstamped(name, callId) {
194
+ const message = `${name} call '${callId}' has no integrity stamp.`;
195
+ if (!this.allowUnstampedCalls) {
196
+ throw new ToolCallIntegrityError(message);
197
+ }
198
+ logger.warn(message);
199
+ }
200
+ async onEventCallback({
201
+ invocationContext,
202
+ event
203
+ }) {
204
+ var _a;
205
+ const session = invocationContext.session;
206
+ const calls = getFunctionCalls(event).filter((fc) => fc.id);
207
+ if (!event.partial) {
208
+ const seen = /* @__PURE__ */ new Set();
209
+ for (const fc of calls) {
210
+ if (seen.has(fc.id)) {
211
+ throw new ToolCallIntegrityError(
212
+ `Event '${event.id}' repeats function call ID '${fc.id}'.`
213
+ );
214
+ }
215
+ seen.add(fc.id);
216
+ }
217
+ }
218
+ const stamps = {};
219
+ for (const fc of calls) {
220
+ stamps[fc.id] = await this.sign(canonicalPayload(session, event, fc));
221
+ }
222
+ if (Object.keys(stamps).length > 0) {
223
+ event.customMetadata = {
224
+ ...(_a = event.customMetadata) != null ? _a : {},
225
+ [TOOL_CALL_HMAC_METADATA_KEY]: stamps
226
+ };
227
+ }
228
+ return void 0;
229
+ }
230
+ async beforeRunCallback({
231
+ invocationContext
232
+ }) {
233
+ const session = invocationContext.session;
234
+ for (const event of session.events) {
235
+ const calls = getFunctionCalls(event);
236
+ if (calls.length === 0 || isRestored(event)) {
237
+ continue;
238
+ }
239
+ const stamps = getStamps(event);
240
+ const verified = /* @__PURE__ */ new Set();
241
+ for (const fc of calls) {
242
+ if (!fc.id) {
243
+ continue;
244
+ }
245
+ if (!hasStamp(stamps, fc.id)) {
246
+ this.unstamped(fc.name, fc.id);
247
+ continue;
248
+ }
249
+ if (verified.has(fc.id)) {
250
+ throw new ToolCallIntegrityError(
251
+ `Event '${event.id}' has duplicate function call ID '${fc.id}'.`
252
+ );
253
+ }
254
+ const payload = canonicalPayload(session, event, fc);
255
+ if (!await this.verify(payload, stamps[fc.id])) {
256
+ throw new ToolCallIntegrityError(
257
+ `${fc.name} call '${fc.id}' does not match its integrity stamp.`
258
+ );
259
+ }
260
+ verified.add(fc.id);
261
+ }
262
+ const unmatched = Object.keys(stamps).filter((id) => !verified.has(id)).sort();
263
+ if (unmatched.length > 0) {
264
+ throw new ToolCallIntegrityError(
265
+ `Event '${event.id}' has integrity stamps with no matching call: ${JSON.stringify(unmatched)}.`
266
+ );
267
+ }
268
+ }
269
+ return void 0;
270
+ }
271
+ async beforeToolCallback({
272
+ tool,
273
+ toolArgs,
274
+ toolContext
275
+ }) {
276
+ const callId = toolContext.functionCallId;
277
+ if (!callId) {
278
+ throw new ToolCallIntegrityError(
279
+ `${tool.name} call has no ID, so its integrity cannot be checked.`
280
+ );
281
+ }
282
+ const session = toolContext.invocationContext.session;
283
+ const stored = [];
284
+ let restored = false;
285
+ for (const event of session.events) {
286
+ for (const fc of getFunctionCalls(event)) {
287
+ if (fc.id !== callId) {
288
+ continue;
289
+ }
290
+ if (isRestored(event)) {
291
+ restored = true;
292
+ } else {
293
+ stored.push([event, fc]);
294
+ }
295
+ }
296
+ }
297
+ if (stored.length === 0) {
298
+ if (restored) {
299
+ throw new ToolCallIntegrityError(
300
+ `${tool.name} call '${callId}' comes from restored history and cannot be executed.`
301
+ );
302
+ }
303
+ this.unstamped(tool.name, callId);
304
+ return void 0;
305
+ }
306
+ const trusted = [];
307
+ for (const [event, fc] of stored) {
308
+ const stamps = getStamps(event);
309
+ if (!hasStamp(stamps, callId)) {
310
+ this.unstamped(tool.name, callId);
311
+ } else if (!await this.verify(
312
+ canonicalPayload(session, event, fc),
313
+ stamps[callId]
314
+ )) {
315
+ throw new ToolCallIntegrityError(
316
+ `${tool.name} call '${callId}' does not match its integrity stamp.`
317
+ );
318
+ }
319
+ trusted.push(fc);
320
+ }
321
+ const executed = canonicalJson(jsonArgs(toolArgs));
322
+ const matches = trusted.some(
323
+ (fc) => fc.name === tool.name && canonicalJson(jsonArgs(fc.args)) === executed
324
+ );
325
+ if (!matches) {
326
+ throw new ToolCallIntegrityError(
327
+ `${tool.name} call '${callId}' arguments do not match its stored call.`
328
+ );
329
+ }
330
+ return void 0;
331
+ }
332
+ };
333
+ __name(_ToolCallIntegrityPlugin, "ToolCallIntegrityPlugin");
334
+ let ToolCallIntegrityPlugin = _ToolCallIntegrityPlugin;
335
+ export {
336
+ TOOL_CALL_HMAC_METADATA_KEY,
337
+ ToolCallIntegrityError,
338
+ ToolCallIntegrityPlugin
339
+ };
@@ -33,6 +33,10 @@ import {
33
33
  } from "../code_executors/built_in_code_executor.js";
34
34
  import { createEvent } from "../events/event.js";
35
35
  import { createEventActions } from "../events/event_actions.js";
36
+ import {
37
+ internalMetadata,
38
+ withoutInternalMetadata
39
+ } from "../events/internal_metadata.js";
36
40
  import { PluginManager } from "../plugins/plugin_manager.js";
37
41
  import {
38
42
  runAsyncGeneratorWithOtelContext,
@@ -218,7 +222,8 @@ const _Runner = class _Runner {
218
222
  author: "user",
219
223
  actions: stateDelta ? createEventActions({ stateDelta }) : void 0,
220
224
  content: newMessage,
221
- customMetadata: params.customMetadata
225
+ // Callers cannot set ADK-internal keys.
226
+ customMetadata: withoutInternalMetadata(params.customMetadata)
222
227
  })
223
228
  });
224
229
  if ((_e = params.abortSignal) == null ? void 0 : _e.aborted) {
@@ -262,7 +267,7 @@ const _Runner = class _Runner {
262
267
  event
263
268
  });
264
269
  const outputEvent = modifiedEvent ? {
265
- ...modifiedEvent,
270
+ ...withInternalMetadataOf(event, modifiedEvent),
266
271
  id: event.id,
267
272
  invocationId: event.invocationId,
268
273
  timestamp: event.timestamp,
@@ -514,7 +519,7 @@ const _Runner = class _Runner {
514
519
  if ((_d2 = params.abortSignal) == null ? void 0 : _d2.aborted) {
515
520
  return;
516
521
  }
517
- const eventToProcess = modifiedEvent != null ? modifiedEvent : event;
522
+ const eventToProcess = modifiedEvent ? withInternalMetadataOf(event, modifiedEvent) : event;
518
523
  if (!eventToProcess.partial && !isLiveModelMediaEventWithInlineData(eventToProcess)) {
519
524
  await this.sessionService.appendEvent({
520
525
  session,
@@ -533,6 +538,18 @@ const _Runner = class _Runner {
533
538
  };
534
539
  __name(_Runner, "Runner");
535
540
  let Runner = _Runner;
541
+ function withInternalMetadataOf(original, replacement) {
542
+ var _a2;
543
+ const internal = internalMetadata(original.customMetadata);
544
+ if (Object.keys(internal).length === 0) {
545
+ return replacement;
546
+ }
547
+ return {
548
+ ...replacement,
549
+ customMetadata: { ...(_a2 = replacement.customMetadata) != null ? _a2 : {}, ...internal }
550
+ };
551
+ }
552
+ __name(withInternalMetadataOf, "withInternalMetadataOf");
536
553
  function isLiveModelMediaEventWithInlineData(event) {
537
554
  var _a2;
538
555
  const parts = (_a2 = event.content) == null ? void 0 : _a2.parts;
@@ -5,7 +5,7 @@ const require = topLevelCreateRequire(import.meta.url);
5
5
  * Copyright 2025 Google LLC
6
6
  * SPDX-License-Identifier: Apache-2.0
7
7
  */
8
- const version = "2.2.0";
8
+ const version = "2.2.1";
9
9
  export {
10
10
  version
11
11
  };
@@ -87,6 +87,7 @@ export { createEvent, generateClientFunctionCallId, getFunctionCalls, getFunctio
87
87
  export type { CreateEventParams, Event, NodeInfo, Route, RouteKey, } from './events/event.js';
88
88
  export { createEventActions } from './events/event_actions.js';
89
89
  export type { EventActions } from './events/event_actions.js';
90
+ export { INTERNAL_METADATA_PREFIX, RESTORED_EVENT_KEY, markRestored, publicEvent, publicMetadata, publicSession, } from './events/internal_metadata.js';
90
91
  export { EventType, toStructuredEvents } from './events/structured_events.js';
91
92
  export type { ActivityEvent, CallCodeEvent, CodeResultEvent, ContentEvent, ErrorEvent, FinishedEvent, StructuredEvent, ThoughtEvent, ToolCallEvent, ToolConfirmationEvent, ToolResultEvent, } from './events/structured_events.js';
92
93
  export { BaseExampleProvider, isBaseExampleProvider, } from './examples/base_example_provider.js';
@@ -121,6 +122,8 @@ export { ADK_HANDLE_MODEL_ERROR_TOOL_NAME, RESERVED_TOOL_CALL_ERROR_TYPE, Reflec
121
122
  export { ReflectAndRetryToolPlugin, type ReflectAndRetryToolPluginOptions, } from './plugins/reflect_retry_tool_plugin.js';
122
123
  export { InMemoryPolicyEngine, PolicyOutcome, SecurityPlugin, getAskUserConfirmationFunctionCalls, } from './plugins/security_plugin.js';
123
124
  export type { BasePolicyEngine, PolicyCheckResult, ToolCallPolicyContext, } from './plugins/security_plugin.js';
125
+ export { ToolCallIntegrityError, ToolCallIntegrityPlugin, } from './plugins/tool_call_integrity_plugin.js';
126
+ export type { ToolCallIntegrityPluginOptions } from './plugins/tool_call_integrity_plugin.js';
124
127
  export { InMemoryRunner } from './runner/in_memory_runner.js';
125
128
  export { Runner, determineAgentForResumption, findEventByLastFunctionResponseId, isRoutableLlmAgent, isRunner, } from './runner/runner.js';
126
129
  export type { RunnerConfig } from './runner/runner.js';
@@ -0,0 +1,43 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { Event } from './event.js';
7
+ export declare const INVOCATION_ABORTED = "INVOCATION_ABORTED";
8
+ export declare const ABORT_MESSAGE = "Invocation was aborted by client.";
9
+ /**
10
+ * Returns whether `event` was synthesized to seal an aborted invocation.
11
+ */
12
+ export declare function isAbortEvent(event: Event): boolean;
13
+ /** Parameters for {@link buildAbortEvents}. */
14
+ export interface BuildAbortEventsParams {
15
+ /** The session history, in chronological order. */
16
+ events: Event[];
17
+ /** The aborted invocation; only its events are considered. */
18
+ invocationId: string;
19
+ /** Author of the abort event returned when nothing is dangling. */
20
+ rootAgentName: string;
21
+ /**
22
+ * Branch for calls whose event has no branch, and for the abort event
23
+ * returned when nothing is dangling.
24
+ */
25
+ branch?: string;
26
+ }
27
+ /**
28
+ * Returns the events that seal an aborted invocation.
29
+ *
30
+ * Each dangling function call gets a synthetic error response carrying the
31
+ * author, branch and isolation scope of the event that issued it, so the
32
+ * response pairs with its call in the issuing agent's own view. Calls sharing
33
+ * those three values are grouped into one event. If nothing is dangling, a
34
+ * single content-less abort event authored by the root agent is returned
35
+ * instead.
36
+ *
37
+ * Long-running calls (including confirmation and credential requests) are
38
+ * sealed too: the invocation that issued them is gone, so they are not left
39
+ * pending for a later turn.
40
+ *
41
+ * @returns The synthetic events, in the order they should be appended.
42
+ */
43
+ export declare function buildAbortEvents({ events, invocationId, rootAgentName, branch, }: BuildAbortEventsParams): Event[];
@@ -0,0 +1,78 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ /**
7
+ * `Event.customMetadata` keys that only ADK code may write.
8
+ *
9
+ * Mirrors adk-python's `google.adk.events._internal_metadata`.
10
+ */
11
+ import type { Session } from '../sessions/session.js';
12
+ import type { Event } from './event.js';
13
+ type Metadata = Record<string, unknown>;
14
+ /**
15
+ * Prefix of `customMetadata` keys that callers cannot set.
16
+ *
17
+ * Keys with this prefix are dropped from the `customMetadata` passed to
18
+ * `Runner.runAsync`, and from events that are restored into a session or
19
+ * received from a remote A2A agent. Stored events keep them, but they are
20
+ * removed from API responses, saved session files and A2A messages.
21
+ *
22
+ * The value matches adk-python so a session store shared between the two
23
+ * treats the same keys as internal.
24
+ */
25
+ export declare const INTERNAL_METADATA_PREFIX = "__adk_internal_";
26
+ /** Set on events that ADK restored into a session from outside it. */
27
+ export declare const RESTORED_EVENT_KEY = "__adk_internal_restored_event";
28
+ /**
29
+ * Returns `metadata` without keys that have the internal prefix.
30
+ *
31
+ * Use it where callers supply metadata. Dropped keys are logged at debug level,
32
+ * because a caller set a key it cannot set.
33
+ *
34
+ * @param metadata A `customMetadata` value. It is not modified.
35
+ * @returns A new object without internal keys. A value that is not a plain
36
+ * object, such as `undefined`, is returned unchanged.
37
+ */
38
+ export declare function withoutInternalMetadata<T>(metadata: T): T;
39
+ /**
40
+ * Returns `metadata` as callers see it, without internal keys.
41
+ *
42
+ * Use it where events leave ADK. Removal there is routine, so nothing is
43
+ * logged.
44
+ *
45
+ * @param metadata A `customMetadata` value. It is not modified.
46
+ * @returns A new object without internal keys, or `undefined` if nothing is
47
+ * left. A value that is not a plain object is returned unchanged.
48
+ */
49
+ export declare function publicMetadata<T>(metadata: T): T | undefined;
50
+ /** Returns only the keys of `metadata` that have the internal prefix. */
51
+ export declare function internalMetadata(metadata: unknown): Metadata;
52
+ /**
53
+ * Marks an event restored from outside the session, in place.
54
+ *
55
+ * Internal metadata carried by the event is removed first, so a caller cannot
56
+ * supply its own.
57
+ *
58
+ * @param event The event about to be appended to a new session.
59
+ * @returns The same event.
60
+ */
61
+ export declare function markRestored<T extends Event>(event: T): T;
62
+ /**
63
+ * Returns the event as callers see it, without internal metadata.
64
+ *
65
+ * @param event A stored event. It is not modified.
66
+ * @returns The same event if it has no internal keys. Otherwise a copy whose
67
+ * `customMetadata` drops them, or is `undefined` if nothing else is left.
68
+ */
69
+ export declare function publicEvent<T extends Event>(event: T): T;
70
+ /**
71
+ * Returns the session as callers see it, without internal metadata.
72
+ *
73
+ * @param session A stored session. It is not modified.
74
+ * @returns The same session if no event changes. Otherwise a copy whose events
75
+ * are passed through {@link publicEvent}.
76
+ */
77
+ export declare function publicSession<T extends Session>(session: T): T;
78
+ export {};
@@ -0,0 +1,59 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { Content, GenerateContentConfig, GenerateContentResponse, GenerateContentResponseUsageMetadata, Part } from '@google/genai';
7
+ import { LlmResponse } from './llm_response.js';
8
+ /** The most times one generation is resumed after the model pauses it. */
9
+ export declare const MAX_RESUMES = 256;
10
+ /** The contents and config of a request that resumes a paused generation. */
11
+ export interface ResumeRequest {
12
+ contents: Content[];
13
+ config: GenerateContentConfig;
14
+ }
15
+ /**
16
+ * Returns the token that resumes `response`, or undefined if it did not pause
17
+ * or has no token.
18
+ */
19
+ export declare function resumeToken(response: GenerateContentResponse): string | undefined;
20
+ /**
21
+ * One generation, carried across the requests that resume it after the model
22
+ * pauses it.
23
+ */
24
+ export declare class GeminiContinuation {
25
+ private readonly config?;
26
+ private readonly contents;
27
+ private readonly parts;
28
+ private usage?;
29
+ private token?;
30
+ private resumes;
31
+ constructor(contents: Content[], config?: GenerateContentConfig | undefined);
32
+ /**
33
+ * Adds one request's output to the generation: its parts to the content and
34
+ * its usage to the total.
35
+ */
36
+ addOutput(newParts: Part[], newUsage: GenerateContentResponseUsageMetadata | undefined): void;
37
+ /**
38
+ * Returns the request that resumes the generation after a request that
39
+ * ended with `nextToken`. Returns undefined if the request did not pause,
40
+ * returned the previous token again, or the generation was already resumed
41
+ * {@link MAX_RESUMES} times.
42
+ */
43
+ resumeRequest(nextToken: string | undefined): ResumeRequest | undefined;
44
+ /** Returns `response` with the content and usage of all requests, if resumed. */
45
+ complete(response: GenerateContentResponse): LlmResponse;
46
+ /**
47
+ * Returns the final streamed `response`, with usage summed across all
48
+ * requests if resumed.
49
+ */
50
+ withSummedUsage(response: LlmResponse): LlmResponse;
51
+ /** Returns whether a request that ended with `nextToken` is resumed. */
52
+ willResume(nextToken: string): boolean;
53
+ /** Whether the generation took more than one request. */
54
+ private get resumed();
55
+ private content;
56
+ private buildResumeRequest;
57
+ /** Appends `newParts`, joining text as the streaming aggregator does. */
58
+ private appendParts;
59
+ }