@iqai/adk-cli 0.1.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 +9 -0
- package/LICENSE.md +9 -0
- package/README.md +289 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1040 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1024 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +67 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1040 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
"use strict";
|
|
4
|
+
var __create = Object.create;
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
8
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
9
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
19
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
20
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
21
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
22
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
23
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
24
|
+
mod
|
|
25
|
+
));
|
|
26
|
+
|
|
27
|
+
// src/index.ts
|
|
28
|
+
var import_chalk5 = __toESM(require("chalk"));
|
|
29
|
+
var import_commander = require("commander");
|
|
30
|
+
|
|
31
|
+
// package.json
|
|
32
|
+
var package_default = {
|
|
33
|
+
name: "@iqai/adk-cli",
|
|
34
|
+
version: "0.1.1",
|
|
35
|
+
description: "CLI tool for creating, running, and testing ADK agents",
|
|
36
|
+
main: "dist/index.js",
|
|
37
|
+
types: "dist/index.d.ts",
|
|
38
|
+
bin: {
|
|
39
|
+
adk: "./dist/index.mjs"
|
|
40
|
+
},
|
|
41
|
+
scripts: {
|
|
42
|
+
build: "tsup",
|
|
43
|
+
dev: "tsup --watch",
|
|
44
|
+
test: "vitest run",
|
|
45
|
+
"test:watch": "vitest"
|
|
46
|
+
},
|
|
47
|
+
repository: {
|
|
48
|
+
type: "git",
|
|
49
|
+
url: "https://github.com/IQAIcom/adk-ts.git",
|
|
50
|
+
directory: "packages/adk-cli"
|
|
51
|
+
},
|
|
52
|
+
keywords: [
|
|
53
|
+
"ai",
|
|
54
|
+
"llm",
|
|
55
|
+
"agent",
|
|
56
|
+
"cli",
|
|
57
|
+
"adk",
|
|
58
|
+
"typescript"
|
|
59
|
+
],
|
|
60
|
+
author: "IQAI",
|
|
61
|
+
license: "MIT",
|
|
62
|
+
dependencies: {
|
|
63
|
+
"@clack/prompts": "^0.11.0",
|
|
64
|
+
"@hono/node-server": "^1.18.1",
|
|
65
|
+
"@iqai/adk": "workspace:*",
|
|
66
|
+
chalk: "^5.4.1",
|
|
67
|
+
commander: "^12.1.0",
|
|
68
|
+
dedent: "^1.6.0",
|
|
69
|
+
giget: "^2.0.0",
|
|
70
|
+
hono: "^4.6.13",
|
|
71
|
+
marked: "^14.1.3",
|
|
72
|
+
"marked-terminal": "^7.2.1",
|
|
73
|
+
esbuild: "^0.23.0"
|
|
74
|
+
},
|
|
75
|
+
devDependencies: {
|
|
76
|
+
"@iqai/tsconfig": "workspace:*",
|
|
77
|
+
"@types/marked-terminal": "^6.1.1",
|
|
78
|
+
"@types/node": "^20.17.30",
|
|
79
|
+
tsup: "^8.4.0",
|
|
80
|
+
typescript: "^5.3.2",
|
|
81
|
+
vitest: "^3.1.3"
|
|
82
|
+
},
|
|
83
|
+
packageManager: "pnpm@9.0.0",
|
|
84
|
+
engines: {
|
|
85
|
+
node: ">=22.0"
|
|
86
|
+
},
|
|
87
|
+
files: [
|
|
88
|
+
"dist",
|
|
89
|
+
"!**/*.test.*",
|
|
90
|
+
"!**/*.json",
|
|
91
|
+
"CHANGELOG.md",
|
|
92
|
+
"LICENSE",
|
|
93
|
+
"README.md"
|
|
94
|
+
],
|
|
95
|
+
publishConfig: {
|
|
96
|
+
access: "public"
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
// src/commands/new.ts
|
|
101
|
+
var import_node_fs = require("fs");
|
|
102
|
+
var import_node_path = require("path");
|
|
103
|
+
var import_prompts = require("@clack/prompts");
|
|
104
|
+
var import_chalk = __toESM(require("chalk"));
|
|
105
|
+
var import_dedent = __toESM(require("dedent"));
|
|
106
|
+
var import_giget = require("giget");
|
|
107
|
+
var templates = [
|
|
108
|
+
{
|
|
109
|
+
value: "simple-agent",
|
|
110
|
+
label: "\u{1F916} Simple Agent",
|
|
111
|
+
hint: "Basic agent with chat capabilities",
|
|
112
|
+
source: "github:IQAIcom/adk-ts/apps/starter-templates/simple-agent"
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
value: "discord-bot",
|
|
116
|
+
label: "\u{1F3AE} Discord Bot",
|
|
117
|
+
hint: "Agent integrated with Discord",
|
|
118
|
+
source: "github:IQAIcom/adk-ts/apps/starter-templates/discord-bot"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
value: "telegram-bot",
|
|
122
|
+
label: "\u{1F4F1} Telegram Bot",
|
|
123
|
+
hint: "Agent integrated with Telegram",
|
|
124
|
+
source: "github:IQAIcom/adk-ts/apps/starter-templates/telegram-bot"
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
value: "hono-server",
|
|
128
|
+
label: "\u{1F680} Hono Server",
|
|
129
|
+
hint: "Web server with agent endpoints",
|
|
130
|
+
source: "github:IQAIcom/adk-ts/apps/starter-templates/hono-server"
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
value: "mcp-starter",
|
|
134
|
+
label: "\u{1F50C} MCP Integration",
|
|
135
|
+
hint: "Model Context Protocol server",
|
|
136
|
+
source: "github:IQAIcom/adk-ts/apps/starter-templates/mcp-starter"
|
|
137
|
+
}
|
|
138
|
+
];
|
|
139
|
+
var packageManagers = [
|
|
140
|
+
{ name: "npm", command: "npm", args: ["install"], label: "\u{1F4E6} npm" },
|
|
141
|
+
{ name: "pnpm", command: "pnpm", args: ["install"], label: "\u26A1 pnpm" },
|
|
142
|
+
{ name: "yarn", command: "yarn", args: ["install"], label: "\u{1F9F6} yarn" },
|
|
143
|
+
{ name: "bun", command: "bun", args: ["install"], label: "\u{1F35E} bun" }
|
|
144
|
+
];
|
|
145
|
+
async function detectAvailablePackageManagers() {
|
|
146
|
+
const { spawn } = await import("child_process");
|
|
147
|
+
const available = [];
|
|
148
|
+
for (const pm of packageManagers) {
|
|
149
|
+
try {
|
|
150
|
+
await new Promise((resolve2, reject) => {
|
|
151
|
+
const child = spawn(pm.command, ["--version"], {
|
|
152
|
+
stdio: "pipe"
|
|
153
|
+
});
|
|
154
|
+
child.on("close", (code) => {
|
|
155
|
+
if (code === 0) {
|
|
156
|
+
available.push(pm);
|
|
157
|
+
}
|
|
158
|
+
resolve2();
|
|
159
|
+
});
|
|
160
|
+
child.on("error", () => resolve2());
|
|
161
|
+
});
|
|
162
|
+
} catch {
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return available.length > 0 ? available : [packageManagers[0]];
|
|
166
|
+
}
|
|
167
|
+
async function createProject(projectName, options) {
|
|
168
|
+
console.clear();
|
|
169
|
+
console.log(
|
|
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! "));
|
|
184
|
+
let finalProjectName = projectName;
|
|
185
|
+
if (!finalProjectName) {
|
|
186
|
+
const response = await (0, import_prompts.text)({
|
|
187
|
+
message: "What is your project name?",
|
|
188
|
+
placeholder: "my-adk-project",
|
|
189
|
+
validate: (value) => {
|
|
190
|
+
if (!value) return "Project name is required";
|
|
191
|
+
if (value.includes(" ")) return "Project name cannot contain spaces";
|
|
192
|
+
if ((0, import_node_fs.existsSync)(value)) return `Directory "${value}" already exists`;
|
|
193
|
+
return void 0;
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
if (typeof response === "symbol") {
|
|
197
|
+
(0, import_prompts.outro)("Operation cancelled");
|
|
198
|
+
process.exit(0);
|
|
199
|
+
}
|
|
200
|
+
finalProjectName = response;
|
|
201
|
+
}
|
|
202
|
+
let selectedTemplate = options?.template;
|
|
203
|
+
if (!selectedTemplate || !templates.find((t) => t.value === selectedTemplate)) {
|
|
204
|
+
const framework = await (0, import_prompts.select)({
|
|
205
|
+
message: "Which template would you like to use?",
|
|
206
|
+
options: templates.map((t) => ({
|
|
207
|
+
value: t.value,
|
|
208
|
+
label: t.label,
|
|
209
|
+
hint: t.hint
|
|
210
|
+
}))
|
|
211
|
+
});
|
|
212
|
+
if (typeof framework === "symbol") {
|
|
213
|
+
(0, import_prompts.outro)("Operation cancelled");
|
|
214
|
+
process.exit(0);
|
|
215
|
+
}
|
|
216
|
+
selectedTemplate = framework;
|
|
217
|
+
}
|
|
218
|
+
const template = templates.find((t) => t.value === selectedTemplate);
|
|
219
|
+
if (!template) {
|
|
220
|
+
(0, import_prompts.outro)("Invalid template selected");
|
|
221
|
+
process.exit(1);
|
|
222
|
+
}
|
|
223
|
+
if ((0, import_node_fs.existsSync)(finalProjectName)) {
|
|
224
|
+
(0, import_prompts.outro)(import_chalk.default.red(`Directory "${finalProjectName}" already exists`));
|
|
225
|
+
process.exit(1);
|
|
226
|
+
}
|
|
227
|
+
const s = (0, import_prompts.spinner)();
|
|
228
|
+
s.start("Downloading template...");
|
|
229
|
+
try {
|
|
230
|
+
await (0, import_giget.downloadTemplate)(template.source, {
|
|
231
|
+
dir: finalProjectName,
|
|
232
|
+
registry: "gh"
|
|
233
|
+
});
|
|
234
|
+
s.stop("Template downloaded!");
|
|
235
|
+
} catch (error) {
|
|
236
|
+
s.stop("Failed to download template");
|
|
237
|
+
(0, import_prompts.outro)(import_chalk.default.red(`Error: ${error}`));
|
|
238
|
+
process.exit(1);
|
|
239
|
+
}
|
|
240
|
+
const availablePackageManagers = await detectAvailablePackageManagers();
|
|
241
|
+
let selectedPackageManager;
|
|
242
|
+
if (availablePackageManagers.length === 1) {
|
|
243
|
+
selectedPackageManager = availablePackageManagers[0];
|
|
244
|
+
} else {
|
|
245
|
+
const packageManagerChoice = await (0, import_prompts.select)({
|
|
246
|
+
message: "Which package manager would you like to use?",
|
|
247
|
+
options: availablePackageManagers.map((pm) => ({
|
|
248
|
+
value: pm.name,
|
|
249
|
+
label: pm.label
|
|
250
|
+
}))
|
|
251
|
+
});
|
|
252
|
+
if (typeof packageManagerChoice === "symbol") {
|
|
253
|
+
(0, import_prompts.outro)("Operation cancelled");
|
|
254
|
+
process.exit(0);
|
|
255
|
+
}
|
|
256
|
+
selectedPackageManager = availablePackageManagers.find(
|
|
257
|
+
(pm) => pm.name === packageManagerChoice
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
const shouldInstall = await (0, import_prompts.confirm)({
|
|
261
|
+
message: "Install dependencies?",
|
|
262
|
+
initialValue: true
|
|
263
|
+
});
|
|
264
|
+
if (typeof shouldInstall === "symbol") {
|
|
265
|
+
(0, import_prompts.outro)("Operation cancelled");
|
|
266
|
+
process.exit(0);
|
|
267
|
+
}
|
|
268
|
+
if (shouldInstall) {
|
|
269
|
+
const s2 = (0, import_prompts.spinner)();
|
|
270
|
+
s2.start(`Installing dependencies with ${selectedPackageManager.name}...`);
|
|
271
|
+
const { spawn } = await import("child_process");
|
|
272
|
+
const projectPath = (0, import_node_path.join)(process.cwd(), finalProjectName);
|
|
273
|
+
try {
|
|
274
|
+
await new Promise((resolve2, reject) => {
|
|
275
|
+
const child = spawn(
|
|
276
|
+
selectedPackageManager.command,
|
|
277
|
+
selectedPackageManager.args,
|
|
278
|
+
{
|
|
279
|
+
cwd: projectPath,
|
|
280
|
+
stdio: "pipe"
|
|
281
|
+
}
|
|
282
|
+
);
|
|
283
|
+
child.on("close", (code) => {
|
|
284
|
+
if (code === 0) {
|
|
285
|
+
resolve2();
|
|
286
|
+
} else {
|
|
287
|
+
reject(new Error(`Package installation failed with code ${code}`));
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
child.on("error", reject);
|
|
291
|
+
});
|
|
292
|
+
s2.stop("Dependencies installed!");
|
|
293
|
+
} catch (error) {
|
|
294
|
+
s2.stop("Failed to install dependencies");
|
|
295
|
+
console.log(
|
|
296
|
+
import_chalk.default.yellow("\nYou can install dependencies manually by running:")
|
|
297
|
+
);
|
|
298
|
+
console.log(
|
|
299
|
+
import_chalk.default.cyan(
|
|
300
|
+
`cd ${finalProjectName} && ${selectedPackageManager.command} ${selectedPackageManager.args.join(" ")}`
|
|
301
|
+
)
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
(0, import_prompts.outro)(
|
|
306
|
+
import_chalk.default.green(import_dedent.default`
|
|
307
|
+
🎉 Project created successfully!
|
|
308
|
+
|
|
309
|
+
Next steps:
|
|
310
|
+
${import_chalk.default.cyan(`cd ${finalProjectName}`)}
|
|
311
|
+
${shouldInstall ? "" : import_chalk.default.cyan(`${selectedPackageManager.command} ${selectedPackageManager.args.join(" ")}`)}
|
|
312
|
+
${import_chalk.default.cyan("npm run dev")} or ${import_chalk.default.cyan("yarn dev")} or ${import_chalk.default.cyan("pnpm dev")}
|
|
313
|
+
|
|
314
|
+
Happy coding! 🚀
|
|
315
|
+
`)
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// src/commands/run.ts
|
|
320
|
+
var p = __toESM(require("@clack/prompts"));
|
|
321
|
+
var import_prompts2 = require("@clack/prompts");
|
|
322
|
+
var import_chalk3 = __toESM(require("chalk"));
|
|
323
|
+
var import_marked = require("marked");
|
|
324
|
+
var import_marked_terminal = require("marked-terminal");
|
|
325
|
+
|
|
326
|
+
// src/commands/serve.ts
|
|
327
|
+
var import_node_fs3 = require("fs");
|
|
328
|
+
var import_node_path3 = require("path");
|
|
329
|
+
var import_chalk2 = __toESM(require("chalk"));
|
|
330
|
+
|
|
331
|
+
// src/server.ts
|
|
332
|
+
var import_node_fs2 = require("fs");
|
|
333
|
+
var import_node_path2 = require("path");
|
|
334
|
+
var import_node_url = require("url");
|
|
335
|
+
var import_node_server = require("@hono/node-server");
|
|
336
|
+
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;
|
|
353
|
+
this.quiet = quiet;
|
|
354
|
+
this.sessionService = new import_adk.InMemorySessionService();
|
|
355
|
+
this.app = new import_hono.Hono();
|
|
356
|
+
this.setupRoutes();
|
|
357
|
+
this.scanAgents();
|
|
358
|
+
}
|
|
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;
|
|
420
|
+
const shouldSkipDirectory = (dirName) => {
|
|
421
|
+
const skipDirs = [
|
|
422
|
+
"node_modules",
|
|
423
|
+
".git",
|
|
424
|
+
".next",
|
|
425
|
+
"dist",
|
|
426
|
+
"build",
|
|
427
|
+
".turbo",
|
|
428
|
+
"coverage",
|
|
429
|
+
".vscode",
|
|
430
|
+
".idea"
|
|
431
|
+
];
|
|
432
|
+
return skipDirs.includes(dirName);
|
|
433
|
+
};
|
|
434
|
+
const scanDirectory = (dir) => {
|
|
435
|
+
if (!(0, import_node_fs2.existsSync)(dir)) return;
|
|
436
|
+
const items = (0, import_node_fs2.readdirSync)(dir);
|
|
437
|
+
for (const item of items) {
|
|
438
|
+
const fullPath = (0, import_node_path2.join)(dir, item);
|
|
439
|
+
const stat = (0, import_node_fs2.statSync)(fullPath);
|
|
440
|
+
if (stat.isDirectory()) {
|
|
441
|
+
if (!shouldSkipDirectory(item)) {
|
|
442
|
+
scanDirectory(fullPath);
|
|
443
|
+
}
|
|
444
|
+
} else if (item === "agent.ts" || item === "agent.js") {
|
|
445
|
+
const relativePath = (0, import_node_path2.relative)(scanDir, dir);
|
|
446
|
+
const loadedAgent = this.loadedAgents.get(relativePath);
|
|
447
|
+
let agentName = relativePath.split("/").pop() || "unknown";
|
|
448
|
+
if (loadedAgent?.agent?.name) {
|
|
449
|
+
agentName = loadedAgent.agent.name;
|
|
450
|
+
} else {
|
|
451
|
+
try {
|
|
452
|
+
const agentFilePath = (0, import_node_path2.join)(dir, item);
|
|
453
|
+
agentName = this.extractAgentNameFromFile(agentFilePath) || agentName;
|
|
454
|
+
} catch {
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
this.agents.set(relativePath, {
|
|
458
|
+
relativePath,
|
|
459
|
+
name: agentName,
|
|
460
|
+
absolutePath: dir,
|
|
461
|
+
instance: loadedAgent?.agent
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
scanDirectory(scanDir);
|
|
467
|
+
if (!this.quiet) {
|
|
468
|
+
console.log(`\u2705 Agent scan complete. Found ${this.agents.size} agents.`);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
async startAgent(agentPath) {
|
|
472
|
+
const agent = this.agents.get(agentPath);
|
|
473
|
+
if (!agent) {
|
|
474
|
+
throw new Error(`Agent not found: ${agentPath}`);
|
|
475
|
+
}
|
|
476
|
+
if (this.loadedAgents.has(agentPath)) {
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
try {
|
|
480
|
+
let agentFilePath = (0, import_node_path2.join)(agent.absolutePath, "agent.js");
|
|
481
|
+
if (!(0, import_node_fs2.existsSync)(agentFilePath)) {
|
|
482
|
+
agentFilePath = (0, import_node_path2.join)(agent.absolutePath, "agent.ts");
|
|
483
|
+
}
|
|
484
|
+
if (!(0, import_node_fs2.existsSync)(agentFilePath)) {
|
|
485
|
+
throw new Error(
|
|
486
|
+
`No agent.js or agent.ts file found in ${agent.absolutePath}`
|
|
487
|
+
);
|
|
488
|
+
}
|
|
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
|
+
}
|
|
517
|
+
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) {
|
|
523
|
+
throw new Error(
|
|
524
|
+
`Invalid agent export in ${agentFilePath}. Expected an LlmAgent instance with a name property.`
|
|
525
|
+
);
|
|
526
|
+
}
|
|
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, {
|
|
530
|
+
userId: `user_${agentPath}`,
|
|
531
|
+
appName: "adk-server"
|
|
532
|
+
});
|
|
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
|
+
const { runner, session } = await agentBuilder.build();
|
|
543
|
+
const loadedAgent = {
|
|
544
|
+
agent: agentModule.agent,
|
|
545
|
+
runner,
|
|
546
|
+
sessionId: session.id,
|
|
547
|
+
userId: `user_${agentPath}`,
|
|
548
|
+
appName: "adk-server"
|
|
549
|
+
};
|
|
550
|
+
this.loadedAgents.set(agentPath, loadedAgent);
|
|
551
|
+
agent.instance = agentModule.agent;
|
|
552
|
+
agent.name = agentModule.agent.name;
|
|
553
|
+
} catch (error) {
|
|
554
|
+
console.error(`\u274C Failed to load agent "${agent.name}":`, error);
|
|
555
|
+
throw new Error(
|
|
556
|
+
`Failed to load agent: ${error instanceof Error ? error.message : String(error)}`
|
|
557
|
+
);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
async stopAgent(agentPath) {
|
|
561
|
+
this.loadedAgents.delete(agentPath);
|
|
562
|
+
const agent = this.agents.get(agentPath);
|
|
563
|
+
if (agent) {
|
|
564
|
+
agent.instance = void 0;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
async sendMessageToAgent(agentPath, message) {
|
|
568
|
+
if (!this.loadedAgents.has(agentPath)) {
|
|
569
|
+
await this.startAgent(agentPath);
|
|
570
|
+
}
|
|
571
|
+
const loadedAgent = this.loadedAgents.get(agentPath);
|
|
572
|
+
if (!loadedAgent) {
|
|
573
|
+
throw new Error("Agent failed to start");
|
|
574
|
+
}
|
|
575
|
+
try {
|
|
576
|
+
const response = await loadedAgent.runner.ask(message);
|
|
577
|
+
return response;
|
|
578
|
+
} catch (error) {
|
|
579
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
580
|
+
console.error(
|
|
581
|
+
`Error sending message to agent ${agentPath}:`,
|
|
582
|
+
errorMessage
|
|
583
|
+
);
|
|
584
|
+
throw new Error(`Failed to send message to agent: ${errorMessage}`);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
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);
|
|
597
|
+
}
|
|
598
|
+
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)}`
|
|
649
|
+
);
|
|
650
|
+
}
|
|
651
|
+
throw new Error("No 'agent' export found in TypeScript module");
|
|
652
|
+
}
|
|
653
|
+
async start() {
|
|
654
|
+
return new Promise((resolve2, reject) => {
|
|
655
|
+
this.server = (0, import_node_server.serve)({
|
|
656
|
+
fetch: this.app.fetch,
|
|
657
|
+
port: this.port,
|
|
658
|
+
hostname: this.host
|
|
659
|
+
});
|
|
660
|
+
setTimeout(() => {
|
|
661
|
+
resolve2();
|
|
662
|
+
}, 100);
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
async stop() {
|
|
666
|
+
return new Promise((resolve2) => {
|
|
667
|
+
for (const [agentPath] of this.loadedAgents) {
|
|
668
|
+
this.stopAgent(agentPath);
|
|
669
|
+
}
|
|
670
|
+
if (this.server) {
|
|
671
|
+
this.server.close();
|
|
672
|
+
}
|
|
673
|
+
resolve2();
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
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
|
+
}
|
|
690
|
+
}
|
|
691
|
+
};
|
|
692
|
+
|
|
693
|
+
// src/commands/serve.ts
|
|
694
|
+
async function serveCommand(options = {}) {
|
|
695
|
+
const port = options.port || 8042;
|
|
696
|
+
const host = options.host || "localhost";
|
|
697
|
+
const agentsDir = (0, import_node_path3.resolve)(options.dir || ".");
|
|
698
|
+
if (!(0, import_node_fs3.existsSync)(agentsDir)) {
|
|
699
|
+
console.error(import_chalk2.default.red(`\u274C Directory not found: ${agentsDir}`));
|
|
700
|
+
process.exit(1);
|
|
701
|
+
}
|
|
702
|
+
if (!options.quiet) {
|
|
703
|
+
console.log(import_chalk2.default.blue(`\u{1F680} ADK Server starting on http://${host}:${port}`));
|
|
704
|
+
}
|
|
705
|
+
const server = new ADKServer(agentsDir, port, host, options.quiet);
|
|
706
|
+
try {
|
|
707
|
+
await server.start();
|
|
708
|
+
if (!options.quiet) {
|
|
709
|
+
console.log(import_chalk2.default.green("\u2705 Server ready"));
|
|
710
|
+
}
|
|
711
|
+
const cleanup = async () => {
|
|
712
|
+
if (!options.quiet) {
|
|
713
|
+
console.log(import_chalk2.default.yellow("\n\u{1F6D1} Stopping server..."));
|
|
714
|
+
}
|
|
715
|
+
await server.stop();
|
|
716
|
+
process.exit(0);
|
|
717
|
+
};
|
|
718
|
+
process.on("SIGINT", cleanup);
|
|
719
|
+
process.on("SIGTERM", cleanup);
|
|
720
|
+
return server;
|
|
721
|
+
} catch (error) {
|
|
722
|
+
console.error(import_chalk2.default.red("\u274C Failed to start ADK server:"), error);
|
|
723
|
+
process.exit(1);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
// src/commands/run.ts
|
|
728
|
+
import_marked.marked.use((0, import_marked_terminal.markedTerminal)());
|
|
729
|
+
async function renderMarkdown(text3) {
|
|
730
|
+
try {
|
|
731
|
+
const result = await (0, import_marked.marked)(text3);
|
|
732
|
+
return typeof result === "string" ? result : text3;
|
|
733
|
+
} catch (error) {
|
|
734
|
+
return text3;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
var AgentChatClient = class {
|
|
738
|
+
apiUrl;
|
|
739
|
+
selectedAgent = null;
|
|
740
|
+
constructor(apiUrl) {
|
|
741
|
+
this.apiUrl = apiUrl;
|
|
742
|
+
}
|
|
743
|
+
async connect() {
|
|
744
|
+
try {
|
|
745
|
+
const response = await fetch(`${this.apiUrl}/health`);
|
|
746
|
+
if (!response.ok) {
|
|
747
|
+
throw new Error("Connection failed");
|
|
748
|
+
}
|
|
749
|
+
} catch (error) {
|
|
750
|
+
throw new Error("\u274C Connection failed");
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
async fetchAgents() {
|
|
754
|
+
try {
|
|
755
|
+
const response = await fetch(`${this.apiUrl}/api/agents`);
|
|
756
|
+
if (!response.ok) {
|
|
757
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
758
|
+
}
|
|
759
|
+
const data = await response.json();
|
|
760
|
+
if (Array.isArray(data)) {
|
|
761
|
+
return data;
|
|
762
|
+
}
|
|
763
|
+
if (data && Array.isArray(data.agents)) {
|
|
764
|
+
return data.agents;
|
|
765
|
+
}
|
|
766
|
+
throw new Error(`Unexpected response format: ${JSON.stringify(data)}`);
|
|
767
|
+
} catch (error) {
|
|
768
|
+
throw new Error(
|
|
769
|
+
`Failed to fetch agents: ${error instanceof Error ? error.message : String(error)}`
|
|
770
|
+
);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
async selectAgent() {
|
|
774
|
+
const agents = await this.fetchAgents();
|
|
775
|
+
if (agents.length === 0) {
|
|
776
|
+
throw new Error("No agents found in the current directory");
|
|
777
|
+
}
|
|
778
|
+
if (agents.length === 1) {
|
|
779
|
+
return agents[0];
|
|
780
|
+
}
|
|
781
|
+
const selectedAgent = await p.select({
|
|
782
|
+
message: "Choose an agent to chat with:",
|
|
783
|
+
options: agents.map((agent) => ({
|
|
784
|
+
label: agent.name,
|
|
785
|
+
value: agent,
|
|
786
|
+
hint: agent.relativePath
|
|
787
|
+
}))
|
|
788
|
+
});
|
|
789
|
+
if (p.isCancel(selectedAgent)) {
|
|
790
|
+
p.cancel("Operation cancelled");
|
|
791
|
+
process.exit(0);
|
|
792
|
+
}
|
|
793
|
+
return selectedAgent;
|
|
794
|
+
}
|
|
795
|
+
// No-op: agents are auto-loaded on message; keeping method removed
|
|
796
|
+
async sendMessage(message) {
|
|
797
|
+
if (!this.selectedAgent) {
|
|
798
|
+
throw new Error("No agent selected");
|
|
799
|
+
}
|
|
800
|
+
const s = (0, import_prompts2.spinner)();
|
|
801
|
+
s.start("\u{1F916} Thinking...");
|
|
802
|
+
try {
|
|
803
|
+
const response = await fetch(
|
|
804
|
+
`${this.apiUrl}/api/agents/${encodeURIComponent(this.selectedAgent.relativePath)}/message`,
|
|
805
|
+
{
|
|
806
|
+
method: "POST",
|
|
807
|
+
headers: {
|
|
808
|
+
"Content-Type": "application/json"
|
|
809
|
+
},
|
|
810
|
+
body: JSON.stringify({ message })
|
|
811
|
+
}
|
|
812
|
+
);
|
|
813
|
+
if (!response.ok) {
|
|
814
|
+
const errorText = await response.text();
|
|
815
|
+
s.stop("\u274C Failed to send message");
|
|
816
|
+
throw new Error(`Failed to send message: ${errorText}`);
|
|
817
|
+
}
|
|
818
|
+
const result = await response.json();
|
|
819
|
+
s.stop("\u{1F916} Assistant:");
|
|
820
|
+
if (result.response) {
|
|
821
|
+
const formattedResponse = await renderMarkdown(result.response);
|
|
822
|
+
import_prompts2.log.message(formattedResponse.trim());
|
|
823
|
+
}
|
|
824
|
+
} catch (error) {
|
|
825
|
+
import_prompts2.log.error("Failed to send message");
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
async startChat() {
|
|
829
|
+
if (!this.selectedAgent) {
|
|
830
|
+
throw new Error("Agent not selected");
|
|
831
|
+
}
|
|
832
|
+
while (true) {
|
|
833
|
+
try {
|
|
834
|
+
const message = await p.text({
|
|
835
|
+
message: "\u{1F4AC} Message:",
|
|
836
|
+
placeholder: "Type your message here..."
|
|
837
|
+
});
|
|
838
|
+
if (p.isCancel(message)) {
|
|
839
|
+
break;
|
|
840
|
+
}
|
|
841
|
+
if (message.trim()) {
|
|
842
|
+
await this.sendMessage(message.trim());
|
|
843
|
+
}
|
|
844
|
+
} catch (error) {
|
|
845
|
+
console.error(import_chalk3.default.red("Error in chat:"), error);
|
|
846
|
+
break;
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
disconnect() {
|
|
851
|
+
}
|
|
852
|
+
setSelectedAgent(agent) {
|
|
853
|
+
this.selectedAgent = agent;
|
|
854
|
+
}
|
|
855
|
+
};
|
|
856
|
+
async function runAgent(agentPath, options = {}) {
|
|
857
|
+
const envVerbose = process.env.ADK_VERBOSE;
|
|
858
|
+
const isVerbose = options.verbose ?? (envVerbose === "1" || envVerbose === "true");
|
|
859
|
+
if (options.server) {
|
|
860
|
+
const apiPort = 8042;
|
|
861
|
+
const host = options.host || "localhost";
|
|
862
|
+
console.log(import_chalk3.default.blue("\u{1F680} Starting ADK Server..."));
|
|
863
|
+
const serveOptions = {
|
|
864
|
+
port: apiPort,
|
|
865
|
+
dir: process.cwd(),
|
|
866
|
+
host,
|
|
867
|
+
quiet: !isVerbose
|
|
868
|
+
};
|
|
869
|
+
try {
|
|
870
|
+
const server = await serveCommand(serveOptions);
|
|
871
|
+
console.log(import_chalk3.default.cyan("Press Ctrl+C to stop the server"));
|
|
872
|
+
process.on("SIGINT", async () => {
|
|
873
|
+
console.log(import_chalk3.default.yellow("\n\u{1F6D1} Stopping server..."));
|
|
874
|
+
await server.stop();
|
|
875
|
+
process.exit(0);
|
|
876
|
+
});
|
|
877
|
+
return new Promise(() => {
|
|
878
|
+
});
|
|
879
|
+
} catch (error) {
|
|
880
|
+
console.error(import_chalk3.default.red("\u274C Failed to start server"));
|
|
881
|
+
process.exit(1);
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
const apiUrl = `http://${options.host || "localhost"}:8042`;
|
|
885
|
+
p.intro("\u{1F916} ADK Agent Chat");
|
|
886
|
+
try {
|
|
887
|
+
const healthResponse = await fetch(`${apiUrl}/health`).catch(() => null);
|
|
888
|
+
if (!healthResponse || !healthResponse.ok) {
|
|
889
|
+
const serverSpinner = (0, import_prompts2.spinner)();
|
|
890
|
+
serverSpinner.start("\u{1F680} Starting server...");
|
|
891
|
+
const serveOptions = {
|
|
892
|
+
port: 8042,
|
|
893
|
+
// Use new default port
|
|
894
|
+
dir: process.cwd(),
|
|
895
|
+
host: options.host || "localhost",
|
|
896
|
+
quiet: !isVerbose
|
|
897
|
+
};
|
|
898
|
+
await serveCommand(serveOptions);
|
|
899
|
+
await new Promise((resolve2) => setTimeout(resolve2, 1e3));
|
|
900
|
+
serverSpinner.stop("\u2705 Server ready");
|
|
901
|
+
}
|
|
902
|
+
const client = new AgentChatClient(apiUrl);
|
|
903
|
+
await client.connect();
|
|
904
|
+
const agentSpinner = (0, import_prompts2.spinner)();
|
|
905
|
+
agentSpinner.start("\u{1F50D} Scanning for agents...");
|
|
906
|
+
const agents = await client.fetchAgents();
|
|
907
|
+
let selectedAgent;
|
|
908
|
+
if (agents.length === 0) {
|
|
909
|
+
agentSpinner.stop("\u274C No agents found");
|
|
910
|
+
p.cancel("No agents found in the current directory");
|
|
911
|
+
process.exit(1);
|
|
912
|
+
} else if (agents.length === 1) {
|
|
913
|
+
selectedAgent = agents[0];
|
|
914
|
+
agentSpinner.stop(`\u{1F916} Found agent: ${selectedAgent.name}`);
|
|
915
|
+
} else {
|
|
916
|
+
agentSpinner.stop(`\u{1F916} Found ${agents.length} agents`);
|
|
917
|
+
const choice = await p.select({
|
|
918
|
+
message: "Choose an agent to chat with:",
|
|
919
|
+
options: agents.map((agent) => ({
|
|
920
|
+
label: agent.name,
|
|
921
|
+
value: agent,
|
|
922
|
+
hint: agent.relativePath
|
|
923
|
+
}))
|
|
924
|
+
});
|
|
925
|
+
if (p.isCancel(choice)) {
|
|
926
|
+
p.cancel("Operation cancelled");
|
|
927
|
+
process.exit(0);
|
|
928
|
+
}
|
|
929
|
+
selectedAgent = choice;
|
|
930
|
+
}
|
|
931
|
+
client.setSelectedAgent(selectedAgent);
|
|
932
|
+
await client.startChat();
|
|
933
|
+
client.disconnect();
|
|
934
|
+
p.outro("Chat ended");
|
|
935
|
+
} catch (error) {
|
|
936
|
+
p.cancel(
|
|
937
|
+
`Error: ${error instanceof Error ? error.message : String(error)}`
|
|
938
|
+
);
|
|
939
|
+
process.exit(1);
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
// src/commands/web.ts
|
|
944
|
+
var import_chalk4 = __toESM(require("chalk"));
|
|
945
|
+
async function webCommand(options = {}) {
|
|
946
|
+
const apiPort = options.port || 8042;
|
|
947
|
+
const webPort = options.webPort || 3e3;
|
|
948
|
+
const host = options.host || "localhost";
|
|
949
|
+
const useLocal = options.local || false;
|
|
950
|
+
const webUrl = options.webUrl || "https://adk-web.iqai.com";
|
|
951
|
+
console.log(import_chalk4.default.blue("\u{1F310} Starting ADK Web Interface..."));
|
|
952
|
+
const serveOptions = {
|
|
953
|
+
port: apiPort,
|
|
954
|
+
dir: options.dir,
|
|
955
|
+
host,
|
|
956
|
+
quiet: true
|
|
957
|
+
};
|
|
958
|
+
await serveCommand(serveOptions);
|
|
959
|
+
let webAppUrl;
|
|
960
|
+
if (useLocal) {
|
|
961
|
+
if (apiPort === 8042) {
|
|
962
|
+
webAppUrl = `http://${host}:${webPort}`;
|
|
963
|
+
} else {
|
|
964
|
+
webAppUrl = `http://${host}:${webPort}?port=${apiPort}`;
|
|
965
|
+
}
|
|
966
|
+
} else {
|
|
967
|
+
if (apiPort === 8042) {
|
|
968
|
+
webAppUrl = webUrl;
|
|
969
|
+
} else {
|
|
970
|
+
webAppUrl = `${webUrl}?port=${apiPort}`;
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
console.log(import_chalk4.default.cyan(`\u{1F517} Open this URL in your browser: ${webAppUrl}`));
|
|
974
|
+
console.log(import_chalk4.default.gray(` API Server: http://${host}:${apiPort}`));
|
|
975
|
+
console.log(import_chalk4.default.cyan("Press Ctrl+C to stop the API server"));
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
// src/index.ts
|
|
979
|
+
import_commander.program.name("adk").description(package_default.description).version(package_default.version);
|
|
980
|
+
import_commander.program.command("new").description("Create a new ADK project").argument("[project-name]", "Name of the project to create").option(
|
|
981
|
+
"-t, --template <template>",
|
|
982
|
+
"Template to use (simple-agent, discord-bot, telegram-bot, hono-server, mcp-starter)",
|
|
983
|
+
"simple-agent"
|
|
984
|
+
).action(async (projectName, options) => {
|
|
985
|
+
try {
|
|
986
|
+
await createProject(projectName, options);
|
|
987
|
+
} catch (error) {
|
|
988
|
+
console.error(import_chalk5.default.red("Error creating project:"), error);
|
|
989
|
+
process.exit(1);
|
|
990
|
+
}
|
|
991
|
+
});
|
|
992
|
+
import_commander.program.command("run").description("Start an interactive chat with an agent").argument(
|
|
993
|
+
"[agent-path]",
|
|
994
|
+
"Path to specific agent (optional - will show selector if multiple agents found)"
|
|
995
|
+
).option("-s, --server", "Start ADK server only (without chat interface)").option(
|
|
996
|
+
"-h, --host <host>",
|
|
997
|
+
"Host for server (when using --server)",
|
|
998
|
+
"localhost"
|
|
999
|
+
).action(async (agentPath, options) => {
|
|
1000
|
+
try {
|
|
1001
|
+
await runAgent(agentPath, options);
|
|
1002
|
+
} catch (error) {
|
|
1003
|
+
console.error(import_chalk5.default.red("Error running agent:"), error);
|
|
1004
|
+
process.exit(1);
|
|
1005
|
+
}
|
|
1006
|
+
});
|
|
1007
|
+
import_commander.program.command("web").description("Start a web interface for testing agents").option("-p, --port <port>", "Port for API server", "8042").option("--web-port <port>", "Port for web app (when using --local)", "3000").option("-h, --host <host>", "Host for servers", "localhost").option(
|
|
1008
|
+
"-d, --dir <directory>",
|
|
1009
|
+
"Directory to scan for agents (default: current directory)",
|
|
1010
|
+
"."
|
|
1011
|
+
).option(
|
|
1012
|
+
"--local",
|
|
1013
|
+
"Run local web app instead of opening production URL",
|
|
1014
|
+
false
|
|
1015
|
+
).option(
|
|
1016
|
+
"--web-url <url>",
|
|
1017
|
+
"URL of the web application (used when not --local)",
|
|
1018
|
+
"https://adk-web.iqai.com"
|
|
1019
|
+
).action(async (options) => {
|
|
1020
|
+
try {
|
|
1021
|
+
await webCommand(options);
|
|
1022
|
+
} catch (error) {
|
|
1023
|
+
console.error(import_chalk5.default.red("Error starting web UI:"), error);
|
|
1024
|
+
process.exit(1);
|
|
1025
|
+
}
|
|
1026
|
+
});
|
|
1027
|
+
import_commander.program.command("serve").description("Start an API server for agent management").option("-p, --port <port>", "Port for the server", "8042").option("-h, --host <host>", "Host for the server", "localhost").option(
|
|
1028
|
+
"-d, --dir <directory>",
|
|
1029
|
+
"Directory to scan for agents (default: current directory)",
|
|
1030
|
+
"."
|
|
1031
|
+
).action(async (options) => {
|
|
1032
|
+
try {
|
|
1033
|
+
await serveCommand(options);
|
|
1034
|
+
} catch (error) {
|
|
1035
|
+
console.error(import_chalk5.default.red("Error starting server:"), error);
|
|
1036
|
+
process.exit(1);
|
|
1037
|
+
}
|
|
1038
|
+
});
|
|
1039
|
+
import_commander.program.parse();
|
|
1040
|
+
//# sourceMappingURL=index.js.map
|