@iqai/adk-cli 0.1.1 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +45 -0
- package/dist/index.js +342 -232
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +343 -233
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -31,7 +31,7 @@ var import_commander = require("commander");
|
|
|
31
31
|
// package.json
|
|
32
32
|
var package_default = {
|
|
33
33
|
name: "@iqai/adk-cli",
|
|
34
|
-
version: "0.
|
|
34
|
+
version: "0.2.1",
|
|
35
35
|
description: "CLI tool for creating, running, and testing ADK agents",
|
|
36
36
|
main: "dist/index.js",
|
|
37
37
|
types: "dist/index.d.ts",
|
|
@@ -166,21 +166,7 @@ async function detectAvailablePackageManagers() {
|
|
|
166
166
|
}
|
|
167
167
|
async function createProject(projectName, options) {
|
|
168
168
|
console.clear();
|
|
169
|
-
|
|
170
|
-
import_chalk.default.magentaBright(import_dedent.default`
|
|
171
|
-
╔══════════════════════════════════════════════════════╗
|
|
172
|
-
║ ║
|
|
173
|
-
║ █████╗ ██████╗ ██╗ ██╗ ████████╗███████╗ ║
|
|
174
|
-
║ ██╔══██╗██╔══██╗██║ ██╔╝ ╚══██╔══╝██╔════╝ ║
|
|
175
|
-
║ ███████║██║ ██║█████╔╝ ██║ ███████╗ ║
|
|
176
|
-
║ ██╔══██║██║ ██║██╔═██╗ ██║ ╚════██║ ║
|
|
177
|
-
║ ██║ ██║██████╔╝██║ ██╗ ██║ ███████║ ║
|
|
178
|
-
║ ╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝ ║
|
|
179
|
-
║ ║
|
|
180
|
-
╚══════════════════════════════════════════════════════╝
|
|
181
|
-
`)
|
|
182
|
-
);
|
|
183
|
-
(0, import_prompts.intro)(import_chalk.default.bgMagenta.bold(" \u2728 Let's build something amazing! "));
|
|
169
|
+
(0, import_prompts.intro)(import_chalk.default.magentaBright("\u{1F9E0} Create new ADK-TS project"));
|
|
184
170
|
let finalProjectName = projectName;
|
|
185
171
|
if (!finalProjectName) {
|
|
186
172
|
const response = await (0, import_prompts.text)({
|
|
@@ -328,95 +314,70 @@ var import_node_fs3 = require("fs");
|
|
|
328
314
|
var import_node_path3 = require("path");
|
|
329
315
|
var import_chalk2 = __toESM(require("chalk"));
|
|
330
316
|
|
|
331
|
-
// src/server.ts
|
|
317
|
+
// src/server/index.ts
|
|
318
|
+
var import_node_server = require("@hono/node-server");
|
|
319
|
+
var import_adk2 = require("@iqai/adk");
|
|
320
|
+
var import_hono = require("hono");
|
|
321
|
+
|
|
322
|
+
// src/server/routes.ts
|
|
323
|
+
var import_cors = require("hono/cors");
|
|
324
|
+
function setupRoutes(app, agentManager, sessionManager, agentsDir) {
|
|
325
|
+
app.use("/*", (0, import_cors.cors)());
|
|
326
|
+
app.get("/health", (c) => c.json({ status: "ok" }));
|
|
327
|
+
app.get("/api/agents", (c) => {
|
|
328
|
+
const agentsList = Array.from(
|
|
329
|
+
agentManager.getAgents().values()
|
|
330
|
+
).map((agent) => ({
|
|
331
|
+
path: agent.absolutePath,
|
|
332
|
+
name: agent.name,
|
|
333
|
+
directory: agent.absolutePath,
|
|
334
|
+
relativePath: agent.relativePath
|
|
335
|
+
}));
|
|
336
|
+
return c.json({ agents: agentsList });
|
|
337
|
+
});
|
|
338
|
+
app.post("/api/agents/refresh", (c) => {
|
|
339
|
+
agentManager.scanAgents(agentsDir);
|
|
340
|
+
const agentsList = Array.from(
|
|
341
|
+
agentManager.getAgents().values()
|
|
342
|
+
).map((agent) => ({
|
|
343
|
+
path: agent.absolutePath,
|
|
344
|
+
name: agent.name,
|
|
345
|
+
directory: agent.absolutePath,
|
|
346
|
+
relativePath: agent.relativePath
|
|
347
|
+
}));
|
|
348
|
+
return c.json({ agents: agentsList });
|
|
349
|
+
});
|
|
350
|
+
app.get("/api/agents/:id/messages", async (c) => {
|
|
351
|
+
const agentPath = decodeURIComponent(c.req.param("id"));
|
|
352
|
+
const loadedAgent = agentManager.getLoadedAgents().get(agentPath);
|
|
353
|
+
if (!loadedAgent) {
|
|
354
|
+
return c.json({ messages: [] });
|
|
355
|
+
}
|
|
356
|
+
const messages = await sessionManager.getSessionMessages(loadedAgent);
|
|
357
|
+
const response = { messages };
|
|
358
|
+
return c.json(response);
|
|
359
|
+
});
|
|
360
|
+
app.post("/api/agents/:id/message", async (c) => {
|
|
361
|
+
const agentPath = decodeURIComponent(c.req.param("id"));
|
|
362
|
+
const { message } = await c.req.json();
|
|
363
|
+
const response = await agentManager.sendMessageToAgent(agentPath, message);
|
|
364
|
+
const messageResponse = { response };
|
|
365
|
+
return c.json(messageResponse);
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// src/server/services.ts
|
|
332
370
|
var import_node_fs2 = require("fs");
|
|
333
371
|
var import_node_path2 = require("path");
|
|
334
372
|
var import_node_url = require("url");
|
|
335
|
-
var import_node_server = require("@hono/node-server");
|
|
336
373
|
var import_adk = require("@iqai/adk");
|
|
337
|
-
var
|
|
338
|
-
|
|
339
|
-
var ADKServer = class {
|
|
340
|
-
agents = /* @__PURE__ */ new Map();
|
|
341
|
-
loadedAgents = /* @__PURE__ */ new Map();
|
|
342
|
-
sessionService;
|
|
343
|
-
app;
|
|
344
|
-
server;
|
|
345
|
-
agentsDir;
|
|
346
|
-
port;
|
|
347
|
-
host;
|
|
348
|
-
quiet;
|
|
349
|
-
constructor(agentsDir, port = 8042, host = "localhost", quiet = false) {
|
|
350
|
-
this.agentsDir = agentsDir;
|
|
351
|
-
this.port = port;
|
|
352
|
-
this.host = host;
|
|
374
|
+
var AgentScanner = class {
|
|
375
|
+
constructor(quiet = false) {
|
|
353
376
|
this.quiet = quiet;
|
|
354
|
-
this.sessionService = new import_adk.InMemorySessionService();
|
|
355
|
-
this.app = new import_hono.Hono();
|
|
356
|
-
this.setupRoutes();
|
|
357
|
-
this.scanAgents();
|
|
358
377
|
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
this.app.get("/api/agents", (c) => {
|
|
363
|
-
const agentsList = Array.from(this.agents.values()).map((agent) => ({
|
|
364
|
-
path: agent.absolutePath,
|
|
365
|
-
name: agent.name,
|
|
366
|
-
directory: agent.absolutePath,
|
|
367
|
-
relativePath: agent.relativePath
|
|
368
|
-
}));
|
|
369
|
-
return c.json({ agents: agentsList });
|
|
370
|
-
});
|
|
371
|
-
this.app.post("/api/agents/refresh", (c) => {
|
|
372
|
-
this.scanAgents();
|
|
373
|
-
const agentsList = Array.from(this.agents.values()).map((agent) => ({
|
|
374
|
-
path: agent.absolutePath,
|
|
375
|
-
name: agent.name,
|
|
376
|
-
directory: agent.absolutePath,
|
|
377
|
-
relativePath: agent.relativePath
|
|
378
|
-
}));
|
|
379
|
-
return c.json({ agents: agentsList });
|
|
380
|
-
});
|
|
381
|
-
this.app.get("/api/agents/:id/messages", async (c) => {
|
|
382
|
-
const agentPath = decodeURIComponent(c.req.param("id"));
|
|
383
|
-
const loadedAgent = this.loadedAgents.get(agentPath);
|
|
384
|
-
if (!loadedAgent) {
|
|
385
|
-
return c.json({ messages: [] });
|
|
386
|
-
}
|
|
387
|
-
try {
|
|
388
|
-
const session = await this.sessionService.getSession(
|
|
389
|
-
loadedAgent.appName,
|
|
390
|
-
loadedAgent.userId,
|
|
391
|
-
loadedAgent.sessionId
|
|
392
|
-
);
|
|
393
|
-
if (!session || !session.events) {
|
|
394
|
-
return c.json({ messages: [] });
|
|
395
|
-
}
|
|
396
|
-
const messages = session.events.map((event, index) => ({
|
|
397
|
-
id: index + 1,
|
|
398
|
-
type: event.author === "user" ? "user" : "assistant",
|
|
399
|
-
content: event.content?.parts?.map(
|
|
400
|
-
(part) => typeof part === "object" && "text" in part ? part.text : ""
|
|
401
|
-
).join("") || "",
|
|
402
|
-
timestamp: new Date(event.timestamp || Date.now()).toISOString()
|
|
403
|
-
}));
|
|
404
|
-
return c.json({ messages });
|
|
405
|
-
} catch (error) {
|
|
406
|
-
console.error("Error fetching messages:", error);
|
|
407
|
-
return c.json({ messages: [] });
|
|
408
|
-
}
|
|
409
|
-
});
|
|
410
|
-
this.app.post("/api/agents/:id/message", async (c) => {
|
|
411
|
-
const agentPath = decodeURIComponent(c.req.param("id"));
|
|
412
|
-
const { message } = await c.req.json();
|
|
413
|
-
const response = await this.sendMessageToAgent(agentPath, message);
|
|
414
|
-
return c.json({ response });
|
|
415
|
-
});
|
|
416
|
-
}
|
|
417
|
-
scanAgents() {
|
|
418
|
-
this.agents.clear();
|
|
419
|
-
const scanDir = !this.agentsDir || !(0, import_node_fs2.existsSync)(this.agentsDir) ? process.cwd() : this.agentsDir;
|
|
378
|
+
scanAgents(agentsDir, loadedAgents) {
|
|
379
|
+
const agents = /* @__PURE__ */ new Map();
|
|
380
|
+
const scanDir = !agentsDir || !(0, import_node_fs2.existsSync)(agentsDir) ? process.cwd() : agentsDir;
|
|
420
381
|
const shouldSkipDirectory = (dirName) => {
|
|
421
382
|
const skipDirs = [
|
|
422
383
|
"node_modules",
|
|
@@ -443,7 +404,7 @@ var ADKServer = class {
|
|
|
443
404
|
}
|
|
444
405
|
} else if (item === "agent.ts" || item === "agent.js") {
|
|
445
406
|
const relativePath = (0, import_node_path2.relative)(scanDir, dir);
|
|
446
|
-
const loadedAgent =
|
|
407
|
+
const loadedAgent = loadedAgents.get(relativePath);
|
|
447
408
|
let agentName = relativePath.split("/").pop() || "unknown";
|
|
448
409
|
if (loadedAgent?.agent?.name) {
|
|
449
410
|
agentName = loadedAgent.agent.name;
|
|
@@ -454,7 +415,7 @@ var ADKServer = class {
|
|
|
454
415
|
} catch {
|
|
455
416
|
}
|
|
456
417
|
}
|
|
457
|
-
|
|
418
|
+
agents.set(relativePath, {
|
|
458
419
|
relativePath,
|
|
459
420
|
name: agentName,
|
|
460
421
|
absolutePath: dir,
|
|
@@ -465,9 +426,225 @@ var ADKServer = class {
|
|
|
465
426
|
};
|
|
466
427
|
scanDirectory(scanDir);
|
|
467
428
|
if (!this.quiet) {
|
|
468
|
-
console.log(`\u2705 Agent scan complete. Found ${
|
|
429
|
+
console.log(`\u2705 Agent scan complete. Found ${agents.size} agents.`);
|
|
430
|
+
}
|
|
431
|
+
return agents;
|
|
432
|
+
}
|
|
433
|
+
extractAgentNameFromFile(filePath) {
|
|
434
|
+
try {
|
|
435
|
+
const content = (0, import_node_fs2.readFileSync)(filePath, "utf-8");
|
|
436
|
+
const nameMatch = content.match(/name\s*:\s*["']([^"']+)["']/);
|
|
437
|
+
if (nameMatch?.[1]) {
|
|
438
|
+
return nameMatch[1];
|
|
439
|
+
}
|
|
440
|
+
return null;
|
|
441
|
+
} catch {
|
|
442
|
+
return null;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
};
|
|
446
|
+
var AgentLoader = class {
|
|
447
|
+
constructor(quiet = false) {
|
|
448
|
+
this.quiet = quiet;
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Import a TypeScript file by compiling it on-demand
|
|
452
|
+
*/
|
|
453
|
+
async importTypeScriptFile(filePath) {
|
|
454
|
+
const startDir = (0, import_node_path2.dirname)(filePath);
|
|
455
|
+
let projectRoot = startDir;
|
|
456
|
+
while (projectRoot !== "/" && projectRoot !== (0, import_node_path2.dirname)(projectRoot)) {
|
|
457
|
+
if ((0, import_node_fs2.existsSync)((0, import_node_path2.join)(projectRoot, "package.json")) || (0, import_node_fs2.existsSync)((0, import_node_path2.join)(projectRoot, ".env"))) {
|
|
458
|
+
break;
|
|
459
|
+
}
|
|
460
|
+
projectRoot = (0, import_node_path2.dirname)(projectRoot);
|
|
461
|
+
}
|
|
462
|
+
if (projectRoot === "/") {
|
|
463
|
+
projectRoot = startDir;
|
|
464
|
+
}
|
|
465
|
+
try {
|
|
466
|
+
const { build } = await import("esbuild");
|
|
467
|
+
const cacheDir = (0, import_node_path2.join)(projectRoot, ".adk-cache");
|
|
468
|
+
if (!(0, import_node_fs2.existsSync)(cacheDir)) {
|
|
469
|
+
(0, import_node_fs2.mkdirSync)(cacheDir, { recursive: true });
|
|
470
|
+
}
|
|
471
|
+
const outFile = (0, import_node_path2.join)(cacheDir, `agent-${Date.now()}.mjs`);
|
|
472
|
+
const plugin = {
|
|
473
|
+
name: "externalize-bare-imports",
|
|
474
|
+
setup(build2) {
|
|
475
|
+
build2.onResolve({ filter: /.*/ }, (args) => {
|
|
476
|
+
if (args.path.startsWith(".") || args.path.startsWith("/") || args.path.startsWith("..")) {
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
return { path: args.path, external: true };
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
const tsconfigPath = (0, import_node_path2.join)(projectRoot, "tsconfig.json");
|
|
484
|
+
await build({
|
|
485
|
+
entryPoints: [filePath],
|
|
486
|
+
outfile: outFile,
|
|
487
|
+
bundle: true,
|
|
488
|
+
format: "esm",
|
|
489
|
+
platform: "node",
|
|
490
|
+
target: ["node22"],
|
|
491
|
+
sourcemap: false,
|
|
492
|
+
logLevel: "silent",
|
|
493
|
+
plugins: [plugin],
|
|
494
|
+
absWorkingDir: projectRoot,
|
|
495
|
+
// Use tsconfig if present for path aliases
|
|
496
|
+
...(0, import_node_fs2.existsSync)(tsconfigPath) ? { tsconfig: tsconfigPath } : {}
|
|
497
|
+
});
|
|
498
|
+
const mod = await import(`${(0, import_node_url.pathToFileURL)(outFile).href}?t=${Date.now()}`);
|
|
499
|
+
let agentExport = mod?.agent;
|
|
500
|
+
if (!agentExport && mod?.default) {
|
|
501
|
+
agentExport = mod.default.agent ?? mod.default;
|
|
502
|
+
}
|
|
503
|
+
try {
|
|
504
|
+
(0, import_node_fs2.unlinkSync)(outFile);
|
|
505
|
+
} catch {
|
|
506
|
+
}
|
|
507
|
+
if (agentExport) {
|
|
508
|
+
const isPrimitive = (v) => v == null || ["string", "number", "boolean"].includes(typeof v);
|
|
509
|
+
if (isPrimitive(agentExport)) {
|
|
510
|
+
if (!this.quiet) {
|
|
511
|
+
console.log(
|
|
512
|
+
`\u2139\uFE0F Ignoring primitive 'agent' export in ${filePath}; scanning module for factory...`
|
|
513
|
+
);
|
|
514
|
+
}
|
|
515
|
+
} else {
|
|
516
|
+
if (!this.quiet) {
|
|
517
|
+
console.log(`\u2705 TS agent imported via esbuild: ${filePath}`);
|
|
518
|
+
}
|
|
519
|
+
return { agent: agentExport };
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
return mod;
|
|
523
|
+
} catch (e) {
|
|
524
|
+
throw new Error(
|
|
525
|
+
`Failed to import TS agent via esbuild: ${e instanceof Error ? e.message : String(e)}`
|
|
526
|
+
);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
loadEnvironmentVariables(agentFilePath) {
|
|
530
|
+
let projectRoot = (0, import_node_path2.dirname)(agentFilePath);
|
|
531
|
+
while (projectRoot !== "/" && projectRoot !== (0, import_node_path2.dirname)(projectRoot)) {
|
|
532
|
+
if ((0, import_node_fs2.existsSync)((0, import_node_path2.join)(projectRoot, "package.json")) || (0, import_node_fs2.existsSync)((0, import_node_path2.join)(projectRoot, ".env"))) {
|
|
533
|
+
break;
|
|
534
|
+
}
|
|
535
|
+
projectRoot = (0, import_node_path2.dirname)(projectRoot);
|
|
536
|
+
}
|
|
537
|
+
const envPath = (0, import_node_path2.join)(projectRoot, ".env");
|
|
538
|
+
if ((0, import_node_fs2.existsSync)(envPath)) {
|
|
539
|
+
try {
|
|
540
|
+
const envContent = (0, import_node_fs2.readFileSync)(envPath, "utf8");
|
|
541
|
+
const envLines = envContent.split("\n");
|
|
542
|
+
for (const line of envLines) {
|
|
543
|
+
const trimmedLine = line.trim();
|
|
544
|
+
if (trimmedLine && !trimmedLine.startsWith("#")) {
|
|
545
|
+
const [key, ...valueParts] = trimmedLine.split("=");
|
|
546
|
+
if (key && valueParts.length > 0) {
|
|
547
|
+
const value = valueParts.join("=").replace(/^"(.*)"$/, "$1");
|
|
548
|
+
process.env[key.trim()] = value.trim();
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
} catch (error) {
|
|
553
|
+
console.warn(
|
|
554
|
+
`\u26A0\uFE0F Warning: Could not load .env file: ${error instanceof Error ? error.message : String(error)}`
|
|
555
|
+
);
|
|
556
|
+
}
|
|
469
557
|
}
|
|
470
558
|
}
|
|
559
|
+
// Minimal resolution logic for agent exports: supports
|
|
560
|
+
// 1) export const agent = new LlmAgent(...)
|
|
561
|
+
// 2) export function agent() { return new LlmAgent(...) }
|
|
562
|
+
// 3) export async function agent() { return new LlmAgent(...) }
|
|
563
|
+
// 4) default export (object or function) returning or containing .agent
|
|
564
|
+
async resolveAgentExport(mod) {
|
|
565
|
+
let candidate = mod?.agent ?? mod?.default?.agent ?? mod?.default ?? mod;
|
|
566
|
+
const isLikelyAgentInstance = (obj) => obj && typeof obj === "object" && typeof obj.name === "string";
|
|
567
|
+
const isPrimitive = (v) => v == null || ["string", "number", "boolean"].includes(typeof v);
|
|
568
|
+
const invokeMaybe = async (fn) => {
|
|
569
|
+
let out = fn();
|
|
570
|
+
if (out && typeof out === "object" && "then" in out) {
|
|
571
|
+
out = await out;
|
|
572
|
+
}
|
|
573
|
+
return out;
|
|
574
|
+
};
|
|
575
|
+
if (!isLikelyAgentInstance(candidate) && isPrimitive(candidate) || !isLikelyAgentInstance(candidate) && candidate && candidate === mod) {
|
|
576
|
+
candidate = mod;
|
|
577
|
+
for (const [key, value] of Object.entries(mod)) {
|
|
578
|
+
if (key === "default") continue;
|
|
579
|
+
const keyLower = key.toLowerCase();
|
|
580
|
+
if (isPrimitive(value)) continue;
|
|
581
|
+
if (isLikelyAgentInstance(value)) {
|
|
582
|
+
candidate = value;
|
|
583
|
+
break;
|
|
584
|
+
}
|
|
585
|
+
if (value && typeof value === "object" && value.agent && isLikelyAgentInstance(value.agent)) {
|
|
586
|
+
candidate = value.agent;
|
|
587
|
+
break;
|
|
588
|
+
}
|
|
589
|
+
if (typeof value === "function" && (/(agent|build|create)/i.test(keyLower) || value.name && /(agent|build|create)/i.test(value.name.toLowerCase()))) {
|
|
590
|
+
try {
|
|
591
|
+
const maybe = await invokeMaybe(value);
|
|
592
|
+
if (isLikelyAgentInstance(maybe)) {
|
|
593
|
+
candidate = maybe;
|
|
594
|
+
break;
|
|
595
|
+
}
|
|
596
|
+
if (maybe && typeof maybe === "object" && maybe.agent && isLikelyAgentInstance(maybe.agent)) {
|
|
597
|
+
candidate = maybe.agent;
|
|
598
|
+
break;
|
|
599
|
+
}
|
|
600
|
+
} catch (e) {
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
if (typeof candidate === "function") {
|
|
606
|
+
try {
|
|
607
|
+
candidate = await invokeMaybe(candidate);
|
|
608
|
+
} catch (e) {
|
|
609
|
+
throw new Error(
|
|
610
|
+
`Failed executing exported agent function: ${e instanceof Error ? e.message : String(e)}`
|
|
611
|
+
);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
if (candidate && typeof candidate === "object" && candidate.agent && isLikelyAgentInstance(candidate.agent)) {
|
|
615
|
+
candidate = candidate.agent;
|
|
616
|
+
}
|
|
617
|
+
if (candidate?.agent && isLikelyAgentInstance(candidate.agent)) {
|
|
618
|
+
candidate = candidate.agent;
|
|
619
|
+
}
|
|
620
|
+
if (!candidate || !isLikelyAgentInstance(candidate)) {
|
|
621
|
+
throw new Error(
|
|
622
|
+
"No agent export resolved (expected variable, function, or function returning an agent)"
|
|
623
|
+
);
|
|
624
|
+
}
|
|
625
|
+
return { agent: candidate };
|
|
626
|
+
}
|
|
627
|
+
};
|
|
628
|
+
var AgentManager = class {
|
|
629
|
+
constructor(sessionService, quiet = false) {
|
|
630
|
+
this.sessionService = sessionService;
|
|
631
|
+
this.quiet = quiet;
|
|
632
|
+
this.scanner = new AgentScanner(quiet);
|
|
633
|
+
this.loader = new AgentLoader(quiet);
|
|
634
|
+
}
|
|
635
|
+
agents = /* @__PURE__ */ new Map();
|
|
636
|
+
loadedAgents = /* @__PURE__ */ new Map();
|
|
637
|
+
scanner;
|
|
638
|
+
loader;
|
|
639
|
+
getAgents() {
|
|
640
|
+
return this.agents;
|
|
641
|
+
}
|
|
642
|
+
getLoadedAgents() {
|
|
643
|
+
return this.loadedAgents;
|
|
644
|
+
}
|
|
645
|
+
scanAgents(agentsDir) {
|
|
646
|
+
this.agents = this.scanner.scanAgents(agentsDir, this.loadedAgents);
|
|
647
|
+
}
|
|
471
648
|
async startAgent(agentPath) {
|
|
472
649
|
const agent = this.agents.get(agentPath);
|
|
473
650
|
if (!agent) {
|
|
@@ -486,70 +663,31 @@ var ADKServer = class {
|
|
|
486
663
|
`No agent.js or agent.ts file found in ${agent.absolutePath}`
|
|
487
664
|
);
|
|
488
665
|
}
|
|
489
|
-
|
|
490
|
-
while (projectRoot !== "/" && projectRoot !== (0, import_node_path2.dirname)(projectRoot)) {
|
|
491
|
-
if ((0, import_node_fs2.existsSync)((0, import_node_path2.join)(projectRoot, "package.json")) || (0, import_node_fs2.existsSync)((0, import_node_path2.join)(projectRoot, ".env"))) {
|
|
492
|
-
break;
|
|
493
|
-
}
|
|
494
|
-
projectRoot = (0, import_node_path2.dirname)(projectRoot);
|
|
495
|
-
}
|
|
496
|
-
const envPath = (0, import_node_path2.join)(projectRoot, ".env");
|
|
497
|
-
if ((0, import_node_fs2.existsSync)(envPath)) {
|
|
498
|
-
try {
|
|
499
|
-
const envContent = (0, import_node_fs2.readFileSync)(envPath, "utf8");
|
|
500
|
-
const envLines = envContent.split("\n");
|
|
501
|
-
for (const line of envLines) {
|
|
502
|
-
const trimmedLine = line.trim();
|
|
503
|
-
if (trimmedLine && !trimmedLine.startsWith("#")) {
|
|
504
|
-
const [key, ...valueParts] = trimmedLine.split("=");
|
|
505
|
-
if (key && valueParts.length > 0) {
|
|
506
|
-
const value = valueParts.join("=").replace(/^"(.*)"$/, "$1");
|
|
507
|
-
process.env[key.trim()] = value.trim();
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
} catch (error) {
|
|
512
|
-
console.warn(
|
|
513
|
-
`\u26A0\uFE0F Warning: Could not load .env file: ${error instanceof Error ? error.message : String(error)}`
|
|
514
|
-
);
|
|
515
|
-
}
|
|
516
|
-
}
|
|
666
|
+
this.loader.loadEnvironmentVariables(agentFilePath);
|
|
517
667
|
const agentFileUrl = (0, import_node_url.pathToFileURL)(agentFilePath).href;
|
|
518
|
-
const agentModule = agentFilePath.endsWith(".ts") ? await this.importTypeScriptFile(agentFilePath) : await import(agentFileUrl);
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
if (!agentModule.agent || typeof agentModule.agent !== "object" || !agentModule.agent.name) {
|
|
668
|
+
const agentModule = agentFilePath.endsWith(".ts") ? await this.loader.importTypeScriptFile(agentFilePath) : await import(agentFileUrl);
|
|
669
|
+
const resolved = await this.loader.resolveAgentExport(agentModule);
|
|
670
|
+
const exportedAgent = resolved.agent;
|
|
671
|
+
if (!exportedAgent?.name) {
|
|
523
672
|
throw new Error(
|
|
524
673
|
`Invalid agent export in ${agentFilePath}. Expected an LlmAgent instance with a name property.`
|
|
525
674
|
);
|
|
526
675
|
}
|
|
527
|
-
|
|
528
|
-
}
|
|
529
|
-
const agentBuilder = import_adk.AgentBuilder.create(agentModule.agent.name).withModel(agentModule.agent.model).withDescription(agentModule.agent.description || "").withInstruction(agentModule.agent.instruction || "").withSessionService(this.sessionService, {
|
|
676
|
+
const agentBuilder = import_adk.AgentBuilder.create(exportedAgent.name).withAgent(exportedAgent).withSessionService(this.sessionService, {
|
|
530
677
|
userId: `user_${agentPath}`,
|
|
531
678
|
appName: "adk-server"
|
|
532
679
|
});
|
|
533
|
-
if (agentModule.agent.tools && Array.isArray(agentModule.agent.tools) && agentModule.agent.tools.length > 0) {
|
|
534
|
-
agentBuilder.withTools(...agentModule.agent.tools);
|
|
535
|
-
if (!this.quiet) {
|
|
536
|
-
const toolNames = agentModule.agent.tools.map((t) => t?.name || "<unnamed>").join(", ");
|
|
537
|
-
console.log(
|
|
538
|
-
`\u{1F9E9} Registered tools for agent "${agentModule.agent.name}": [${toolNames}]`
|
|
539
|
-
);
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
680
|
const { runner, session } = await agentBuilder.build();
|
|
543
681
|
const loadedAgent = {
|
|
544
|
-
agent:
|
|
682
|
+
agent: exportedAgent,
|
|
545
683
|
runner,
|
|
546
684
|
sessionId: session.id,
|
|
547
685
|
userId: `user_${agentPath}`,
|
|
548
686
|
appName: "adk-server"
|
|
549
687
|
};
|
|
550
688
|
this.loadedAgents.set(agentPath, loadedAgent);
|
|
551
|
-
agent.instance =
|
|
552
|
-
agent.name =
|
|
689
|
+
agent.instance = exportedAgent;
|
|
690
|
+
agent.name = exportedAgent.name;
|
|
553
691
|
} catch (error) {
|
|
554
692
|
console.error(`\u274C Failed to load agent "${agent.name}":`, error);
|
|
555
693
|
throw new Error(
|
|
@@ -584,78 +722,65 @@ var ADKServer = class {
|
|
|
584
722
|
throw new Error(`Failed to send message to agent: ${errorMessage}`);
|
|
585
723
|
}
|
|
586
724
|
}
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
async importTypeScriptFile(filePath) {
|
|
591
|
-
let projectRoot = (0, import_node_path2.dirname)(filePath);
|
|
592
|
-
while (projectRoot !== "/" && projectRoot !== (0, import_node_path2.dirname)(projectRoot)) {
|
|
593
|
-
if ((0, import_node_fs2.existsSync)((0, import_node_path2.join)(projectRoot, "package.json")) || (0, import_node_fs2.existsSync)((0, import_node_path2.join)(projectRoot, ".env"))) {
|
|
594
|
-
break;
|
|
595
|
-
}
|
|
596
|
-
projectRoot = (0, import_node_path2.dirname)(projectRoot);
|
|
725
|
+
stopAllAgents() {
|
|
726
|
+
for (const [agentPath] of this.loadedAgents.entries()) {
|
|
727
|
+
this.stopAgent(agentPath);
|
|
597
728
|
}
|
|
729
|
+
}
|
|
730
|
+
};
|
|
731
|
+
var SessionManager = class {
|
|
732
|
+
constructor(sessionService) {
|
|
733
|
+
this.sessionService = sessionService;
|
|
734
|
+
}
|
|
735
|
+
async getSessionMessages(loadedAgent) {
|
|
598
736
|
try {
|
|
599
|
-
const
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
}
|
|
604
|
-
const outFile = (0, import_node_path2.join)(cacheDir, `agent-${Date.now()}.mjs`);
|
|
605
|
-
const plugin = {
|
|
606
|
-
name: "externalize-bare-imports",
|
|
607
|
-
setup(build2) {
|
|
608
|
-
build2.onResolve({ filter: /.*/ }, (args) => {
|
|
609
|
-
if (args.path.startsWith(".") || args.path.startsWith("/") || args.path.startsWith("..")) {
|
|
610
|
-
return;
|
|
611
|
-
}
|
|
612
|
-
return { path: args.path, external: true };
|
|
613
|
-
});
|
|
614
|
-
}
|
|
615
|
-
};
|
|
616
|
-
const tsconfigPath = (0, import_node_path2.join)(projectRoot, "tsconfig.json");
|
|
617
|
-
await build({
|
|
618
|
-
entryPoints: [filePath],
|
|
619
|
-
outfile: outFile,
|
|
620
|
-
bundle: true,
|
|
621
|
-
format: "esm",
|
|
622
|
-
platform: "node",
|
|
623
|
-
target: ["node22"],
|
|
624
|
-
sourcemap: false,
|
|
625
|
-
logLevel: "silent",
|
|
626
|
-
plugins: [plugin],
|
|
627
|
-
absWorkingDir: projectRoot,
|
|
628
|
-
// Use tsconfig if present for path aliases
|
|
629
|
-
...(0, import_node_fs2.existsSync)(tsconfigPath) ? { tsconfig: tsconfigPath } : {}
|
|
630
|
-
});
|
|
631
|
-
const mod = await import(`${(0, import_node_url.pathToFileURL)(outFile).href}?t=${Date.now()}`);
|
|
632
|
-
let agentExport = mod?.agent;
|
|
633
|
-
if (!agentExport && mod?.default) {
|
|
634
|
-
agentExport = mod.default.agent ?? mod.default;
|
|
635
|
-
}
|
|
636
|
-
try {
|
|
637
|
-
(0, import_node_fs2.unlinkSync)(outFile);
|
|
638
|
-
} catch {
|
|
639
|
-
}
|
|
640
|
-
if (agentExport) {
|
|
641
|
-
if (!this.quiet) {
|
|
642
|
-
console.log(`\u2705 TS agent imported via esbuild: ${filePath}`);
|
|
643
|
-
}
|
|
644
|
-
return { agent: agentExport };
|
|
645
|
-
}
|
|
646
|
-
} catch (e) {
|
|
647
|
-
throw new Error(
|
|
648
|
-
`Failed to import TS agent via esbuild: ${e instanceof Error ? e.message : String(e)}`
|
|
737
|
+
const session = await this.sessionService.getSession(
|
|
738
|
+
loadedAgent.appName,
|
|
739
|
+
loadedAgent.userId,
|
|
740
|
+
loadedAgent.sessionId
|
|
649
741
|
);
|
|
742
|
+
if (!session || !session.events) {
|
|
743
|
+
return [];
|
|
744
|
+
}
|
|
745
|
+
const messages = session.events.map((event, index) => ({
|
|
746
|
+
id: index + 1,
|
|
747
|
+
type: event.author === "user" ? "user" : "assistant",
|
|
748
|
+
content: event.content?.parts?.map(
|
|
749
|
+
(part) => typeof part === "object" && "text" in part ? part.text : ""
|
|
750
|
+
).join("") || "",
|
|
751
|
+
timestamp: new Date(event.timestamp || Date.now()).toISOString()
|
|
752
|
+
}));
|
|
753
|
+
return messages;
|
|
754
|
+
} catch (error) {
|
|
755
|
+
console.error("Error fetching messages:", error);
|
|
756
|
+
return [];
|
|
650
757
|
}
|
|
651
|
-
|
|
758
|
+
}
|
|
759
|
+
};
|
|
760
|
+
|
|
761
|
+
// src/server/index.ts
|
|
762
|
+
var ADKServer = class {
|
|
763
|
+
agentManager;
|
|
764
|
+
sessionManager;
|
|
765
|
+
sessionService;
|
|
766
|
+
app;
|
|
767
|
+
server;
|
|
768
|
+
config;
|
|
769
|
+
constructor(agentsDir, port = 8042, host = "localhost", quiet = false) {
|
|
770
|
+
this.config = { agentsDir, port, host, quiet };
|
|
771
|
+
this.sessionService = new import_adk2.InMemorySessionService();
|
|
772
|
+
this.agentManager = new AgentManager(this.sessionService, quiet);
|
|
773
|
+
this.sessionManager = new SessionManager(this.sessionService);
|
|
774
|
+
this.app = new import_hono.Hono();
|
|
775
|
+
setupRoutes(this.app, this.agentManager, this.sessionManager, agentsDir);
|
|
776
|
+
this.agentManager.scanAgents(agentsDir);
|
|
652
777
|
}
|
|
653
778
|
async start() {
|
|
654
|
-
return new Promise((resolve2
|
|
779
|
+
return new Promise((resolve2) => {
|
|
655
780
|
this.server = (0, import_node_server.serve)({
|
|
656
781
|
fetch: this.app.fetch,
|
|
657
|
-
port: this.port,
|
|
658
|
-
hostname: this.host
|
|
782
|
+
port: this.config.port,
|
|
783
|
+
hostname: this.config.host
|
|
659
784
|
});
|
|
660
785
|
setTimeout(() => {
|
|
661
786
|
resolve2();
|
|
@@ -664,9 +789,7 @@ var ADKServer = class {
|
|
|
664
789
|
}
|
|
665
790
|
async stop() {
|
|
666
791
|
return new Promise((resolve2) => {
|
|
667
|
-
|
|
668
|
-
this.stopAgent(agentPath);
|
|
669
|
-
}
|
|
792
|
+
this.agentManager.stopAllAgents();
|
|
670
793
|
if (this.server) {
|
|
671
794
|
this.server.close();
|
|
672
795
|
}
|
|
@@ -674,19 +797,7 @@ var ADKServer = class {
|
|
|
674
797
|
});
|
|
675
798
|
}
|
|
676
799
|
getPort() {
|
|
677
|
-
return this.port;
|
|
678
|
-
}
|
|
679
|
-
extractAgentNameFromFile(filePath) {
|
|
680
|
-
try {
|
|
681
|
-
const content = (0, import_node_fs2.readFileSync)(filePath, "utf-8");
|
|
682
|
-
const nameMatch = content.match(/name\s*:\s*["']([^"']+)["']/);
|
|
683
|
-
if (nameMatch?.[1]) {
|
|
684
|
-
return nameMatch[1];
|
|
685
|
-
}
|
|
686
|
-
return null;
|
|
687
|
-
} catch {
|
|
688
|
-
return null;
|
|
689
|
-
}
|
|
800
|
+
return this.config.port;
|
|
690
801
|
}
|
|
691
802
|
};
|
|
692
803
|
|
|
@@ -979,8 +1090,7 @@ async function webCommand(options = {}) {
|
|
|
979
1090
|
import_commander.program.name("adk").description(package_default.description).version(package_default.version);
|
|
980
1091
|
import_commander.program.command("new").description("Create a new ADK project").argument("[project-name]", "Name of the project to create").option(
|
|
981
1092
|
"-t, --template <template>",
|
|
982
|
-
"Template to use (simple-agent, discord-bot, telegram-bot, hono-server, mcp-starter)"
|
|
983
|
-
"simple-agent"
|
|
1093
|
+
"Template to use (simple-agent, discord-bot, telegram-bot, hono-server, mcp-starter)"
|
|
984
1094
|
).action(async (projectName, options) => {
|
|
985
1095
|
try {
|
|
986
1096
|
await createProject(projectName, options);
|