@iqai/adk-cli 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,44 @@
1
1
  # @iqai/adk-cli
2
2
 
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 17341fc: Refactor agent loading and resolution logic with enhanced flexibility and reliability
8
+
9
+ This major enhancement improves the ADK CLI server's agent loading capabilities and adds new features to the core framework:
10
+
11
+ **CLI Server Improvements:**
12
+
13
+ - **Modular Architecture**: Refactored monolithic server file into organized modules (`server/index.ts`, `server/routes.ts`, `server/services.ts`, `server/types.ts`)
14
+ - **Enhanced Agent Resolution**: New `resolveAgentExport` method supports multiple export patterns:
15
+ - Direct agent exports: `export const agent = new LlmAgent(...)`
16
+ - Function factories: `export function agent() { return new LlmAgent(...) }`
17
+ - Async factories: `export async function agent() { return new LlmAgent(...) }`
18
+ - Container objects: `export default { agent: ... }`
19
+ - Primitive exports with fallback scanning
20
+ - **Improved TypeScript Import Handling**: Better project root detection and module resolution for TypeScript files
21
+
22
+ **Core Framework Enhancements:**
23
+
24
+ - **New AgentBuilder Method**: Added `withAgent()` method to directly provide existing agent instances with definition locking to prevent accidental configuration overwrites
25
+ - **Two-Tier Tool Deduplication**: Implemented robust deduplication logic to prevent duplicate function declarations that cause errors with LLM providers (especially Google)
26
+ - **Better Type Safety**: Improved type definitions and replaced `any[]` usage with proper typed interfaces
27
+
28
+ **Testing & Reliability:**
29
+
30
+ - **Comprehensive Test Coverage**: New `agent-resolution.test.ts` with extensive fixtures testing various agent export patterns
31
+ - **Multiple Test Fixtures**: Added 6 different agent export pattern examples for validation
32
+ - **Edge Case Handling**: Improved error handling and logging throughout the agent loading pipeline
33
+
34
+ These changes provide a more flexible, reliable, and maintainable foundation for agent development and deployment while maintaining backward compatibility.
35
+
36
+ ### Patch Changes
37
+
38
+ - Updated dependencies [17341fc]
39
+ - Updated dependencies [1564b7b]
40
+ - @iqai/adk@0.2.0
41
+
3
42
  ## 0.1.1
4
43
 
5
44
  ### Patch Changes
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.1.1",
34
+ version: "0.2.0",
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",
@@ -328,95 +328,70 @@ var import_node_fs3 = require("fs");
328
328
  var import_node_path3 = require("path");
329
329
  var import_chalk2 = __toESM(require("chalk"));
330
330
 
331
- // src/server.ts
331
+ // src/server/index.ts
332
+ var import_node_server = require("@hono/node-server");
333
+ var import_adk2 = require("@iqai/adk");
334
+ var import_hono = require("hono");
335
+
336
+ // src/server/routes.ts
337
+ var import_cors = require("hono/cors");
338
+ function setupRoutes(app, agentManager, sessionManager, agentsDir) {
339
+ app.use("/*", (0, import_cors.cors)());
340
+ app.get("/health", (c) => c.json({ status: "ok" }));
341
+ app.get("/api/agents", (c) => {
342
+ const agentsList = Array.from(
343
+ agentManager.getAgents().values()
344
+ ).map((agent) => ({
345
+ path: agent.absolutePath,
346
+ name: agent.name,
347
+ directory: agent.absolutePath,
348
+ relativePath: agent.relativePath
349
+ }));
350
+ return c.json({ agents: agentsList });
351
+ });
352
+ app.post("/api/agents/refresh", (c) => {
353
+ agentManager.scanAgents(agentsDir);
354
+ const agentsList = Array.from(
355
+ agentManager.getAgents().values()
356
+ ).map((agent) => ({
357
+ path: agent.absolutePath,
358
+ name: agent.name,
359
+ directory: agent.absolutePath,
360
+ relativePath: agent.relativePath
361
+ }));
362
+ return c.json({ agents: agentsList });
363
+ });
364
+ app.get("/api/agents/:id/messages", async (c) => {
365
+ const agentPath = decodeURIComponent(c.req.param("id"));
366
+ const loadedAgent = agentManager.getLoadedAgents().get(agentPath);
367
+ if (!loadedAgent) {
368
+ return c.json({ messages: [] });
369
+ }
370
+ const messages = await sessionManager.getSessionMessages(loadedAgent);
371
+ const response = { messages };
372
+ return c.json(response);
373
+ });
374
+ app.post("/api/agents/:id/message", async (c) => {
375
+ const agentPath = decodeURIComponent(c.req.param("id"));
376
+ const { message } = await c.req.json();
377
+ const response = await agentManager.sendMessageToAgent(agentPath, message);
378
+ const messageResponse = { response };
379
+ return c.json(messageResponse);
380
+ });
381
+ }
382
+
383
+ // src/server/services.ts
332
384
  var import_node_fs2 = require("fs");
333
385
  var import_node_path2 = require("path");
334
386
  var import_node_url = require("url");
335
- var import_node_server = require("@hono/node-server");
336
387
  var import_adk = require("@iqai/adk");
337
- var import_hono = require("hono");
338
- var import_cors = require("hono/cors");
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;
388
+ var AgentScanner = class {
389
+ constructor(quiet = false) {
353
390
  this.quiet = quiet;
354
- this.sessionService = new import_adk.InMemorySessionService();
355
- this.app = new import_hono.Hono();
356
- this.setupRoutes();
357
- this.scanAgents();
358
391
  }
359
- setupRoutes() {
360
- this.app.use("/*", (0, import_cors.cors)());
361
- this.app.get("/health", (c) => c.json({ status: "ok" }));
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;
392
+ scanAgents(agentsDir, loadedAgents) {
393
+ const agents = /* @__PURE__ */ new Map();
394
+ const scanDir = !agentsDir || !(0, import_node_fs2.existsSync)(agentsDir) ? process.cwd() : agentsDir;
420
395
  const shouldSkipDirectory = (dirName) => {
421
396
  const skipDirs = [
422
397
  "node_modules",
@@ -443,7 +418,7 @@ var ADKServer = class {
443
418
  }
444
419
  } else if (item === "agent.ts" || item === "agent.js") {
445
420
  const relativePath = (0, import_node_path2.relative)(scanDir, dir);
446
- const loadedAgent = this.loadedAgents.get(relativePath);
421
+ const loadedAgent = loadedAgents.get(relativePath);
447
422
  let agentName = relativePath.split("/").pop() || "unknown";
448
423
  if (loadedAgent?.agent?.name) {
449
424
  agentName = loadedAgent.agent.name;
@@ -454,7 +429,7 @@ var ADKServer = class {
454
429
  } catch {
455
430
  }
456
431
  }
457
- this.agents.set(relativePath, {
432
+ agents.set(relativePath, {
458
433
  relativePath,
459
434
  name: agentName,
460
435
  absolutePath: dir,
@@ -465,9 +440,225 @@ var ADKServer = class {
465
440
  };
466
441
  scanDirectory(scanDir);
467
442
  if (!this.quiet) {
468
- console.log(`\u2705 Agent scan complete. Found ${this.agents.size} agents.`);
443
+ console.log(`\u2705 Agent scan complete. Found ${agents.size} agents.`);
444
+ }
445
+ return agents;
446
+ }
447
+ extractAgentNameFromFile(filePath) {
448
+ try {
449
+ const content = (0, import_node_fs2.readFileSync)(filePath, "utf-8");
450
+ const nameMatch = content.match(/name\s*:\s*["']([^"']+)["']/);
451
+ if (nameMatch?.[1]) {
452
+ return nameMatch[1];
453
+ }
454
+ return null;
455
+ } catch {
456
+ return null;
469
457
  }
470
458
  }
459
+ };
460
+ var AgentLoader = class {
461
+ constructor(quiet = false) {
462
+ this.quiet = quiet;
463
+ }
464
+ /**
465
+ * Import a TypeScript file by compiling it on-demand
466
+ */
467
+ async importTypeScriptFile(filePath) {
468
+ const startDir = (0, import_node_path2.dirname)(filePath);
469
+ let projectRoot = startDir;
470
+ while (projectRoot !== "/" && projectRoot !== (0, import_node_path2.dirname)(projectRoot)) {
471
+ 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"))) {
472
+ break;
473
+ }
474
+ projectRoot = (0, import_node_path2.dirname)(projectRoot);
475
+ }
476
+ if (projectRoot === "/") {
477
+ projectRoot = startDir;
478
+ }
479
+ try {
480
+ const { build } = await import("esbuild");
481
+ const cacheDir = (0, import_node_path2.join)(projectRoot, ".adk-cache");
482
+ if (!(0, import_node_fs2.existsSync)(cacheDir)) {
483
+ (0, import_node_fs2.mkdirSync)(cacheDir, { recursive: true });
484
+ }
485
+ const outFile = (0, import_node_path2.join)(cacheDir, `agent-${Date.now()}.mjs`);
486
+ const plugin = {
487
+ name: "externalize-bare-imports",
488
+ setup(build2) {
489
+ build2.onResolve({ filter: /.*/ }, (args) => {
490
+ if (args.path.startsWith(".") || args.path.startsWith("/") || args.path.startsWith("..")) {
491
+ return;
492
+ }
493
+ return { path: args.path, external: true };
494
+ });
495
+ }
496
+ };
497
+ const tsconfigPath = (0, import_node_path2.join)(projectRoot, "tsconfig.json");
498
+ await build({
499
+ entryPoints: [filePath],
500
+ outfile: outFile,
501
+ bundle: true,
502
+ format: "esm",
503
+ platform: "node",
504
+ target: ["node22"],
505
+ sourcemap: false,
506
+ logLevel: "silent",
507
+ plugins: [plugin],
508
+ absWorkingDir: projectRoot,
509
+ // Use tsconfig if present for path aliases
510
+ ...(0, import_node_fs2.existsSync)(tsconfigPath) ? { tsconfig: tsconfigPath } : {}
511
+ });
512
+ const mod = await import(`${(0, import_node_url.pathToFileURL)(outFile).href}?t=${Date.now()}`);
513
+ let agentExport = mod?.agent;
514
+ if (!agentExport && mod?.default) {
515
+ agentExport = mod.default.agent ?? mod.default;
516
+ }
517
+ try {
518
+ (0, import_node_fs2.unlinkSync)(outFile);
519
+ } catch {
520
+ }
521
+ if (agentExport) {
522
+ const isPrimitive = (v) => v == null || ["string", "number", "boolean"].includes(typeof v);
523
+ if (isPrimitive(agentExport)) {
524
+ if (!this.quiet) {
525
+ console.log(
526
+ `\u2139\uFE0F Ignoring primitive 'agent' export in ${filePath}; scanning module for factory...`
527
+ );
528
+ }
529
+ } else {
530
+ if (!this.quiet) {
531
+ console.log(`\u2705 TS agent imported via esbuild: ${filePath}`);
532
+ }
533
+ return { agent: agentExport };
534
+ }
535
+ }
536
+ return mod;
537
+ } catch (e) {
538
+ throw new Error(
539
+ `Failed to import TS agent via esbuild: ${e instanceof Error ? e.message : String(e)}`
540
+ );
541
+ }
542
+ }
543
+ loadEnvironmentVariables(agentFilePath) {
544
+ let projectRoot = (0, import_node_path2.dirname)(agentFilePath);
545
+ while (projectRoot !== "/" && projectRoot !== (0, import_node_path2.dirname)(projectRoot)) {
546
+ 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"))) {
547
+ break;
548
+ }
549
+ projectRoot = (0, import_node_path2.dirname)(projectRoot);
550
+ }
551
+ const envPath = (0, import_node_path2.join)(projectRoot, ".env");
552
+ if ((0, import_node_fs2.existsSync)(envPath)) {
553
+ try {
554
+ const envContent = (0, import_node_fs2.readFileSync)(envPath, "utf8");
555
+ const envLines = envContent.split("\n");
556
+ for (const line of envLines) {
557
+ const trimmedLine = line.trim();
558
+ if (trimmedLine && !trimmedLine.startsWith("#")) {
559
+ const [key, ...valueParts] = trimmedLine.split("=");
560
+ if (key && valueParts.length > 0) {
561
+ const value = valueParts.join("=").replace(/^"(.*)"$/, "$1");
562
+ process.env[key.trim()] = value.trim();
563
+ }
564
+ }
565
+ }
566
+ } catch (error) {
567
+ console.warn(
568
+ `\u26A0\uFE0F Warning: Could not load .env file: ${error instanceof Error ? error.message : String(error)}`
569
+ );
570
+ }
571
+ }
572
+ }
573
+ // Minimal resolution logic for agent exports: supports
574
+ // 1) export const agent = new LlmAgent(...)
575
+ // 2) export function agent() { return new LlmAgent(...) }
576
+ // 3) export async function agent() { return new LlmAgent(...) }
577
+ // 4) default export (object or function) returning or containing .agent
578
+ async resolveAgentExport(mod) {
579
+ let candidate = mod?.agent ?? mod?.default?.agent ?? mod?.default ?? mod;
580
+ const isLikelyAgentInstance = (obj) => obj && typeof obj === "object" && typeof obj.name === "string";
581
+ const isPrimitive = (v) => v == null || ["string", "number", "boolean"].includes(typeof v);
582
+ const invokeMaybe = async (fn) => {
583
+ let out = fn();
584
+ if (out && typeof out === "object" && "then" in out) {
585
+ out = await out;
586
+ }
587
+ return out;
588
+ };
589
+ if (!isLikelyAgentInstance(candidate) && isPrimitive(candidate) || !isLikelyAgentInstance(candidate) && candidate && candidate === mod) {
590
+ candidate = mod;
591
+ for (const [key, value] of Object.entries(mod)) {
592
+ if (key === "default") continue;
593
+ const keyLower = key.toLowerCase();
594
+ if (isPrimitive(value)) continue;
595
+ if (isLikelyAgentInstance(value)) {
596
+ candidate = value;
597
+ break;
598
+ }
599
+ if (value && typeof value === "object" && value.agent && isLikelyAgentInstance(value.agent)) {
600
+ candidate = value.agent;
601
+ break;
602
+ }
603
+ if (typeof value === "function" && (/(agent|build|create)/i.test(keyLower) || value.name && /(agent|build|create)/i.test(value.name.toLowerCase()))) {
604
+ try {
605
+ const maybe = await invokeMaybe(value);
606
+ if (isLikelyAgentInstance(maybe)) {
607
+ candidate = maybe;
608
+ break;
609
+ }
610
+ if (maybe && typeof maybe === "object" && maybe.agent && isLikelyAgentInstance(maybe.agent)) {
611
+ candidate = maybe.agent;
612
+ break;
613
+ }
614
+ } catch (e) {
615
+ }
616
+ }
617
+ }
618
+ }
619
+ if (typeof candidate === "function") {
620
+ try {
621
+ candidate = await invokeMaybe(candidate);
622
+ } catch (e) {
623
+ throw new Error(
624
+ `Failed executing exported agent function: ${e instanceof Error ? e.message : String(e)}`
625
+ );
626
+ }
627
+ }
628
+ if (candidate && typeof candidate === "object" && candidate.agent && isLikelyAgentInstance(candidate.agent)) {
629
+ candidate = candidate.agent;
630
+ }
631
+ if (candidate?.agent && isLikelyAgentInstance(candidate.agent)) {
632
+ candidate = candidate.agent;
633
+ }
634
+ if (!candidate || !isLikelyAgentInstance(candidate)) {
635
+ throw new Error(
636
+ "No agent export resolved (expected variable, function, or function returning an agent)"
637
+ );
638
+ }
639
+ return { agent: candidate };
640
+ }
641
+ };
642
+ var AgentManager = class {
643
+ constructor(sessionService, quiet = false) {
644
+ this.sessionService = sessionService;
645
+ this.quiet = quiet;
646
+ this.scanner = new AgentScanner(quiet);
647
+ this.loader = new AgentLoader(quiet);
648
+ }
649
+ agents = /* @__PURE__ */ new Map();
650
+ loadedAgents = /* @__PURE__ */ new Map();
651
+ scanner;
652
+ loader;
653
+ getAgents() {
654
+ return this.agents;
655
+ }
656
+ getLoadedAgents() {
657
+ return this.loadedAgents;
658
+ }
659
+ scanAgents(agentsDir) {
660
+ this.agents = this.scanner.scanAgents(agentsDir, this.loadedAgents);
661
+ }
471
662
  async startAgent(agentPath) {
472
663
  const agent = this.agents.get(agentPath);
473
664
  if (!agent) {
@@ -486,70 +677,31 @@ var ADKServer = class {
486
677
  `No agent.js or agent.ts file found in ${agent.absolutePath}`
487
678
  );
488
679
  }
489
- let projectRoot = (0, import_node_path2.dirname)(agentFilePath);
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
- }
680
+ this.loader.loadEnvironmentVariables(agentFilePath);
517
681
  const agentFileUrl = (0, import_node_url.pathToFileURL)(agentFilePath).href;
518
- const agentModule = agentFilePath.endsWith(".ts") ? await this.importTypeScriptFile(agentFilePath) : await import(agentFileUrl);
519
- if (!agentModule.agent) {
520
- throw new Error(`No 'agent' export found in ${agentFilePath}`);
521
- }
522
- if (!agentModule.agent || typeof agentModule.agent !== "object" || !agentModule.agent.name) {
682
+ const agentModule = agentFilePath.endsWith(".ts") ? await this.loader.importTypeScriptFile(agentFilePath) : await import(agentFileUrl);
683
+ const resolved = await this.loader.resolveAgentExport(agentModule);
684
+ const exportedAgent = resolved.agent;
685
+ if (!exportedAgent?.name) {
523
686
  throw new Error(
524
687
  `Invalid agent export in ${agentFilePath}. Expected an LlmAgent instance with a name property.`
525
688
  );
526
689
  }
527
- if (!agentModule.agent.model || !agentModule.agent.instruction) {
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, {
690
+ const agentBuilder = import_adk.AgentBuilder.create(exportedAgent.name).withAgent(exportedAgent).withSessionService(this.sessionService, {
530
691
  userId: `user_${agentPath}`,
531
692
  appName: "adk-server"
532
693
  });
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
694
  const { runner, session } = await agentBuilder.build();
543
695
  const loadedAgent = {
544
- agent: agentModule.agent,
696
+ agent: exportedAgent,
545
697
  runner,
546
698
  sessionId: session.id,
547
699
  userId: `user_${agentPath}`,
548
700
  appName: "adk-server"
549
701
  };
550
702
  this.loadedAgents.set(agentPath, loadedAgent);
551
- agent.instance = agentModule.agent;
552
- agent.name = agentModule.agent.name;
703
+ agent.instance = exportedAgent;
704
+ agent.name = exportedAgent.name;
553
705
  } catch (error) {
554
706
  console.error(`\u274C Failed to load agent "${agent.name}":`, error);
555
707
  throw new Error(
@@ -584,78 +736,65 @@ var ADKServer = class {
584
736
  throw new Error(`Failed to send message to agent: ${errorMessage}`);
585
737
  }
586
738
  }
587
- /**
588
- * Import a TypeScript file by compiling it on-demand
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);
739
+ stopAllAgents() {
740
+ for (const [agentPath] of this.loadedAgents.entries()) {
741
+ this.stopAgent(agentPath);
597
742
  }
743
+ }
744
+ };
745
+ var SessionManager = class {
746
+ constructor(sessionService) {
747
+ this.sessionService = sessionService;
748
+ }
749
+ async getSessionMessages(loadedAgent) {
598
750
  try {
599
- const { build } = await import("esbuild");
600
- const cacheDir = (0, import_node_path2.join)(projectRoot, ".adk-cache");
601
- if (!(0, import_node_fs2.existsSync)(cacheDir)) {
602
- (0, import_node_fs2.mkdirSync)(cacheDir, { recursive: true });
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)}`
751
+ const session = await this.sessionService.getSession(
752
+ loadedAgent.appName,
753
+ loadedAgent.userId,
754
+ loadedAgent.sessionId
649
755
  );
756
+ if (!session || !session.events) {
757
+ return [];
758
+ }
759
+ const messages = session.events.map((event, index) => ({
760
+ id: index + 1,
761
+ type: event.author === "user" ? "user" : "assistant",
762
+ content: event.content?.parts?.map(
763
+ (part) => typeof part === "object" && "text" in part ? part.text : ""
764
+ ).join("") || "",
765
+ timestamp: new Date(event.timestamp || Date.now()).toISOString()
766
+ }));
767
+ return messages;
768
+ } catch (error) {
769
+ console.error("Error fetching messages:", error);
770
+ return [];
650
771
  }
651
- throw new Error("No 'agent' export found in TypeScript module");
772
+ }
773
+ };
774
+
775
+ // src/server/index.ts
776
+ var ADKServer = class {
777
+ agentManager;
778
+ sessionManager;
779
+ sessionService;
780
+ app;
781
+ server;
782
+ config;
783
+ constructor(agentsDir, port = 8042, host = "localhost", quiet = false) {
784
+ this.config = { agentsDir, port, host, quiet };
785
+ this.sessionService = new import_adk2.InMemorySessionService();
786
+ this.agentManager = new AgentManager(this.sessionService, quiet);
787
+ this.sessionManager = new SessionManager(this.sessionService);
788
+ this.app = new import_hono.Hono();
789
+ setupRoutes(this.app, this.agentManager, this.sessionManager, agentsDir);
790
+ this.agentManager.scanAgents(agentsDir);
652
791
  }
653
792
  async start() {
654
- return new Promise((resolve2, reject) => {
793
+ return new Promise((resolve2) => {
655
794
  this.server = (0, import_node_server.serve)({
656
795
  fetch: this.app.fetch,
657
- port: this.port,
658
- hostname: this.host
796
+ port: this.config.port,
797
+ hostname: this.config.host
659
798
  });
660
799
  setTimeout(() => {
661
800
  resolve2();
@@ -664,9 +803,7 @@ var ADKServer = class {
664
803
  }
665
804
  async stop() {
666
805
  return new Promise((resolve2) => {
667
- for (const [agentPath] of this.loadedAgents) {
668
- this.stopAgent(agentPath);
669
- }
806
+ this.agentManager.stopAllAgents();
670
807
  if (this.server) {
671
808
  this.server.close();
672
809
  }
@@ -674,19 +811,7 @@ var ADKServer = class {
674
811
  });
675
812
  }
676
813
  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
- }
814
+ return this.config.port;
690
815
  }
691
816
  };
692
817