create-bk-agent 0.23.3 → 0.23.5

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.
Files changed (42) hide show
  1. package/dist/src/add/patcher.js +106 -68
  2. package/dist/src/scaffold.js +28 -15
  3. package/package.json +2 -2
  4. package/templates/base/autonomous/package.json +1 -1
  5. package/templates/base/autonomous/src/index.ts +83 -83
  6. package/templates/base/coding/package.json +1 -1
  7. package/templates/base/enterprise/package.json +1 -1
  8. package/templates/base/minimal/package.json +1 -1
  9. package/templates/base/minimal/src/index.ts +43 -43
  10. package/templates/base/multi-agent/package.json +2 -2
  11. package/templates/base/multi-agent/src/engine.ts +78 -78
  12. package/templates/base/orchestrator/_common/package.json +1 -1
  13. package/templates/base/single/package.json +2 -2
  14. package/templates/base/single/src/engine.ts +67 -67
  15. package/templates/autonomous/.env.example +0 -8
  16. package/templates/autonomous/package.json +0 -25
  17. package/templates/autonomous/src/index.ts +0 -64
  18. package/templates/autonomous/tsconfig.json +0 -16
  19. package/templates/base/multi-agent/src/providers/openai-compatible.ts +0 -104
  20. package/templates/base/single/src/providers/openai-compatible.ts +0 -104
  21. package/templates/coding/.env.example +0 -8
  22. package/templates/coding/package.json +0 -26
  23. package/templates/coding/src/index.ts +0 -42
  24. package/templates/coding/tsconfig.json +0 -17
  25. package/templates/domain-agent/.env.example +0 -7
  26. package/templates/domain-agent/package.json +0 -27
  27. package/templates/domain-agent/src/agents/orchestrator.ts +0 -22
  28. package/templates/domain-agent/src/agents/specialist-a.ts +0 -17
  29. package/templates/domain-agent/src/agents/specialist-b.ts +0 -16
  30. package/templates/domain-agent/src/config.ts +0 -19
  31. package/templates/domain-agent/src/engine.ts +0 -49
  32. package/templates/domain-agent/src/index.ts +0 -27
  33. package/templates/domain-agent/src/providers/openai-compatible.ts +0 -104
  34. package/templates/domain-agent/src/tools/example-tools.ts +0 -28
  35. package/templates/domain-agent/tsconfig.json +0 -17
  36. package/templates/mcp-server/package.json +0 -30
  37. package/templates/mcp-server/src/server.ts +0 -40
  38. package/templates/mcp-server/src/tools/example.ts +0 -10
  39. package/templates/mcp-server/tsconfig.json +0 -16
  40. package/templates/minimal/package.json +0 -25
  41. package/templates/minimal/src/index.ts +0 -40
  42. package/templates/minimal/tsconfig.json +0 -16
@@ -134,87 +134,125 @@ function addPackageDevDependency(pkgFile, depName, version) {
134
134
  fs.writeFileSync(pkgFile, JSON.stringify(pkg, null, 2) + '\n');
135
135
  return true;
136
136
  }
137
- // ── AgentEngine options patcher ───────────────────────────────────────────────
138
137
  /**
139
- * Adds `mcpServers: [{ name, url }]` to the first AgentEngine constructor call.
140
- * If mcpServers already exists, appends a new entry to the existing array.
141
- * Returns true on success.
138
+ * `mcpServers` is an option of createBaseEngine only. AgentEngine takes an `mcpManager`, so patching
139
+ * `mcpServers` into `new AgentEngine({...})` produced code that does not compile (an unknown property).
142
140
  */
143
- function addMcpServerEntry(file, name, url) {
144
- const content = fs.readFileSync(file, 'utf-8');
145
- const entry = ` { name: '${name}', url: '${url}' },`;
146
- if (content.includes(`url: '${url}'`))
147
- return true; // already registered
148
- if (content.includes('mcpServers:')) {
149
- // Append into existing array — insert after 'mcpServers: ['
150
- const updated = content.replace(/(mcpServers:\s*\[)/, `$1\n${entry}`);
151
- if (updated === content)
152
- return false;
153
- fs.writeFileSync(file, updated);
154
- return true;
155
- }
156
- // Insert new mcpServers block before the closing of AgentEngine({ ... })
157
- const lines = content.split('\n');
141
+ function findEngineCall(content) {
142
+ const base = content.search(/createBaseEngine\s*\(\s*\{/);
143
+ if (base !== -1)
144
+ return { kind: 'base', open: content.indexOf('{', base) };
145
+ const engine = content.search(/new AgentEngine\s*\(\s*\{/);
146
+ if (engine !== -1)
147
+ return { kind: 'engine', open: content.indexOf('{', engine) };
148
+ return null;
149
+ }
150
+ /** Index of the `}` that closes the object literal opened at `open`, skipping strings, templates and comments. */
151
+ function matchingBrace(content, open) {
158
152
  let depth = 0;
159
- let engineStart = -1;
160
- let closeIdx = -1;
161
- for (let i = 0; i < lines.length; i++) {
162
- if (lines[i].includes('new AgentEngine({')) {
163
- engineStart = i;
164
- depth = 0;
153
+ for (let i = open; i < content.length; i++) {
154
+ const c = content[i];
155
+ const next = content[i + 1];
156
+ if (c === '/' && next === '/') {
157
+ i = content.indexOf('\n', i);
158
+ if (i === -1)
159
+ return -1;
160
+ continue;
161
+ }
162
+ if (c === '/' && next === '*') {
163
+ i = content.indexOf('*/', i + 2);
164
+ if (i === -1)
165
+ return -1;
166
+ i++;
167
+ continue;
168
+ }
169
+ if (c === "'" || c === '"') {
170
+ for (i++; i < content.length && content[i] !== c; i++)
171
+ if (content[i] === '\\')
172
+ i++;
173
+ continue;
165
174
  }
166
- if (engineStart !== -1) {
167
- depth += (lines[i].match(/\{/g) ?? []).length;
168
- depth -= (lines[i].match(/\}/g) ?? []).length;
169
- if (depth === 0 && i > engineStart) {
170
- closeIdx = i;
171
- break;
175
+ if (c === '`') {
176
+ for (i++; i < content.length && content[i] !== '`'; i++) {
177
+ if (content[i] === '\\') {
178
+ i++;
179
+ continue;
180
+ }
181
+ if (content[i] === '$' && content[i + 1] === '{') {
182
+ const inner = matchingBrace(content, i + 1);
183
+ if (inner === -1)
184
+ return -1;
185
+ i = inner;
186
+ }
172
187
  }
188
+ continue;
173
189
  }
190
+ if (c === '{')
191
+ depth++;
192
+ else if (c === '}' && --depth === 0)
193
+ return i;
174
194
  }
175
- if (closeIdx === -1)
176
- return false;
177
- lines.splice(closeIdx, 0, ` mcpServers: [\n${entry}\n ],`);
178
- fs.writeFileSync(file, lines.join('\n'));
179
- return true;
195
+ return -1;
180
196
  }
181
197
  /**
182
- * Adds a stdio MCP entry `{ name, transport: 'stdio', command, args }` to AgentEngine.
183
- * If mcpServers already exists, appends. Returns true on success.
198
+ * Registers one MCP server entry (an object literal source) in the project's engine:
199
+ * appends to an existing list, or adds the option, keeping the file valid TypeScript.
184
200
  */
185
- function addMcpStdioEntry(file, name, npmPackage) {
201
+ function addMcpEntry(file, entry, alreadyThere) {
186
202
  const content = fs.readFileSync(file, 'utf-8');
187
- const entry = ` { name: '${name}', transport: 'stdio' as const, command: 'npx', args: ['-y', '${npmPackage}'] },`;
188
- if (content.includes(`'${npmPackage}'`))
189
- return true; // already registered
190
- if (content.includes('mcpServers:')) {
191
- const updated = content.replace(/(mcpServers:\s*\[)/, `$1\n${entry}`);
192
- if (updated === content)
193
- return false;
194
- fs.writeFileSync(file, updated);
203
+ if (content.includes(alreadyThere))
204
+ return true;
205
+ const call = findEngineCall(content);
206
+ if (!call)
207
+ return false;
208
+ const line = ` ${entry},`;
209
+ // An existing list: add to its start.
210
+ const existing = call.kind === 'base' ? /mcpServers:\s*\[/ : /new MCPClientManager\(\s*\[/;
211
+ const m = existing.exec(content);
212
+ if (m) {
213
+ fs.writeFileSync(file, content.slice(0, m.index + m[0].length) + '\n' + line + content.slice(m.index + m[0].length));
195
214
  return true;
196
215
  }
197
- const lines = content.split('\n');
198
- let depth = 0;
199
- let engineStart = -1;
200
- let closeIdx = -1;
201
- for (let i = 0; i < lines.length; i++) {
202
- if (lines[i].includes('new AgentEngine({')) {
203
- engineStart = i;
204
- depth = 0;
205
- }
206
- if (engineStart !== -1) {
207
- depth += (lines[i].match(/\{/g) ?? []).length;
208
- depth -= (lines[i].match(/\}/g) ?? []).length;
209
- if (depth === 0 && i > engineStart) {
210
- closeIdx = i;
211
- break;
212
- }
213
- }
214
- }
215
- if (closeIdx === -1)
216
+ // No list yet: add the option just before the closing brace of the options object.
217
+ const close = matchingBrace(content, call.open);
218
+ if (close === -1)
216
219
  return false;
217
- lines.splice(closeIdx, 0, ` mcpServers: [\n${entry}\n ],`);
218
- fs.writeFileSync(file, lines.join('\n'));
220
+ const before = content.slice(0, close).replace(/\s+$/, '');
221
+ const needsComma = !/[,{]$/.test(before); // the last property may have no trailing comma
222
+ const option = call.kind === 'base'
223
+ ? ` mcpServers: [\n${line}\n ],`
224
+ : ` mcpManager: new MCPClientManager([\n${line}\n ]),`;
225
+ fs.writeFileSync(file, before + (needsComma ? ',' : '') + '\n' + option + '\n' + content.slice(close));
226
+ if (call.kind === 'engine')
227
+ addMcpManagerImport(file);
219
228
  return true;
220
229
  }
230
+ /** Makes `MCPClientManager` available from agent-core: into the existing import, or as a new one. */
231
+ function addMcpManagerImport(file) {
232
+ const content = fs.readFileSync(file, 'utf-8');
233
+ if (/\bMCPClientManager\b[^;]*from\s+['"]@backendkit-labs\/agent-core['"]/.test(content))
234
+ return;
235
+ const named = /import\s*\{([^}]*)\}\s*from\s*(['"])@backendkit-labs\/agent-core\2/.exec(content);
236
+ if (named) {
237
+ const names = named[1].replace(/\s+$/, '');
238
+ const sep = names.trim().endsWith(',') ? '' : ',';
239
+ const multiline = named[1].includes('\n');
240
+ const added = multiline ? `${names}${sep}\n MCPClientManager,\n` : `${names}${sep} MCPClientManager `;
241
+ fs.writeFileSync(file, content.replace(named[0], `import {${added}} from ${named[2]}@backendkit-labs/agent-core${named[2]}`));
242
+ return;
243
+ }
244
+ addImportLine(file, "import { MCPClientManager } from '@backendkit-labs/agent-core';");
245
+ }
246
+ /**
247
+ * Adds a remote MCP server `{ name, url }` to the engine of a generated project (createBaseEngine or AgentEngine).
248
+ * Appends if a list exists. Returns true on success.
249
+ */
250
+ function addMcpServerEntry(file, name, url) {
251
+ return addMcpEntry(file, `{ name: '${name}', url: '${url}' }`, `url: '${url}'`);
252
+ }
253
+ /**
254
+ * Adds a stdio MCP server `{ name, command: 'npx', args: ['-y', pkg] }`. Returns true on success.
255
+ */
256
+ function addMcpStdioEntry(file, name, npmPackage) {
257
+ return addMcpEntry(file, `{ name: '${name}', command: 'npx', args: ['-y', '${npmPackage}'] }`, `'${npmPackage}'`);
258
+ }
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.GENERATED_DEP_RANGES = void 0;
36
+ exports.ORCHESTRATOR_PROVIDERS = exports.GENERATED_DEP_RANGES = exports.PROVIDER_ENV = exports.PROVIDER_DEFAULTS = void 0;
37
37
  exports.scaffold = scaffold;
38
38
  exports.installDeps = installDeps;
39
39
  const fs = __importStar(require("fs"));
@@ -46,11 +46,23 @@ const DEPLOY_DIR = path.join(TEMPLATES_DIR, 'deploy');
46
46
  // The rest (coding, autonomous, minimal) are self-contained in base/.
47
47
  const LAYERED = ['multi-agent', 'single', 'enterprise'];
48
48
  // ── Provider env var hints ────────────────────────────────────────────────────
49
- const PROVIDER_ENV = {
50
- anthropic: { varName: 'ANTHROPIC_API_KEY', placeholder: 'sk-ant-...', model: 'claude-sonnet-4-6' },
51
- openai: { varName: 'OPENAI_API_KEY', placeholder: 'sk-...', model: 'gpt-4o', baseUrl: 'https://api.openai.com/v1' },
52
- deepseek: { varName: 'LLM_API_KEY', placeholder: 'sk-...', model: 'deepseek-chat', baseUrl: 'https://api.deepseek.com/v1' },
53
- ollama: { varName: 'OLLAMA_BASE_URL', placeholder: 'http://localhost:11434', model: 'llama3.2' },
49
+ /**
50
+ * What is true of a provider whichever kind of project is generated: its default model and API endpoint.
51
+ * The two tables below (project .env, orchestrator.yaml) used to repeat these and could drift apart.
52
+ * Each keeps its own environment-variable naming, which does differ on purpose (a generated project reads
53
+ * `LLM_API_KEY` for DeepSeek, the orchestrator `DEEPSEEK_API_KEY`).
54
+ */
55
+ exports.PROVIDER_DEFAULTS = {
56
+ anthropic: { model: 'claude-sonnet-4-6' },
57
+ openai: { model: 'gpt-4o', baseUrl: 'https://api.openai.com/v1' },
58
+ deepseek: { model: 'deepseek-chat', baseUrl: 'https://api.deepseek.com/v1' },
59
+ ollama: { model: 'llama3.2' },
60
+ };
61
+ exports.PROVIDER_ENV = {
62
+ anthropic: { varName: 'ANTHROPIC_API_KEY', placeholder: 'sk-ant-...', ...exports.PROVIDER_DEFAULTS.anthropic },
63
+ openai: { varName: 'OPENAI_API_KEY', placeholder: 'sk-...', ...exports.PROVIDER_DEFAULTS.openai },
64
+ deepseek: { varName: 'LLM_API_KEY', placeholder: 'sk-...', ...exports.PROVIDER_DEFAULTS.deepseek },
65
+ ollama: { varName: 'OLLAMA_BASE_URL', placeholder: 'http://localhost:11434', ...exports.PROVIDER_DEFAULTS.ollama },
54
66
  };
55
67
  // ── Copy directory (overlay-safe) ─────────────────────────────────────────────
56
68
  // dst may already exist from the base layer — files are overwritten, dirs merged.
@@ -135,7 +147,7 @@ function writeEnv(dir, provider, choices) {
135
147
  fs.writeFileSync(envFile, content);
136
148
  return;
137
149
  }
138
- const p = PROVIDER_ENV[provider];
150
+ const p = exports.PROVIDER_ENV[provider];
139
151
  const content = [
140
152
  '# Generated by create-bk-agent',
141
153
  `${p.varName}=${p.placeholder}`,
@@ -168,14 +180,15 @@ function injectSkillPack(targetDir, pack) {
168
180
  ].join('\n');
169
181
  fs.appendFileSync(engineFile, block + '\n');
170
182
  }
171
- const ORCHESTRATOR_PROVIDERS = {
172
- deepseek: { id: 'deepseek', keyVar: 'DEEPSEEK_API_KEY', model: 'deepseek-chat', baseUrl: 'https://api.deepseek.com/v1' },
173
- anthropic: { id: 'anthropic', keyVar: 'ANTHROPIC_API_KEY', model: 'claude-sonnet-4-6' },
174
- openai: { id: 'openai', keyVar: 'OPENAI_API_KEY', model: 'gpt-4o', baseUrl: 'https://api.openai.com/v1' },
175
- ollama: { id: 'ollama', keyVar: '', model: 'llama3.2', baseUrl: 'http://localhost:11434' },
183
+ exports.ORCHESTRATOR_PROVIDERS = {
184
+ deepseek: { id: 'deepseek', keyVar: 'DEEPSEEK_API_KEY', ...exports.PROVIDER_DEFAULTS.deepseek },
185
+ anthropic: { id: 'anthropic', keyVar: 'ANTHROPIC_API_KEY', ...exports.PROVIDER_DEFAULTS.anthropic },
186
+ openai: { id: 'openai', keyVar: 'OPENAI_API_KEY', ...exports.PROVIDER_DEFAULTS.openai },
187
+ // orchestrator.yaml wants an explicit base_url for Ollama; a generated project reads it from OLLAMA_BASE_URL instead
188
+ ollama: { id: 'ollama', keyVar: '', ...exports.PROVIDER_DEFAULTS.ollama, baseUrl: 'http://localhost:11434' },
176
189
  };
177
190
  function buildProvidersBlock(provider) {
178
- const p = ORCHESTRATOR_PROVIDERS[provider];
191
+ const p = exports.ORCHESTRATOR_PROVIDERS[provider];
179
192
  const lines = ['providers:', ` ${p.id}:`];
180
193
  if (p.keyVar)
181
194
  lines.push(` api_key: \${${p.keyVar}}`);
@@ -197,7 +210,7 @@ function scaffoldOrchestrator(choices, targetDir) {
197
210
  const orchYaml = path.join(targetDir, 'orchestrator.yaml');
198
211
  if (fs.existsSync(orchYaml)) {
199
212
  let content = fs.readFileSync(orchYaml, 'utf-8');
200
- const providerId = ORCHESTRATOR_PROVIDERS[choices.provider].id;
213
+ const providerId = exports.ORCHESTRATOR_PROVIDERS[choices.provider].id;
201
214
  const providersBlock = buildProvidersBlock(choices.provider);
202
215
  content = content.replace(/__PROVIDER_ID__/g, providerId);
203
216
  content = content.replace('__PROVIDERS_BLOCK__', providersBlock);
@@ -214,7 +227,7 @@ function scaffoldOrchestrator(choices, targetDir) {
214
227
  const envExample = path.join(targetDir, '.env.example');
215
228
  const envFile = path.join(targetDir, '.env');
216
229
  if (fs.existsSync(envExample) && !fs.existsSync(envFile)) {
217
- const p = ORCHESTRATOR_PROVIDERS[choices.provider];
230
+ const p = exports.ORCHESTRATOR_PROVIDERS[choices.provider];
218
231
  const keyLine = p.keyVar
219
232
  ? `${p.keyVar}=your-api-key-here`
220
233
  : `# No API key needed for Ollama\nOLLAMA_BASE_URL=${p.baseUrl}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-bk-agent",
3
- "version": "0.23.3",
3
+ "version": "0.23.5",
4
4
  "description": "Create a new BackendKit agent project",
5
5
  "main": "dist/src/index.js",
6
6
  "bin": {
@@ -28,7 +28,7 @@
28
28
  "test": "jest"
29
29
  },
30
30
  "peerDependencies": {
31
- "@backendkit-labs/agent-core": ">=0.24.0 <0.36.0"
31
+ "@backendkit-labs/agent-core": ">=0.24.0 <0.38.0"
32
32
  },
33
33
  "peerDependenciesMeta": {
34
34
  "@backendkit-labs/agent-core": {
@@ -11,7 +11,7 @@
11
11
  "typecheck": "tsc --noEmit"
12
12
  },
13
13
  "dependencies": {
14
- "@backendkit-labs/agent-core": "^0.35.0",
14
+ "@backendkit-labs/agent-core": "^0.37.0",
15
15
  "dotenv": "^16.0.0"
16
16
  },
17
17
  "devDependencies": {
@@ -1,83 +1,83 @@
1
- import 'dotenv/config';
2
- import * as os from 'os';
3
- import * as path from 'path';
4
- import { createAutonomousAgent, createMemorySystem } from '@backendkit-labs/agent-core';
5
- import type { AgentProfile } from '@backendkit-labs/agent-core';
6
-
7
- // ── Agent definition ──────────────────────────────────────────────────────────
8
-
9
- const monitorAgent: AgentProfile = {
10
- id: 'monitor',
11
- name: 'Monitor',
12
- icon: '👁',
13
- description: 'Monitors events and executes scheduled tasks',
14
- allowedTools: [],
15
- delegatesTo: [],
16
- systemPrompt: `You are an autonomous monitor agent.
17
- // TODO: describe what this agent monitors and what actions it takes.
18
- When activated by a trigger, analyze the input and take appropriate action.`,
19
- };
20
-
21
- // ── Provider ──────────────────────────────────────────────────────────────────
22
-
23
- const provider = process.env.LLM_PROVIDER ?? 'anthropic';
24
- const apiKey = process.env.ANTHROPIC_API_KEY ?? process.env.OPENAI_API_KEY ?? '';
25
-
26
- if (!apiKey) { console.error('Missing API key'); process.exit(1); }
27
-
28
- // ── Memory — persists context between trigger executions ──────────────────────
29
-
30
- const APP_DIR = path.join(os.homedir(), '.my-autonomous-agent');
31
- const MEM_DIR = path.join(APP_DIR, 'memory');
32
-
33
- const memory = createMemorySystem({
34
- episodic: { provider: 'json', path: path.join(MEM_DIR, 'episodes.json') },
35
- semantic: { provider: 'json', path: path.join(MEM_DIR, 'knowledge.json') },
36
- procedural: { provider: 'json', path: path.join(MEM_DIR, 'patterns.json') },
37
- retention: { maxEpisodes: 200 },
38
- });
39
-
40
- // ── Autonomous agent ──────────────────────────────────────────────────────────
41
-
42
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
43
- const agent = createAutonomousAgent({
44
- providers: { [provider]: { apiKey } } as any,
45
- defaultProvider: provider,
46
- agents: [monitorAgent],
47
- defaultAgent: 'monitor',
48
- goal: 'TODO: describe the agent goal',
49
- memorySystem: memory,
50
-
51
- triggers: [
52
- // Run every day at 9:00 AM
53
- {
54
- type: 'schedule',
55
- cron: '0 9 * * *',
56
- task: 'Run daily check and report findings',
57
- },
58
-
59
- // Listen for webhook events (e.g. from GitHub, Slack, etc.)
60
- {
61
- type: 'webhook',
62
- path: '/events',
63
- // secret: process.env.WEBHOOK_SECRET,
64
- },
65
-
66
- // TODO: add more triggers as needed
67
- // { type: 'event', topic: 'my.custom.event' },
68
- ],
69
-
70
- webhookPort: parseInt(process.env.WEBHOOK_PORT ?? '3000'),
71
- });
72
-
73
- // ── Start ─────────────────────────────────────────────────────────────────────
74
-
75
- void (async () => {
76
- await agent.start();
77
- console.log('Autonomous agent started.');
78
- console.log('Webhook listening on port', process.env.WEBHOOK_PORT ?? 3000);
79
- console.log(`Memory stored in: ${APP_DIR}`);
80
-
81
- process.on('SIGTERM', async () => { await agent.stop(); process.exit(0); });
82
- process.on('SIGINT', async () => { await agent.stop(); process.exit(0); });
83
- })();
1
+ import 'dotenv/config';
2
+ import * as os from 'os';
3
+ import * as path from 'path';
4
+ import { createAutonomousAgent, createMemorySystem } from '@backendkit-labs/agent-core';
5
+ import type { AgentProfile } from '@backendkit-labs/agent-core';
6
+
7
+ // ── Agent definition ──────────────────────────────────────────────────────────
8
+
9
+ const monitorAgent: AgentProfile = {
10
+ id: 'monitor',
11
+ name: 'Monitor',
12
+ icon: '👁',
13
+ description: 'Monitors events and executes scheduled tasks',
14
+ allowedTools: [], // the tools this agent may call, by name; empty means none (a tool that is registered but not listed here is refused)
15
+ delegatesTo: [],
16
+ systemPrompt: `You are an autonomous monitor agent.
17
+ // TODO: describe what this agent monitors and what actions it takes.
18
+ When activated by a trigger, analyze the input and take appropriate action.`,
19
+ };
20
+
21
+ // ── Provider ──────────────────────────────────────────────────────────────────
22
+
23
+ const provider = process.env.LLM_PROVIDER ?? 'anthropic';
24
+ const apiKey = process.env.ANTHROPIC_API_KEY ?? process.env.OPENAI_API_KEY ?? '';
25
+
26
+ if (!apiKey) { console.error('Missing API key'); process.exit(1); }
27
+
28
+ // ── Memory — persists context between trigger executions ──────────────────────
29
+
30
+ const APP_DIR = path.join(os.homedir(), '.my-autonomous-agent');
31
+ const MEM_DIR = path.join(APP_DIR, 'memory');
32
+
33
+ const memory = createMemorySystem({
34
+ episodic: { provider: 'json', path: path.join(MEM_DIR, 'episodes.json') },
35
+ semantic: { provider: 'json', path: path.join(MEM_DIR, 'knowledge.json') },
36
+ procedural: { provider: 'json', path: path.join(MEM_DIR, 'patterns.json') },
37
+ retention: { maxEpisodes: 200 },
38
+ });
39
+
40
+ // ── Autonomous agent ──────────────────────────────────────────────────────────
41
+
42
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
43
+ const agent = createAutonomousAgent({
44
+ providers: { [provider]: { apiKey } } as any,
45
+ defaultProvider: provider,
46
+ agents: [monitorAgent],
47
+ defaultAgent: 'monitor',
48
+ goal: 'TODO: describe the agent goal',
49
+ memorySystem: memory,
50
+
51
+ triggers: [
52
+ // Run every day at 9:00 AM
53
+ {
54
+ type: 'schedule',
55
+ cron: '0 9 * * *',
56
+ task: 'Run daily check and report findings',
57
+ },
58
+
59
+ // Listen for webhook events (e.g. from GitHub, Slack, etc.)
60
+ {
61
+ type: 'webhook',
62
+ path: '/events',
63
+ // secret: process.env.WEBHOOK_SECRET,
64
+ },
65
+
66
+ // TODO: add more triggers as needed
67
+ // { type: 'event', topic: 'my.custom.event' },
68
+ ],
69
+
70
+ webhookPort: parseInt(process.env.WEBHOOK_PORT ?? '3000'),
71
+ });
72
+
73
+ // ── Start ─────────────────────────────────────────────────────────────────────
74
+
75
+ void (async () => {
76
+ await agent.start();
77
+ console.log('Autonomous agent started.');
78
+ console.log('Webhook listening on port', process.env.WEBHOOK_PORT ?? 3000);
79
+ console.log(`Memory stored in: ${APP_DIR}`);
80
+
81
+ process.on('SIGTERM', async () => { await agent.stop(); process.exit(0); });
82
+ process.on('SIGINT', async () => { await agent.stop(); process.exit(0); });
83
+ })();
@@ -12,7 +12,7 @@
12
12
  },
13
13
  "dependencies": {
14
14
  "@backendkit-labs/agent-coding": "^0.28.0",
15
- "@backendkit-labs/agent-core": "^0.35.0",
15
+ "@backendkit-labs/agent-core": "^0.37.0",
16
16
  "dotenv": "^16.0.0"
17
17
  },
18
18
  "devDependencies": {
@@ -12,7 +12,7 @@
12
12
  "typecheck": "tsc --noEmit"
13
13
  },
14
14
  "dependencies": {
15
- "@backendkit-labs/agent-core": "^0.35.0",
15
+ "@backendkit-labs/agent-core": "^0.37.0",
16
16
  "@backendkit-labs/agent-coding": "^0.28.0",
17
17
  "@backendkit-labs/agent-enterprise": "^0.8.0",
18
18
  "dotenv": "^16.0.0",
@@ -11,7 +11,7 @@
11
11
  "typecheck": "tsc --noEmit"
12
12
  },
13
13
  "dependencies": {
14
- "@backendkit-labs/agent-core": "^0.35.0",
14
+ "@backendkit-labs/agent-core": "^0.37.0",
15
15
  "dotenv": "^16.0.0"
16
16
  },
17
17
  "devDependencies": {
@@ -1,43 +1,43 @@
1
- import 'dotenv/config';
2
- import { createBaseEngine } from '@backendkit-labs/agent-core';
3
- import type { AgentProfile, LLMProvider } from '@backendkit-labs/agent-core';
4
-
5
- // ── Provider ──────────────────────────────────────────────────────────────────
6
- // TODO: replace with the actual provider for your chosen LLM
7
- // e.g. AnthropicProvider from @backendkit-labs/agent-coding
8
- // or implement LLMProvider interface directly
9
-
10
- const myProvider: LLMProvider = {
11
- chat: async (_messages, _tools, callbacks) => {
12
- // TODO: call your LLM API here
13
- callbacks.onDone({ role: 'assistant', content: 'Hello from my agent!' });
14
- },
15
- };
16
-
17
- // ── Agent ─────────────────────────────────────────────────────────────────────
18
-
19
- const myAgent: AgentProfile = {
20
- id: 'my-agent',
21
- name: 'My Agent',
22
- icon: '🤖',
23
- description: 'TODO: describe your agent',
24
- allowedTools: [],
25
- delegatesTo: [],
26
- systemPrompt: 'TODO: write your system prompt here.',
27
- };
28
-
29
- // ── Engine ────────────────────────────────────────────────────────────────────
30
-
31
- const engine = createBaseEngine({
32
- providers: { default: myProvider },
33
- defaultProvider: 'default',
34
- agents: [myAgent],
35
- defaultAgent: 'my-agent',
36
- });
37
-
38
- // ── Run ───────────────────────────────────────────────────────────────────────
39
-
40
- void (async () => {
41
- const input = process.argv[2] ?? 'Hello';
42
- await engine.run(input);
43
- })();
1
+ import 'dotenv/config';
2
+ import { createBaseEngine } from '@backendkit-labs/agent-core';
3
+ import type { AgentProfile, LLMProvider } from '@backendkit-labs/agent-core';
4
+
5
+ // ── Provider ──────────────────────────────────────────────────────────────────
6
+ // TODO: replace with the actual provider for your chosen LLM
7
+ // e.g. AnthropicProvider from @backendkit-labs/agent-coding
8
+ // or implement LLMProvider interface directly
9
+
10
+ const myProvider: LLMProvider = {
11
+ chat: async (_messages, _tools, callbacks) => {
12
+ // TODO: call your LLM API here
13
+ callbacks.onDone({ role: 'assistant', content: 'Hello from my agent!' });
14
+ },
15
+ };
16
+
17
+ // ── Agent ─────────────────────────────────────────────────────────────────────
18
+
19
+ const myAgent: AgentProfile = {
20
+ id: 'my-agent',
21
+ name: 'My Agent',
22
+ icon: '🤖',
23
+ description: 'TODO: describe your agent',
24
+ allowedTools: [], // the tools this agent may call, by name; empty means none (a tool that is registered but not listed here is refused)
25
+ delegatesTo: [],
26
+ systemPrompt: 'TODO: write your system prompt here.',
27
+ };
28
+
29
+ // ── Engine ────────────────────────────────────────────────────────────────────
30
+
31
+ const engine = createBaseEngine({
32
+ providers: { default: myProvider },
33
+ defaultProvider: 'default',
34
+ agents: [myAgent],
35
+ defaultAgent: 'my-agent',
36
+ });
37
+
38
+ // ── Run ───────────────────────────────────────────────────────────────────────
39
+
40
+ void (async () => {
41
+ const input = process.argv[2] ?? 'Hello';
42
+ await engine.run(input);
43
+ })();
@@ -12,9 +12,9 @@
12
12
  "typecheck": "tsc --noEmit"
13
13
  },
14
14
  "dependencies": {
15
- "@backendkit-labs/agent-core": "^0.35.0",
15
+ "@backendkit-labs/agent-core": "^0.37.0",
16
+ "@backendkit-labs/agent-providers": "^0.3.3",
16
17
  "dotenv": "^16.0.0",
17
- "openai": "^4.0.0",
18
18
  "zod": "^4.6.6"
19
19
  },
20
20
  "devDependencies": {