@google/adk 1.5.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/a2a/a2a_remote_agent.js +12 -2
- package/dist/cjs/a2a/agent_to_a2a.js +0 -1
- package/dist/cjs/a2a/auth.js +65 -0
- package/dist/cjs/a2a/event_converter_utils.js +40 -15
- package/dist/cjs/agents/functions.js +20 -7
- package/dist/cjs/agents/llm_agent.js +2 -1
- package/dist/cjs/agents/processors/basic_llm_request_processor.js +3 -2
- package/dist/cjs/agents/processors/content_request_processor.js +2 -21
- package/dist/cjs/agents/processors/instructions_llm_request_processor.js +3 -1
- package/dist/cjs/artifacts/in_memory_artifact_service.js +10 -9
- package/dist/cjs/auth/credential_service/in_memory_credential_service.js +14 -3
- package/dist/cjs/code_executors/unsafe_local_code_executor.js +23 -12
- package/dist/cjs/common.js +6 -0
- package/dist/cjs/context/agent_controlled_context_compactor.js +2 -11
- package/dist/cjs/context/compaction_utils.js +14 -2
- package/dist/cjs/context/token_based_context_compactor.js +2 -20
- package/dist/cjs/index.js +3 -0
- package/dist/cjs/memory/in_memory_memory_service.js +13 -2
- package/dist/cjs/memory/vertex_ai_memory_bank_service.js +3 -0
- package/dist/cjs/plugins/base_plugin.js +4 -2
- package/dist/cjs/runner/runner.js +18 -11
- package/dist/cjs/sessions/base_session_service.js +8 -3
- package/dist/cjs/sessions/in_memory_session_service.js +8 -8
- package/dist/cjs/sessions/vertex_ai_session_service.js +22 -10
- package/dist/cjs/skills/loader.js +40 -6
- package/dist/cjs/tools/get_user_choice_tool.js +53 -0
- package/dist/cjs/tools/mcp/mcp_session_manager.js +35 -21
- package/dist/cjs/tools/request_input_tool.js +54 -0
- package/dist/cjs/utils/crypto_shim.js +43 -0
- package/dist/cjs/utils/env_aware_utils.js +15 -13
- package/dist/cjs/utils/error_utils.js +120 -0
- package/dist/cjs/utils/file_utils.js +5 -2
- package/dist/cjs/utils/output_schema_utils.js +43 -0
- package/dist/cjs/utils/vertex_ai_utils.js +3 -0
- package/dist/cjs/version.js +1 -1
- package/dist/esm/a2a/a2a_remote_agent.js +12 -2
- package/dist/esm/a2a/agent_to_a2a.js +0 -1
- package/dist/esm/a2a/auth.js +37 -0
- package/dist/esm/a2a/event_converter_utils.js +40 -15
- package/dist/esm/agents/functions.js +20 -7
- package/dist/esm/agents/llm_agent.js +2 -1
- package/dist/esm/agents/processors/basic_llm_request_processor.js +3 -2
- package/dist/esm/agents/processors/content_request_processor.js +2 -21
- package/dist/esm/agents/processors/instructions_llm_request_processor.js +3 -1
- package/dist/esm/artifacts/in_memory_artifact_service.js +10 -9
- package/dist/esm/auth/credential_service/in_memory_credential_service.js +14 -3
- package/dist/esm/code_executors/unsafe_local_code_executor.js +22 -11
- package/dist/esm/common.js +4 -0
- package/dist/esm/context/agent_controlled_context_compactor.js +2 -11
- package/dist/esm/context/compaction_utils.js +12 -1
- package/dist/esm/context/token_based_context_compactor.js +6 -21
- package/dist/esm/index.js +2 -0
- package/dist/esm/memory/in_memory_memory_service.js +13 -2
- package/dist/esm/memory/vertex_ai_memory_bank_service.js +7 -1
- package/dist/esm/plugins/base_plugin.js +4 -2
- package/dist/esm/runner/runner.js +18 -11
- package/dist/esm/sessions/base_session_service.js +8 -3
- package/dist/esm/sessions/in_memory_session_service.js +8 -8
- package/dist/esm/sessions/vertex_ai_session_service.js +26 -11
- package/dist/esm/skills/loader.js +40 -6
- package/dist/esm/tools/get_user_choice_tool.js +25 -0
- package/dist/esm/tools/mcp/mcp_session_manager.js +35 -21
- package/dist/esm/tools/request_input_tool.js +26 -0
- package/dist/esm/utils/crypto_shim.js +15 -0
- package/dist/esm/utils/env_aware_utils.js +15 -13
- package/dist/esm/utils/error_utils.js +92 -0
- package/dist/esm/utils/file_utils.js +5 -2
- package/dist/esm/utils/output_schema_utils.js +15 -0
- package/dist/esm/utils/vertex_ai_utils.js +2 -0
- package/dist/esm/version.js +1 -1
- package/dist/types/a2a/auth.d.ts +30 -0
- package/dist/types/a2a/event_converter_utils.d.ts +4 -1
- package/dist/types/auth/credential_service/in_memory_credential_service.d.ts +11 -0
- package/dist/types/code_executors/unsafe_local_code_executor.d.ts +5 -1
- package/dist/types/common.d.ts +2 -0
- package/dist/types/context/agent_controlled_context_compactor.d.ts +0 -1
- package/dist/types/context/compaction_utils.d.ts +8 -0
- package/dist/types/context/token_based_context_compactor.d.ts +0 -1
- package/dist/types/index.d.ts +2 -1
- package/dist/types/memory/in_memory_memory_service.d.ts +11 -0
- package/dist/types/plugins/base_plugin.d.ts +4 -2
- package/dist/types/sessions/base_session_service.d.ts +8 -0
- package/dist/types/sessions/in_memory_session_service.d.ts +9 -0
- package/dist/types/sessions/vertex_ai_session_service.d.ts +19 -1
- package/dist/types/skills/loader.d.ts +5 -0
- package/dist/types/tools/get_user_choice_tool.d.ts +14 -0
- package/dist/types/tools/request_input_tool.d.ts +15 -0
- package/dist/types/utils/crypto_shim.d.ts +16 -0
- package/dist/types/utils/env_aware_utils.d.ts +23 -0
- package/dist/types/utils/error_utils.d.ts +18 -0
- package/dist/types/utils/output_schema_utils.d.ts +18 -0
- package/dist/types/utils/vertex_ai_utils.d.ts +1 -0
- package/dist/types/version.d.ts +1 -1
- package/dist/web/a2a/a2a_remote_agent.js +12 -2
- package/dist/web/a2a/agent_to_a2a.js +0 -1
- package/dist/web/a2a/auth.js +37 -0
- package/dist/web/a2a/event_converter_utils.js +40 -15
- package/dist/web/agents/functions.js +20 -7
- package/dist/web/agents/llm_agent.js +2 -1
- package/dist/web/agents/processors/basic_llm_request_processor.js +3 -2
- package/dist/web/agents/processors/content_request_processor.js +2 -21
- package/dist/web/agents/processors/instructions_llm_request_processor.js +3 -1
- package/dist/web/artifacts/in_memory_artifact_service.js +10 -9
- package/dist/web/auth/credential_service/in_memory_credential_service.js +14 -3
- package/dist/web/code_executors/unsafe_local_code_executor.js +22 -11
- package/dist/web/common.js +4 -0
- package/dist/web/context/agent_controlled_context_compactor.js +2 -11
- package/dist/web/context/compaction_utils.js +12 -1
- package/dist/web/context/token_based_context_compactor.js +6 -21
- package/dist/web/index.js +2 -0
- package/dist/web/memory/in_memory_memory_service.js +13 -2
- package/dist/web/memory/vertex_ai_memory_bank_service.js +7 -1
- package/dist/web/plugins/base_plugin.js +4 -2
- package/dist/web/runner/runner.js +17 -11
- package/dist/web/sessions/base_session_service.js +8 -3
- package/dist/web/sessions/in_memory_session_service.js +8 -8
- package/dist/web/sessions/vertex_ai_session_service.js +24 -11
- package/dist/web/skills/loader.js +40 -6
- package/dist/web/tools/get_user_choice_tool.js +25 -0
- package/dist/web/tools/mcp/mcp_session_manager.js +35 -21
- package/dist/web/tools/request_input_tool.js +26 -0
- package/dist/web/utils/crypto_shim.js +15 -0
- package/dist/web/utils/env_aware_utils.js +15 -13
- package/dist/web/utils/error_utils.js +92 -0
- package/dist/web/utils/file_utils.js +5 -2
- package/dist/web/utils/output_schema_utils.js +15 -0
- package/dist/web/utils/vertex_ai_utils.js +2 -0
- package/dist/web/version.js +1 -1
- package/package.json +1 -1
|
@@ -70,16 +70,14 @@ class InMemoryArtifactService {
|
|
|
70
70
|
userId,
|
|
71
71
|
sessionId
|
|
72
72
|
}) {
|
|
73
|
-
const sessionPrefix =
|
|
74
|
-
const
|
|
73
|
+
const sessionPrefix = artifactPrefix("session", appName, userId, sessionId);
|
|
74
|
+
const userPrefix = artifactPrefix("user", appName, userId);
|
|
75
75
|
const filenames = [];
|
|
76
76
|
for (const path in this.artifacts) {
|
|
77
77
|
if (path.startsWith(sessionPrefix)) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const filename = path.replace(usernamespacePrefix, "");
|
|
82
|
-
filenames.push(filename);
|
|
78
|
+
filenames.push(decodeURIComponent(path.slice(sessionPrefix.length)));
|
|
79
|
+
} else if (path.startsWith(userPrefix)) {
|
|
80
|
+
filenames.push(decodeURIComponent(path.slice(userPrefix.length)));
|
|
83
81
|
}
|
|
84
82
|
}
|
|
85
83
|
return Promise.resolve(filenames.sort());
|
|
@@ -150,9 +148,12 @@ class InMemoryArtifactService {
|
|
|
150
148
|
}
|
|
151
149
|
function artifactPath(appName, userId, sessionId, filename) {
|
|
152
150
|
if (fileHasUserNamespace(filename)) {
|
|
153
|
-
return `${appName
|
|
151
|
+
return `${artifactPrefix("user", appName, userId)}${encodeURIComponent(filename)}`;
|
|
154
152
|
}
|
|
155
|
-
return `${appName
|
|
153
|
+
return `${artifactPrefix("session", appName, userId, sessionId)}${encodeURIComponent(filename)}`;
|
|
154
|
+
}
|
|
155
|
+
function artifactPrefix(scope, ...parts) {
|
|
156
|
+
return `${[scope, ...parts].map(encodeURIComponent).join("/")}/`;
|
|
156
157
|
}
|
|
157
158
|
function fileHasUserNamespace(filename) {
|
|
158
159
|
return filename.startsWith("user:");
|
|
@@ -7,7 +7,18 @@ const require = topLevelCreateRequire(import.meta.url);
|
|
|
7
7
|
*/
|
|
8
8
|
class InMemoryCredentialService {
|
|
9
9
|
constructor() {
|
|
10
|
-
|
|
10
|
+
/**
|
|
11
|
+
* A map from app name to a map from user ID to a map from credential key to
|
|
12
|
+
* credential.
|
|
13
|
+
*
|
|
14
|
+
* `appName`, `userId` and `credentialKey` are all attacker-influenced, so
|
|
15
|
+
* every level is created with `Object.create(null)`. On an ordinary `{}`
|
|
16
|
+
* literal a key of `__proto__` resolves to the inherited `__proto__`
|
|
17
|
+
* accessor rather than creating an own property, so nested assignment
|
|
18
|
+
* pollutes every object in the process, and a lookup of an inherited key
|
|
19
|
+
* such as `toString` returns a function instead of `undefined`.
|
|
20
|
+
*/
|
|
21
|
+
this.credentials = /* @__PURE__ */ Object.create(null);
|
|
11
22
|
}
|
|
12
23
|
loadCredential(authConfig, toolContext) {
|
|
13
24
|
const credentialBucket = this.getBucketForCurrentContext(toolContext);
|
|
@@ -22,10 +33,10 @@ class InMemoryCredentialService {
|
|
|
22
33
|
getBucketForCurrentContext(toolContext) {
|
|
23
34
|
const { appName, userId } = toolContext.invocationContext.session;
|
|
24
35
|
if (!this.credentials[appName]) {
|
|
25
|
-
this.credentials[appName] =
|
|
36
|
+
this.credentials[appName] = /* @__PURE__ */ Object.create(null);
|
|
26
37
|
}
|
|
27
38
|
if (!this.credentials[appName][userId]) {
|
|
28
|
-
this.credentials[appName][userId] =
|
|
39
|
+
this.credentials[appName][userId] = /* @__PURE__ */ Object.create(null);
|
|
29
40
|
}
|
|
30
41
|
return this.credentials[appName][userId];
|
|
31
42
|
}
|
|
@@ -5,7 +5,7 @@ const require = topLevelCreateRequire(import.meta.url);
|
|
|
5
5
|
* Copyright 2026 Google LLC
|
|
6
6
|
* SPDX-License-Identifier: Apache-2.0
|
|
7
7
|
*/
|
|
8
|
-
import { spawn } from "child_process";
|
|
8
|
+
import { spawn } from "node:child_process";
|
|
9
9
|
import * as fs from "node:fs/promises";
|
|
10
10
|
import * as os from "node:os";
|
|
11
11
|
import * as path from "node:path";
|
|
@@ -17,13 +17,21 @@ import {
|
|
|
17
17
|
CodeExecutionLanguage
|
|
18
18
|
} from "./code_execution_utils.js";
|
|
19
19
|
const IS_WINDOWS = os.platform() === "win32";
|
|
20
|
+
const POWERSHELL_BASE_ARGS = [
|
|
21
|
+
"-NoLogo",
|
|
22
|
+
"-NoProfile",
|
|
23
|
+
"-ExecutionPolicy",
|
|
24
|
+
"Bypass",
|
|
25
|
+
"-File"
|
|
26
|
+
];
|
|
27
|
+
const CMD_BASE_ARGS = ["/D", "/c"];
|
|
28
|
+
function isPowerShellCommand(commandPath) {
|
|
29
|
+
return /^(powershell|pwsh)(\.exe)?$/i.test(path.win32.basename(commandPath));
|
|
30
|
+
}
|
|
20
31
|
async function createTempScriptFile(code, language, shellCommandPath) {
|
|
21
|
-
const tempDir =
|
|
22
|
-
os.tmpdir(),
|
|
23
|
-
"adk_js_unsafe_code_executor",
|
|
24
|
-
Date.now().toString() + "_" + Math.random().toString(36).slice(2)
|
|
32
|
+
const tempDir = await fs.mkdtemp(
|
|
33
|
+
path.join(os.tmpdir(), "adk_js_unsafe_code_executor_")
|
|
25
34
|
);
|
|
26
|
-
await fs.mkdir(tempDir, { recursive: true });
|
|
27
35
|
const ext = getExtensionForLanguage(language, shellCommandPath) || ".js";
|
|
28
36
|
const filePath = path.join(tempDir, `script${ext}`);
|
|
29
37
|
await fs.writeFile(filePath, code);
|
|
@@ -43,6 +51,9 @@ function getExtensionForLanguage(language, shellCommandPath) {
|
|
|
43
51
|
return ".bat";
|
|
44
52
|
}
|
|
45
53
|
if (language === CodeExecutionLanguage.SHELL) {
|
|
54
|
+
if (shellCommandPath && isPowerShellCommand(shellCommandPath)) {
|
|
55
|
+
return ".ps1";
|
|
56
|
+
}
|
|
46
57
|
if (IS_WINDOWS) {
|
|
47
58
|
if (shellCommandPath && shellCommandPath.toLowerCase().includes("cmd")) {
|
|
48
59
|
return ".bat";
|
|
@@ -101,17 +112,17 @@ class UnsafeLocalCodeExecutor extends BaseCodeExecutor {
|
|
|
101
112
|
command = this.pythonCommandPath;
|
|
102
113
|
} else if (language === CodeExecutionLanguage.SHELL) {
|
|
103
114
|
command = this.shellCommandPath;
|
|
104
|
-
if (this.shellCommandPath
|
|
105
|
-
args = [
|
|
115
|
+
if (isPowerShellCommand(this.shellCommandPath)) {
|
|
116
|
+
args = [...POWERSHELL_BASE_ARGS, filePath];
|
|
106
117
|
} else if (this.shellCommandPath.toLowerCase().includes("cmd")) {
|
|
107
|
-
args = [
|
|
118
|
+
args = [...CMD_BASE_ARGS, filePath];
|
|
108
119
|
}
|
|
109
120
|
} else if (language === CodeExecutionLanguage.POWERSHELL) {
|
|
110
121
|
command = IS_WINDOWS ? "powershell" : "pwsh";
|
|
111
|
-
args = [
|
|
122
|
+
args = [...POWERSHELL_BASE_ARGS, filePath];
|
|
112
123
|
} else if (language === CodeExecutionLanguage.WINDOWS_CMD) {
|
|
113
124
|
command = "cmd.exe";
|
|
114
|
-
args = [
|
|
125
|
+
args = [...CMD_BASE_ARGS, filePath];
|
|
115
126
|
}
|
|
116
127
|
if (params.codeExecutionInput.args) {
|
|
117
128
|
if (Array.isArray(params.codeExecutionInput.args)) {
|
package/dist/esm/common.js
CHANGED
|
@@ -121,6 +121,7 @@ import {
|
|
|
121
121
|
import { ExampleTool } from "./tools/example_tool.js";
|
|
122
122
|
import { EXIT_LOOP, ExitLoopTool } from "./tools/exit_loop_tool.js";
|
|
123
123
|
import { FunctionTool, isFunctionTool } from "./tools/function_tool.js";
|
|
124
|
+
import { getUserChoiceTool } from "./tools/get_user_choice_tool.js";
|
|
124
125
|
import {
|
|
125
126
|
GOOGLE_MAPS_GROUNDING,
|
|
126
127
|
GoogleMapsGroundingTool
|
|
@@ -137,6 +138,7 @@ import {
|
|
|
137
138
|
PRELOAD_MEMORY,
|
|
138
139
|
PreloadMemoryTool
|
|
139
140
|
} from "./tools/preload_memory_tool.js";
|
|
141
|
+
import { requestInputTool } from "./tools/request_input_tool.js";
|
|
140
142
|
import { ToolConfirmation } from "./tools/tool_confirmation.js";
|
|
141
143
|
import { URL_CONTEXT, UrlContextTool } from "./tools/url_context_tool.js";
|
|
142
144
|
import { VertexAiSearchTool } from "./tools/vertex_ai_search_tool.js";
|
|
@@ -305,6 +307,7 @@ export {
|
|
|
305
307
|
getFunctionCalls,
|
|
306
308
|
getFunctionResponses,
|
|
307
309
|
getLogger,
|
|
310
|
+
getUserChoiceTool,
|
|
308
311
|
hasThoughts,
|
|
309
312
|
hasTrailingCodeExecutionResult,
|
|
310
313
|
isAgentTool,
|
|
@@ -332,6 +335,7 @@ export {
|
|
|
332
335
|
loadWebPage,
|
|
333
336
|
populateClientFunctionCallId,
|
|
334
337
|
pruneThoughts,
|
|
338
|
+
requestInputTool,
|
|
335
339
|
runWithClientLabel,
|
|
336
340
|
setLogLevel,
|
|
337
341
|
setLogger,
|
|
@@ -5,9 +5,9 @@ const require = topLevelCreateRequire(import.meta.url);
|
|
|
5
5
|
* Copyright 2026 Google LLC
|
|
6
6
|
* SPDX-License-Identifier: Apache-2.0
|
|
7
7
|
*/
|
|
8
|
-
import { isCompactedEvent } from "../events/compacted_event.js";
|
|
9
8
|
import { createEvent } from "../events/event.js";
|
|
10
9
|
import { ContextCompactionTrigger } from "../plugins/base_plugin.js";
|
|
10
|
+
import { getActiveEvents } from "./compaction_utils.js";
|
|
11
11
|
class AgentControlledContextCompactor {
|
|
12
12
|
constructor(options) {
|
|
13
13
|
this.trigger = ContextCompactionTrigger.AgentControlled;
|
|
@@ -18,7 +18,7 @@ class AgentControlledContextCompactor {
|
|
|
18
18
|
}
|
|
19
19
|
async compact(invocationContext) {
|
|
20
20
|
const events = invocationContext.session.events;
|
|
21
|
-
const activeEvents =
|
|
21
|
+
const activeEvents = getActiveEvents(events);
|
|
22
22
|
const consolidateToolCallIndex = activeEvents.reduce(
|
|
23
23
|
(acc, e, idx) => {
|
|
24
24
|
var _a, _b;
|
|
@@ -66,15 +66,6 @@ class AgentControlledContextCompactor {
|
|
|
66
66
|
delete invocationContext.session.state["temp:consolidate_context"];
|
|
67
67
|
delete invocationContext.session.state["temp:consolidate_context_detail"];
|
|
68
68
|
}
|
|
69
|
-
getActiveEvents(events) {
|
|
70
|
-
const latest = events.filter(isCompactedEvent).pop();
|
|
71
|
-
return latest ? [
|
|
72
|
-
latest,
|
|
73
|
-
...events.filter(
|
|
74
|
-
(e) => !isCompactedEvent(e) && e.timestamp > latest.endTime
|
|
75
|
-
)
|
|
76
|
-
] : events;
|
|
77
|
-
}
|
|
78
69
|
}
|
|
79
70
|
export {
|
|
80
71
|
AgentControlledContextCompactor
|
|
@@ -5,10 +5,20 @@ const require = topLevelCreateRequire(import.meta.url);
|
|
|
5
5
|
* Copyright 2026 Google LLC
|
|
6
6
|
* SPDX-License-Identifier: Apache-2.0
|
|
7
7
|
*/
|
|
8
|
+
import { isCompactedEvent } from "../events/compacted_event.js";
|
|
8
9
|
import {
|
|
9
10
|
getFunctionCalls,
|
|
10
11
|
getFunctionResponses
|
|
11
12
|
} from "../events/event.js";
|
|
13
|
+
function getActiveEvents(events) {
|
|
14
|
+
const latest = events.filter(isCompactedEvent).pop();
|
|
15
|
+
return latest ? [
|
|
16
|
+
latest,
|
|
17
|
+
...events.filter(
|
|
18
|
+
(e) => !isCompactedEvent(e) && e.timestamp > latest.endTime
|
|
19
|
+
)
|
|
20
|
+
] : events;
|
|
21
|
+
}
|
|
12
22
|
function calculateRetainStartIndex(rawEvents, eventRetentionSize) {
|
|
13
23
|
let retainStartIndex = Math.max(0, rawEvents.length - eventRetentionSize);
|
|
14
24
|
while (retainStartIndex > 0) {
|
|
@@ -23,5 +33,6 @@ function calculateRetainStartIndex(rawEvents, eventRetentionSize) {
|
|
|
23
33
|
return retainStartIndex;
|
|
24
34
|
}
|
|
25
35
|
export {
|
|
26
|
-
calculateRetainStartIndex
|
|
36
|
+
calculateRetainStartIndex,
|
|
37
|
+
getActiveEvents
|
|
27
38
|
};
|
|
@@ -7,7 +7,10 @@ const require = topLevelCreateRequire(import.meta.url);
|
|
|
7
7
|
*/
|
|
8
8
|
import { getContents } from "../agents/processors/content_processor_utils.js";
|
|
9
9
|
import { isCompactedEvent } from "../events/compacted_event.js";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
calculateRetainStartIndex,
|
|
12
|
+
getActiveEvents
|
|
13
|
+
} from "./compaction_utils.js";
|
|
11
14
|
const CHARS_PER_TOKEN = 4;
|
|
12
15
|
class TokenBasedContextCompactor {
|
|
13
16
|
constructor(options) {
|
|
@@ -15,27 +18,9 @@ class TokenBasedContextCompactor {
|
|
|
15
18
|
this.eventRetentionSize = options.eventRetentionSize;
|
|
16
19
|
this.summarizer = options.summarizer;
|
|
17
20
|
}
|
|
18
|
-
getActiveEvents(events) {
|
|
19
|
-
let latestCompactedEvent = void 0;
|
|
20
|
-
for (let i = events.length - 1; i >= 0; i--) {
|
|
21
|
-
const e = events[i];
|
|
22
|
-
if (isCompactedEvent(e)) {
|
|
23
|
-
if (!latestCompactedEvent || e.endTime > latestCompactedEvent.endTime) {
|
|
24
|
-
latestCompactedEvent = e;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
if (!latestCompactedEvent) {
|
|
29
|
-
return events;
|
|
30
|
-
}
|
|
31
|
-
const activeRawEvents = events.filter(
|
|
32
|
-
(e) => !isCompactedEvent(e) && e.timestamp > latestCompactedEvent.endTime
|
|
33
|
-
);
|
|
34
|
-
return [latestCompactedEvent, ...activeRawEvents];
|
|
35
|
-
}
|
|
36
21
|
shouldCompact(invocationContext) {
|
|
37
22
|
const events = invocationContext.session.events;
|
|
38
|
-
const activeEvents =
|
|
23
|
+
const activeEvents = getActiveEvents(events);
|
|
39
24
|
const rawEvents = activeEvents.filter((e) => !isCompactedEvent(e));
|
|
40
25
|
if (rawEvents.length <= this.eventRetentionSize) {
|
|
41
26
|
return false;
|
|
@@ -58,7 +43,7 @@ class TokenBasedContextCompactor {
|
|
|
58
43
|
}
|
|
59
44
|
async compact(invocationContext) {
|
|
60
45
|
const events = invocationContext.session.events;
|
|
61
|
-
const activeEvents =
|
|
46
|
+
const activeEvents = getActiveEvents(events);
|
|
62
47
|
const rawEvents = activeEvents.filter((e) => !isCompactedEvent(e));
|
|
63
48
|
if (rawEvents.length <= this.eventRetentionSize) {
|
|
64
49
|
return;
|
package/dist/esm/index.js
CHANGED
|
@@ -9,6 +9,7 @@ import { AGENT_CARD_PATH, RemoteA2AAgent } from "./a2a/a2a_remote_agent.js";
|
|
|
9
9
|
import { getA2AAgentCard } from "./a2a/agent_card.js";
|
|
10
10
|
import { A2AAgentExecutor } from "./a2a/agent_executor.js";
|
|
11
11
|
import { toA2a } from "./a2a/agent_to_a2a.js";
|
|
12
|
+
import { bearerTokenUserBuilder } from "./a2a/auth.js";
|
|
12
13
|
import { InvocationContext } from "./agents/invocation_context.js";
|
|
13
14
|
import { FileArtifactService } from "./artifacts/file_artifact_service.js";
|
|
14
15
|
import { GcsArtifactService } from "./artifacts/gcs_artifact_service.js";
|
|
@@ -56,6 +57,7 @@ export {
|
|
|
56
57
|
RunSkillScriptTool,
|
|
57
58
|
UnsafeLocalCodeExecutor,
|
|
58
59
|
VertexAiSessionService,
|
|
60
|
+
bearerTokenUserBuilder,
|
|
59
61
|
getA2AAgentCard,
|
|
60
62
|
getArtifactServiceFromUri,
|
|
61
63
|
getSessionServiceFromUri,
|
|
@@ -8,12 +8,23 @@ const require = topLevelCreateRequire(import.meta.url);
|
|
|
8
8
|
class InMemoryMemoryService {
|
|
9
9
|
constructor() {
|
|
10
10
|
this.memories = [];
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* A map from user key to a map from session ID to events.
|
|
13
|
+
*
|
|
14
|
+
* The inner map is keyed by `session.id`, which arrives off the request path
|
|
15
|
+
* and contains no `/`, so it can be exactly `__proto__`. On a plain object
|
|
16
|
+
* literal that key would reach the inherited `__proto__` setter and
|
|
17
|
+
* re-parent the map instead of creating an own property, silently dropping
|
|
18
|
+
* the session from the `Object.values` scan in `searchMemory`. The outer key
|
|
19
|
+
* always contains a `/` (see `getUserKey`) and cannot collide, but is
|
|
20
|
+
* created the same way for consistency.
|
|
21
|
+
*/
|
|
22
|
+
this.sessionEvents = /* @__PURE__ */ Object.create(null);
|
|
12
23
|
}
|
|
13
24
|
async addSessionToMemory(session) {
|
|
14
25
|
const userKey = getUserKey(session.appName, session.userId);
|
|
15
26
|
if (!this.sessionEvents[userKey]) {
|
|
16
|
-
this.sessionEvents[userKey] =
|
|
27
|
+
this.sessionEvents[userKey] = /* @__PURE__ */ Object.create(null);
|
|
17
28
|
}
|
|
18
29
|
this.sessionEvents[userKey][session.id] = session.events.filter(
|
|
19
30
|
(event) => {
|
|
@@ -8,7 +8,10 @@ const require = topLevelCreateRequire(import.meta.url);
|
|
|
8
8
|
import { Client } from "@google-cloud/vertexai";
|
|
9
9
|
import { createUserContent } from "@google/genai";
|
|
10
10
|
import { logger } from "../utils/logger.js";
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
EXPRESS_MODE_UNSUPPORTED_MESSAGE,
|
|
13
|
+
getExpressModeApiKey
|
|
14
|
+
} from "../utils/vertex_ai_utils.js";
|
|
12
15
|
const GENERATE_MEMORIES_KNOWN_FIELDS = [
|
|
13
16
|
"disableConsolidation",
|
|
14
17
|
"waitForCompletion",
|
|
@@ -89,6 +92,9 @@ class VertexAiMemoryBankService {
|
|
|
89
92
|
if (options.client) {
|
|
90
93
|
this.memories = options.client.agentEnginesInternal.memories;
|
|
91
94
|
} else {
|
|
95
|
+
if (this.expressModeApiKey && (!this.projectId || !this.location)) {
|
|
96
|
+
throw new Error(EXPRESS_MODE_UNSUPPORTED_MESSAGE);
|
|
97
|
+
}
|
|
92
98
|
const client = new Client({
|
|
93
99
|
project: this.projectId,
|
|
94
100
|
location: this.location
|
|
@@ -73,8 +73,10 @@ class BasePlugin {
|
|
|
73
73
|
* @param params.invocationContext The context for the entire invocation.
|
|
74
74
|
* @param params.event The event raised by the runner.
|
|
75
75
|
* @returns An optional value. A non-`undefined` return may be used by the
|
|
76
|
-
* framework to modify or replace the response.
|
|
77
|
-
*
|
|
76
|
+
* framework to modify or replace the response. Copy `params.event` when
|
|
77
|
+
* constructing a replacement to preserve fields that are not being
|
|
78
|
+
* modified, such as event actions. Returning `undefined` allows the
|
|
79
|
+
* original response to be used.
|
|
78
80
|
*/
|
|
79
81
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
80
82
|
async onEventCallback(params) {
|
|
@@ -120,7 +120,7 @@ class Runner {
|
|
|
120
120
|
ctx,
|
|
121
121
|
this,
|
|
122
122
|
async function* () {
|
|
123
|
-
var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
123
|
+
var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
|
|
124
124
|
const session = await this.sessionService.getSession({
|
|
125
125
|
appName: this.appName,
|
|
126
126
|
userId,
|
|
@@ -237,24 +237,31 @@ class Runner {
|
|
|
237
237
|
if ((_h = params.abortSignal) == null ? void 0 : _h.aborted) {
|
|
238
238
|
return;
|
|
239
239
|
}
|
|
240
|
-
if (!event.partial) {
|
|
241
|
-
await this.sessionService.appendEvent({ session, event });
|
|
242
|
-
}
|
|
243
240
|
const modifiedEvent = await this.pluginManager.runOnEventCallback({
|
|
244
241
|
invocationContext,
|
|
245
242
|
event
|
|
246
243
|
});
|
|
247
|
-
|
|
248
|
-
|
|
244
|
+
const outputEvent = modifiedEvent ? {
|
|
245
|
+
...modifiedEvent,
|
|
246
|
+
id: event.id,
|
|
247
|
+
invocationId: event.invocationId,
|
|
248
|
+
timestamp: event.timestamp,
|
|
249
|
+
author: modifiedEvent.author || event.author,
|
|
250
|
+
branch: (_i = modifiedEvent.branch) != null ? _i : event.branch
|
|
251
|
+
} : event;
|
|
252
|
+
if (!event.partial) {
|
|
253
|
+
await this.sessionService.appendEvent({
|
|
254
|
+
session,
|
|
255
|
+
event: outputEvent
|
|
256
|
+
});
|
|
249
257
|
}
|
|
250
|
-
if (
|
|
251
|
-
|
|
252
|
-
} else {
|
|
253
|
-
yield event;
|
|
258
|
+
if ((_j = params.abortSignal) == null ? void 0 : _j.aborted) {
|
|
259
|
+
return;
|
|
254
260
|
}
|
|
261
|
+
yield outputEvent;
|
|
255
262
|
}
|
|
256
263
|
await this.pluginManager.runAfterRunCallback({ invocationContext });
|
|
257
|
-
if ((
|
|
264
|
+
if ((_k = params.abortSignal) == null ? void 0 : _k.aborted) {
|
|
258
265
|
return;
|
|
259
266
|
}
|
|
260
267
|
}
|
|
@@ -61,7 +61,12 @@ class BaseSessionService {
|
|
|
61
61
|
if (key.startsWith(State.TEMP_PREFIX)) {
|
|
62
62
|
continue;
|
|
63
63
|
}
|
|
64
|
-
session.state
|
|
64
|
+
Object.defineProperty(session.state, key, {
|
|
65
|
+
value,
|
|
66
|
+
writable: true,
|
|
67
|
+
enumerable: true,
|
|
68
|
+
configurable: true
|
|
69
|
+
});
|
|
65
70
|
}
|
|
66
71
|
}
|
|
67
72
|
}
|
|
@@ -70,7 +75,7 @@ function trimTempDeltaState(event) {
|
|
|
70
75
|
return event;
|
|
71
76
|
}
|
|
72
77
|
const stateDelta = event.actions.stateDelta;
|
|
73
|
-
const filteredStateDelta =
|
|
78
|
+
const filteredStateDelta = /* @__PURE__ */ Object.create(null);
|
|
74
79
|
for (const [key, value] of Object.entries(stateDelta)) {
|
|
75
80
|
if (!key.startsWith(State.TEMP_PREFIX)) {
|
|
76
81
|
filteredStateDelta[key] = value;
|
|
@@ -80,7 +85,7 @@ function trimTempDeltaState(event) {
|
|
|
80
85
|
return event;
|
|
81
86
|
}
|
|
82
87
|
function trimTempState(state) {
|
|
83
|
-
const filteredState =
|
|
88
|
+
const filteredState = /* @__PURE__ */ Object.create(null);
|
|
84
89
|
for (const [key, value] of Object.entries(state)) {
|
|
85
90
|
if (!key.startsWith(State.TEMP_PREFIX)) {
|
|
86
91
|
filteredState[key] = value;
|
|
@@ -25,15 +25,15 @@ class InMemorySessionService extends BaseSessionService {
|
|
|
25
25
|
* A map from app name to a map from user ID to a map from session ID to
|
|
26
26
|
* session.
|
|
27
27
|
*/
|
|
28
|
-
this.sessions =
|
|
28
|
+
this.sessions = /* @__PURE__ */ Object.create(null);
|
|
29
29
|
/**
|
|
30
30
|
* A map from app name to a map from user ID to a map from key to the value.
|
|
31
31
|
*/
|
|
32
|
-
this.userState =
|
|
32
|
+
this.userState = /* @__PURE__ */ Object.create(null);
|
|
33
33
|
/**
|
|
34
34
|
* A map from app name to a map from key to the value.
|
|
35
35
|
*/
|
|
36
|
-
this.appState =
|
|
36
|
+
this.appState = /* @__PURE__ */ Object.create(null);
|
|
37
37
|
}
|
|
38
38
|
async createSession({
|
|
39
39
|
appName,
|
|
@@ -52,10 +52,10 @@ class InMemorySessionService extends BaseSessionService {
|
|
|
52
52
|
lastUpdateTime: Date.now()
|
|
53
53
|
});
|
|
54
54
|
if (!this.sessions[appName]) {
|
|
55
|
-
this.sessions[appName] =
|
|
55
|
+
this.sessions[appName] = /* @__PURE__ */ Object.create(null);
|
|
56
56
|
}
|
|
57
57
|
if (!this.sessions[appName][userId]) {
|
|
58
|
-
this.sessions[appName][userId] =
|
|
58
|
+
this.sessions[appName][userId] = /* @__PURE__ */ Object.create(null);
|
|
59
59
|
}
|
|
60
60
|
this.sessions[appName][userId][session.id] = session;
|
|
61
61
|
const copiedSession = cloneDeep(session);
|
|
@@ -220,12 +220,12 @@ class InMemorySessionService extends BaseSessionService {
|
|
|
220
220
|
if (event.actions && event.actions.stateDelta) {
|
|
221
221
|
for (const key of Object.keys(event.actions.stateDelta)) {
|
|
222
222
|
if (key.startsWith(State.APP_PREFIX)) {
|
|
223
|
-
this.appState[appName] = this.appState[appName] ||
|
|
223
|
+
this.appState[appName] = this.appState[appName] || /* @__PURE__ */ Object.create(null);
|
|
224
224
|
this.appState[appName][key.replace(State.APP_PREFIX, "")] = event.actions.stateDelta[key];
|
|
225
225
|
}
|
|
226
226
|
if (key.startsWith(State.USER_PREFIX)) {
|
|
227
|
-
this.userState[appName] = this.userState[appName] ||
|
|
228
|
-
this.userState[appName][userId] = this.userState[appName][userId] ||
|
|
227
|
+
this.userState[appName] = this.userState[appName] || /* @__PURE__ */ Object.create(null);
|
|
228
|
+
this.userState[appName][userId] = this.userState[appName][userId] || /* @__PURE__ */ Object.create(null);
|
|
229
229
|
this.userState[appName][userId][key.replace(State.USER_PREFIX, "")] = event.actions.stateDelta[key];
|
|
230
230
|
}
|
|
231
231
|
}
|
|
@@ -19,7 +19,10 @@ import { Client } from "@google-cloud/vertexai/build/src/genai/client.js";
|
|
|
19
19
|
import { isCompactedEvent } from "../events/compacted_event.js";
|
|
20
20
|
import { experimental } from "../utils/experimental.js";
|
|
21
21
|
import { logger } from "../utils/logger.js";
|
|
22
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
EXPRESS_MODE_UNSUPPORTED_MESSAGE,
|
|
24
|
+
getExpressModeApiKey
|
|
25
|
+
} from "../utils/vertex_ai_utils.js";
|
|
23
26
|
import { partialCopy } from "../utils/partial_copy.js";
|
|
24
27
|
import {
|
|
25
28
|
BaseSessionService,
|
|
@@ -47,16 +50,14 @@ let VertexAiSessionService = class extends BaseSessionService {
|
|
|
47
50
|
this.location,
|
|
48
51
|
options.expressModeApiKey
|
|
49
52
|
);
|
|
50
|
-
if (!options.sessions) {
|
|
51
|
-
if (!this.expressModeApiKey && (!this.projectId || !this.location)) {
|
|
52
|
-
throw new Error(
|
|
53
|
-
"Either (Project ID and Location) or an expressModeApiKey is required."
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
53
|
if (options.sessions) {
|
|
58
54
|
this.sessions = options.sessions;
|
|
59
55
|
} else {
|
|
56
|
+
if (!this.projectId || !this.location) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
this.expressModeApiKey ? EXPRESS_MODE_UNSUPPORTED_MESSAGE : "Project ID and Location are required."
|
|
59
|
+
);
|
|
60
|
+
}
|
|
60
61
|
const client = new Client({
|
|
61
62
|
project: this.projectId,
|
|
62
63
|
location: this.location
|
|
@@ -80,13 +81,25 @@ let VertexAiSessionService = class extends BaseSessionService {
|
|
|
80
81
|
}
|
|
81
82
|
return match[3];
|
|
82
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Creates a session on Vertex AI Agent Engine.
|
|
86
|
+
*
|
|
87
|
+
* @throws if both `ttl` and `expireTime` are specified.
|
|
88
|
+
*/
|
|
83
89
|
async createSession({
|
|
84
90
|
appName,
|
|
85
91
|
userId,
|
|
86
92
|
state,
|
|
87
|
-
sessionId
|
|
93
|
+
sessionId,
|
|
94
|
+
ttl,
|
|
95
|
+
expireTime
|
|
88
96
|
}) {
|
|
89
97
|
var _a;
|
|
98
|
+
if (ttl != null && expireTime != null) {
|
|
99
|
+
throw new Error(
|
|
100
|
+
"Cannot specify both 'ttl' and 'expireTime' simultaneously."
|
|
101
|
+
);
|
|
102
|
+
}
|
|
90
103
|
const reasoningEngineId = this.getReasoningEngineId(appName);
|
|
91
104
|
const filteredState = state ? trimTempState(state) : void 0;
|
|
92
105
|
let apiResponse = await this.sessions.createInternal({
|
|
@@ -94,7 +107,9 @@ let VertexAiSessionService = class extends BaseSessionService {
|
|
|
94
107
|
userId,
|
|
95
108
|
config: {
|
|
96
109
|
...filteredState ? { sessionState: filteredState } : {},
|
|
97
|
-
...sessionId ? { sessionId } : {}
|
|
110
|
+
...sessionId ? { sessionId } : {},
|
|
111
|
+
...ttl != null ? { ttl } : {},
|
|
112
|
+
...expireTime != null ? { expireTime } : {}
|
|
98
113
|
}
|
|
99
114
|
});
|
|
100
115
|
const operationName = apiResponse.name;
|
|
@@ -180,7 +195,7 @@ let VertexAiSessionService = class extends BaseSessionService {
|
|
|
180
195
|
return session;
|
|
181
196
|
} catch (error) {
|
|
182
197
|
const err = error;
|
|
183
|
-
if (err.code === GRPC_NOT_FOUND || err.code === HTTP_NOT_FOUND) {
|
|
198
|
+
if (err.code === GRPC_NOT_FOUND || err.code === HTTP_NOT_FOUND || err.status === HTTP_NOT_FOUND) {
|
|
184
199
|
return void 0;
|
|
185
200
|
}
|
|
186
201
|
logger.error(`Error getting session from Vertex AI: ${err.message}`);
|
|
@@ -18,6 +18,9 @@ const ALLOWED_FRONTMATTER_KEYS = /* @__PURE__ */ new Set([
|
|
|
18
18
|
"description",
|
|
19
19
|
"license",
|
|
20
20
|
"allowed-tools",
|
|
21
|
+
// Camel-case alias: FrontmatterSchema's preprocessor derives `allowedTools`
|
|
22
|
+
// from `allowed-tools`, and `.loose()` passes either spelling through.
|
|
23
|
+
"allowedTools",
|
|
21
24
|
"metadata",
|
|
22
25
|
"compatibility"
|
|
23
26
|
]);
|
|
@@ -80,7 +83,7 @@ async function loadDir(directoryPath) {
|
|
|
80
83
|
}
|
|
81
84
|
return files;
|
|
82
85
|
}
|
|
83
|
-
function
|
|
86
|
+
function parseFrontmatterYaml(content) {
|
|
84
87
|
if (!content.startsWith("---")) {
|
|
85
88
|
throw new Error("SKILL.md must start with YAML frontmatter (---)");
|
|
86
89
|
}
|
|
@@ -92,15 +95,34 @@ function parseSkillMdContent(content) {
|
|
|
92
95
|
const body = parts.filter((_, i) => i >= 2).join("---").trim();
|
|
93
96
|
try {
|
|
94
97
|
const parsed = yaml.load(frontmatterStr);
|
|
95
|
-
if (typeof parsed !== "object" || parsed === null) {
|
|
98
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
96
99
|
throw new Error("SKILL.md frontmatter must be a YAML mapping");
|
|
97
100
|
}
|
|
98
|
-
|
|
99
|
-
return { frontmatter, body };
|
|
101
|
+
return { raw: parsed, body };
|
|
100
102
|
} catch (e) {
|
|
101
103
|
throw new Error(`Invalid YAML in frontmatter: ${e.message}`);
|
|
102
104
|
}
|
|
103
105
|
}
|
|
106
|
+
function validateFrontmatter(raw) {
|
|
107
|
+
try {
|
|
108
|
+
return FrontmatterSchema.parse(raw);
|
|
109
|
+
} catch (e) {
|
|
110
|
+
throw new Error(`Invalid YAML in frontmatter: ${e.message}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function parseSkillMdContent(content) {
|
|
114
|
+
const { raw, body } = parseFrontmatterYaml(content);
|
|
115
|
+
return { frontmatter: validateFrontmatter(raw), body };
|
|
116
|
+
}
|
|
117
|
+
function isDangerousZipEntryName(entryName) {
|
|
118
|
+
if (path.posix.isAbsolute(entryName) || path.win32.isAbsolute(entryName)) {
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
return entryName.split(/[/\\]/).some((segment) => segment === "..");
|
|
122
|
+
}
|
|
123
|
+
function isBareSkillName(name) {
|
|
124
|
+
return name !== "." && name !== ".." && path.basename(name) === name;
|
|
125
|
+
}
|
|
104
126
|
async function loadSkillFromDir(skillDir) {
|
|
105
127
|
const resolvedDir = path.resolve(skillDir);
|
|
106
128
|
const skill = await loadSkillFile(skillDir);
|
|
@@ -240,6 +262,11 @@ async function loadAllSkillsInDir(skillsBasePath) {
|
|
|
240
262
|
function loadSkillFromZipBuffer(zipBuffer) {
|
|
241
263
|
const zip = new AdmZip(zipBuffer);
|
|
242
264
|
const entries = zip.getEntries();
|
|
265
|
+
for (const entry of entries) {
|
|
266
|
+
if (isDangerousZipEntryName(entry.entryName)) {
|
|
267
|
+
throw new Error(`Dangerous zip entry ignored: ${entry.entryName}`);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
243
270
|
let skillMdContent = "";
|
|
244
271
|
for (const entry of entries) {
|
|
245
272
|
if (entry.isDirectory) continue;
|
|
@@ -251,8 +278,15 @@ function loadSkillFromZipBuffer(zipBuffer) {
|
|
|
251
278
|
if (!skillMdContent) {
|
|
252
279
|
throw new Error("SKILL.md not found in zipped filesystem.");
|
|
253
280
|
}
|
|
254
|
-
const {
|
|
255
|
-
const
|
|
281
|
+
const { raw, body } = parseFrontmatterYaml(skillMdContent);
|
|
282
|
+
const skillName = raw["name"];
|
|
283
|
+
if (!skillName) {
|
|
284
|
+
throw new Error("SKILL.md frontmatter must contain 'name'");
|
|
285
|
+
}
|
|
286
|
+
if (typeof skillName !== "string" || !isBareSkillName(skillName)) {
|
|
287
|
+
throw new Error(`Invalid skill name in SKILL.md: ${String(skillName)}`);
|
|
288
|
+
}
|
|
289
|
+
const frontmatter = validateFrontmatter(raw);
|
|
256
290
|
const references = {};
|
|
257
291
|
const assets = {};
|
|
258
292
|
const scripts = {};
|