@inkeep/agents-cli 0.0.0-dev-20250910233151
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/LICENSE.md +56 -0
- package/README.md +500 -0
- package/dist/commands/create.d.ts +12 -0
- package/dist/commands/create.js +728 -0
- package/dist/config.d.ts +14 -0
- package/dist/config.js +9 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +38240 -0
- package/package.json +84 -0
|
@@ -0,0 +1,728 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/commands/create.ts
|
|
4
|
+
import color from "picocolors";
|
|
5
|
+
import * as p from "@clack/prompts";
|
|
6
|
+
import fs from "fs-extra";
|
|
7
|
+
import { exec } from "child_process";
|
|
8
|
+
import { promisify } from "util";
|
|
9
|
+
import path from "path";
|
|
10
|
+
var execAsync = promisify(exec);
|
|
11
|
+
var createAgents = async (args = {}) => {
|
|
12
|
+
let { tenantId, projectId, dirName, openAiKey, anthropicKey, manageApiPort, runApiPort } = args;
|
|
13
|
+
p.intro(color.inverse(" Create Agents Directory "));
|
|
14
|
+
if (!dirName) {
|
|
15
|
+
const dirResponse = await p.text({
|
|
16
|
+
message: "What do you want to name your agents directory?",
|
|
17
|
+
placeholder: "agents",
|
|
18
|
+
defaultValue: "agents",
|
|
19
|
+
validate: (value) => {
|
|
20
|
+
if (!value || value.trim() === "") {
|
|
21
|
+
return "Directory name is required";
|
|
22
|
+
}
|
|
23
|
+
return void 0;
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
if (p.isCancel(dirResponse)) {
|
|
27
|
+
p.cancel("Operation cancelled");
|
|
28
|
+
process.exit(0);
|
|
29
|
+
}
|
|
30
|
+
dirName = dirResponse;
|
|
31
|
+
}
|
|
32
|
+
if (!tenantId) {
|
|
33
|
+
const tenantIdResponse = await p.text({
|
|
34
|
+
message: "Enter your tenant ID :",
|
|
35
|
+
placeholder: "(default)",
|
|
36
|
+
defaultValue: "default"
|
|
37
|
+
});
|
|
38
|
+
if (p.isCancel(tenantIdResponse)) {
|
|
39
|
+
p.cancel("Operation cancelled");
|
|
40
|
+
process.exit(0);
|
|
41
|
+
}
|
|
42
|
+
tenantId = tenantIdResponse;
|
|
43
|
+
}
|
|
44
|
+
if (!projectId) {
|
|
45
|
+
const projectIdResponse = await p.text({
|
|
46
|
+
message: "Enter your project ID:",
|
|
47
|
+
placeholder: "(default)",
|
|
48
|
+
defaultValue: "default"
|
|
49
|
+
});
|
|
50
|
+
if (p.isCancel(projectIdResponse)) {
|
|
51
|
+
p.cancel("Operation cancelled");
|
|
52
|
+
process.exit(0);
|
|
53
|
+
}
|
|
54
|
+
projectId = projectIdResponse;
|
|
55
|
+
}
|
|
56
|
+
if (!anthropicKey) {
|
|
57
|
+
const anthropicKeyResponse = await p.text({
|
|
58
|
+
message: "Enter your Anthropic API key (recommended):",
|
|
59
|
+
placeholder: "sk-ant-...",
|
|
60
|
+
defaultValue: ""
|
|
61
|
+
});
|
|
62
|
+
if (p.isCancel(anthropicKeyResponse)) {
|
|
63
|
+
p.cancel("Operation cancelled");
|
|
64
|
+
process.exit(0);
|
|
65
|
+
}
|
|
66
|
+
anthropicKey = anthropicKeyResponse || void 0;
|
|
67
|
+
}
|
|
68
|
+
if (!openAiKey) {
|
|
69
|
+
const openAiKeyResponse = await p.text({
|
|
70
|
+
message: "Enter your OpenAI API key (optional):",
|
|
71
|
+
placeholder: "sk-...",
|
|
72
|
+
defaultValue: ""
|
|
73
|
+
});
|
|
74
|
+
if (p.isCancel(openAiKeyResponse)) {
|
|
75
|
+
p.cancel("Operation cancelled");
|
|
76
|
+
process.exit(0);
|
|
77
|
+
}
|
|
78
|
+
openAiKey = openAiKeyResponse || void 0;
|
|
79
|
+
}
|
|
80
|
+
const s = p.spinner();
|
|
81
|
+
s.start("Creating directory structure...");
|
|
82
|
+
try {
|
|
83
|
+
const directoryPath = path.resolve(process.cwd(), dirName);
|
|
84
|
+
if (await fs.pathExists(directoryPath)) {
|
|
85
|
+
s.stop();
|
|
86
|
+
const overwrite = await p.confirm({
|
|
87
|
+
message: `Directory ${dirName} already exists. Do you want to overwrite it?`
|
|
88
|
+
});
|
|
89
|
+
if (p.isCancel(overwrite) || !overwrite) {
|
|
90
|
+
p.cancel("Operation cancelled");
|
|
91
|
+
process.exit(0);
|
|
92
|
+
}
|
|
93
|
+
s.start("Cleaning existing directory...");
|
|
94
|
+
await fs.emptyDir(directoryPath);
|
|
95
|
+
}
|
|
96
|
+
await fs.ensureDir(directoryPath);
|
|
97
|
+
process.chdir(directoryPath);
|
|
98
|
+
const config = {
|
|
99
|
+
dirName,
|
|
100
|
+
tenantId,
|
|
101
|
+
projectId,
|
|
102
|
+
openAiKey,
|
|
103
|
+
anthropicKey,
|
|
104
|
+
manageApiPort: manageApiPort || "3002",
|
|
105
|
+
runApiPort: runApiPort || "3003"
|
|
106
|
+
};
|
|
107
|
+
s.message("Setting up workspace structure...");
|
|
108
|
+
await createWorkspaceStructure(projectId);
|
|
109
|
+
s.message("Creating package configurations...");
|
|
110
|
+
await setupPackageConfigurations(dirName);
|
|
111
|
+
s.message("Setting up environment files...");
|
|
112
|
+
await createEnvironmentFiles(config);
|
|
113
|
+
s.message("Creating service files...");
|
|
114
|
+
await createServiceFiles(config);
|
|
115
|
+
s.message("Creating documentation...");
|
|
116
|
+
await createDocumentation(config);
|
|
117
|
+
s.message("Setting up Turbo...");
|
|
118
|
+
await createTurboConfig();
|
|
119
|
+
s.message("Installing dependencies (this may take a while)...");
|
|
120
|
+
await installDependencies();
|
|
121
|
+
s.message("Setting up database...");
|
|
122
|
+
await setupDatabase();
|
|
123
|
+
s.stop();
|
|
124
|
+
p.note(
|
|
125
|
+
`${color.green("\u2713")} Project created at: ${color.cyan(directoryPath)}
|
|
126
|
+
|
|
127
|
+
${color.yellow("Next steps:")}
|
|
128
|
+
cd ${dirName}
|
|
129
|
+
npm run dev (for APIs only)
|
|
130
|
+
npx inkeep dev (for APIs + Management Dashboard)
|
|
131
|
+
|
|
132
|
+
${color.yellow("Available services:")}
|
|
133
|
+
\u2022 Management API: http://localhost:${manageApiPort || "3002"}
|
|
134
|
+
\u2022 Execution API: http://localhost:${runApiPort || "3003"}
|
|
135
|
+
\u2022 Management Dashboard: Available with 'npx inkeep dev'
|
|
136
|
+
|
|
137
|
+
${color.yellow("Configuration:")}
|
|
138
|
+
\u2022 Edit .env for environment variables
|
|
139
|
+
\u2022 Edit src/${projectId}/hello.graph.ts for agent definitions
|
|
140
|
+
\u2022 Use 'npx inkeep push' to deploy agents to the platform
|
|
141
|
+
\u2022 Use 'npx inkeep chat' to test your agents locally
|
|
142
|
+
`,
|
|
143
|
+
"Ready to go!"
|
|
144
|
+
);
|
|
145
|
+
} catch (error) {
|
|
146
|
+
s.stop();
|
|
147
|
+
p.cancel(
|
|
148
|
+
`Error creating directory: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
149
|
+
);
|
|
150
|
+
process.exit(1);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
async function createWorkspaceStructure(projectId) {
|
|
154
|
+
await fs.ensureDir(`src/${projectId}`);
|
|
155
|
+
await fs.ensureDir("apps/manage-api/src");
|
|
156
|
+
await fs.ensureDir("apps/run-api/src");
|
|
157
|
+
await fs.ensureDir("apps/shared");
|
|
158
|
+
}
|
|
159
|
+
async function setupPackageConfigurations(dirName) {
|
|
160
|
+
const rootPackageJson = {
|
|
161
|
+
name: dirName,
|
|
162
|
+
version: "0.1.0",
|
|
163
|
+
description: "An Inkeep Agent Framework directory",
|
|
164
|
+
private: true,
|
|
165
|
+
type: "module",
|
|
166
|
+
scripts: {
|
|
167
|
+
dev: "turbo dev",
|
|
168
|
+
"db:push": "drizzle-kit push"
|
|
169
|
+
},
|
|
170
|
+
dependencies: {},
|
|
171
|
+
devDependencies: {
|
|
172
|
+
"@biomejs/biome": "^1.8.0",
|
|
173
|
+
"@inkeep/agents-cli": "^0.1.1",
|
|
174
|
+
"drizzle-kit": "^0.31.4",
|
|
175
|
+
tsx: "^4.19.0",
|
|
176
|
+
turbo: "^2.5.5"
|
|
177
|
+
},
|
|
178
|
+
engines: {
|
|
179
|
+
node: ">=22.x"
|
|
180
|
+
},
|
|
181
|
+
packageManager: "npm@10.0.0",
|
|
182
|
+
workspaces: ["apps/*"]
|
|
183
|
+
};
|
|
184
|
+
await fs.writeJson("package.json", rootPackageJson, { spaces: 2 });
|
|
185
|
+
rootPackageJson.dependencies = {
|
|
186
|
+
"@inkeep/agents-core": "^0.1.0",
|
|
187
|
+
"@inkeep/agents-sdk": "^0.1.0",
|
|
188
|
+
zod: "^4.1.5"
|
|
189
|
+
};
|
|
190
|
+
await fs.writeJson("package.json", rootPackageJson, { spaces: 2 });
|
|
191
|
+
const manageApiPackageJson = {
|
|
192
|
+
name: `@${dirName}/manage-api`,
|
|
193
|
+
version: "0.1.0",
|
|
194
|
+
description: "Management API for agents",
|
|
195
|
+
type: "module",
|
|
196
|
+
scripts: {
|
|
197
|
+
build: "tsc",
|
|
198
|
+
dev: "tsx watch src/index.ts",
|
|
199
|
+
start: "node dist/index.js"
|
|
200
|
+
},
|
|
201
|
+
dependencies: {
|
|
202
|
+
"@inkeep/agents-manage-api": "^0.1.1",
|
|
203
|
+
"@inkeep/agents-core": "^0.1.0",
|
|
204
|
+
"@hono/node-server": "^1.14.3"
|
|
205
|
+
},
|
|
206
|
+
devDependencies: {
|
|
207
|
+
"@types/node": "^20.12.0",
|
|
208
|
+
tsx: "^4.19.0",
|
|
209
|
+
typescript: "^5.4.0"
|
|
210
|
+
},
|
|
211
|
+
engines: {
|
|
212
|
+
node: ">=22.x"
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
await fs.writeJson("apps/manage-api/package.json", manageApiPackageJson, { spaces: 2 });
|
|
216
|
+
const runApiPackageJson = {
|
|
217
|
+
name: `@${dirName}/run-api`,
|
|
218
|
+
version: "0.1.0",
|
|
219
|
+
description: "Run API for agents",
|
|
220
|
+
type: "module",
|
|
221
|
+
scripts: {
|
|
222
|
+
dev: "tsx watch src/index.ts",
|
|
223
|
+
start: "node dist/index.js"
|
|
224
|
+
},
|
|
225
|
+
dependencies: {
|
|
226
|
+
"@inkeep/agents-run-api": "^0.1.1",
|
|
227
|
+
"@inkeep/agents-core": "^0.1.0",
|
|
228
|
+
"@hono/node-server": "^1.14.3"
|
|
229
|
+
},
|
|
230
|
+
devDependencies: {
|
|
231
|
+
"@types/node": "^20.12.0",
|
|
232
|
+
tsx: "^4.19.0",
|
|
233
|
+
typescript: "^5.4.0"
|
|
234
|
+
},
|
|
235
|
+
engines: {
|
|
236
|
+
node: ">=22.x"
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
await fs.writeJson("apps/run-api/package.json", runApiPackageJson, { spaces: 2 });
|
|
240
|
+
const apiTsConfig = {
|
|
241
|
+
compilerOptions: {
|
|
242
|
+
target: "ES2022",
|
|
243
|
+
module: "ESNext",
|
|
244
|
+
moduleResolution: "bundler",
|
|
245
|
+
strict: true,
|
|
246
|
+
esModuleInterop: true,
|
|
247
|
+
skipLibCheck: true,
|
|
248
|
+
forceConsistentCasingInFileNames: true,
|
|
249
|
+
declaration: true,
|
|
250
|
+
outDir: "./dist",
|
|
251
|
+
rootDir: "..",
|
|
252
|
+
allowImportingTsExtensions: false,
|
|
253
|
+
resolveJsonModule: true,
|
|
254
|
+
isolatedModules: true,
|
|
255
|
+
noEmit: false
|
|
256
|
+
},
|
|
257
|
+
include: ["src/**/*", "../shared/**/*"],
|
|
258
|
+
exclude: ["node_modules", "dist", "**/*.test.ts"]
|
|
259
|
+
};
|
|
260
|
+
await fs.writeJson("apps/manage-api/tsconfig.json", apiTsConfig, { spaces: 2 });
|
|
261
|
+
await fs.writeJson("apps/run-api/tsconfig.json", apiTsConfig, { spaces: 2 });
|
|
262
|
+
}
|
|
263
|
+
async function createEnvironmentFiles(config) {
|
|
264
|
+
const envContent = `# Environment
|
|
265
|
+
ENVIRONMENT=development
|
|
266
|
+
|
|
267
|
+
# Database
|
|
268
|
+
DB_FILE_NAME=file:./local.db
|
|
269
|
+
|
|
270
|
+
# AI Provider Keys
|
|
271
|
+
ANTHROPIC_API_KEY=${config.anthropicKey || "your-anthropic-key-here"}
|
|
272
|
+
OPENAI_API_KEY=${config.openAiKey || "your-openai-key-here"}
|
|
273
|
+
|
|
274
|
+
# Logging
|
|
275
|
+
LOG_LEVEL=debug
|
|
276
|
+
|
|
277
|
+
# Service Ports
|
|
278
|
+
MANAGE_API_PORT=${config.manageApiPort}
|
|
279
|
+
RUN_API_PORT=${config.runApiPort}
|
|
280
|
+
|
|
281
|
+
# UI Configuration (for dashboard)
|
|
282
|
+
NEXT_PUBLIC_INKEEP_AGENTS_MANAGE_API_URL=http://localhost:${config.manageApiPort}
|
|
283
|
+
NEXT_PUBLIC_INKEEP_AGENTS_RUN_API_URL=http://localhost:${config.runApiPort}
|
|
284
|
+
`;
|
|
285
|
+
await fs.writeFile(".env", envContent);
|
|
286
|
+
const envExample = envContent.replace(/=.+$/gm, "=");
|
|
287
|
+
await fs.writeFile(".env.example", envExample);
|
|
288
|
+
const runApiEnvContent = `# Environment
|
|
289
|
+
ENVIRONMENT=development
|
|
290
|
+
|
|
291
|
+
# Database (relative path from API directory)
|
|
292
|
+
DB_FILE_NAME=file:../../local.db
|
|
293
|
+
|
|
294
|
+
# AI Provider Keys
|
|
295
|
+
ANTHROPIC_API_KEY=${config.anthropicKey || "your-anthropic-key-here"}
|
|
296
|
+
OPENAI_API_KEY=${config.openAiKey || "your-openai-key-here"}
|
|
297
|
+
`;
|
|
298
|
+
const manageApiEnvContent = `# Environment
|
|
299
|
+
ENVIRONMENT=development
|
|
300
|
+
|
|
301
|
+
# Database (relative path from API directory)
|
|
302
|
+
DB_FILE_NAME=file:../../local.db
|
|
303
|
+
`;
|
|
304
|
+
await fs.writeFile("apps/manage-api/.env", manageApiEnvContent);
|
|
305
|
+
await fs.writeFile("apps/run-api/.env", runApiEnvContent);
|
|
306
|
+
const gitignore = `# Dependencies
|
|
307
|
+
node_modules/
|
|
308
|
+
.pnpm-store/
|
|
309
|
+
|
|
310
|
+
# Environment variables
|
|
311
|
+
.env
|
|
312
|
+
.env.local
|
|
313
|
+
.env.development.local
|
|
314
|
+
.env.test.local
|
|
315
|
+
.env.production.local
|
|
316
|
+
|
|
317
|
+
# Build outputs
|
|
318
|
+
dist/
|
|
319
|
+
build/
|
|
320
|
+
.next/
|
|
321
|
+
.turbo/
|
|
322
|
+
|
|
323
|
+
# Logs
|
|
324
|
+
*.log
|
|
325
|
+
logs/
|
|
326
|
+
|
|
327
|
+
# Database
|
|
328
|
+
*.db
|
|
329
|
+
*.sqlite
|
|
330
|
+
*.sqlite3
|
|
331
|
+
|
|
332
|
+
# IDE
|
|
333
|
+
.vscode/
|
|
334
|
+
.idea/
|
|
335
|
+
*.swp
|
|
336
|
+
*.swo
|
|
337
|
+
|
|
338
|
+
# OS
|
|
339
|
+
.DS_Store
|
|
340
|
+
Thumbs.db
|
|
341
|
+
|
|
342
|
+
# Coverage
|
|
343
|
+
coverage/
|
|
344
|
+
.nyc_output/
|
|
345
|
+
|
|
346
|
+
# Temporary files
|
|
347
|
+
*.tmp
|
|
348
|
+
*.temp
|
|
349
|
+
.cache/
|
|
350
|
+
|
|
351
|
+
# Runtime data
|
|
352
|
+
pids/
|
|
353
|
+
*.pid
|
|
354
|
+
*.seed
|
|
355
|
+
*.pid.lock
|
|
356
|
+
`;
|
|
357
|
+
await fs.writeFile(".gitignore", gitignore);
|
|
358
|
+
const biomeConfig = {
|
|
359
|
+
linter: {
|
|
360
|
+
enabled: true,
|
|
361
|
+
rules: {
|
|
362
|
+
recommended: true
|
|
363
|
+
}
|
|
364
|
+
},
|
|
365
|
+
formatter: {
|
|
366
|
+
enabled: true,
|
|
367
|
+
indentStyle: "space",
|
|
368
|
+
indentWidth: 2
|
|
369
|
+
},
|
|
370
|
+
organizeImports: {
|
|
371
|
+
enabled: true
|
|
372
|
+
},
|
|
373
|
+
javascript: {
|
|
374
|
+
formatter: {
|
|
375
|
+
semicolons: "always",
|
|
376
|
+
quoteStyle: "single"
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
await fs.writeJson("biome.json", biomeConfig, { spaces: 2 });
|
|
381
|
+
}
|
|
382
|
+
async function createServiceFiles(config) {
|
|
383
|
+
const agentsGraph = `import { agent, agentGraph } from '@inkeep/agents-sdk';
|
|
384
|
+
|
|
385
|
+
// Router agent - the entry point that routes users to specialist agents
|
|
386
|
+
const helloAgent = agent({
|
|
387
|
+
id: 'hello',
|
|
388
|
+
name: 'Hello Agent',
|
|
389
|
+
description: 'A hello agent that just says hello.',
|
|
390
|
+
prompt: \`You are a hello agent that just says hello. You only reply with the word "hello", but you may do it in different variations like h3110, h3110w0rld, h3110w0rld! etc...\`,
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
// Create the agent graph
|
|
395
|
+
export const graph = agentGraph({
|
|
396
|
+
id: 'hello',
|
|
397
|
+
name: 'Hello Graph',
|
|
398
|
+
description: 'A graph that contains the hello agent.',
|
|
399
|
+
defaultAgent: helloAgent,
|
|
400
|
+
agents: () => [helloAgent],
|
|
401
|
+
});`;
|
|
402
|
+
await fs.writeFile(`src/${config.projectId}/hello.graph.ts`, agentsGraph);
|
|
403
|
+
const inkeepConfig = `import { defineConfig } from '@inkeep/agents-cli/config';
|
|
404
|
+
|
|
405
|
+
const config = defineConfig({
|
|
406
|
+
tenantId: "${config.tenantId}",
|
|
407
|
+
projectId: "${config.projectId}",
|
|
408
|
+
agentsManageApiUrl: \`http://localhost:\${process.env.MANAGE_API_PORT || '3002'}\`,
|
|
409
|
+
agentsRunApiUrl: \`http://localhost:\${process.env.RUN_API_PORT || '3003'}\`,
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
export default config;`;
|
|
413
|
+
await fs.writeFile(`src/${config.projectId}/inkeep.config.ts`, inkeepConfig);
|
|
414
|
+
const projectEnvContent = `# Environment
|
|
415
|
+
ENVIRONMENT=development
|
|
416
|
+
|
|
417
|
+
# Database (relative path from project directory)
|
|
418
|
+
DB_FILE_NAME=file:../../local.db
|
|
419
|
+
|
|
420
|
+
# UI Configuration (for dashboard)
|
|
421
|
+
NEXT_PUBLIC_INKEEP_AGENTS_MANAGE_API_URL=http://localhost:${config.manageApiPort}
|
|
422
|
+
NEXT_PUBLIC_INKEEP_AGENTS_RUN_API_URL=http://localhost:${config.runApiPort}
|
|
423
|
+
|
|
424
|
+
`;
|
|
425
|
+
await fs.writeFile(`src/${config.projectId}/.env`, projectEnvContent);
|
|
426
|
+
const credentialStoresFile = `import {
|
|
427
|
+
InMemoryCredentialStore,
|
|
428
|
+
createNangoCredentialStore,
|
|
429
|
+
createKeyChainStore,
|
|
430
|
+
} from '@inkeep/agents-core';
|
|
431
|
+
|
|
432
|
+
// Shared credential stores configuration for all services
|
|
433
|
+
export const credentialStores = [
|
|
434
|
+
new InMemoryCredentialStore('memory-default'),
|
|
435
|
+
...(process.env.NANGO_SECRET_KEY
|
|
436
|
+
? [
|
|
437
|
+
createNangoCredentialStore('nango-default', {
|
|
438
|
+
apiUrl: process.env.NANGO_HOST || 'https://api.nango.dev',
|
|
439
|
+
secretKey: process.env.NANGO_SECRET_KEY,
|
|
440
|
+
}),
|
|
441
|
+
]
|
|
442
|
+
: []),
|
|
443
|
+
createKeyChainStore('keychain-default'),
|
|
444
|
+
];
|
|
445
|
+
`;
|
|
446
|
+
await fs.writeFile("apps/shared/credential-stores.ts", credentialStoresFile);
|
|
447
|
+
const manageApiIndex = `import { serve } from '@hono/node-server';
|
|
448
|
+
import { createManagementApp } from '@inkeep/agents-manage-api';
|
|
449
|
+
import { getLogger } from '@inkeep/agents-core';
|
|
450
|
+
import { credentialStores } from '../../shared/credential-stores.js';
|
|
451
|
+
|
|
452
|
+
const logger = getLogger('management-api');
|
|
453
|
+
|
|
454
|
+
// Create the Hono app
|
|
455
|
+
const app = createManagementApp({
|
|
456
|
+
serverConfig: {
|
|
457
|
+
port: Number(process.env.MANAGE_API_PORT) || 3002,
|
|
458
|
+
serverOptions: {
|
|
459
|
+
requestTimeout: 60000,
|
|
460
|
+
keepAliveTimeout: 60000,
|
|
461
|
+
keepAlive: true,
|
|
462
|
+
},
|
|
463
|
+
},
|
|
464
|
+
credentialStores,
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
const port = Number(process.env.MANAGE_API_PORT) || 3002;
|
|
468
|
+
|
|
469
|
+
// Start the server using @hono/node-server
|
|
470
|
+
serve(
|
|
471
|
+
{
|
|
472
|
+
fetch: app.fetch,
|
|
473
|
+
port,
|
|
474
|
+
},
|
|
475
|
+
(info) => {
|
|
476
|
+
logger.info({}, \`\u{1F4DD} Management API running on http://localhost:\${info.port}\`);
|
|
477
|
+
logger.info({}, \`\u{1F4DD} OpenAPI documentation available at http://localhost:\${info.port}/openapi.json\`);
|
|
478
|
+
}
|
|
479
|
+
);`;
|
|
480
|
+
await fs.writeFile("apps/manage-api/src/index.ts", manageApiIndex);
|
|
481
|
+
const runApiIndex = `import { serve } from '@hono/node-server';
|
|
482
|
+
import { createExecutionApp } from '@inkeep/agents-run-api';
|
|
483
|
+
import { credentialStores } from '../../shared/credential-stores.js';
|
|
484
|
+
import { getLogger } from '@inkeep/agents-core';
|
|
485
|
+
|
|
486
|
+
const logger = getLogger('execution-api');
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
// Create the Hono app
|
|
490
|
+
const app = createExecutionApp({
|
|
491
|
+
serverConfig: {
|
|
492
|
+
port: Number(process.env.RUN_API_PORT) || 3003,
|
|
493
|
+
serverOptions: {
|
|
494
|
+
requestTimeout: 120000,
|
|
495
|
+
keepAliveTimeout: 60000,
|
|
496
|
+
keepAlive: true,
|
|
497
|
+
},
|
|
498
|
+
},
|
|
499
|
+
credentialStores,
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
const port = Number(process.env.RUN_API_PORT) || 3003;
|
|
503
|
+
|
|
504
|
+
// Start the server using @hono/node-server
|
|
505
|
+
serve(
|
|
506
|
+
{
|
|
507
|
+
fetch: app.fetch,
|
|
508
|
+
port,
|
|
509
|
+
},
|
|
510
|
+
(info) => {
|
|
511
|
+
logger.info({}, \`\u{1F4DD} Execution API running on http://localhost:\${info.port}\`);
|
|
512
|
+
logger.info({}, \`\u{1F4DD} OpenAPI documentation available at http://localhost:\${info.port}/openapi.json\`);
|
|
513
|
+
}
|
|
514
|
+
);`;
|
|
515
|
+
await fs.writeFile("apps/run-api/src/index.ts", runApiIndex);
|
|
516
|
+
const drizzleConfig = `import { defineConfig } from 'drizzle-kit';
|
|
517
|
+
|
|
518
|
+
export default defineConfig({
|
|
519
|
+
schema: 'node_modules/@inkeep/agents-core/dist/db/schema.js',
|
|
520
|
+
dialect: 'sqlite',
|
|
521
|
+
dbCredentials: {
|
|
522
|
+
url: process.env.DB_FILE_NAME || 'file:./local.db'
|
|
523
|
+
},
|
|
524
|
+
});`;
|
|
525
|
+
await fs.writeFile("drizzle.config.ts", drizzleConfig);
|
|
526
|
+
}
|
|
527
|
+
async function createTurboConfig() {
|
|
528
|
+
const turboConfig = {
|
|
529
|
+
$schema: "https://turbo.build/schema.json",
|
|
530
|
+
ui: "tui",
|
|
531
|
+
globalDependencies: ["**/.env", "**/.env.local", "**/.env.*"],
|
|
532
|
+
globalEnv: [
|
|
533
|
+
"NODE_ENV",
|
|
534
|
+
"CI",
|
|
535
|
+
"ANTHROPIC_API_KEY",
|
|
536
|
+
"OPENAI_API_KEY",
|
|
537
|
+
"ENVIRONMENT",
|
|
538
|
+
"DB_FILE_NAME",
|
|
539
|
+
"MANAGE_API_PORT",
|
|
540
|
+
"RUN_API_PORT",
|
|
541
|
+
"LOG_LEVEL",
|
|
542
|
+
"NANGO_SECRET_KEY"
|
|
543
|
+
],
|
|
544
|
+
tasks: {
|
|
545
|
+
build: {
|
|
546
|
+
dependsOn: ["^build"],
|
|
547
|
+
inputs: ["$TURBO_DEFAULT$", ".env*"],
|
|
548
|
+
outputs: ["dist/**", "build/**", ".next/**", "!.next/cache/**"]
|
|
549
|
+
},
|
|
550
|
+
dev: {
|
|
551
|
+
cache: false,
|
|
552
|
+
persistent: true
|
|
553
|
+
},
|
|
554
|
+
start: {
|
|
555
|
+
dependsOn: ["build"],
|
|
556
|
+
cache: false
|
|
557
|
+
},
|
|
558
|
+
"db:push": {
|
|
559
|
+
cache: false,
|
|
560
|
+
inputs: ["drizzle.config.ts", "src/data/db/schema.ts"]
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
};
|
|
564
|
+
await fs.writeJson("turbo.json", turboConfig, { spaces: 2 });
|
|
565
|
+
}
|
|
566
|
+
async function createDocumentation(config) {
|
|
567
|
+
const readme = `# ${config.dirName}
|
|
568
|
+
|
|
569
|
+
An Inkeep Agent Framework project with multi-service architecture.
|
|
570
|
+
|
|
571
|
+
## Architecture
|
|
572
|
+
|
|
573
|
+
This project follows a workspace structure with the following services:
|
|
574
|
+
|
|
575
|
+
- **Agents Management API** (Port 3002): Agent configuration and managemen
|
|
576
|
+
- Handles entity management and configuration endpoints.
|
|
577
|
+
- **Agents Run API** (Port 3003): Agent execution and chat processing
|
|
578
|
+
- Handles agent communication. You can interact with your agents either over MCP from an MCP client or through our React UI components library
|
|
579
|
+
- **Management Dashboard** (Port 3000): Web interface available via \`npx inkeep dev\`
|
|
580
|
+
- The agent framework visual builder. From the builder you can create, manage and visualize all your graphs.
|
|
581
|
+
|
|
582
|
+
## Quick Start
|
|
583
|
+
|
|
584
|
+
1. **Start services:**
|
|
585
|
+
\`\`\`bash
|
|
586
|
+
# Start Agents Management API and Agents Run API
|
|
587
|
+
npm run dev
|
|
588
|
+
|
|
589
|
+
# Start Dashboard
|
|
590
|
+
npx inkeep dev
|
|
591
|
+
\`\`\`
|
|
592
|
+
|
|
593
|
+
3. **Deploy your first agent graph:**
|
|
594
|
+
\`\`\`bash
|
|
595
|
+
# Navigate to your project's graph directory
|
|
596
|
+
cd src/${config.projectId}/
|
|
597
|
+
|
|
598
|
+
# Push the hello graph to create it
|
|
599
|
+
npx inkeep push hello.graph.ts
|
|
600
|
+
\`\`\`
|
|
601
|
+
- Follow the prompts to create the project and graph
|
|
602
|
+
- Click on the "View graph in UI:" link to see the graph in the management dashboard
|
|
603
|
+
|
|
604
|
+
## Project Structure
|
|
605
|
+
|
|
606
|
+
\`\`\`
|
|
607
|
+
${config.dirName}/
|
|
608
|
+
\u251C\u2500\u2500 src/
|
|
609
|
+
\u2502 \u251C\u2500\u2500 /${config.projectId} # Agent configurations
|
|
610
|
+
\u251C\u2500\u2500 apps/
|
|
611
|
+
\u2502 \u251C\u2500\u2500 manage-api/ # Agents Management API service
|
|
612
|
+
\u2502 \u251C\u2500\u2500 run-api/ # Agents Run API service
|
|
613
|
+
\u2502 \u2514\u2500\u2500 shared/ # Shared code between API services
|
|
614
|
+
\u2502 \u2514\u2500\u2500 credential-stores.ts # Shared credential store configuration
|
|
615
|
+
\u251C\u2500\u2500 turbo.json # Turbo configuration
|
|
616
|
+
\u2514\u2500\u2500 package.json # Root package configuration with npm workspaces
|
|
617
|
+
\`\`\`
|
|
618
|
+
|
|
619
|
+
## Configuration
|
|
620
|
+
|
|
621
|
+
### Environment Variables
|
|
622
|
+
|
|
623
|
+
Environment variables are defined in the following places:
|
|
624
|
+
|
|
625
|
+
- \`apps/manage-api/.env\`: Agents Management API environment variables
|
|
626
|
+
- \`apps/run-api/.env\`: Agents Run API environment variables
|
|
627
|
+
- \`src/${config.projectId}/.env\`: Inkeep CLI environment variables
|
|
628
|
+
- \`.env\`: Root environment variables
|
|
629
|
+
|
|
630
|
+
To change the API keys used by your agents modify \`apps/run-api/.env\`. You are required to define at least one LLM provider key.
|
|
631
|
+
|
|
632
|
+
\`\`\`bash
|
|
633
|
+
# AI Provider Keys
|
|
634
|
+
ANTHROPIC_API_KEY=your-anthropic-key-here
|
|
635
|
+
OPENAI_API_KEY=your-openai-key-here
|
|
636
|
+
\`\`\`
|
|
637
|
+
|
|
638
|
+
To change the ports used by your services modify \`apps/manage-api/.env\` and \`apps/run-api/.env\` respectively:
|
|
639
|
+
|
|
640
|
+
\`\`\`bash
|
|
641
|
+
# Service port for apps/run-api
|
|
642
|
+
RUN_API_PORT=3003
|
|
643
|
+
|
|
644
|
+
# Service port for apps/manage-api
|
|
645
|
+
MANAGE_API_PORT
|
|
646
|
+
\`\`\`
|
|
647
|
+
|
|
648
|
+
After changing the API Service ports make sure that you modify the dashboard API urls from whichever directory you are running \`npx inkeep dev\`:
|
|
649
|
+
|
|
650
|
+
\`\`\`bash
|
|
651
|
+
# UI Configuration (for dashboard)
|
|
652
|
+
NEXT_PUBLIC_INKEEP_AGENTS_MANAGE_API_URL=http://localhost:${config.manageApiPort}
|
|
653
|
+
NEXT_PUBLIC_INKEEP_AGENTS_RUN_API_URL=http://localhost:${config.runApiPort}
|
|
654
|
+
\`\`\`
|
|
655
|
+
|
|
656
|
+
### Agent Configuration
|
|
657
|
+
|
|
658
|
+
Your agents are defined in \`src/${config.projectId}/index.ts\`. The default setup includes:
|
|
659
|
+
|
|
660
|
+
- **Hello Agent**: A hello agent that just says hello.
|
|
661
|
+
|
|
662
|
+
Your inkeep configuration is defined in \`src/${config.projectId}/inkeep.config.ts\`. The inkeep configuration is used to configure defaults for the inkeep CLI. The configuration includes:
|
|
663
|
+
|
|
664
|
+
- \`tenantId\`: The tenant ID
|
|
665
|
+
- \`projectId\`: The project ID
|
|
666
|
+
- \`agentsManageApiUrl\`: The management API URL
|
|
667
|
+
- \`agentsRunApiUrl\`: The execution API URL
|
|
668
|
+
|
|
669
|
+
|
|
670
|
+
## Development
|
|
671
|
+
|
|
672
|
+
### Updating Your Agents
|
|
673
|
+
|
|
674
|
+
1. Edit \`src/${config.projectId}/index.ts\`
|
|
675
|
+
2. Push the graph to the platform to update: \`npx inkeep push hello.graph.ts\`
|
|
676
|
+
|
|
677
|
+
### API Documentation
|
|
678
|
+
|
|
679
|
+
Once services are running, view the OpenAPI documentation:
|
|
680
|
+
|
|
681
|
+
- Management API: http://localhost:${config.manageApiPort}/docs
|
|
682
|
+
- Execution API: http://localhost:${config.runApiPort}/docs
|
|
683
|
+
|
|
684
|
+
## Learn More
|
|
685
|
+
|
|
686
|
+
- [Inkeep Documentation](https://docs.inkeep.com)
|
|
687
|
+
|
|
688
|
+
## Troubleshooting
|
|
689
|
+
|
|
690
|
+
## Inkeep CLI commands
|
|
691
|
+
|
|
692
|
+
- Ensure you are runnning commands from \`cd src/${config.projectId}\`.
|
|
693
|
+
- Validate the \`inkeep.config.ts\` file has the correct api urls.
|
|
694
|
+
- Validate that the \`.env\` file in \`src/${config.projectId}\` has the correct \`DB_FILE_NAME\`.
|
|
695
|
+
|
|
696
|
+
### Services won't start
|
|
697
|
+
|
|
698
|
+
1. Ensure all dependencies are installed: \`npm install\`
|
|
699
|
+
2. Check that ports 3000-3003 are available
|
|
700
|
+
|
|
701
|
+
### Agents won't respond
|
|
702
|
+
|
|
703
|
+
1. Ensure that the Agents Run API is running and includes a valid Anthropic or OpenAI API key in its .env file
|
|
704
|
+
`;
|
|
705
|
+
await fs.writeFile("README.md", readme);
|
|
706
|
+
}
|
|
707
|
+
async function installDependencies() {
|
|
708
|
+
await execAsync("npm install");
|
|
709
|
+
}
|
|
710
|
+
async function setupDatabase() {
|
|
711
|
+
try {
|
|
712
|
+
await execAsync("npx drizzle-kit push");
|
|
713
|
+
} catch (error) {
|
|
714
|
+
throw new Error(
|
|
715
|
+
`Failed to setup database: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
716
|
+
);
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
async function createCommand(dirName, options) {
|
|
720
|
+
await createAgents({
|
|
721
|
+
dirName,
|
|
722
|
+
...options
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
export {
|
|
726
|
+
createAgents,
|
|
727
|
+
createCommand
|
|
728
|
+
};
|