@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.
- package/dist/cjs/a2a/event_converter_utils.js +5 -1
- package/dist/cjs/a2a/metadata_converter_utils.js +2 -1
- package/dist/cjs/common.js +18 -0
- package/dist/cjs/events/abort_events.js +135 -0
- package/dist/cjs/events/internal_metadata.js +131 -0
- package/dist/cjs/models/gemini_continuation.js +232 -0
- package/dist/cjs/plugins/debug_logging_plugin.js +653 -0
- package/dist/cjs/plugins/plugin_manager.js +1 -1
- package/dist/cjs/plugins/tool_call_integrity_plugin.js +364 -0
- package/dist/cjs/runner/runner.js +17 -3
- package/dist/cjs/version.js +1 -1
- package/dist/esm/a2a/event_converter_utils.js +5 -1
- package/dist/esm/a2a/metadata_converter_utils.js +2 -1
- package/dist/esm/common.js +20 -0
- package/dist/esm/events/abort_events.js +110 -0
- package/dist/esm/events/internal_metadata.js +97 -0
- package/dist/esm/models/gemini_continuation.js +205 -0
- package/dist/esm/plugins/debug_logging_plugin.js +615 -0
- package/dist/esm/plugins/plugin_manager.js +1 -1
- package/dist/esm/plugins/tool_call_integrity_plugin.js +339 -0
- package/dist/esm/runner/runner.js +20 -3
- package/dist/esm/version.js +1 -1
- package/dist/types/common.d.ts +3 -0
- package/dist/types/events/abort_events.d.ts +43 -0
- package/dist/types/events/internal_metadata.d.ts +78 -0
- package/dist/types/models/gemini_continuation.d.ts +59 -0
- package/dist/types/plugins/debug_logging_plugin.d.ts +157 -0
- package/dist/types/plugins/tool_call_integrity_plugin.d.ts +116 -0
- package/dist/types/version.d.ts +1 -1
- package/dist/web/index_web.js +59 -59
- package/dist/web/index_web.js.map +4 -4
- package/package.json +1 -1
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
"use strict";
|
|
8
|
+
var __defProp = Object.defineProperty;
|
|
9
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
10
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
11
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
12
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
13
|
+
var __export = (target, all) => {
|
|
14
|
+
for (var name in all)
|
|
15
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
16
|
+
};
|
|
17
|
+
var __copyProps = (to, from, except, desc) => {
|
|
18
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
19
|
+
for (let key of __getOwnPropNames(from))
|
|
20
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
21
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
22
|
+
}
|
|
23
|
+
return to;
|
|
24
|
+
};
|
|
25
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
26
|
+
var tool_call_integrity_plugin_exports = {};
|
|
27
|
+
__export(tool_call_integrity_plugin_exports, {
|
|
28
|
+
TOOL_CALL_HMAC_METADATA_KEY: () => TOOL_CALL_HMAC_METADATA_KEY,
|
|
29
|
+
ToolCallIntegrityError: () => ToolCallIntegrityError,
|
|
30
|
+
ToolCallIntegrityPlugin: () => ToolCallIntegrityPlugin
|
|
31
|
+
});
|
|
32
|
+
module.exports = __toCommonJS(tool_call_integrity_plugin_exports);
|
|
33
|
+
var import_event = require("../events/event.js");
|
|
34
|
+
var import_internal_metadata = require("../events/internal_metadata.js");
|
|
35
|
+
var import_logger = require("../utils/logger.js");
|
|
36
|
+
var import_base_plugin = require("./base_plugin.js");
|
|
37
|
+
/**
|
|
38
|
+
* @license
|
|
39
|
+
* Copyright 2026 Google LLC
|
|
40
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
41
|
+
*/
|
|
42
|
+
const TOOL_CALL_HMAC_METADATA_KEY = `${import_internal_metadata.INTERNAL_METADATA_PREFIX}fc_hmac`;
|
|
43
|
+
const STAMP_PREFIX = "v1:";
|
|
44
|
+
const _ToolCallIntegrityError = class _ToolCallIntegrityError extends Error {
|
|
45
|
+
constructor(message) {
|
|
46
|
+
super(message);
|
|
47
|
+
this.name = "ToolCallIntegrityError";
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
__name(_ToolCallIntegrityError, "ToolCallIntegrityError");
|
|
51
|
+
let ToolCallIntegrityError = _ToolCallIntegrityError;
|
|
52
|
+
function jsonForm(value) {
|
|
53
|
+
const json = JSON.stringify(value);
|
|
54
|
+
return json === void 0 ? null : JSON.parse(json);
|
|
55
|
+
}
|
|
56
|
+
__name(jsonForm, "jsonForm");
|
|
57
|
+
function canonicalJson(value) {
|
|
58
|
+
if (Array.isArray(value)) {
|
|
59
|
+
return `[${value.map((item) => canonicalJson(item)).join(",")}]`;
|
|
60
|
+
}
|
|
61
|
+
if (value !== null && typeof value === "object") {
|
|
62
|
+
const object = value;
|
|
63
|
+
const entries = Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson(object[key])}`);
|
|
64
|
+
return `{${entries.join(",")}}`;
|
|
65
|
+
}
|
|
66
|
+
return JSON.stringify(value);
|
|
67
|
+
}
|
|
68
|
+
__name(canonicalJson, "canonicalJson");
|
|
69
|
+
function jsonArgs(args) {
|
|
70
|
+
const json = jsonForm(args != null ? args : {});
|
|
71
|
+
return json != null ? json : {};
|
|
72
|
+
}
|
|
73
|
+
__name(jsonArgs, "jsonArgs");
|
|
74
|
+
function canonicalPayload(session, event, functionCall) {
|
|
75
|
+
var _a, _b, _c, _d, _e;
|
|
76
|
+
return new TextEncoder().encode(
|
|
77
|
+
canonicalJson({
|
|
78
|
+
app_name: session.appName,
|
|
79
|
+
user_id: session.userId,
|
|
80
|
+
session_id: session.id,
|
|
81
|
+
invocation_id: (_a = event.invocationId) != null ? _a : null,
|
|
82
|
+
branch: (_b = event.branch) != null ? _b : null,
|
|
83
|
+
author: (_c = event.author) != null ? _c : null,
|
|
84
|
+
name: (_d = functionCall.name) != null ? _d : null,
|
|
85
|
+
id: (_e = functionCall.id) != null ? _e : null,
|
|
86
|
+
args: jsonArgs(functionCall.args)
|
|
87
|
+
})
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
__name(canonicalPayload, "canonicalPayload");
|
|
91
|
+
function isStampMap(value) {
|
|
92
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) && Object.values(value).every(
|
|
93
|
+
// eslint-disable-next-line no-control-regex
|
|
94
|
+
(stamp) => typeof stamp === "string" && /^[\x00-\x7f]*$/.test(stamp)
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
__name(isStampMap, "isStampMap");
|
|
98
|
+
function isRestored(event) {
|
|
99
|
+
var _a;
|
|
100
|
+
return Boolean((_a = event.customMetadata) == null ? void 0 : _a[import_internal_metadata.RESTORED_EVENT_KEY]);
|
|
101
|
+
}
|
|
102
|
+
__name(isRestored, "isRestored");
|
|
103
|
+
function getStamps(event) {
|
|
104
|
+
var _a;
|
|
105
|
+
const stamps = (_a = event.customMetadata) == null ? void 0 : _a[TOOL_CALL_HMAC_METADATA_KEY];
|
|
106
|
+
if (stamps === void 0 || stamps === null) {
|
|
107
|
+
return {};
|
|
108
|
+
}
|
|
109
|
+
if (!isStampMap(stamps)) {
|
|
110
|
+
throw new ToolCallIntegrityError(
|
|
111
|
+
`Event '${event.id}' has a malformed integrity stamp.`
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
return stamps;
|
|
115
|
+
}
|
|
116
|
+
__name(getStamps, "getStamps");
|
|
117
|
+
function hasStamp(stamps, callId) {
|
|
118
|
+
return Object.hasOwn(stamps, callId);
|
|
119
|
+
}
|
|
120
|
+
__name(hasStamp, "hasStamp");
|
|
121
|
+
function toHex(bytes) {
|
|
122
|
+
return Array.from(
|
|
123
|
+
new Uint8Array(bytes),
|
|
124
|
+
(b) => b.toString(16).padStart(2, "0")
|
|
125
|
+
).join("");
|
|
126
|
+
}
|
|
127
|
+
__name(toHex, "toHex");
|
|
128
|
+
function fromHex(hex) {
|
|
129
|
+
if (!/^[0-9a-f]{64}$/.test(hex)) {
|
|
130
|
+
return void 0;
|
|
131
|
+
}
|
|
132
|
+
const bytes = new Uint8Array(hex.length / 2);
|
|
133
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
134
|
+
bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
135
|
+
}
|
|
136
|
+
return bytes;
|
|
137
|
+
}
|
|
138
|
+
__name(fromHex, "fromHex");
|
|
139
|
+
function getSubtleCrypto() {
|
|
140
|
+
var _a;
|
|
141
|
+
const subtle = (_a = globalThis.crypto) == null ? void 0 : _a.subtle;
|
|
142
|
+
if (!subtle) {
|
|
143
|
+
throw new Error(
|
|
144
|
+
"ToolCallIntegrityPlugin requires the Web Crypto API (globalThis.crypto.subtle), which is not available in this environment."
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
return subtle;
|
|
148
|
+
}
|
|
149
|
+
__name(getSubtleCrypto, "getSubtleCrypto");
|
|
150
|
+
const _ToolCallIntegrityPlugin = class _ToolCallIntegrityPlugin extends import_base_plugin.BasePlugin {
|
|
151
|
+
/**
|
|
152
|
+
* @throws {Error} If `secretKey` is empty or contains a key that is not
|
|
153
|
+
* non-empty bytes.
|
|
154
|
+
*/
|
|
155
|
+
constructor(options) {
|
|
156
|
+
var _a, _b;
|
|
157
|
+
super((_a = options.name) != null ? _a : "tool_call_integrity");
|
|
158
|
+
const secretKey = options.secretKey;
|
|
159
|
+
const rawKeys = secretKey instanceof Uint8Array ? [secretKey] : Array.isArray(secretKey) ? [...secretKey] : [];
|
|
160
|
+
if (rawKeys.length === 0 || !rawKeys.every((key) => key instanceof Uint8Array && key.length > 0)) {
|
|
161
|
+
throw new Error(
|
|
162
|
+
"secretKey must be non-empty bytes or a non-empty list of them."
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
this.keys = rawKeys.map((key) => new Uint8Array(key));
|
|
166
|
+
this.allowUnstampedCalls = (_b = options.allowUnstampedCalls) != null ? _b : false;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Returns a copy with internal metadata removed and marked as restored.
|
|
170
|
+
*
|
|
171
|
+
* Use it on events that your code copies into another session, so that the
|
|
172
|
+
* history passes the integrity check. The copy only keeps the history: its
|
|
173
|
+
* function calls are never executed.
|
|
174
|
+
*
|
|
175
|
+
* @param event The event to copy. It is not modified.
|
|
176
|
+
* @returns The marked copy, ready to append to the new session.
|
|
177
|
+
*/
|
|
178
|
+
static prepareRestoredEvent(event) {
|
|
179
|
+
return (0, import_internal_metadata.markRestored)((0, import_event.createEvent)(structuredClone(event)));
|
|
180
|
+
}
|
|
181
|
+
getCryptoKeys() {
|
|
182
|
+
if (!this.cryptoKeys) {
|
|
183
|
+
const subtle = getSubtleCrypto();
|
|
184
|
+
this.cryptoKeys = Promise.all(
|
|
185
|
+
this.keys.map(
|
|
186
|
+
(key) => subtle.importKey("raw", key, { name: "HMAC", hash: "SHA-256" }, false, [
|
|
187
|
+
"sign",
|
|
188
|
+
"verify"
|
|
189
|
+
])
|
|
190
|
+
)
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
return this.cryptoKeys;
|
|
194
|
+
}
|
|
195
|
+
async sign(payload) {
|
|
196
|
+
const [primary] = await this.getCryptoKeys();
|
|
197
|
+
const digest = await getSubtleCrypto().sign("HMAC", primary, payload);
|
|
198
|
+
return STAMP_PREFIX + toHex(digest);
|
|
199
|
+
}
|
|
200
|
+
/** `subtle.verify` compares in constant time. */
|
|
201
|
+
async verify(payload, stamp) {
|
|
202
|
+
if (!stamp.startsWith(STAMP_PREFIX)) {
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
const signature = fromHex(stamp.slice(STAMP_PREFIX.length));
|
|
206
|
+
if (!signature) {
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
const subtle = getSubtleCrypto();
|
|
210
|
+
for (const key of await this.getCryptoKeys()) {
|
|
211
|
+
if (await subtle.verify("HMAC", key, signature, payload)) {
|
|
212
|
+
return true;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
unstamped(name, callId) {
|
|
218
|
+
const message = `${name} call '${callId}' has no integrity stamp.`;
|
|
219
|
+
if (!this.allowUnstampedCalls) {
|
|
220
|
+
throw new ToolCallIntegrityError(message);
|
|
221
|
+
}
|
|
222
|
+
import_logger.logger.warn(message);
|
|
223
|
+
}
|
|
224
|
+
async onEventCallback({
|
|
225
|
+
invocationContext,
|
|
226
|
+
event
|
|
227
|
+
}) {
|
|
228
|
+
var _a;
|
|
229
|
+
const session = invocationContext.session;
|
|
230
|
+
const calls = (0, import_event.getFunctionCalls)(event).filter((fc) => fc.id);
|
|
231
|
+
if (!event.partial) {
|
|
232
|
+
const seen = /* @__PURE__ */ new Set();
|
|
233
|
+
for (const fc of calls) {
|
|
234
|
+
if (seen.has(fc.id)) {
|
|
235
|
+
throw new ToolCallIntegrityError(
|
|
236
|
+
`Event '${event.id}' repeats function call ID '${fc.id}'.`
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
seen.add(fc.id);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
const stamps = {};
|
|
243
|
+
for (const fc of calls) {
|
|
244
|
+
stamps[fc.id] = await this.sign(canonicalPayload(session, event, fc));
|
|
245
|
+
}
|
|
246
|
+
if (Object.keys(stamps).length > 0) {
|
|
247
|
+
event.customMetadata = {
|
|
248
|
+
...(_a = event.customMetadata) != null ? _a : {},
|
|
249
|
+
[TOOL_CALL_HMAC_METADATA_KEY]: stamps
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
return void 0;
|
|
253
|
+
}
|
|
254
|
+
async beforeRunCallback({
|
|
255
|
+
invocationContext
|
|
256
|
+
}) {
|
|
257
|
+
const session = invocationContext.session;
|
|
258
|
+
for (const event of session.events) {
|
|
259
|
+
const calls = (0, import_event.getFunctionCalls)(event);
|
|
260
|
+
if (calls.length === 0 || isRestored(event)) {
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
const stamps = getStamps(event);
|
|
264
|
+
const verified = /* @__PURE__ */ new Set();
|
|
265
|
+
for (const fc of calls) {
|
|
266
|
+
if (!fc.id) {
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
if (!hasStamp(stamps, fc.id)) {
|
|
270
|
+
this.unstamped(fc.name, fc.id);
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
if (verified.has(fc.id)) {
|
|
274
|
+
throw new ToolCallIntegrityError(
|
|
275
|
+
`Event '${event.id}' has duplicate function call ID '${fc.id}'.`
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
const payload = canonicalPayload(session, event, fc);
|
|
279
|
+
if (!await this.verify(payload, stamps[fc.id])) {
|
|
280
|
+
throw new ToolCallIntegrityError(
|
|
281
|
+
`${fc.name} call '${fc.id}' does not match its integrity stamp.`
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
verified.add(fc.id);
|
|
285
|
+
}
|
|
286
|
+
const unmatched = Object.keys(stamps).filter((id) => !verified.has(id)).sort();
|
|
287
|
+
if (unmatched.length > 0) {
|
|
288
|
+
throw new ToolCallIntegrityError(
|
|
289
|
+
`Event '${event.id}' has integrity stamps with no matching call: ${JSON.stringify(unmatched)}.`
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return void 0;
|
|
294
|
+
}
|
|
295
|
+
async beforeToolCallback({
|
|
296
|
+
tool,
|
|
297
|
+
toolArgs,
|
|
298
|
+
toolContext
|
|
299
|
+
}) {
|
|
300
|
+
const callId = toolContext.functionCallId;
|
|
301
|
+
if (!callId) {
|
|
302
|
+
throw new ToolCallIntegrityError(
|
|
303
|
+
`${tool.name} call has no ID, so its integrity cannot be checked.`
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
const session = toolContext.invocationContext.session;
|
|
307
|
+
const stored = [];
|
|
308
|
+
let restored = false;
|
|
309
|
+
for (const event of session.events) {
|
|
310
|
+
for (const fc of (0, import_event.getFunctionCalls)(event)) {
|
|
311
|
+
if (fc.id !== callId) {
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
if (isRestored(event)) {
|
|
315
|
+
restored = true;
|
|
316
|
+
} else {
|
|
317
|
+
stored.push([event, fc]);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
if (stored.length === 0) {
|
|
322
|
+
if (restored) {
|
|
323
|
+
throw new ToolCallIntegrityError(
|
|
324
|
+
`${tool.name} call '${callId}' comes from restored history and cannot be executed.`
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
this.unstamped(tool.name, callId);
|
|
328
|
+
return void 0;
|
|
329
|
+
}
|
|
330
|
+
const trusted = [];
|
|
331
|
+
for (const [event, fc] of stored) {
|
|
332
|
+
const stamps = getStamps(event);
|
|
333
|
+
if (!hasStamp(stamps, callId)) {
|
|
334
|
+
this.unstamped(tool.name, callId);
|
|
335
|
+
} else if (!await this.verify(
|
|
336
|
+
canonicalPayload(session, event, fc),
|
|
337
|
+
stamps[callId]
|
|
338
|
+
)) {
|
|
339
|
+
throw new ToolCallIntegrityError(
|
|
340
|
+
`${tool.name} call '${callId}' does not match its integrity stamp.`
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
trusted.push(fc);
|
|
344
|
+
}
|
|
345
|
+
const executed = canonicalJson(jsonArgs(toolArgs));
|
|
346
|
+
const matches = trusted.some(
|
|
347
|
+
(fc) => fc.name === tool.name && canonicalJson(jsonArgs(fc.args)) === executed
|
|
348
|
+
);
|
|
349
|
+
if (!matches) {
|
|
350
|
+
throw new ToolCallIntegrityError(
|
|
351
|
+
`${tool.name} call '${callId}' arguments do not match its stored call.`
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
return void 0;
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
__name(_ToolCallIntegrityPlugin, "ToolCallIntegrityPlugin");
|
|
358
|
+
let ToolCallIntegrityPlugin = _ToolCallIntegrityPlugin;
|
|
359
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
360
|
+
0 && (module.exports = {
|
|
361
|
+
TOOL_CALL_HMAC_METADATA_KEY,
|
|
362
|
+
ToolCallIntegrityError,
|
|
363
|
+
ToolCallIntegrityPlugin
|
|
364
|
+
});
|
|
@@ -45,6 +45,7 @@ var import_session_artifact_service = require("../artifacts/session_artifact_ser
|
|
|
45
45
|
var import_built_in_code_executor = require("../code_executors/built_in_code_executor.js");
|
|
46
46
|
var import_event = require("../events/event.js");
|
|
47
47
|
var import_event_actions = require("../events/event_actions.js");
|
|
48
|
+
var import_internal_metadata = require("../events/internal_metadata.js");
|
|
48
49
|
var import_plugin_manager = require("../plugins/plugin_manager.js");
|
|
49
50
|
var import_tracing = require("../telemetry/tracing.js");
|
|
50
51
|
var import_base_toolset = require("../tools/base_toolset.js");
|
|
@@ -230,7 +231,8 @@ const _Runner = class _Runner {
|
|
|
230
231
|
author: "user",
|
|
231
232
|
actions: stateDelta ? (0, import_event_actions.createEventActions)({ stateDelta }) : void 0,
|
|
232
233
|
content: newMessage,
|
|
233
|
-
|
|
234
|
+
// Callers cannot set ADK-internal keys.
|
|
235
|
+
customMetadata: (0, import_internal_metadata.withoutInternalMetadata)(params.customMetadata)
|
|
234
236
|
})
|
|
235
237
|
});
|
|
236
238
|
if ((_e = params.abortSignal) == null ? void 0 : _e.aborted) {
|
|
@@ -274,7 +276,7 @@ const _Runner = class _Runner {
|
|
|
274
276
|
event
|
|
275
277
|
});
|
|
276
278
|
const outputEvent = modifiedEvent ? {
|
|
277
|
-
...modifiedEvent,
|
|
279
|
+
...withInternalMetadataOf(event, modifiedEvent),
|
|
278
280
|
id: event.id,
|
|
279
281
|
invocationId: event.invocationId,
|
|
280
282
|
timestamp: event.timestamp,
|
|
@@ -526,7 +528,7 @@ const _Runner = class _Runner {
|
|
|
526
528
|
if ((_d2 = params.abortSignal) == null ? void 0 : _d2.aborted) {
|
|
527
529
|
return;
|
|
528
530
|
}
|
|
529
|
-
const eventToProcess = modifiedEvent
|
|
531
|
+
const eventToProcess = modifiedEvent ? withInternalMetadataOf(event, modifiedEvent) : event;
|
|
530
532
|
if (!eventToProcess.partial && !isLiveModelMediaEventWithInlineData(eventToProcess)) {
|
|
531
533
|
await this.sessionService.appendEvent({
|
|
532
534
|
session,
|
|
@@ -545,6 +547,18 @@ const _Runner = class _Runner {
|
|
|
545
547
|
};
|
|
546
548
|
__name(_Runner, "Runner");
|
|
547
549
|
let Runner = _Runner;
|
|
550
|
+
function withInternalMetadataOf(original, replacement) {
|
|
551
|
+
var _a2;
|
|
552
|
+
const internal = (0, import_internal_metadata.internalMetadata)(original.customMetadata);
|
|
553
|
+
if (Object.keys(internal).length === 0) {
|
|
554
|
+
return replacement;
|
|
555
|
+
}
|
|
556
|
+
return {
|
|
557
|
+
...replacement,
|
|
558
|
+
customMetadata: { ...(_a2 = replacement.customMetadata) != null ? _a2 : {}, ...internal }
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
__name(withInternalMetadataOf, "withInternalMetadataOf");
|
|
548
562
|
function isLiveModelMediaEventWithInlineData(event) {
|
|
549
563
|
var _a2;
|
|
550
564
|
const parts = (_a2 = event.content) == null ? void 0 : _a2.parts;
|
package/dist/cjs/version.js
CHANGED
|
@@ -32,7 +32,7 @@ module.exports = __toCommonJS(version_exports);
|
|
|
32
32
|
* Copyright 2025 Google LLC
|
|
33
33
|
* SPDX-License-Identifier: Apache-2.0
|
|
34
34
|
*/
|
|
35
|
-
const version = "2.2.
|
|
35
|
+
const version = "2.2.1";
|
|
36
36
|
// Annotate the CommonJS export names for ESM import in node:
|
|
37
37
|
0 && (module.exports = {
|
|
38
38
|
version
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
} from "@google/genai";
|
|
14
14
|
import { createEvent } from "../events/event.js";
|
|
15
15
|
import { createEventActions } from "../events/event_actions.js";
|
|
16
|
+
import { withoutInternalMetadata } from "../events/internal_metadata.js";
|
|
16
17
|
import { randomUUID } from "../utils/env_aware_utils.js";
|
|
17
18
|
import {
|
|
18
19
|
getEventMetadata,
|
|
@@ -191,7 +192,10 @@ function createAdkEventFromMetadata(a2aEvent) {
|
|
|
191
192
|
citationMetadata: metadata[A2AMetadataKeys.CITATION_METADATA],
|
|
192
193
|
groundingMetadata: metadata[A2AMetadataKeys.GROUNDING_METADATA],
|
|
193
194
|
usageMetadata: metadata[A2AMetadataKeys.USAGE_METADATA],
|
|
194
|
-
|
|
195
|
+
// A remote peer cannot set ADK-internal keys on the events we emit for it.
|
|
196
|
+
customMetadata: withoutInternalMetadata(
|
|
197
|
+
metadata[A2AMetadataKeys.CUSTOM_METADATA]
|
|
198
|
+
),
|
|
195
199
|
// Only fields in PEER_SETTABLE_ACTION_FIELDS may be restored from
|
|
196
200
|
// metadata a remote A2A peer controls. Every other action field either
|
|
197
201
|
// mutates the caller's own session or drives the caller's own control
|
|
@@ -7,6 +7,7 @@ var __name = (target, value) => __defProp(target, "name", { value, configurable:
|
|
|
7
7
|
* Copyright 2026 Google LLC
|
|
8
8
|
* SPDX-License-Identifier: Apache-2.0
|
|
9
9
|
*/
|
|
10
|
+
import { publicMetadata } from "../events/internal_metadata.js";
|
|
10
11
|
import { isTask } from "./a2a_event.js";
|
|
11
12
|
const ADK_METADATA_KEY_PREFIX = "adk_";
|
|
12
13
|
const A2A_METADATA_KEY_PREFIX = "a2a:";
|
|
@@ -64,7 +65,7 @@ function getA2AEventMetadata(adkEvent, {
|
|
|
64
65
|
[A2AMetadataKeys.CITATION_METADATA]: adkEvent.citationMetadata,
|
|
65
66
|
[A2AMetadataKeys.GROUNDING_METADATA]: adkEvent.groundingMetadata,
|
|
66
67
|
[A2AMetadataKeys.USAGE_METADATA]: adkEvent.usageMetadata,
|
|
67
|
-
[A2AMetadataKeys.CUSTOM_METADATA]: adkEvent.customMetadata,
|
|
68
|
+
[A2AMetadataKeys.CUSTOM_METADATA]: publicMetadata(adkEvent.customMetadata),
|
|
68
69
|
[A2AMetadataKeys.PARTIAL]: adkEvent.partial,
|
|
69
70
|
[A2AMetadataKeys.IS_LONG_RUNNING]: (adkEvent.longRunningToolIds || []).length > 0
|
|
70
71
|
};
|
package/dist/esm/common.js
CHANGED
|
@@ -95,6 +95,14 @@ import {
|
|
|
95
95
|
stringifyContent
|
|
96
96
|
} from "./events/event.js";
|
|
97
97
|
import { createEventActions } from "./events/event_actions.js";
|
|
98
|
+
import {
|
|
99
|
+
INTERNAL_METADATA_PREFIX,
|
|
100
|
+
RESTORED_EVENT_KEY,
|
|
101
|
+
markRestored,
|
|
102
|
+
publicEvent,
|
|
103
|
+
publicMetadata,
|
|
104
|
+
publicSession
|
|
105
|
+
} from "./events/internal_metadata.js";
|
|
98
106
|
import { EventType, toStructuredEvents } from "./events/structured_events.js";
|
|
99
107
|
import {
|
|
100
108
|
BaseExampleProvider,
|
|
@@ -140,6 +148,10 @@ import {
|
|
|
140
148
|
SecurityPlugin,
|
|
141
149
|
getAskUserConfirmationFunctionCalls
|
|
142
150
|
} from "./plugins/security_plugin.js";
|
|
151
|
+
import {
|
|
152
|
+
ToolCallIntegrityError,
|
|
153
|
+
ToolCallIntegrityPlugin
|
|
154
|
+
} from "./plugins/tool_call_integrity_plugin.js";
|
|
143
155
|
import { InMemoryRunner } from "./runner/in_memory_runner.js";
|
|
144
156
|
import {
|
|
145
157
|
Runner,
|
|
@@ -348,6 +360,7 @@ export {
|
|
|
348
360
|
GoogleSearchTool,
|
|
349
361
|
Graph,
|
|
350
362
|
INTERACTIONS_REQUEST_PROCESSOR,
|
|
363
|
+
INTERNAL_METADATA_PREFIX,
|
|
351
364
|
InMemoryArtifactService,
|
|
352
365
|
InMemoryCredentialService,
|
|
353
366
|
InMemoryMemoryService,
|
|
@@ -396,6 +409,7 @@ export {
|
|
|
396
409
|
REQUEST_CREDENTIAL_FUNCTION_CALL_NAME,
|
|
397
410
|
REQUEST_INPUT_FUNCTION_CALL_NAME,
|
|
398
411
|
RESERVED_TOOL_CALL_ERROR_TYPE,
|
|
412
|
+
RESTORED_EVENT_KEY,
|
|
399
413
|
ReadonlyContext,
|
|
400
414
|
ReflectAndRetryModelPlugin,
|
|
401
415
|
ReflectAndRetryToolPlugin,
|
|
@@ -416,6 +430,8 @@ export {
|
|
|
416
430
|
StreamingMode,
|
|
417
431
|
Task,
|
|
418
432
|
TokenBasedContextCompactor,
|
|
433
|
+
ToolCallIntegrityError,
|
|
434
|
+
ToolCallIntegrityPlugin,
|
|
419
435
|
ToolConfirmation,
|
|
420
436
|
ToolContext,
|
|
421
437
|
ToolErrorType,
|
|
@@ -499,11 +515,15 @@ export {
|
|
|
499
515
|
isWebMCPSupported,
|
|
500
516
|
isWorkflow,
|
|
501
517
|
logger,
|
|
518
|
+
markRestored,
|
|
502
519
|
node,
|
|
503
520
|
normalizeRetryExceptions,
|
|
504
521
|
populateClientFunctionCallId,
|
|
505
522
|
prepareRetryConfig,
|
|
506
523
|
pruneThoughts,
|
|
524
|
+
publicEvent,
|
|
525
|
+
publicMetadata,
|
|
526
|
+
publicSession,
|
|
507
527
|
renameReservedKeywords,
|
|
508
528
|
requestInputTool,
|
|
509
529
|
requireAgent,
|
|
@@ -0,0 +1,110 @@
|
|
|
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 {
|
|
11
|
+
createEvent,
|
|
12
|
+
getFunctionCalls,
|
|
13
|
+
getFunctionResponses,
|
|
14
|
+
isFinalResponse
|
|
15
|
+
} from "./event.js";
|
|
16
|
+
const INVOCATION_ABORTED = "INVOCATION_ABORTED";
|
|
17
|
+
const ABORT_MESSAGE = "Invocation was aborted by client.";
|
|
18
|
+
function isAbortEvent(event) {
|
|
19
|
+
return event.errorCode === INVOCATION_ABORTED;
|
|
20
|
+
}
|
|
21
|
+
__name(isAbortEvent, "isAbortEvent");
|
|
22
|
+
function isPausedTaskReply(event) {
|
|
23
|
+
return Boolean(event.isolationScope) && event.author !== "user" && isFinalResponse(event);
|
|
24
|
+
}
|
|
25
|
+
__name(isPausedTaskReply, "isPausedTaskReply");
|
|
26
|
+
function buildAbortEvents({
|
|
27
|
+
events,
|
|
28
|
+
invocationId,
|
|
29
|
+
rootAgentName,
|
|
30
|
+
branch
|
|
31
|
+
}) {
|
|
32
|
+
var _a, _b;
|
|
33
|
+
const invocationEvents = events.filter(
|
|
34
|
+
(e) => e.invocationId === invocationId
|
|
35
|
+
);
|
|
36
|
+
if (invocationEvents.length > 0 && isPausedTaskReply(invocationEvents[invocationEvents.length - 1])) {
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
const answeredCallIds = /* @__PURE__ */ new Set();
|
|
40
|
+
for (const event of invocationEvents) {
|
|
41
|
+
for (const fr of getFunctionResponses(event)) {
|
|
42
|
+
if (fr.id) {
|
|
43
|
+
answeredCallIds.add(fr.id);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const groupedCalls = /* @__PURE__ */ new Map();
|
|
48
|
+
for (const event of invocationEvents) {
|
|
49
|
+
for (const fc of getFunctionCalls(event)) {
|
|
50
|
+
if (!fc.id || answeredCallIds.has(fc.id)) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
const callBranch = event.branch || branch;
|
|
54
|
+
const key = JSON.stringify([
|
|
55
|
+
(_a = event.author) != null ? _a : null,
|
|
56
|
+
callBranch != null ? callBranch : null,
|
|
57
|
+
(_b = event.isolationScope) != null ? _b : null
|
|
58
|
+
]);
|
|
59
|
+
let group = groupedCalls.get(key);
|
|
60
|
+
if (!group) {
|
|
61
|
+
group = {
|
|
62
|
+
author: event.author,
|
|
63
|
+
branch: callBranch,
|
|
64
|
+
isolationScope: event.isolationScope,
|
|
65
|
+
calls: []
|
|
66
|
+
};
|
|
67
|
+
groupedCalls.set(key, group);
|
|
68
|
+
}
|
|
69
|
+
group.calls.push(fc);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (groupedCalls.size === 0) {
|
|
73
|
+
return [
|
|
74
|
+
createEvent({
|
|
75
|
+
invocationId,
|
|
76
|
+
author: rootAgentName,
|
|
77
|
+
branch,
|
|
78
|
+
errorCode: INVOCATION_ABORTED,
|
|
79
|
+
errorMessage: ABORT_MESSAGE
|
|
80
|
+
})
|
|
81
|
+
];
|
|
82
|
+
}
|
|
83
|
+
return [...groupedCalls.values()].map(
|
|
84
|
+
(group) => createEvent({
|
|
85
|
+
invocationId,
|
|
86
|
+
author: group.author,
|
|
87
|
+
branch: group.branch,
|
|
88
|
+
isolationScope: group.isolationScope,
|
|
89
|
+
content: {
|
|
90
|
+
role: "user",
|
|
91
|
+
parts: group.calls.map((fc) => ({
|
|
92
|
+
functionResponse: {
|
|
93
|
+
id: fc.id,
|
|
94
|
+
name: fc.name,
|
|
95
|
+
response: { error: ABORT_MESSAGE }
|
|
96
|
+
}
|
|
97
|
+
}))
|
|
98
|
+
},
|
|
99
|
+
errorCode: INVOCATION_ABORTED,
|
|
100
|
+
errorMessage: ABORT_MESSAGE
|
|
101
|
+
})
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
__name(buildAbortEvents, "buildAbortEvents");
|
|
105
|
+
export {
|
|
106
|
+
ABORT_MESSAGE,
|
|
107
|
+
INVOCATION_ABORTED,
|
|
108
|
+
buildAbortEvents,
|
|
109
|
+
isAbortEvent
|
|
110
|
+
};
|