@nestjs-adk/core 0.0.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/README.md +28 -0
- package/dist/index.cjs +1452 -0
- package/dist/index.d.ts +49 -0
- package/dist/index.mjs +1394 -0
- package/dist/lib/abstracts/adk-agent.d.ts +17 -0
- package/dist/lib/abstracts/adk-engine.d.ts +6 -0
- package/dist/lib/abstracts/adk-skill.d.ts +3 -0
- package/dist/lib/abstracts/adk-tool.d.ts +6 -0
- package/dist/lib/abstracts/adk-workflow.d.ts +6 -0
- package/dist/lib/abstracts/artifact-store.d.ts +10 -0
- package/dist/lib/abstracts/embedder.d.ts +13 -0
- package/dist/lib/abstracts/memory-store.d.ts +13 -0
- package/dist/lib/abstracts/session-store.d.ts +8 -0
- package/dist/lib/constants.d.ts +8 -0
- package/dist/lib/decorators/agent.decorator.d.ts +2 -0
- package/dist/lib/decorators/skill.decorator.d.ts +6 -0
- package/dist/lib/decorators/tool.decorator.d.ts +6 -0
- package/dist/lib/decorators/workflow-agent.decorator.d.ts +2 -0
- package/dist/lib/embeddings/similarity.d.ts +3 -0
- package/dist/lib/errors/adk.error.d.ts +4 -0
- package/dist/lib/errors/boot.errors.d.ts +43 -0
- package/dist/lib/errors/index.d.ts +3 -0
- package/dist/lib/errors/runtime.errors.d.ts +51 -0
- package/dist/lib/models/context-policy.d.ts +16 -0
- package/dist/lib/models/model-specs.d.ts +48 -0
- package/dist/lib/module/adk-options.d.ts +24 -0
- package/dist/lib/module/adk.module.d.ts +8 -0
- package/dist/lib/prompts/adk-prompt.d.ts +8 -0
- package/dist/lib/prompts/prompt-files.d.ts +11 -0
- package/dist/lib/registry/agent-definition.d.ts +44 -0
- package/dist/lib/registry/agent-ref.d.ts +26 -0
- package/dist/lib/registry/agent-registry.d.ts +28 -0
- package/dist/lib/runner/agent-runner.d.ts +44 -0
- package/dist/lib/runner/instruction-builder.d.ts +7 -0
- package/dist/lib/runner/run-logger.d.ts +13 -0
- package/dist/lib/runner/state-bag.d.ts +9 -0
- package/dist/lib/sessions/agent-sessions.d.ts +15 -0
- package/dist/lib/stores/in-memory-artifact-store.d.ts +12 -0
- package/dist/lib/stores/in-memory-session-store.d.ts +11 -0
- package/dist/lib/testing/scripted-engine.d.ts +27 -0
- package/dist/lib/testing/scripted-model.d.ts +8 -0
- package/dist/lib/types/events.d.ts +113 -0
- package/dist/lib/types/options.d.ts +44 -0
- package/dist/lib/types/resolved-agent.d.ts +22 -0
- package/dist/lib/types/tool-context.d.ts +15 -0
- package/dist/lib/types/toolset.d.ts +10 -0
- package/package.json +35 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,1452 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var common = require('@nestjs/common');
|
|
4
|
+
var node_crypto = require('node:crypto');
|
|
5
|
+
var node_path = require('node:path');
|
|
6
|
+
var promises = require('node:fs/promises');
|
|
7
|
+
var core = require('@nestjs/core');
|
|
8
|
+
var zod = require('zod');
|
|
9
|
+
|
|
10
|
+
/******************************************************************************
|
|
11
|
+
Copyright (c) Microsoft Corporation.
|
|
12
|
+
|
|
13
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
14
|
+
purpose with or without fee is hereby granted.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
17
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
18
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
19
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
20
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
21
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
22
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
23
|
+
***************************************************************************** */
|
|
24
|
+
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
function __decorate(decorators, target, key, desc) {
|
|
28
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
29
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
30
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
31
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function __param(paramIndex, decorator) {
|
|
35
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function __metadata(metadataKey, metadataValue) {
|
|
39
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
43
|
+
var e = new Error(message);
|
|
44
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const AGENT_METADATA = Symbol("adk:agent");
|
|
48
|
+
const TOOL_METADATA = Symbol("adk:tool");
|
|
49
|
+
const SKILL_METADATA = Symbol("adk:skill");
|
|
50
|
+
const WORKFLOW_METADATA = Symbol("adk:workflow");
|
|
51
|
+
const INLINE_TOOLS_METADATA = Symbol("adk:inline-tools");
|
|
52
|
+
const INLINE_SKILLS_METADATA = Symbol("adk:inline-skills");
|
|
53
|
+
const ADK_OPTIONS = Symbol("adk:options");
|
|
54
|
+
const ADK_RUNNER = Symbol("adk:runner");
|
|
55
|
+
|
|
56
|
+
class AdkAgent {
|
|
57
|
+
ask(input) {
|
|
58
|
+
return this.adkRunner.ask(this.constructor, input);
|
|
59
|
+
}
|
|
60
|
+
stream(input) {
|
|
61
|
+
return this.adkRunner.run(this.constructor, input);
|
|
62
|
+
}
|
|
63
|
+
approve(params) {
|
|
64
|
+
return this.adkRunner.approve(this.constructor, params);
|
|
65
|
+
}
|
|
66
|
+
reject(params) {
|
|
67
|
+
return this.adkRunner.reject(this.constructor, params);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
__decorate([
|
|
71
|
+
common.Inject(ADK_RUNNER),
|
|
72
|
+
__metadata("design:type", Function)
|
|
73
|
+
], AdkAgent.prototype, "adkRunner", void 0);
|
|
74
|
+
|
|
75
|
+
class AdkEngine {
|
|
76
|
+
native() {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
class AdkSkill {
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
class AdkTool {
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
class AdkWorkflow {
|
|
88
|
+
ask(input) {
|
|
89
|
+
return this.adkRunner.ask(this.constructor, input);
|
|
90
|
+
}
|
|
91
|
+
stream(input) {
|
|
92
|
+
return this.adkRunner.run(this.constructor, input);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
__decorate([
|
|
96
|
+
common.Inject(ADK_RUNNER),
|
|
97
|
+
__metadata("design:type", Function)
|
|
98
|
+
], AdkWorkflow.prototype, "adkRunner", void 0);
|
|
99
|
+
|
|
100
|
+
class ArtifactStore {
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
class AdkError extends Error {
|
|
104
|
+
constructor(message, options) {
|
|
105
|
+
super(message, options);
|
|
106
|
+
this.name = new.target.name;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
class AiEmptyResponseError extends AdkError {
|
|
111
|
+
constructor(agent) {
|
|
112
|
+
super(`Agent "${agent}" finished the run with an empty final response.`);
|
|
113
|
+
this.code = "AI_EMPTY_RESPONSE";
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
class ToolExecutionError extends AdkError {
|
|
117
|
+
constructor(tool, cause) {
|
|
118
|
+
super(`Tool "${tool}" threw during execution.`, { cause });
|
|
119
|
+
this.tool = tool;
|
|
120
|
+
this.code = "TOOL_EXECUTION_FAILED";
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
class ModelsExhaustedError extends AdkError {
|
|
124
|
+
constructor(failures) {
|
|
125
|
+
super(`Model router exhausted all targets (${failures.map((f) => f.target).join(", ")}).`);
|
|
126
|
+
this.failures = failures;
|
|
127
|
+
this.code = "MODELS_EXHAUSTED";
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
class SessionNotFoundError extends AdkError {
|
|
131
|
+
constructor(sessionId) {
|
|
132
|
+
super(`Session "${sessionId}" was not found.`);
|
|
133
|
+
this.code = "SESSION_NOT_FOUND";
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
class EmbedderNotConfiguredError extends AdkError {
|
|
137
|
+
constructor() {
|
|
138
|
+
super("No Embedder configured. Set AdkModule.forRoot({ embedder: YourEmbedder }) — the lib ships no default.");
|
|
139
|
+
this.code = "EMBEDDER_NOT_CONFIGURED";
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
class AgentNotFoundError extends AdkError {
|
|
143
|
+
constructor(agent) {
|
|
144
|
+
super(`Agent "${agent}" is not registered.`);
|
|
145
|
+
this.code = "AGENT_NOT_FOUND";
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
class SkillNotFoundError extends AdkError {
|
|
149
|
+
constructor(skill, agent) {
|
|
150
|
+
super(`Skill "${skill}" requested via load_skill does not exist on agent "${agent}".`);
|
|
151
|
+
this.code = "SKILL_NOT_FOUND";
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
class OutputValidationError extends AdkError {
|
|
155
|
+
constructor(agent, rawOutput, issues) {
|
|
156
|
+
super(`Agent "${agent}" returned output that does not match its declared schema.`);
|
|
157
|
+
this.rawOutput = rawOutput;
|
|
158
|
+
this.issues = issues;
|
|
159
|
+
this.code = "OUTPUT_VALIDATION_FAILED";
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
class McpConnectionError extends AdkError {
|
|
163
|
+
constructor(server, cause) {
|
|
164
|
+
super(`MCP server "${server}" connection failed.`, { cause });
|
|
165
|
+
this.code = "MCP_CONNECTION_FAILED";
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
class ApprovalNotFoundError extends AdkError {
|
|
169
|
+
constructor(callId, sessionId) {
|
|
170
|
+
super(`Pending approval "${callId}" was not found in session "${sessionId}".`);
|
|
171
|
+
this.code = "APPROVAL_NOT_FOUND";
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
class Embedder {
|
|
176
|
+
static setActive(instance) {
|
|
177
|
+
Embedder.active = instance;
|
|
178
|
+
}
|
|
179
|
+
static getActive() {
|
|
180
|
+
if (!Embedder.active)
|
|
181
|
+
throw new EmbedderNotConfiguredError();
|
|
182
|
+
return Embedder.active;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
exports.Similarity = class Similarity {
|
|
187
|
+
cosine(a, b) {
|
|
188
|
+
if (a.length !== b.length || a.length === 0) {
|
|
189
|
+
throw new Error(`Similarity.cosine: vectors must have the same non-zero length (got ${a.length} and ${b.length}).`);
|
|
190
|
+
}
|
|
191
|
+
let dot = 0;
|
|
192
|
+
let normA = 0;
|
|
193
|
+
let normB = 0;
|
|
194
|
+
for (let i = 0; i < a.length; i++) {
|
|
195
|
+
const x = a[i];
|
|
196
|
+
const y = b[i];
|
|
197
|
+
dot += x * y;
|
|
198
|
+
normA += x * x;
|
|
199
|
+
normB += y * y;
|
|
200
|
+
}
|
|
201
|
+
if (normA === 0 || normB === 0)
|
|
202
|
+
return 0;
|
|
203
|
+
return dot / (Math.sqrt(normA) * Math.sqrt(normB));
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
exports.Similarity = __decorate([
|
|
207
|
+
common.Injectable()
|
|
208
|
+
], exports.Similarity);
|
|
209
|
+
|
|
210
|
+
class MemoryStore {
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
class SessionStore {
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
exports.InMemoryArtifactStore = class InMemoryArtifactStore extends ArtifactStore {
|
|
217
|
+
constructor() {
|
|
218
|
+
super(...arguments);
|
|
219
|
+
this.artifacts = new Map();
|
|
220
|
+
}
|
|
221
|
+
async save(ref, part) {
|
|
222
|
+
let session = this.artifacts.get(ref.sessionId);
|
|
223
|
+
if (!session) {
|
|
224
|
+
session = new Map();
|
|
225
|
+
this.artifacts.set(ref.sessionId, session);
|
|
226
|
+
}
|
|
227
|
+
let versions = session.get(ref.name);
|
|
228
|
+
if (!versions) {
|
|
229
|
+
versions = [];
|
|
230
|
+
session.set(ref.name, versions);
|
|
231
|
+
}
|
|
232
|
+
versions.push(structuredClone(part));
|
|
233
|
+
return versions.length - 1;
|
|
234
|
+
}
|
|
235
|
+
async load(ref, version) {
|
|
236
|
+
const versions = this.artifacts.get(ref.sessionId)?.get(ref.name);
|
|
237
|
+
if (!versions?.length)
|
|
238
|
+
return null;
|
|
239
|
+
const part = versions[version ?? versions.length - 1];
|
|
240
|
+
return part ? structuredClone(part) : null;
|
|
241
|
+
}
|
|
242
|
+
async listKeys(scope) {
|
|
243
|
+
return [...(this.artifacts.get(scope.sessionId)?.keys() ?? [])];
|
|
244
|
+
}
|
|
245
|
+
async listVersions(ref) {
|
|
246
|
+
const versions = this.artifacts.get(ref.sessionId)?.get(ref.name) ?? [];
|
|
247
|
+
return versions.map((_, index) => index);
|
|
248
|
+
}
|
|
249
|
+
async delete(ref) {
|
|
250
|
+
this.artifacts.get(ref.sessionId)?.delete(ref.name);
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
exports.InMemoryArtifactStore = __decorate([
|
|
254
|
+
common.Injectable()
|
|
255
|
+
], exports.InMemoryArtifactStore);
|
|
256
|
+
|
|
257
|
+
exports.InMemorySessionStore = class InMemorySessionStore extends SessionStore {
|
|
258
|
+
constructor() {
|
|
259
|
+
super(...arguments);
|
|
260
|
+
this.sessions = new Map();
|
|
261
|
+
}
|
|
262
|
+
async get(id) {
|
|
263
|
+
const session = this.sessions.get(id);
|
|
264
|
+
return session ? structuredClone(session) : null;
|
|
265
|
+
}
|
|
266
|
+
async create(init) {
|
|
267
|
+
const now = new Date();
|
|
268
|
+
const session = {
|
|
269
|
+
id: init.id ?? node_crypto.randomUUID(),
|
|
270
|
+
userId: init.userId,
|
|
271
|
+
state: structuredClone(init.state ?? {}),
|
|
272
|
+
events: [],
|
|
273
|
+
createdAt: now,
|
|
274
|
+
updatedAt: now,
|
|
275
|
+
};
|
|
276
|
+
this.sessions.set(session.id, session);
|
|
277
|
+
return structuredClone(session);
|
|
278
|
+
}
|
|
279
|
+
async appendEvent(sessionId, event) {
|
|
280
|
+
const session = this.require(sessionId);
|
|
281
|
+
session.events.push(structuredClone(event));
|
|
282
|
+
session.updatedAt = new Date();
|
|
283
|
+
}
|
|
284
|
+
async updateState(sessionId, delta) {
|
|
285
|
+
const session = this.require(sessionId);
|
|
286
|
+
session.state = { ...session.state, ...structuredClone(delta) };
|
|
287
|
+
session.updatedAt = new Date();
|
|
288
|
+
}
|
|
289
|
+
async delete(id) {
|
|
290
|
+
this.sessions.delete(id);
|
|
291
|
+
}
|
|
292
|
+
require(sessionId) {
|
|
293
|
+
const session = this.sessions.get(sessionId);
|
|
294
|
+
if (!session)
|
|
295
|
+
throw new SessionNotFoundError(sessionId);
|
|
296
|
+
return session;
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
exports.InMemorySessionStore = __decorate([
|
|
300
|
+
common.Injectable()
|
|
301
|
+
], exports.InMemorySessionStore);
|
|
302
|
+
|
|
303
|
+
exports.AgentSessions = class AgentSessions {
|
|
304
|
+
constructor(store) {
|
|
305
|
+
this.store = store;
|
|
306
|
+
}
|
|
307
|
+
get(id) {
|
|
308
|
+
return this.store.get(id);
|
|
309
|
+
}
|
|
310
|
+
create(init = {}) {
|
|
311
|
+
return this.store.create(init);
|
|
312
|
+
}
|
|
313
|
+
async append(sessionId, input) {
|
|
314
|
+
const session = await this.store.get(sessionId);
|
|
315
|
+
if (!session)
|
|
316
|
+
throw new SessionNotFoundError(sessionId);
|
|
317
|
+
const event = {
|
|
318
|
+
v: 1,
|
|
319
|
+
id: node_crypto.randomUUID(),
|
|
320
|
+
at: Date.now(),
|
|
321
|
+
author: input.author ?? "system",
|
|
322
|
+
type: input.type,
|
|
323
|
+
data: input.data,
|
|
324
|
+
};
|
|
325
|
+
await this.store.appendEvent(sessionId, event);
|
|
326
|
+
return event;
|
|
327
|
+
}
|
|
328
|
+
delete(id) {
|
|
329
|
+
return this.store.delete(id);
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
exports.AgentSessions = __decorate([
|
|
333
|
+
common.Injectable(),
|
|
334
|
+
__metadata("design:paramtypes", [SessionStore])
|
|
335
|
+
], exports.AgentSessions);
|
|
336
|
+
|
|
337
|
+
var PromptFiles_1;
|
|
338
|
+
const DEFAULT_PROMPTS_DIR = "./prompts";
|
|
339
|
+
const LIB_FRAMES = ["prompt-files", "adk-prompt", "agent.decorator"];
|
|
340
|
+
exports.PromptFiles = class PromptFiles {
|
|
341
|
+
static { PromptFiles_1 = this; }
|
|
342
|
+
static { this.cache = new Map(); }
|
|
343
|
+
resolvePath(path, promptsDir, callerDir) {
|
|
344
|
+
if (node_path.isAbsolute(path))
|
|
345
|
+
return path;
|
|
346
|
+
if ((path.startsWith("./") || path.startsWith("../")) && callerDir)
|
|
347
|
+
return node_path.resolve(callerDir, path);
|
|
348
|
+
return node_path.join(promptsDir ?? DEFAULT_PROMPTS_DIR, path);
|
|
349
|
+
}
|
|
350
|
+
async render(path, options = {}) {
|
|
351
|
+
const absolute = this.resolvePath(path, options.promptsDir, options.callerDir);
|
|
352
|
+
let template = PromptFiles_1.cache.get(absolute);
|
|
353
|
+
if (template === undefined) {
|
|
354
|
+
template = await promises.readFile(absolute, "utf8");
|
|
355
|
+
PromptFiles_1.cache.set(absolute, template);
|
|
356
|
+
}
|
|
357
|
+
return options.vars ? this.interpolate(template, options.vars) : template;
|
|
358
|
+
}
|
|
359
|
+
interpolate(template, vars) {
|
|
360
|
+
return template.replace(/\{\{(\w+)\}\}/g, (_, key) => String(vars[key] ?? ""));
|
|
361
|
+
}
|
|
362
|
+
callerDir() {
|
|
363
|
+
const frames = new Error().stack?.split("\n") ?? [];
|
|
364
|
+
for (const frame of frames) {
|
|
365
|
+
const match = frame.match(/\(?([^() ]+?):\d+:\d+\)?$/);
|
|
366
|
+
const file = match?.[1];
|
|
367
|
+
if (!file || file.startsWith("node:") || file.includes("node_modules") || file.includes("\0"))
|
|
368
|
+
continue;
|
|
369
|
+
if (LIB_FRAMES.some((name) => file.includes(name)))
|
|
370
|
+
continue;
|
|
371
|
+
return node_path.dirname(file);
|
|
372
|
+
}
|
|
373
|
+
return undefined;
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
exports.PromptFiles = PromptFiles_1 = __decorate([
|
|
377
|
+
common.Injectable()
|
|
378
|
+
], exports.PromptFiles);
|
|
379
|
+
|
|
380
|
+
function Agent(options) {
|
|
381
|
+
return (target) => {
|
|
382
|
+
let normalized = options;
|
|
383
|
+
if (options.promptFile?.startsWith("./") || options.promptFile?.startsWith("../")) {
|
|
384
|
+
const callerDir = new exports.PromptFiles().callerDir();
|
|
385
|
+
if (callerDir)
|
|
386
|
+
normalized = { ...options, promptFile: node_path.resolve(callerDir, options.promptFile) };
|
|
387
|
+
}
|
|
388
|
+
Reflect.defineMetadata(AGENT_METADATA, normalized, target);
|
|
389
|
+
common.Injectable()(target);
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
function Skill(options) {
|
|
394
|
+
const normalized = { ...options, mode: options.mode ?? "on-demand" };
|
|
395
|
+
return (target, propertyKey) => {
|
|
396
|
+
if (propertyKey !== undefined) {
|
|
397
|
+
const ctor = target.constructor;
|
|
398
|
+
const inline = Reflect.getOwnMetadata(INLINE_SKILLS_METADATA, ctor) ?? [];
|
|
399
|
+
inline.push({ method: String(propertyKey), options: normalized });
|
|
400
|
+
Reflect.defineMetadata(INLINE_SKILLS_METADATA, inline, ctor);
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
Reflect.defineMetadata(SKILL_METADATA, normalized, target);
|
|
404
|
+
common.Injectable()(target);
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
function Tool(options) {
|
|
409
|
+
return (target, propertyKey) => {
|
|
410
|
+
if (propertyKey !== undefined) {
|
|
411
|
+
const ctor = target.constructor;
|
|
412
|
+
const inline = Reflect.getOwnMetadata(INLINE_TOOLS_METADATA, ctor) ?? [];
|
|
413
|
+
inline.push({
|
|
414
|
+
method: String(propertyKey),
|
|
415
|
+
options: { ...options, name: options.name ?? String(propertyKey) },
|
|
416
|
+
});
|
|
417
|
+
Reflect.defineMetadata(INLINE_TOOLS_METADATA, inline, ctor);
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
Reflect.defineMetadata(TOOL_METADATA, options, target);
|
|
421
|
+
common.Injectable()(target);
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
function WorkflowAgent(options) {
|
|
426
|
+
return (target) => {
|
|
427
|
+
Reflect.defineMetadata(WORKFLOW_METADATA, options, target);
|
|
428
|
+
common.Injectable()(target);
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
class AdkPrompt {
|
|
433
|
+
constructor() {
|
|
434
|
+
this.files = new exports.PromptFiles();
|
|
435
|
+
}
|
|
436
|
+
fromFile(path, vars) {
|
|
437
|
+
const callerDir = path.startsWith("./") || path.startsWith("../") ? this.files.callerDir() : undefined;
|
|
438
|
+
return this.files.render(path, { promptsDir: this.adkOptions?.prompts?.dir, callerDir, vars });
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
__decorate([
|
|
442
|
+
common.Optional(),
|
|
443
|
+
common.Inject(ADK_OPTIONS),
|
|
444
|
+
__metadata("design:type", Object)
|
|
445
|
+
], AdkPrompt.prototype, "adkOptions", void 0);
|
|
446
|
+
|
|
447
|
+
class AdkBootError extends AdkError {
|
|
448
|
+
}
|
|
449
|
+
class DuplicateAgentNameError extends AdkBootError {
|
|
450
|
+
constructor(name, classes) {
|
|
451
|
+
super(`Agent name "${name}" is declared by both ${classes[0]} and ${classes[1]}. Agent names must be unique.`);
|
|
452
|
+
this.code = "DUPLICATE_AGENT_NAME";
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
class ReservedMethodError extends AdkBootError {
|
|
456
|
+
constructor(agentClass, method) {
|
|
457
|
+
super(`Agent ${agentClass} declares a method "${method}", which shadows the execution handle inherited from AdkAgent/AdkWorkflow (ask/stream/approve/reject). Rename the method.`);
|
|
458
|
+
this.code = "RESERVED_METHOD";
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
class UnregisteredToolError extends AdkBootError {
|
|
462
|
+
constructor(agentClass, toolClass) {
|
|
463
|
+
super(`Agent ${agentClass} references tool ${toolClass}, but it is not registered as a provider in any module. ` +
|
|
464
|
+
`Add ${toolClass} to a module's providers.`);
|
|
465
|
+
this.code = "UNREGISTERED_TOOL";
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
class UnregisteredSkillError extends AdkBootError {
|
|
469
|
+
constructor(agentClass, skillClass) {
|
|
470
|
+
super(`Agent ${agentClass} references skill ${skillClass}, but it is not registered as a provider in any module. ` +
|
|
471
|
+
`Add ${skillClass} to a module's providers.`);
|
|
472
|
+
this.code = "UNREGISTERED_SKILL";
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
class UnregisteredSubAgentError extends AdkBootError {
|
|
476
|
+
constructor(agentClass, subAgentClass) {
|
|
477
|
+
super(`Agent ${agentClass} references sub-agent ${subAgentClass}, but it is not registered as a provider in any module.`);
|
|
478
|
+
this.code = "UNREGISTERED_SUB_AGENT";
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
class MissingModelError extends AdkBootError {
|
|
482
|
+
constructor(agentClass) {
|
|
483
|
+
super(`Agent ${agentClass} has no model and AdkModule.forRoot() has no defaultModel. Set @Agent({ model }) or forRoot({ defaultModel }).`);
|
|
484
|
+
this.code = "MISSING_MODEL";
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
class InvalidWorkflowError extends AdkBootError {
|
|
488
|
+
constructor(workflowClass, reason) {
|
|
489
|
+
super(`Workflow ${workflowClass} is invalid: ${reason}`);
|
|
490
|
+
this.code = "INVALID_WORKFLOW";
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
class ConflictingPromptError extends AdkBootError {
|
|
494
|
+
constructor(agentClass) {
|
|
495
|
+
super(`Agent ${agentClass} declares both "prompt" and "promptFile". Pick exactly one.`);
|
|
496
|
+
this.code = "CONFLICTING_PROMPT";
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
class UnregisteredPromptError extends AdkBootError {
|
|
500
|
+
constructor(agentClass, promptClass) {
|
|
501
|
+
super(`Agent ${agentClass} references prompt ${promptClass}, but it is not registered as a provider in any module. Add ${promptClass} to a module's providers.`);
|
|
502
|
+
this.code = "UNREGISTERED_PROMPT";
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
class UnresolvedToolsetError extends AdkBootError {
|
|
506
|
+
constructor(agentClass, toolsetName) {
|
|
507
|
+
super(`Agent ${agentClass} references toolset "${toolsetName}", but no ToolsetResolver is registered. Import a provider module (e.g. McpModule.forRoot from @nestjs-adk/mcp).`);
|
|
508
|
+
this.code = "UNRESOLVED_TOOLSET";
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
function toolset(name, filter) {
|
|
513
|
+
return { __adkToolset: name, filter };
|
|
514
|
+
}
|
|
515
|
+
function isToolsetRef(value) {
|
|
516
|
+
return typeof value === "object" && value !== null && "__adkToolset" in value;
|
|
517
|
+
}
|
|
518
|
+
class ToolsetResolver {
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
class AgentDefinition {
|
|
522
|
+
constructor(name, type, instance, options, model, tools, skills, subAgents, promptText, promptFile, promptInstance, workflow, output, outputKey, toolsets = []) {
|
|
523
|
+
this.name = name;
|
|
524
|
+
this.type = type;
|
|
525
|
+
this.instance = instance;
|
|
526
|
+
this.options = options;
|
|
527
|
+
this.model = model;
|
|
528
|
+
this.tools = tools;
|
|
529
|
+
this.skills = skills;
|
|
530
|
+
this.subAgents = subAgents;
|
|
531
|
+
this.promptText = promptText;
|
|
532
|
+
this.promptFile = promptFile;
|
|
533
|
+
this.promptInstance = promptInstance;
|
|
534
|
+
this.workflow = workflow;
|
|
535
|
+
this.output = output;
|
|
536
|
+
this.outputKey = outputKey;
|
|
537
|
+
this.toolsets = toolsets;
|
|
538
|
+
}
|
|
539
|
+
get description() {
|
|
540
|
+
return this.options?.description ?? this.workflow?.description ?? "";
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
class AgentRef {
|
|
545
|
+
constructor(registry, agentType, getRunner) {
|
|
546
|
+
this.registry = registry;
|
|
547
|
+
this.agentType = agentType;
|
|
548
|
+
this.getRunner = getRunner;
|
|
549
|
+
}
|
|
550
|
+
get name() {
|
|
551
|
+
return this.definition.name;
|
|
552
|
+
}
|
|
553
|
+
get definition() {
|
|
554
|
+
return this.registry.getByType(this.agentType);
|
|
555
|
+
}
|
|
556
|
+
ask(input) {
|
|
557
|
+
return this.getRunner().ask(this.agentType, input);
|
|
558
|
+
}
|
|
559
|
+
stream(input) {
|
|
560
|
+
return this.getRunner().run(this.agentType, input);
|
|
561
|
+
}
|
|
562
|
+
approve(params) {
|
|
563
|
+
return this.getRunner().approve(this.agentType, params);
|
|
564
|
+
}
|
|
565
|
+
reject(params) {
|
|
566
|
+
return this.getRunner().reject(this.agentType, params);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
exports.AgentRegistry = class AgentRegistry {
|
|
571
|
+
constructor(discovery, moduleRef, options) {
|
|
572
|
+
this.discovery = discovery;
|
|
573
|
+
this.moduleRef = moduleRef;
|
|
574
|
+
this.options = options;
|
|
575
|
+
this.byName = new Map();
|
|
576
|
+
this.byType = new Map();
|
|
577
|
+
this.refs = new Map();
|
|
578
|
+
this.modelOverrides = new Map();
|
|
579
|
+
this.built = false;
|
|
580
|
+
}
|
|
581
|
+
onApplicationBootstrap() {
|
|
582
|
+
this.build();
|
|
583
|
+
}
|
|
584
|
+
list() {
|
|
585
|
+
this.ensureBuilt();
|
|
586
|
+
return [...this.byName.values()];
|
|
587
|
+
}
|
|
588
|
+
get(name) {
|
|
589
|
+
this.ensureBuilt();
|
|
590
|
+
const definition = this.byName.get(name);
|
|
591
|
+
if (!definition)
|
|
592
|
+
throw new AgentNotFoundError(name);
|
|
593
|
+
return definition;
|
|
594
|
+
}
|
|
595
|
+
getByType(type) {
|
|
596
|
+
this.ensureBuilt();
|
|
597
|
+
const definition = this.byType.get(type);
|
|
598
|
+
if (!definition)
|
|
599
|
+
throw new AgentNotFoundError(type.name);
|
|
600
|
+
return definition;
|
|
601
|
+
}
|
|
602
|
+
overrideModel(type, model) {
|
|
603
|
+
this.modelOverrides.set(type, model);
|
|
604
|
+
}
|
|
605
|
+
modelFor(definition) {
|
|
606
|
+
return this.modelOverrides.get(definition.type) ?? definition.model;
|
|
607
|
+
}
|
|
608
|
+
getRef(type) {
|
|
609
|
+
let ref = this.refs.get(type);
|
|
610
|
+
if (!ref) {
|
|
611
|
+
ref = new AgentRef(this, type, () => this.moduleRef.get(ADK_RUNNER, { strict: false }));
|
|
612
|
+
this.refs.set(type, ref);
|
|
613
|
+
}
|
|
614
|
+
return ref;
|
|
615
|
+
}
|
|
616
|
+
ensureBuilt() {
|
|
617
|
+
if (!this.built)
|
|
618
|
+
this.build();
|
|
619
|
+
}
|
|
620
|
+
build() {
|
|
621
|
+
if (this.built)
|
|
622
|
+
return;
|
|
623
|
+
this.built = true;
|
|
624
|
+
const wrappers = this.discovery
|
|
625
|
+
.getProviders()
|
|
626
|
+
.filter((wrapper) => typeof wrapper.metatype === "function" && wrapper.instance);
|
|
627
|
+
const toolInstances = new Map();
|
|
628
|
+
const skillInstances = new Map();
|
|
629
|
+
const agentWrappers = [];
|
|
630
|
+
for (const wrapper of wrappers) {
|
|
631
|
+
const type = wrapper.metatype;
|
|
632
|
+
if (Reflect.getMetadata(TOOL_METADATA, type))
|
|
633
|
+
toolInstances.set(type, wrapper.instance);
|
|
634
|
+
if (Reflect.getMetadata(SKILL_METADATA, type))
|
|
635
|
+
skillInstances.set(type, wrapper.instance);
|
|
636
|
+
if (Reflect.getMetadata(AGENT_METADATA, type) || Reflect.getMetadata(WORKFLOW_METADATA, type)) {
|
|
637
|
+
agentWrappers.push({ type, instance: wrapper.instance });
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
const agentTypes = new Set(agentWrappers.map((w) => w.type));
|
|
641
|
+
for (const { type, instance } of agentWrappers) {
|
|
642
|
+
const definition = this.createDefinition(type, instance, toolInstances, skillInstances, agentTypes);
|
|
643
|
+
const existing = this.byName.get(definition.name);
|
|
644
|
+
if (existing)
|
|
645
|
+
throw new DuplicateAgentNameError(definition.name, [existing.type.name, type.name]);
|
|
646
|
+
this.byName.set(definition.name, definition);
|
|
647
|
+
this.byType.set(type, definition);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
createDefinition(type, instance, toolInstances, skillInstances, agentTypes) {
|
|
651
|
+
const agentOptions = Reflect.getMetadata(AGENT_METADATA, type);
|
|
652
|
+
const workflow = Reflect.getMetadata(WORKFLOW_METADATA, type);
|
|
653
|
+
for (const reserved of ["ask", "stream", "approve", "reject"]) {
|
|
654
|
+
if (Object.getOwnPropertyNames(type.prototype).includes(reserved)) {
|
|
655
|
+
throw new ReservedMethodError(type.name, reserved);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
if (workflow) {
|
|
659
|
+
if (workflow.agents.length === 0)
|
|
660
|
+
throw new InvalidWorkflowError(type.name, "it has no agents");
|
|
661
|
+
for (const agent of workflow.agents) {
|
|
662
|
+
if (!agentTypes.has(agent)) {
|
|
663
|
+
throw new InvalidWorkflowError(type.name, `agent ${agent.name} is not registered as a provider`);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
return new AgentDefinition(workflow.name, type, instance, undefined, undefined, [], [], [], undefined, undefined, undefined, workflow);
|
|
667
|
+
}
|
|
668
|
+
const options = agentOptions;
|
|
669
|
+
const model = options.model ?? this.options.defaultModel;
|
|
670
|
+
if (model === undefined)
|
|
671
|
+
throw new MissingModelError(type.name);
|
|
672
|
+
const tools = [];
|
|
673
|
+
const toolsets = [];
|
|
674
|
+
for (const toolRef of options.tools ?? []) {
|
|
675
|
+
if (isToolsetRef(toolRef)) {
|
|
676
|
+
if (!this.hasToolsetResolver())
|
|
677
|
+
throw new UnresolvedToolsetError(type.name, toolRef.__adkToolset);
|
|
678
|
+
toolsets.push(toolRef);
|
|
679
|
+
continue;
|
|
680
|
+
}
|
|
681
|
+
const toolInstance = toolInstances.get(toolRef);
|
|
682
|
+
if (!toolInstance)
|
|
683
|
+
throw new UnregisteredToolError(type.name, toolRef.name);
|
|
684
|
+
const toolOptions = Reflect.getMetadata(TOOL_METADATA, toolRef);
|
|
685
|
+
tools.push({ kind: "class", type: toolRef, instance: toolInstance, options: toolOptions });
|
|
686
|
+
}
|
|
687
|
+
const inlineTools = Reflect.getMetadata(INLINE_TOOLS_METADATA, type) ?? [];
|
|
688
|
+
for (const inline of inlineTools)
|
|
689
|
+
tools.push({ kind: "inline", method: inline.method, options: inline.options });
|
|
690
|
+
const skills = [];
|
|
691
|
+
for (const skillType of options.skills ?? []) {
|
|
692
|
+
const skillInstance = skillInstances.get(skillType);
|
|
693
|
+
if (!skillInstance)
|
|
694
|
+
throw new UnregisteredSkillError(type.name, skillType.name);
|
|
695
|
+
const skillOptions = Reflect.getMetadata(SKILL_METADATA, skillType);
|
|
696
|
+
skills.push({ kind: "class", type: skillType, instance: skillInstance, options: skillOptions });
|
|
697
|
+
}
|
|
698
|
+
const inlineSkills = Reflect.getMetadata(INLINE_SKILLS_METADATA, type) ?? [];
|
|
699
|
+
for (const inline of inlineSkills)
|
|
700
|
+
skills.push({ kind: "inline", method: inline.method, options: inline.options });
|
|
701
|
+
if (options.prompt !== undefined && options.promptFile !== undefined)
|
|
702
|
+
throw new ConflictingPromptError(type.name);
|
|
703
|
+
let promptText;
|
|
704
|
+
let promptInstance;
|
|
705
|
+
if (typeof options.prompt === "string") {
|
|
706
|
+
promptText = options.prompt;
|
|
707
|
+
}
|
|
708
|
+
else if (options.prompt) {
|
|
709
|
+
try {
|
|
710
|
+
promptInstance = this.moduleRef.get(options.prompt, { strict: false });
|
|
711
|
+
}
|
|
712
|
+
catch {
|
|
713
|
+
throw new UnregisteredPromptError(type.name, options.prompt.name);
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
const subAgents = [];
|
|
717
|
+
for (const subAgent of options.subAgents ?? []) {
|
|
718
|
+
if (!agentTypes.has(subAgent))
|
|
719
|
+
throw new UnregisteredSubAgentError(type.name, subAgent.name);
|
|
720
|
+
subAgents.push(subAgent);
|
|
721
|
+
}
|
|
722
|
+
return new AgentDefinition(options.name, type, instance, options, model, tools, skills, subAgents, promptText, options.promptFile, promptInstance, undefined, options.output, options.outputKey, toolsets);
|
|
723
|
+
}
|
|
724
|
+
hasToolsetResolver() {
|
|
725
|
+
try {
|
|
726
|
+
return Boolean(this.moduleRef.get(ToolsetResolver, { strict: false }));
|
|
727
|
+
}
|
|
728
|
+
catch {
|
|
729
|
+
return false;
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
};
|
|
733
|
+
exports.AgentRegistry = __decorate([
|
|
734
|
+
common.Injectable(),
|
|
735
|
+
__param(2, common.Inject(ADK_OPTIONS)),
|
|
736
|
+
__metadata("design:paramtypes", [core.DiscoveryService,
|
|
737
|
+
core.ModuleRef, Object])
|
|
738
|
+
], exports.AgentRegistry);
|
|
739
|
+
|
|
740
|
+
function contextPolicy(options) {
|
|
741
|
+
return { __adkContextPolicy: true, ...options };
|
|
742
|
+
}
|
|
743
|
+
const DEFAULT_OFFLOAD_THRESHOLD = 20_000;
|
|
744
|
+
|
|
745
|
+
const promptFiles = new exports.PromptFiles();
|
|
746
|
+
async function skillContent(definition, binding) {
|
|
747
|
+
if (binding.kind === "class")
|
|
748
|
+
return binding.instance.content();
|
|
749
|
+
const method = definition.instance[binding.method];
|
|
750
|
+
return (await method?.call(definition.instance)) ?? "";
|
|
751
|
+
}
|
|
752
|
+
async function resolvePrompt(definition, options, ctx) {
|
|
753
|
+
if (definition.promptInstance)
|
|
754
|
+
return definition.promptInstance.build(ctx);
|
|
755
|
+
if (definition.promptText !== undefined)
|
|
756
|
+
return definition.promptText;
|
|
757
|
+
if (definition.promptFile)
|
|
758
|
+
return promptFiles.render(definition.promptFile, { promptsDir: options.promptsDir });
|
|
759
|
+
return undefined;
|
|
760
|
+
}
|
|
761
|
+
async function buildInstruction(definition, options = {}, ctx) {
|
|
762
|
+
const sections = [];
|
|
763
|
+
const prompt = await resolvePrompt(definition, options, ctx);
|
|
764
|
+
if (prompt)
|
|
765
|
+
sections.push(prompt);
|
|
766
|
+
const catalog = [];
|
|
767
|
+
for (const skill of definition.skills) {
|
|
768
|
+
if (skill.options.mode === "always") {
|
|
769
|
+
sections.push(`## Skill: ${skill.options.name}\n${await skillContent(definition, skill)}`);
|
|
770
|
+
}
|
|
771
|
+
else {
|
|
772
|
+
catalog.push(`- ${skill.options.name}: ${skill.options.description}`);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
if (catalog.length > 0) {
|
|
776
|
+
sections.push(`## Available skills\nLook up a skill's content with the load_skill(name) tool.\n${catalog.join("\n")}`);
|
|
777
|
+
}
|
|
778
|
+
return sections.length > 0 ? sections.join("\n\n") : undefined;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
const PREVIEW_LENGTH = 160;
|
|
782
|
+
const LEVEL_WEIGHT = { info: 0, debug: 1, verbose: 2 };
|
|
783
|
+
class RunLogger {
|
|
784
|
+
static create(option, agentName) {
|
|
785
|
+
if (!option)
|
|
786
|
+
return undefined;
|
|
787
|
+
return new RunLogger(agentName, option === true ? "info" : option);
|
|
788
|
+
}
|
|
789
|
+
constructor(agentName, level) {
|
|
790
|
+
this.level = level;
|
|
791
|
+
this.startedAt = Date.now();
|
|
792
|
+
this.logger = new common.Logger(`Adk:${agentName}`);
|
|
793
|
+
}
|
|
794
|
+
start(input) {
|
|
795
|
+
const session = input.sessionId ?? "ephemeral";
|
|
796
|
+
this.logger.log(`run start session=${session} user=${input.userId ?? "-"} message=${this.preview(input.message)}`);
|
|
797
|
+
}
|
|
798
|
+
event(event) {
|
|
799
|
+
switch (event.type) {
|
|
800
|
+
case "run_start":
|
|
801
|
+
return;
|
|
802
|
+
case "tool_call":
|
|
803
|
+
if (this.enabled("debug"))
|
|
804
|
+
this.logger.debug(`tool call ${event.tool} args=${this.preview(json(event.args))}`);
|
|
805
|
+
return;
|
|
806
|
+
case "tool_result":
|
|
807
|
+
if (this.enabled("debug")) {
|
|
808
|
+
this.logger.debug(`tool result ${event.tool} result=${this.preview(json(event.result))}`);
|
|
809
|
+
}
|
|
810
|
+
return;
|
|
811
|
+
case "llm_response":
|
|
812
|
+
if (this.enabled("verbose") && event.text) {
|
|
813
|
+
this.logger.verbose(`llm response text=${this.preview(event.text)}${usageSuffix(event.usage)}`);
|
|
814
|
+
}
|
|
815
|
+
return;
|
|
816
|
+
case "model_rerouted":
|
|
817
|
+
this.logger.warn(`model rerouted from=${event.from} to=${event.to} reason=${event.reason}`);
|
|
818
|
+
return;
|
|
819
|
+
case "approval_required":
|
|
820
|
+
this.logger.warn(`approval required tool=${event.tool} callId=${event.callId} args=${this.preview(json(event.args))}`);
|
|
821
|
+
return;
|
|
822
|
+
case "final":
|
|
823
|
+
this.logger.log(`run done in ${Date.now() - this.startedAt}ms text=${this.preview(event.text)}${usageSuffix(event.usage)}`);
|
|
824
|
+
return;
|
|
825
|
+
default:
|
|
826
|
+
if (this.enabled("verbose"))
|
|
827
|
+
this.logger.verbose(json(event));
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
enabled(level) {
|
|
831
|
+
return LEVEL_WEIGHT[level] <= LEVEL_WEIGHT[this.level];
|
|
832
|
+
}
|
|
833
|
+
preview(value) {
|
|
834
|
+
if (this.level === "verbose" || value.length <= PREVIEW_LENGTH)
|
|
835
|
+
return value;
|
|
836
|
+
return `${value.slice(0, PREVIEW_LENGTH)}... (+${value.length - PREVIEW_LENGTH} chars)`;
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
function usageSuffix(usage) {
|
|
840
|
+
if (!usage)
|
|
841
|
+
return "";
|
|
842
|
+
const cached = usage.cachedTokens != null ? ` cached=${usage.cachedTokens}` : "";
|
|
843
|
+
return ` | tokens in=${usage.promptTokens} out=${usage.outputTokens}${cached} total=${usage.totalTokens}`;
|
|
844
|
+
}
|
|
845
|
+
function json(value) {
|
|
846
|
+
try {
|
|
847
|
+
return JSON.stringify(value) ?? "undefined";
|
|
848
|
+
}
|
|
849
|
+
catch {
|
|
850
|
+
return String(value);
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
class DeltaStateBag {
|
|
855
|
+
constructor(initial) {
|
|
856
|
+
this.initial = initial;
|
|
857
|
+
this.changes = new Map();
|
|
858
|
+
}
|
|
859
|
+
get(key) {
|
|
860
|
+
if (this.changes.has(key))
|
|
861
|
+
return this.changes.get(key);
|
|
862
|
+
return this.initial[key];
|
|
863
|
+
}
|
|
864
|
+
set(key, value) {
|
|
865
|
+
this.changes.set(key, value);
|
|
866
|
+
}
|
|
867
|
+
delta() {
|
|
868
|
+
return Object.fromEntries(this.changes);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
const EMPTY_USAGE = { promptTokens: 0, outputTokens: 0, totalTokens: 0 };
|
|
873
|
+
const HITL_STATE_KEY = "__adk_hitl";
|
|
874
|
+
exports.AgentRunner = class AgentRunner {
|
|
875
|
+
constructor(engine, registry, store, artifacts, options, toolsets) {
|
|
876
|
+
this.engine = engine;
|
|
877
|
+
this.registry = registry;
|
|
878
|
+
this.store = store;
|
|
879
|
+
this.artifacts = artifacts;
|
|
880
|
+
this.options = options;
|
|
881
|
+
this.toolsets = toolsets;
|
|
882
|
+
}
|
|
883
|
+
async *run(agentType, input) {
|
|
884
|
+
const definition = this.definitionOf(agentType);
|
|
885
|
+
const log = RunLogger.create(this.options.logging, definition.name);
|
|
886
|
+
log?.start(input);
|
|
887
|
+
const session = await this.openSession(input);
|
|
888
|
+
const state = new DeltaStateBag({ ...(session?.state ?? {}), ...(input.state ?? {}) });
|
|
889
|
+
const runtime = { scope: input.sessionId ?? node_crypto.randomUUID(), pendings: [] };
|
|
890
|
+
const ctx = this.createToolContext(definition, input, state);
|
|
891
|
+
const resolved = await this.resolveAgent(definition, ctx, runtime);
|
|
892
|
+
const engineInput = { ...input, history: session?.events };
|
|
893
|
+
if (session)
|
|
894
|
+
await this.persist(session.id, "user", "message", { text: input.message });
|
|
895
|
+
for await (const event of this.engine.run(resolved, engineInput)) {
|
|
896
|
+
log?.event(event);
|
|
897
|
+
if (session)
|
|
898
|
+
await this.persistAgentEvent(session.id, event);
|
|
899
|
+
if (event.type === "final" && definition.output && definition.outputKey) {
|
|
900
|
+
const parsed = definition.output.safeParse(tryParseJson(event.text));
|
|
901
|
+
if (parsed.success)
|
|
902
|
+
state.set(definition.outputKey, parsed.data);
|
|
903
|
+
}
|
|
904
|
+
yield event;
|
|
905
|
+
}
|
|
906
|
+
for (const pending of runtime.pendings) {
|
|
907
|
+
const approval = {
|
|
908
|
+
type: "approval_required",
|
|
909
|
+
agent: pending.agent,
|
|
910
|
+
callId: pending.callId,
|
|
911
|
+
tool: pending.tool,
|
|
912
|
+
args: pending.args,
|
|
913
|
+
};
|
|
914
|
+
log?.event(approval);
|
|
915
|
+
yield approval;
|
|
916
|
+
}
|
|
917
|
+
if (session) {
|
|
918
|
+
const delta = state.delta();
|
|
919
|
+
if (Object.keys(delta).length > 0)
|
|
920
|
+
await this.store.updateState(session.id, delta);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
async ask(agentType, input) {
|
|
924
|
+
const events = [];
|
|
925
|
+
let text = "";
|
|
926
|
+
let usage = EMPTY_USAGE;
|
|
927
|
+
let agentName = typeof agentType === "string" ? agentType : agentType.name;
|
|
928
|
+
for await (const event of this.run(agentType, input)) {
|
|
929
|
+
events.push(event);
|
|
930
|
+
if (event.type === "run_start")
|
|
931
|
+
agentName = event.agent;
|
|
932
|
+
if (event.type === "final") {
|
|
933
|
+
text = event.text;
|
|
934
|
+
usage = event.usage;
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
const pending = [];
|
|
938
|
+
for (const event of events) {
|
|
939
|
+
if (event.type === "approval_required") {
|
|
940
|
+
pending.push({ callId: event.callId, tool: event.tool, args: event.args, agent: event.agent });
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
if (pending.length > 0)
|
|
944
|
+
return { text, usage, events, status: "pending_approval", pending };
|
|
945
|
+
if (!text.trim())
|
|
946
|
+
throw new AiEmptyResponseError(agentName);
|
|
947
|
+
const definition = this.definitionOf(agentType);
|
|
948
|
+
let output;
|
|
949
|
+
if (definition.output) {
|
|
950
|
+
const result = definition.output.safeParse(tryParseJson(text));
|
|
951
|
+
if (!result.success)
|
|
952
|
+
throw new OutputValidationError(agentName, text, result.error.issues);
|
|
953
|
+
output = result.data;
|
|
954
|
+
}
|
|
955
|
+
return { text, usage, events, status: "completed", output };
|
|
956
|
+
}
|
|
957
|
+
async approve(agentType, params) {
|
|
958
|
+
const definition = this.definitionOf(agentType);
|
|
959
|
+
const { session, entry, rest } = await this.takePending(params.sessionId, params.callId);
|
|
960
|
+
const binding = definition.tools.find((candidate) => candidate.options.name === entry.tool);
|
|
961
|
+
if (!binding)
|
|
962
|
+
throw new ApprovalNotFoundError(params.callId, params.sessionId);
|
|
963
|
+
const state = new DeltaStateBag(session.state);
|
|
964
|
+
const ctx = this.createToolContext(definition, { message: "", sessionId: session.id, userId: session.userId }, state);
|
|
965
|
+
const result = await this.executeBinding(definition, binding, entry.args, ctx);
|
|
966
|
+
await this.persist(session.id, "tool", "tool_result", { callId: entry.callId, tool: entry.tool, result });
|
|
967
|
+
await this.store.updateState(session.id, { [HITL_STATE_KEY]: rest });
|
|
968
|
+
const message = params.message ??
|
|
969
|
+
`[system] Action "${entry.tool}" was approved by the user and executed. Result: ${JSON.stringify(result)}. Continue the conversation.`;
|
|
970
|
+
return this.ask(agentType, { sessionId: session.id, userId: session.userId, message });
|
|
971
|
+
}
|
|
972
|
+
async reject(agentType, params) {
|
|
973
|
+
const { session, entry, rest } = await this.takePending(params.sessionId, params.callId);
|
|
974
|
+
await this.store.updateState(session.id, { [HITL_STATE_KEY]: rest });
|
|
975
|
+
const reason = params.reason ? ` (reason: ${params.reason})` : "";
|
|
976
|
+
const message = `[system] The user rejected action "${entry.tool}"${reason}. The action was NOT executed. Continue the conversation.`;
|
|
977
|
+
return this.ask(agentType, { sessionId: session.id, userId: session.userId, message });
|
|
978
|
+
}
|
|
979
|
+
resolve(agentType, input = { message: "" }) {
|
|
980
|
+
const definition = this.definitionOf(agentType);
|
|
981
|
+
const state = new DeltaStateBag({ ...(input.state ?? {}) });
|
|
982
|
+
return this.resolveAgent(definition, this.createToolContext(definition, input, state), {
|
|
983
|
+
scope: input.sessionId ?? node_crypto.randomUUID(),
|
|
984
|
+
pendings: [],
|
|
985
|
+
});
|
|
986
|
+
}
|
|
987
|
+
definitionOf(agentType) {
|
|
988
|
+
return typeof agentType === "string" ? this.registry.get(agentType) : this.registry.getByType(agentType);
|
|
989
|
+
}
|
|
990
|
+
async openSession(input) {
|
|
991
|
+
if (!input.sessionId)
|
|
992
|
+
return null;
|
|
993
|
+
const existing = await this.store.get(input.sessionId);
|
|
994
|
+
if (existing)
|
|
995
|
+
return existing;
|
|
996
|
+
return this.store.create({ id: input.sessionId, userId: input.userId });
|
|
997
|
+
}
|
|
998
|
+
async takePending(sessionId, callId) {
|
|
999
|
+
const session = await this.store.get(sessionId);
|
|
1000
|
+
if (!session)
|
|
1001
|
+
throw new SessionNotFoundError(sessionId);
|
|
1002
|
+
const pendings = session.state[HITL_STATE_KEY] ?? [];
|
|
1003
|
+
const entry = pendings.find((candidate) => candidate.callId === callId);
|
|
1004
|
+
if (!entry)
|
|
1005
|
+
throw new ApprovalNotFoundError(callId, sessionId);
|
|
1006
|
+
return { session, entry, rest: pendings.filter((candidate) => candidate.callId !== callId) };
|
|
1007
|
+
}
|
|
1008
|
+
createToolContext(definition, input, state) {
|
|
1009
|
+
return {
|
|
1010
|
+
agentName: definition.name,
|
|
1011
|
+
sessionId: input.sessionId,
|
|
1012
|
+
userId: input.userId,
|
|
1013
|
+
state,
|
|
1014
|
+
attributes: input.attributes ?? {},
|
|
1015
|
+
signal: input.signal ?? new AbortController().signal,
|
|
1016
|
+
actions: { endRun: () => undefined },
|
|
1017
|
+
};
|
|
1018
|
+
}
|
|
1019
|
+
policyOf(definition) {
|
|
1020
|
+
return definition.options?.context ?? this.options.context;
|
|
1021
|
+
}
|
|
1022
|
+
async resolveAgent(definition, ctx, runtime) {
|
|
1023
|
+
const policy = this.policyOf(definition);
|
|
1024
|
+
const offloadEnabled = policy?.offload !== false;
|
|
1025
|
+
const threshold = (policy?.offload || undefined)?.threshold ?? DEFAULT_OFFLOAD_THRESHOLD;
|
|
1026
|
+
const tools = definition.tools.map((binding) => ({
|
|
1027
|
+
name: binding.options.name ?? "",
|
|
1028
|
+
description: binding.options.description,
|
|
1029
|
+
schema: binding.options.schema,
|
|
1030
|
+
execute: async (input) => {
|
|
1031
|
+
if (await this.needsApproval(definition, binding, input, ctx)) {
|
|
1032
|
+
const pending = {
|
|
1033
|
+
callId: node_crypto.randomUUID(),
|
|
1034
|
+
tool: binding.options.name ?? "",
|
|
1035
|
+
args: input,
|
|
1036
|
+
agent: definition.name,
|
|
1037
|
+
};
|
|
1038
|
+
runtime.pendings.push(pending);
|
|
1039
|
+
const existing = ctx.state.get(HITL_STATE_KEY) ?? [];
|
|
1040
|
+
ctx.state.set(HITL_STATE_KEY, [...existing, pending]);
|
|
1041
|
+
return {
|
|
1042
|
+
pending_approval: true,
|
|
1043
|
+
callId: pending.callId,
|
|
1044
|
+
note: `Action "${pending.tool}" requires user approval and was NOT executed. Let the user know it is awaiting approval.`,
|
|
1045
|
+
};
|
|
1046
|
+
}
|
|
1047
|
+
const raw = await this.executeBinding(definition, binding, input, ctx);
|
|
1048
|
+
if (!offloadEnabled || binding.options.offload === false)
|
|
1049
|
+
return raw;
|
|
1050
|
+
return this.maybeOffload(raw, binding.options.name ?? "", threshold, runtime.scope);
|
|
1051
|
+
},
|
|
1052
|
+
}));
|
|
1053
|
+
for (const ref of definition.toolsets) {
|
|
1054
|
+
const external = (await this.toolsets?.resolve(ref)) ?? [];
|
|
1055
|
+
for (const tool of external) {
|
|
1056
|
+
tools.push({
|
|
1057
|
+
...tool,
|
|
1058
|
+
execute: async (input) => {
|
|
1059
|
+
const raw = await tool.execute(input);
|
|
1060
|
+
return offloadEnabled ? this.maybeOffload(raw, tool.name, threshold, runtime.scope) : raw;
|
|
1061
|
+
},
|
|
1062
|
+
});
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
if (offloadEnabled && tools.length > 0)
|
|
1066
|
+
tools.push(this.createReadArtifactTool(runtime.scope));
|
|
1067
|
+
if (definition.skills.some((skill) => skill.options.mode === "on-demand")) {
|
|
1068
|
+
tools.push(this.createLoadSkillTool(definition));
|
|
1069
|
+
}
|
|
1070
|
+
const subAgents = [];
|
|
1071
|
+
for (const subType of definition.subAgents) {
|
|
1072
|
+
const subDefinition = this.registry.getByType(subType);
|
|
1073
|
+
subAgents.push(await this.resolveAgent(subDefinition, { ...ctx, agentName: subDefinition.name }, runtime));
|
|
1074
|
+
}
|
|
1075
|
+
let workflow;
|
|
1076
|
+
if (definition.workflow) {
|
|
1077
|
+
const agents = [];
|
|
1078
|
+
for (const agentType of definition.workflow.agents) {
|
|
1079
|
+
const agentDefinition = this.registry.getByType(agentType);
|
|
1080
|
+
agents.push(await this.resolveAgent(agentDefinition, { ...ctx, agentName: agentDefinition.name }, runtime));
|
|
1081
|
+
}
|
|
1082
|
+
workflow = { mode: definition.workflow.mode, agents, maxIterations: definition.workflow.maxIterations };
|
|
1083
|
+
}
|
|
1084
|
+
return {
|
|
1085
|
+
name: definition.name,
|
|
1086
|
+
description: definition.description,
|
|
1087
|
+
instruction: await buildInstruction(definition, { promptsDir: this.options.prompts?.dir }, ctx),
|
|
1088
|
+
model: this.registry.modelFor(definition),
|
|
1089
|
+
tools,
|
|
1090
|
+
subAgents,
|
|
1091
|
+
workflow,
|
|
1092
|
+
outputSchema: definition.output,
|
|
1093
|
+
context: policy,
|
|
1094
|
+
};
|
|
1095
|
+
}
|
|
1096
|
+
async needsApproval(definition, binding, input, ctx) {
|
|
1097
|
+
const requirement = binding.options.requiresApproval;
|
|
1098
|
+
if (!requirement)
|
|
1099
|
+
return false;
|
|
1100
|
+
if (requirement === true)
|
|
1101
|
+
return true;
|
|
1102
|
+
const self = binding.kind === "class" ? binding.instance : definition.instance;
|
|
1103
|
+
return requirement.call(self, input, ctx);
|
|
1104
|
+
}
|
|
1105
|
+
async executeBinding(definition, binding, input, ctx) {
|
|
1106
|
+
try {
|
|
1107
|
+
if (binding.kind === "class")
|
|
1108
|
+
return await binding.instance.execute(input, ctx);
|
|
1109
|
+
const method = definition.instance[binding.method];
|
|
1110
|
+
return await method?.call(definition.instance, input, ctx);
|
|
1111
|
+
}
|
|
1112
|
+
catch (error) {
|
|
1113
|
+
throw new ToolExecutionError(binding.options.name ?? "unknown", error);
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
async maybeOffload(raw, tool, threshold, scope) {
|
|
1117
|
+
if (raw === undefined || raw === null)
|
|
1118
|
+
return raw;
|
|
1119
|
+
const serialized = typeof raw === "string" ? raw : JSON.stringify(raw);
|
|
1120
|
+
if (serialized.length <= threshold)
|
|
1121
|
+
return raw;
|
|
1122
|
+
const name = `tool-results/${tool}-${node_crypto.randomUUID()}`;
|
|
1123
|
+
const version = await this.artifacts.save({ sessionId: scope, name }, { mimeType: "application/json", data: serialized });
|
|
1124
|
+
return {
|
|
1125
|
+
__artifact: {
|
|
1126
|
+
name,
|
|
1127
|
+
version,
|
|
1128
|
+
bytes: serialized.length,
|
|
1129
|
+
preview: serialized.slice(0, 300),
|
|
1130
|
+
note: "Result externalized due to size. Use read_artifact(name) to read the full content.",
|
|
1131
|
+
},
|
|
1132
|
+
};
|
|
1133
|
+
}
|
|
1134
|
+
createReadArtifactTool(scope) {
|
|
1135
|
+
return {
|
|
1136
|
+
name: "read_artifact",
|
|
1137
|
+
description: "Reads the full content of an externalized result (__artifact reference).",
|
|
1138
|
+
schema: zod.z.object({
|
|
1139
|
+
name: zod.z.string().describe("Artifact name (the __artifact.name field)."),
|
|
1140
|
+
version: zod.z.number().optional(),
|
|
1141
|
+
}),
|
|
1142
|
+
execute: async (input) => {
|
|
1143
|
+
const { name, version } = input;
|
|
1144
|
+
const part = await this.artifacts.load({ sessionId: scope, name }, version);
|
|
1145
|
+
if (!part)
|
|
1146
|
+
return { error: `Artifact "${name}" not found.` };
|
|
1147
|
+
return { name, content: part.data };
|
|
1148
|
+
},
|
|
1149
|
+
};
|
|
1150
|
+
}
|
|
1151
|
+
createLoadSkillTool(definition) {
|
|
1152
|
+
return {
|
|
1153
|
+
name: "load_skill",
|
|
1154
|
+
description: "Loads the full content of a catalog skill by name.",
|
|
1155
|
+
schema: zod.z.object({ name: zod.z.string().describe("Skill name in the catalog.") }),
|
|
1156
|
+
execute: async (input) => {
|
|
1157
|
+
const name = input.name ?? "";
|
|
1158
|
+
const binding = definition.skills.find((skill) => skill.options.name === name);
|
|
1159
|
+
if (!binding) {
|
|
1160
|
+
const available = definition.skills.map((skill) => skill.options.name).join(", ");
|
|
1161
|
+
return { error: `Skill "${name}" does not exist. Available: ${available}` };
|
|
1162
|
+
}
|
|
1163
|
+
return { name, content: await skillContent(definition, binding) };
|
|
1164
|
+
},
|
|
1165
|
+
};
|
|
1166
|
+
}
|
|
1167
|
+
async persistAgentEvent(sessionId, event) {
|
|
1168
|
+
switch (event.type) {
|
|
1169
|
+
case "tool_call":
|
|
1170
|
+
return this.persist(sessionId, "agent", "tool_call", {
|
|
1171
|
+
callId: event.callId,
|
|
1172
|
+
tool: event.tool,
|
|
1173
|
+
args: event.args,
|
|
1174
|
+
});
|
|
1175
|
+
case "tool_result":
|
|
1176
|
+
return this.persist(sessionId, "tool", "tool_result", {
|
|
1177
|
+
callId: event.callId,
|
|
1178
|
+
tool: event.tool,
|
|
1179
|
+
result: event.result,
|
|
1180
|
+
});
|
|
1181
|
+
case "final":
|
|
1182
|
+
return this.persist(sessionId, "agent", "message", { text: event.text });
|
|
1183
|
+
default:
|
|
1184
|
+
return;
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
async persist(sessionId, author, type, data) {
|
|
1188
|
+
await this.store.appendEvent(sessionId, { v: 1, id: node_crypto.randomUUID(), at: Date.now(), author, type, data });
|
|
1189
|
+
}
|
|
1190
|
+
};
|
|
1191
|
+
exports.AgentRunner = __decorate([
|
|
1192
|
+
common.Injectable(),
|
|
1193
|
+
__param(4, common.Inject(ADK_OPTIONS)),
|
|
1194
|
+
__param(5, common.Optional()),
|
|
1195
|
+
__metadata("design:paramtypes", [AdkEngine,
|
|
1196
|
+
exports.AgentRegistry,
|
|
1197
|
+
SessionStore,
|
|
1198
|
+
ArtifactStore, Object, ToolsetResolver])
|
|
1199
|
+
], exports.AgentRunner);
|
|
1200
|
+
function tryParseJson(text) {
|
|
1201
|
+
try {
|
|
1202
|
+
return JSON.parse(text);
|
|
1203
|
+
}
|
|
1204
|
+
catch {
|
|
1205
|
+
const match = text.match(/\{[\s\S]*\}/);
|
|
1206
|
+
if (!match)
|
|
1207
|
+
return text;
|
|
1208
|
+
try {
|
|
1209
|
+
return JSON.parse(match[0]);
|
|
1210
|
+
}
|
|
1211
|
+
catch {
|
|
1212
|
+
return text;
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
var AdkModule_1;
|
|
1218
|
+
async function resolveStore(moduleRef, cls) {
|
|
1219
|
+
try {
|
|
1220
|
+
return moduleRef.get(cls, { strict: false });
|
|
1221
|
+
}
|
|
1222
|
+
catch {
|
|
1223
|
+
return moduleRef.create(cls);
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
exports.AdkModule = AdkModule_1 = class AdkModule {
|
|
1227
|
+
static forRoot(options) {
|
|
1228
|
+
return AdkModule_1.assemble(options.engine, [{ provide: ADK_OPTIONS, useValue: options }]);
|
|
1229
|
+
}
|
|
1230
|
+
static forRootAsync(options) {
|
|
1231
|
+
const optionsProvider = {
|
|
1232
|
+
provide: ADK_OPTIONS,
|
|
1233
|
+
useFactory: async (...args) => ({ ...(await options.useFactory(...args)), engine: options.engine }),
|
|
1234
|
+
inject: options.inject ?? [],
|
|
1235
|
+
};
|
|
1236
|
+
return AdkModule_1.assemble(options.engine, [optionsProvider], options.imports);
|
|
1237
|
+
}
|
|
1238
|
+
static assemble(engine, optionsProviders, imports = []) {
|
|
1239
|
+
const storeProviders = [
|
|
1240
|
+
{
|
|
1241
|
+
provide: SessionStore,
|
|
1242
|
+
useFactory: (options, moduleRef) => resolveStore(moduleRef, options.session ?? exports.InMemorySessionStore),
|
|
1243
|
+
inject: [ADK_OPTIONS, core.ModuleRef],
|
|
1244
|
+
},
|
|
1245
|
+
{
|
|
1246
|
+
provide: ArtifactStore,
|
|
1247
|
+
useFactory: (options, moduleRef) => resolveStore(moduleRef, options.artifacts ?? exports.InMemoryArtifactStore),
|
|
1248
|
+
inject: [ADK_OPTIONS, core.ModuleRef],
|
|
1249
|
+
},
|
|
1250
|
+
{
|
|
1251
|
+
provide: Embedder,
|
|
1252
|
+
useFactory: async (options, moduleRef) => {
|
|
1253
|
+
const instance = options.embedder ? await resolveStore(moduleRef, options.embedder) : undefined;
|
|
1254
|
+
Embedder.setActive(instance);
|
|
1255
|
+
return instance;
|
|
1256
|
+
},
|
|
1257
|
+
inject: [ADK_OPTIONS, core.ModuleRef],
|
|
1258
|
+
},
|
|
1259
|
+
];
|
|
1260
|
+
return {
|
|
1261
|
+
module: AdkModule_1,
|
|
1262
|
+
global: true,
|
|
1263
|
+
imports: [core.DiscoveryModule, ...(imports ?? [])],
|
|
1264
|
+
providers: [
|
|
1265
|
+
...optionsProviders,
|
|
1266
|
+
{ provide: AdkEngine, useClass: engine },
|
|
1267
|
+
...storeProviders,
|
|
1268
|
+
exports.Similarity,
|
|
1269
|
+
exports.AgentRegistry,
|
|
1270
|
+
exports.AgentRunner,
|
|
1271
|
+
{ provide: ADK_RUNNER, useExisting: exports.AgentRunner },
|
|
1272
|
+
exports.AgentSessions,
|
|
1273
|
+
],
|
|
1274
|
+
exports: [
|
|
1275
|
+
ADK_OPTIONS,
|
|
1276
|
+
AdkEngine,
|
|
1277
|
+
SessionStore,
|
|
1278
|
+
ArtifactStore,
|
|
1279
|
+
Embedder,
|
|
1280
|
+
exports.Similarity,
|
|
1281
|
+
exports.AgentRegistry,
|
|
1282
|
+
exports.AgentRunner,
|
|
1283
|
+
ADK_RUNNER,
|
|
1284
|
+
exports.AgentSessions,
|
|
1285
|
+
],
|
|
1286
|
+
};
|
|
1287
|
+
}
|
|
1288
|
+
};
|
|
1289
|
+
exports.AdkModule = AdkModule_1 = __decorate([
|
|
1290
|
+
common.Module({})
|
|
1291
|
+
], exports.AdkModule);
|
|
1292
|
+
|
|
1293
|
+
class Gemini {
|
|
1294
|
+
constructor(model, options = {}) {
|
|
1295
|
+
this.model = model;
|
|
1296
|
+
this.__adkModelSpec = "gemini";
|
|
1297
|
+
Object.assign(this, options);
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
class OpenAiLike {
|
|
1301
|
+
constructor(model, options = {}) {
|
|
1302
|
+
this.model = model;
|
|
1303
|
+
this.__adkModelSpec = "openai-like";
|
|
1304
|
+
Object.assign(this, options);
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
class ModelRouter {
|
|
1308
|
+
constructor(options) {
|
|
1309
|
+
this.__adkModelSpec = "router";
|
|
1310
|
+
this.targets = Array.isArray(options.targets)
|
|
1311
|
+
? Object.fromEntries(options.targets.map((target, index) => [`target_${index}`, target]))
|
|
1312
|
+
: options.targets;
|
|
1313
|
+
this.strategy = options.strategy ?? "failover";
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
function isModelSpec(model) {
|
|
1317
|
+
return typeof model === "object" && model !== null && "__adkModelSpec" in model;
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
function callTool(tool, args) {
|
|
1321
|
+
return { kind: "tool_call", tool, args };
|
|
1322
|
+
}
|
|
1323
|
+
function fail(message) {
|
|
1324
|
+
return { kind: "fail", message };
|
|
1325
|
+
}
|
|
1326
|
+
function text(value, usage) {
|
|
1327
|
+
return {
|
|
1328
|
+
kind: "text",
|
|
1329
|
+
text: value,
|
|
1330
|
+
usage: {
|
|
1331
|
+
promptTokens: usage?.promptTokens ?? 10,
|
|
1332
|
+
outputTokens: usage?.outputTokens ?? 5,
|
|
1333
|
+
totalTokens: usage?.totalTokens ?? 15,
|
|
1334
|
+
},
|
|
1335
|
+
};
|
|
1336
|
+
}
|
|
1337
|
+
exports.ScriptedEngine = class ScriptedEngine extends AdkEngine {
|
|
1338
|
+
constructor() {
|
|
1339
|
+
super(...arguments);
|
|
1340
|
+
this.scripts = [];
|
|
1341
|
+
this.draft = [];
|
|
1342
|
+
}
|
|
1343
|
+
enqueue(turns) {
|
|
1344
|
+
this.scripts.push(turns);
|
|
1345
|
+
}
|
|
1346
|
+
push(turn) {
|
|
1347
|
+
this.draft.push(turn);
|
|
1348
|
+
}
|
|
1349
|
+
async *run(agent, input) {
|
|
1350
|
+
this.lastAgent = agent;
|
|
1351
|
+
this.lastInput = input;
|
|
1352
|
+
const turns = this.draft.length > 0 ? this.draft.splice(0) : (this.scripts.shift() ?? [text("")]);
|
|
1353
|
+
yield { type: "run_start", agent: agent.name, sessionId: input.sessionId };
|
|
1354
|
+
const total = { promptTokens: 0, outputTokens: 0, totalTokens: 0 };
|
|
1355
|
+
let finalText = "";
|
|
1356
|
+
for (const turn of turns) {
|
|
1357
|
+
if (turn.kind === "fail")
|
|
1358
|
+
throw new Error(turn.message);
|
|
1359
|
+
if (turn.kind === "tool_call") {
|
|
1360
|
+
const tool = agent.tools.find((candidate) => candidate.name === turn.tool);
|
|
1361
|
+
if (!tool)
|
|
1362
|
+
throw new Error(`ScriptedEngine: tool "${turn.tool}" not found on agent "${agent.name}".`);
|
|
1363
|
+
const callId = node_crypto.randomUUID();
|
|
1364
|
+
yield { type: "tool_call", agent: agent.name, callId, tool: turn.tool, args: turn.args };
|
|
1365
|
+
const result = await tool.execute(turn.args);
|
|
1366
|
+
yield { type: "tool_result", agent: agent.name, callId, tool: turn.tool, result };
|
|
1367
|
+
continue;
|
|
1368
|
+
}
|
|
1369
|
+
total.promptTokens += turn.usage.promptTokens;
|
|
1370
|
+
total.outputTokens += turn.usage.outputTokens;
|
|
1371
|
+
total.totalTokens += turn.usage.totalTokens;
|
|
1372
|
+
finalText = turn.text;
|
|
1373
|
+
yield { type: "llm_response", agent: agent.name, text: turn.text, usage: turn.usage };
|
|
1374
|
+
}
|
|
1375
|
+
yield { type: "final", agent: agent.name, text: finalText, usage: total };
|
|
1376
|
+
}
|
|
1377
|
+
};
|
|
1378
|
+
exports.ScriptedEngine = __decorate([
|
|
1379
|
+
common.Injectable()
|
|
1380
|
+
], exports.ScriptedEngine);
|
|
1381
|
+
|
|
1382
|
+
class ScriptedModel {
|
|
1383
|
+
constructor(...scripts) {
|
|
1384
|
+
this.__adkScriptedModel = true;
|
|
1385
|
+
this.scripts = [...scripts];
|
|
1386
|
+
}
|
|
1387
|
+
enqueue(turns) {
|
|
1388
|
+
this.scripts.push(turns);
|
|
1389
|
+
return this;
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
function isScriptedModel(model) {
|
|
1393
|
+
return typeof model === "object" && model !== null && "__adkScriptedModel" in model;
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
exports.ADK_OPTIONS = ADK_OPTIONS;
|
|
1397
|
+
exports.AdkAgent = AdkAgent;
|
|
1398
|
+
exports.AdkBootError = AdkBootError;
|
|
1399
|
+
exports.AdkEngine = AdkEngine;
|
|
1400
|
+
exports.AdkError = AdkError;
|
|
1401
|
+
exports.AdkPrompt = AdkPrompt;
|
|
1402
|
+
exports.AdkSkill = AdkSkill;
|
|
1403
|
+
exports.AdkTool = AdkTool;
|
|
1404
|
+
exports.AdkWorkflow = AdkWorkflow;
|
|
1405
|
+
exports.Agent = Agent;
|
|
1406
|
+
exports.AgentDefinition = AgentDefinition;
|
|
1407
|
+
exports.AgentNotFoundError = AgentNotFoundError;
|
|
1408
|
+
exports.AgentRef = AgentRef;
|
|
1409
|
+
exports.AiEmptyResponseError = AiEmptyResponseError;
|
|
1410
|
+
exports.ApprovalNotFoundError = ApprovalNotFoundError;
|
|
1411
|
+
exports.ArtifactStore = ArtifactStore;
|
|
1412
|
+
exports.ConflictingPromptError = ConflictingPromptError;
|
|
1413
|
+
exports.DEFAULT_OFFLOAD_THRESHOLD = DEFAULT_OFFLOAD_THRESHOLD;
|
|
1414
|
+
exports.DeltaStateBag = DeltaStateBag;
|
|
1415
|
+
exports.DuplicateAgentNameError = DuplicateAgentNameError;
|
|
1416
|
+
exports.Embedder = Embedder;
|
|
1417
|
+
exports.EmbedderNotConfiguredError = EmbedderNotConfiguredError;
|
|
1418
|
+
exports.Gemini = Gemini;
|
|
1419
|
+
exports.InvalidWorkflowError = InvalidWorkflowError;
|
|
1420
|
+
exports.McpConnectionError = McpConnectionError;
|
|
1421
|
+
exports.MemoryStore = MemoryStore;
|
|
1422
|
+
exports.MissingModelError = MissingModelError;
|
|
1423
|
+
exports.ModelRouter = ModelRouter;
|
|
1424
|
+
exports.ModelsExhaustedError = ModelsExhaustedError;
|
|
1425
|
+
exports.OpenAiLike = OpenAiLike;
|
|
1426
|
+
exports.OutputValidationError = OutputValidationError;
|
|
1427
|
+
exports.ReservedMethodError = ReservedMethodError;
|
|
1428
|
+
exports.RunLogger = RunLogger;
|
|
1429
|
+
exports.ScriptedModel = ScriptedModel;
|
|
1430
|
+
exports.SessionNotFoundError = SessionNotFoundError;
|
|
1431
|
+
exports.SessionStore = SessionStore;
|
|
1432
|
+
exports.Skill = Skill;
|
|
1433
|
+
exports.SkillNotFoundError = SkillNotFoundError;
|
|
1434
|
+
exports.Tool = Tool;
|
|
1435
|
+
exports.ToolExecutionError = ToolExecutionError;
|
|
1436
|
+
exports.ToolsetResolver = ToolsetResolver;
|
|
1437
|
+
exports.UnregisteredPromptError = UnregisteredPromptError;
|
|
1438
|
+
exports.UnregisteredSkillError = UnregisteredSkillError;
|
|
1439
|
+
exports.UnregisteredSubAgentError = UnregisteredSubAgentError;
|
|
1440
|
+
exports.UnregisteredToolError = UnregisteredToolError;
|
|
1441
|
+
exports.UnresolvedToolsetError = UnresolvedToolsetError;
|
|
1442
|
+
exports.WorkflowAgent = WorkflowAgent;
|
|
1443
|
+
exports.buildInstruction = buildInstruction;
|
|
1444
|
+
exports.callTool = callTool;
|
|
1445
|
+
exports.contextPolicy = contextPolicy;
|
|
1446
|
+
exports.fail = fail;
|
|
1447
|
+
exports.isModelSpec = isModelSpec;
|
|
1448
|
+
exports.isScriptedModel = isScriptedModel;
|
|
1449
|
+
exports.isToolsetRef = isToolsetRef;
|
|
1450
|
+
exports.skillContent = skillContent;
|
|
1451
|
+
exports.text = text;
|
|
1452
|
+
exports.toolset = toolset;
|