@alejandroroman/agent-kit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_memory/config.d.ts +14 -0
- package/dist/_memory/config.js +16 -0
- package/dist/_memory/db/client.d.ts +2 -0
- package/dist/_memory/db/client.js +15 -0
- package/dist/_memory/db/schema.d.ts +14 -0
- package/dist/_memory/db/schema.js +51 -0
- package/dist/_memory/embeddings/ollama.d.ts +12 -0
- package/dist/_memory/embeddings/ollama.js +22 -0
- package/dist/_memory/embeddings/provider.d.ts +4 -0
- package/dist/_memory/embeddings/provider.js +1 -0
- package/dist/_memory/index.d.ts +10 -0
- package/dist/_memory/index.js +6 -0
- package/dist/_memory/search.d.ts +30 -0
- package/dist/_memory/search.js +121 -0
- package/dist/_memory/server.d.ts +8 -0
- package/dist/_memory/server.js +126 -0
- package/dist/_memory/store.d.ts +51 -0
- package/dist/_memory/store.js +115 -0
- package/dist/agent/loop.d.ts +3 -0
- package/dist/agent/loop.js +195 -0
- package/dist/agent/setup.d.ts +6 -0
- package/dist/agent/setup.js +11 -0
- package/dist/agent/soul.d.ts +1 -0
- package/dist/agent/soul.js +8 -0
- package/dist/agent/types.d.ts +23 -0
- package/dist/agent/types.js +1 -0
- package/dist/api/agents.d.ts +2 -0
- package/dist/api/agents.js +43 -0
- package/dist/api/config.d.ts +2 -0
- package/dist/api/config.js +20 -0
- package/dist/api/cron.d.ts +2 -0
- package/dist/api/cron.js +15 -0
- package/dist/api/health.d.ts +2 -0
- package/dist/api/health.js +8 -0
- package/dist/api/logs.d.ts +5 -0
- package/dist/api/logs.js +28 -0
- package/dist/api/router.d.ts +6 -0
- package/dist/api/router.js +80 -0
- package/dist/api/sessions.d.ts +2 -0
- package/dist/api/sessions.js +67 -0
- package/dist/api/types.d.ts +12 -0
- package/dist/api/types.js +13 -0
- package/dist/api/usage.d.ts +3 -0
- package/dist/api/usage.js +50 -0
- package/dist/bootstrap.d.ts +51 -0
- package/dist/bootstrap.js +110 -0
- package/dist/cli/chat.d.ts +1 -0
- package/dist/cli/chat.js +102 -0
- package/dist/cli/config-writer.d.ts +40 -0
- package/dist/cli/config-writer.js +108 -0
- package/dist/cli/create.d.ts +1 -0
- package/dist/cli/create.js +37 -0
- package/dist/cli/init.d.ts +1 -0
- package/dist/cli/init.js +85 -0
- package/dist/cli/list.d.ts +1 -0
- package/dist/cli/list.js +36 -0
- package/dist/cli/ollama.d.ts +6 -0
- package/dist/cli/ollama.js +44 -0
- package/dist/cli/setup-agent/index.d.ts +9 -0
- package/dist/cli/setup-agent/index.js +100 -0
- package/dist/cli/setup-agent/soul.d.ts +2 -0
- package/dist/cli/setup-agent/soul.js +79 -0
- package/dist/cli/setup-agent/tools.d.ts +9 -0
- package/dist/cli/setup-agent/tools.js +362 -0
- package/dist/cli/start.d.ts +1 -0
- package/dist/cli/start.js +235 -0
- package/dist/cli/ui.d.ts +17 -0
- package/dist/cli/ui.js +79 -0
- package/dist/cli/validate.d.ts +1 -0
- package/dist/cli/validate.js +47 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.js +59 -0
- package/dist/config/index.d.ts +4 -0
- package/dist/config/index.js +3 -0
- package/dist/config/loader.d.ts +2 -0
- package/dist/config/loader.js +10 -0
- package/dist/config/resolve.d.ts +22 -0
- package/dist/config/resolve.js +45 -0
- package/dist/config/schema.d.ts +217 -0
- package/dist/config/schema.js +159 -0
- package/dist/cron/scheduler.d.ts +22 -0
- package/dist/cron/scheduler.js +115 -0
- package/dist/gateways/slack/client.d.ts +13 -0
- package/dist/gateways/slack/client.js +44 -0
- package/dist/gateways/slack/format.d.ts +30 -0
- package/dist/gateways/slack/format.js +170 -0
- package/dist/gateways/slack/handler.d.ts +9 -0
- package/dist/gateways/slack/handler.js +95 -0
- package/dist/gateways/slack/index.d.ts +16 -0
- package/dist/gateways/slack/index.js +102 -0
- package/dist/gateways/slack/listener.d.ts +10 -0
- package/dist/gateways/slack/listener.js +35 -0
- package/dist/gateways/slack/sessions.d.ts +11 -0
- package/dist/gateways/slack/sessions.js +32 -0
- package/dist/gateways/slack/types.d.ts +13 -0
- package/dist/gateways/slack/types.js +7 -0
- package/dist/heartbeat/index.d.ts +2 -0
- package/dist/heartbeat/index.js +1 -0
- package/dist/heartbeat/runner.d.ts +31 -0
- package/dist/heartbeat/runner.js +215 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +207 -0
- package/dist/llm/anthropic.d.ts +12 -0
- package/dist/llm/anthropic.js +89 -0
- package/dist/llm/fallback.d.ts +6 -0
- package/dist/llm/fallback.js +30 -0
- package/dist/llm/index.d.ts +9 -0
- package/dist/llm/index.js +40 -0
- package/dist/llm/openai.d.ts +12 -0
- package/dist/llm/openai.js +85 -0
- package/dist/llm/provider.d.ts +12 -0
- package/dist/llm/provider.js +9 -0
- package/dist/llm/types.d.ts +73 -0
- package/dist/llm/types.js +6 -0
- package/dist/logger.d.ts +2 -0
- package/dist/logger.js +15 -0
- package/dist/multi/registry.d.ts +15 -0
- package/dist/multi/registry.js +28 -0
- package/dist/multi/spawn.d.ts +14 -0
- package/dist/multi/spawn.js +14 -0
- package/dist/scripts/validate-agent-cli.d.ts +1 -0
- package/dist/scripts/validate-agent-cli.js +47 -0
- package/dist/scripts/validate-agent.d.ts +17 -0
- package/dist/scripts/validate-agent.js +242 -0
- package/dist/session/compaction.d.ts +4 -0
- package/dist/session/compaction.js +30 -0
- package/dist/session/manager.d.ts +9 -0
- package/dist/session/manager.js +41 -0
- package/dist/skills/activate.d.ts +11 -0
- package/dist/skills/activate.js +62 -0
- package/dist/skills/index.d.ts +3 -0
- package/dist/skills/index.js +3 -0
- package/dist/skills/loader.d.ts +3 -0
- package/dist/skills/loader.js +20 -0
- package/dist/skills/schema.d.ts +8 -0
- package/dist/skills/schema.js +7 -0
- package/dist/text.d.ts +8 -0
- package/dist/text.js +24 -0
- package/dist/tools/builtin/index.d.ts +21 -0
- package/dist/tools/builtin/index.js +21 -0
- package/dist/tools/builtin/memory.d.ts +8 -0
- package/dist/tools/builtin/memory.js +164 -0
- package/dist/tools/builtin/read-file.d.ts +3 -0
- package/dist/tools/builtin/read-file.js +30 -0
- package/dist/tools/builtin/run-command.d.ts +3 -0
- package/dist/tools/builtin/run-command.js +37 -0
- package/dist/tools/builtin/spawn.d.ts +15 -0
- package/dist/tools/builtin/spawn.js +59 -0
- package/dist/tools/builtin/web-search.d.ts +8 -0
- package/dist/tools/builtin/web-search.js +99 -0
- package/dist/tools/builtin/write-file.d.ts +3 -0
- package/dist/tools/builtin/write-file.js +34 -0
- package/dist/tools/registry.d.ts +10 -0
- package/dist/tools/registry.js +26 -0
- package/dist/tools/sandbox.d.ts +9 -0
- package/dist/tools/sandbox.js +74 -0
- package/dist/tools/types.d.ts +8 -0
- package/dist/tools/types.js +7 -0
- package/dist/usage/index.d.ts +4 -0
- package/dist/usage/index.js +3 -0
- package/dist/usage/pricing.d.ts +10 -0
- package/dist/usage/pricing.js +35 -0
- package/dist/usage/schema.d.ts +1 -0
- package/dist/usage/schema.js +45 -0
- package/dist/usage/store.d.ts +10 -0
- package/dist/usage/store.js +227 -0
- package/dist/usage/types.d.ts +61 -0
- package/dist/usage/types.js +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import * as readline from "readline";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import { loadConfig } from "../config/index.js";
|
|
4
|
+
import { runAgentLoop } from "../agent/loop.js";
|
|
5
|
+
import { compactMessages } from "../session/compaction.js";
|
|
6
|
+
import { CronScheduler } from "../cron/scheduler.js";
|
|
7
|
+
import { HeartbeatRunner } from "../heartbeat/index.js";
|
|
8
|
+
import { createSlackGateway } from "../gateways/slack/index.js";
|
|
9
|
+
import { createApiServer } from "../api/router.js";
|
|
10
|
+
import { createLogger } from "../logger.js";
|
|
11
|
+
import { buildAgentRuntime, buildSystemPrompt, initUsageStore, createAgentExecutor, } from "../bootstrap.js";
|
|
12
|
+
import { ensureOllama } from "./ollama.js";
|
|
13
|
+
import { resolveApiKey } from "./ui.js";
|
|
14
|
+
const log = createLogger("start");
|
|
15
|
+
const CONFIG_PATH = path.join(process.cwd(), "agent-kit.json");
|
|
16
|
+
const DATA_DIR = path.join(process.cwd(), "data");
|
|
17
|
+
const SKILLS_DIR = path.join(process.cwd(), "skills");
|
|
18
|
+
const DEFAULT_AGENT = "default";
|
|
19
|
+
export async function start() {
|
|
20
|
+
await resolveApiKey({ save: false });
|
|
21
|
+
const config = loadConfig(CONFIG_PATH);
|
|
22
|
+
// Ollama check (warn only)
|
|
23
|
+
if (config.defaults.memory) {
|
|
24
|
+
const ollama = await ensureOllama();
|
|
25
|
+
if (!ollama.running) {
|
|
26
|
+
log.warn("Ollama not running — memory tools unavailable");
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const { usageStore, apiPort } = initUsageStore(config);
|
|
30
|
+
const apiServer = createApiServer({
|
|
31
|
+
config,
|
|
32
|
+
configPath: CONFIG_PATH,
|
|
33
|
+
usageStore,
|
|
34
|
+
dataDir: DATA_DIR,
|
|
35
|
+
}, apiPort);
|
|
36
|
+
// Build primary agent runtime (for REPL)
|
|
37
|
+
const agentName = process.argv[3] ?? DEFAULT_AGENT;
|
|
38
|
+
if (!config.agents[agentName]) {
|
|
39
|
+
const names = Object.keys(config.agents).join(", ");
|
|
40
|
+
console.error(`Agent "${agentName}" not found. Available: ${names}`);
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
const runtime = buildAgentRuntime(agentName, config, {
|
|
44
|
+
dataDir: DATA_DIR,
|
|
45
|
+
skillsDir: SKILLS_DIR,
|
|
46
|
+
usageStore,
|
|
47
|
+
});
|
|
48
|
+
runtime.toolRegistry.validateAgents(config.agents);
|
|
49
|
+
const { resolved, toolRegistry, agentRegistry, promptFragments, skillsIndex, soul, session } = runtime;
|
|
50
|
+
// Cron scheduler
|
|
51
|
+
const scheduler = new CronScheduler(config, toolRegistry, agentRegistry, DATA_DIR, SKILLS_DIR, usageStore);
|
|
52
|
+
const enabledJobs = scheduler.getJobs().filter((j) => j.enabled);
|
|
53
|
+
// Agent executor for Slack
|
|
54
|
+
const executeAgent = createAgentExecutor(config, {
|
|
55
|
+
dataDir: DATA_DIR,
|
|
56
|
+
skillsDir: SKILLS_DIR,
|
|
57
|
+
agentRegistry,
|
|
58
|
+
usageStore,
|
|
59
|
+
source: "slack",
|
|
60
|
+
});
|
|
61
|
+
// Slack gateway
|
|
62
|
+
let gateway;
|
|
63
|
+
const hasSlackBindings = Object.values(config.agents).some((a) => a.slack);
|
|
64
|
+
if (hasSlackBindings && process.env.SLACK_BOT_TOKEN && process.env.SLACK_APP_TOKEN) {
|
|
65
|
+
try {
|
|
66
|
+
gateway = createSlackGateway(config, { onAgentRequest: executeAgent });
|
|
67
|
+
await gateway.start();
|
|
68
|
+
const bindingCount = Object.values(config.agents).filter((a) => a.slack).length;
|
|
69
|
+
log.info({ bindings: bindingCount }, "Slack connected");
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
log.warn({ err }, "Slack failed to connect");
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// API server
|
|
76
|
+
try {
|
|
77
|
+
const actualPort = await apiServer.start();
|
|
78
|
+
log.info({ port: actualPort }, "API server started");
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
log.warn({ err }, "failed to start API server");
|
|
82
|
+
}
|
|
83
|
+
// Cron
|
|
84
|
+
if (enabledJobs.length > 0) {
|
|
85
|
+
scheduler.start({
|
|
86
|
+
onResult: (jobId, agentName, result) => {
|
|
87
|
+
log.info({ jobId, tokens: result.usage.inputTokens + result.usage.outputTokens }, "cron job completed");
|
|
88
|
+
process.stdout.write("You: ");
|
|
89
|
+
const channelOverride = config.cron.find((j) => j.id === jobId)?.slack?.channelId;
|
|
90
|
+
gateway?.onJobResult(agentName, jobId, result, channelOverride).catch((err) => log.warn({ err, jobId }, "failed to post cron result to Slack"));
|
|
91
|
+
},
|
|
92
|
+
onError: (jobId, agentName, error) => {
|
|
93
|
+
log.error({ err: error, jobId }, "cron job failed");
|
|
94
|
+
process.stdout.write("You: ");
|
|
95
|
+
const channelOverride = config.cron.find((j) => j.id === jobId)?.slack?.channelId;
|
|
96
|
+
gateway?.onJobError(agentName, jobId, error, channelOverride).catch((err) => log.warn({ err, jobId }, "failed to post cron error to Slack"));
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
// Heartbeat
|
|
101
|
+
const heartbeat = new HeartbeatRunner(config, agentRegistry, DATA_DIR, SKILLS_DIR, usageStore);
|
|
102
|
+
const heartbeatAgents = heartbeat.getHeartbeatAgents();
|
|
103
|
+
if (heartbeatAgents.length > 0) {
|
|
104
|
+
heartbeat.start({
|
|
105
|
+
onResult: (agentName, result) => {
|
|
106
|
+
log.info({ agent: agentName, tokens: result.usage.inputTokens + result.usage.outputTokens }, "heartbeat alert");
|
|
107
|
+
process.stdout.write("You: ");
|
|
108
|
+
const channelOverride = config.agents[agentName]?.heartbeat?.slack?.channelId;
|
|
109
|
+
gateway?.onJobResult(agentName, "heartbeat", result, channelOverride).catch((err) => log.warn({ err, agent: agentName }, "failed to post heartbeat result to Slack"));
|
|
110
|
+
},
|
|
111
|
+
onError: (agentName, error) => {
|
|
112
|
+
log.error({ err: error, agent: agentName }, "heartbeat failed");
|
|
113
|
+
process.stdout.write("You: ");
|
|
114
|
+
const channelOverride = config.agents[agentName]?.heartbeat?.slack?.channelId;
|
|
115
|
+
gateway?.onJobError(agentName, "heartbeat", error, channelOverride).catch((err) => log.warn({ err, agent: agentName }, "failed to post heartbeat error to Slack"));
|
|
116
|
+
},
|
|
117
|
+
onSuppressed: (agentName) => {
|
|
118
|
+
log.debug({ agent: agentName }, "heartbeat OK, suppressed");
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
// Status dashboard
|
|
123
|
+
const agentList = Object.entries(config.agents);
|
|
124
|
+
console.log();
|
|
125
|
+
console.log(" Agent Kit");
|
|
126
|
+
console.log();
|
|
127
|
+
console.log(` Agents: ${agentList.length}`);
|
|
128
|
+
for (const [name, def] of agentList) {
|
|
129
|
+
const emoji = def.emoji ?? " ";
|
|
130
|
+
const display = def.displayName ?? name;
|
|
131
|
+
console.log(` ${emoji} ${display} (${name})`);
|
|
132
|
+
}
|
|
133
|
+
console.log();
|
|
134
|
+
console.log(` REPL agent: ${agentName} (${resolved.model})`);
|
|
135
|
+
if (enabledJobs.length > 0) {
|
|
136
|
+
console.log(` Cron: ${enabledJobs.length} job(s)`);
|
|
137
|
+
}
|
|
138
|
+
if (heartbeatAgents.length > 0) {
|
|
139
|
+
console.log(` Heartbeat: ${heartbeatAgents.join(", ")}`);
|
|
140
|
+
}
|
|
141
|
+
if (gateway) {
|
|
142
|
+
const bindingCount = Object.values(config.agents).filter((a) => a.slack).length;
|
|
143
|
+
console.log(` Slack: ${bindingCount} binding(s)`);
|
|
144
|
+
}
|
|
145
|
+
if (config.defaults.usage) {
|
|
146
|
+
console.log(` Usage: tracking enabled`);
|
|
147
|
+
}
|
|
148
|
+
console.log();
|
|
149
|
+
console.log(` Commands: /new (reset), /agents, /help, /quit`);
|
|
150
|
+
console.log();
|
|
151
|
+
// REPL
|
|
152
|
+
let messages = session.getMessages();
|
|
153
|
+
const rl = readline.createInterface({
|
|
154
|
+
input: process.stdin,
|
|
155
|
+
output: process.stdout,
|
|
156
|
+
});
|
|
157
|
+
const shutdown = async () => {
|
|
158
|
+
scheduler.stop();
|
|
159
|
+
heartbeat.stop();
|
|
160
|
+
await gateway?.stop();
|
|
161
|
+
await apiServer.stop();
|
|
162
|
+
try {
|
|
163
|
+
usageStore?.close();
|
|
164
|
+
}
|
|
165
|
+
catch { }
|
|
166
|
+
rl.close();
|
|
167
|
+
};
|
|
168
|
+
const ask = () => {
|
|
169
|
+
rl.question("You: ", async (input) => {
|
|
170
|
+
const trimmed = input.trim();
|
|
171
|
+
if (trimmed === "/quit") {
|
|
172
|
+
await shutdown();
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
if (trimmed === "/new") {
|
|
176
|
+
messages = [];
|
|
177
|
+
console.log(" Session reset.\n");
|
|
178
|
+
ask();
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
if (trimmed === "/agents") {
|
|
182
|
+
for (const [name, def] of agentList) {
|
|
183
|
+
const emoji = def.emoji ?? " ";
|
|
184
|
+
const display = def.displayName ?? name;
|
|
185
|
+
console.log(` ${emoji} ${display} (${name})`);
|
|
186
|
+
}
|
|
187
|
+
console.log();
|
|
188
|
+
ask();
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
if (trimmed === "/help") {
|
|
192
|
+
console.log(" /new — Reset conversation");
|
|
193
|
+
console.log(" /agents — List agents");
|
|
194
|
+
console.log(" /quit — Shut down\n");
|
|
195
|
+
ask();
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
if (!trimmed) {
|
|
199
|
+
ask();
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
const userMsg = { role: "user", content: trimmed };
|
|
203
|
+
messages.push(userMsg);
|
|
204
|
+
session.append(userMsg);
|
|
205
|
+
messages = await compactMessages(messages, resolved.model, resolved.compactionThreshold);
|
|
206
|
+
try {
|
|
207
|
+
const systemPrompt = buildSystemPrompt(soul, skillsIndex, promptFragments);
|
|
208
|
+
const result = await runAgentLoop(messages, {
|
|
209
|
+
model: resolved.model,
|
|
210
|
+
fallbacks: resolved.fallbacks,
|
|
211
|
+
systemPrompt,
|
|
212
|
+
toolRegistry,
|
|
213
|
+
maxIterations: resolved.maxIterations,
|
|
214
|
+
compactionThreshold: resolved.compactionThreshold,
|
|
215
|
+
maxToolResultSize: resolved.maxToolResultSize,
|
|
216
|
+
agentName,
|
|
217
|
+
usageStore,
|
|
218
|
+
source: "cli",
|
|
219
|
+
});
|
|
220
|
+
const newMessages = result.messages.slice(messages.length - 1);
|
|
221
|
+
for (const msg of newMessages) {
|
|
222
|
+
session.append(msg);
|
|
223
|
+
}
|
|
224
|
+
messages = result.messages;
|
|
225
|
+
console.log(`\nAgent: ${result.text}`);
|
|
226
|
+
console.log(` (${result.usage.inputTokens + result.usage.outputTokens} tokens)\n`);
|
|
227
|
+
}
|
|
228
|
+
catch (err) {
|
|
229
|
+
console.error(`\n Error: ${err instanceof Error ? err.message : err}\n`);
|
|
230
|
+
}
|
|
231
|
+
ask();
|
|
232
|
+
});
|
|
233
|
+
};
|
|
234
|
+
ask();
|
|
235
|
+
}
|
package/dist/cli/ui.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare function banner(): void;
|
|
2
|
+
export declare function status(label: string, value: string): void;
|
|
3
|
+
export declare function done(message: string): void;
|
|
4
|
+
export declare function onCancel(): void;
|
|
5
|
+
/**
|
|
6
|
+
* Check if a @clack/prompts value was cancelled. Exits the process if so.
|
|
7
|
+
* The `return` after `isCancel()` in callers is technically unreachable
|
|
8
|
+
* but satisfies TypeScript control flow analysis.
|
|
9
|
+
*/
|
|
10
|
+
export declare function isCancel(value: unknown): value is symbol;
|
|
11
|
+
/**
|
|
12
|
+
* Resolve the Anthropic API key: env var → .env file → interactive prompt.
|
|
13
|
+
* Sets process.env.ANTHROPIC_API_KEY so downstream LLM providers pick it up.
|
|
14
|
+
*/
|
|
15
|
+
export declare function resolveApiKey(opts?: {
|
|
16
|
+
save?: boolean;
|
|
17
|
+
}): Promise<string>;
|
package/dist/cli/ui.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import * as p from "@clack/prompts";
|
|
4
|
+
const VERSION = "0.1.0";
|
|
5
|
+
export function banner() {
|
|
6
|
+
console.log();
|
|
7
|
+
p.intro(`agent-kit v${VERSION}`);
|
|
8
|
+
}
|
|
9
|
+
export function status(label, value) {
|
|
10
|
+
p.log.info(`${label}: ${value}`);
|
|
11
|
+
}
|
|
12
|
+
export function done(message) {
|
|
13
|
+
p.outro(message);
|
|
14
|
+
}
|
|
15
|
+
export function onCancel() {
|
|
16
|
+
p.cancel("Cancelled.");
|
|
17
|
+
process.exit(0);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Check if a @clack/prompts value was cancelled. Exits the process if so.
|
|
21
|
+
* The `return` after `isCancel()` in callers is technically unreachable
|
|
22
|
+
* but satisfies TypeScript control flow analysis.
|
|
23
|
+
*/
|
|
24
|
+
export function isCancel(value) {
|
|
25
|
+
if (p.isCancel(value)) {
|
|
26
|
+
onCancel(); // calls process.exit(0)
|
|
27
|
+
}
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Resolve the Anthropic API key: env var → .env file → interactive prompt.
|
|
32
|
+
* Sets process.env.ANTHROPIC_API_KEY so downstream LLM providers pick it up.
|
|
33
|
+
*/
|
|
34
|
+
export async function resolveApiKey(opts) {
|
|
35
|
+
// 1. Check env var
|
|
36
|
+
if (process.env.ANTHROPIC_API_KEY) {
|
|
37
|
+
return process.env.ANTHROPIC_API_KEY;
|
|
38
|
+
}
|
|
39
|
+
// 2. Check .env file
|
|
40
|
+
const envPath = path.join(process.cwd(), ".env");
|
|
41
|
+
if (fs.existsSync(envPath)) {
|
|
42
|
+
const content = fs.readFileSync(envPath, "utf-8");
|
|
43
|
+
const match = content.match(/^ANTHROPIC_API_KEY=(.+)$/m);
|
|
44
|
+
if (match) {
|
|
45
|
+
const key = match[1].trim().replace(/^["']|["']$/g, "");
|
|
46
|
+
process.env.ANTHROPIC_API_KEY = key;
|
|
47
|
+
return key;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// 3. Interactive prompt
|
|
51
|
+
const key = await p.text({
|
|
52
|
+
message: "Enter your Anthropic API key:",
|
|
53
|
+
placeholder: "sk-ant-...",
|
|
54
|
+
validate: (val) => {
|
|
55
|
+
if (!val?.trim())
|
|
56
|
+
return "API key is required";
|
|
57
|
+
if (!val.startsWith("sk-ant-"))
|
|
58
|
+
return "Key should start with sk-ant-";
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
if (isCancel(key))
|
|
62
|
+
process.exit(0);
|
|
63
|
+
const apiKey = key.trim();
|
|
64
|
+
process.env.ANTHROPIC_API_KEY = apiKey;
|
|
65
|
+
// 4. Offer to save to .env
|
|
66
|
+
if (opts?.save !== false) {
|
|
67
|
+
const shouldSave = await p.confirm({
|
|
68
|
+
message: "Save API key to .env for future use?",
|
|
69
|
+
});
|
|
70
|
+
if (!isCancel(shouldSave) && shouldSave) {
|
|
71
|
+
const envContent = fs.existsSync(envPath)
|
|
72
|
+
? fs.readFileSync(envPath, "utf-8") + "\n"
|
|
73
|
+
: "";
|
|
74
|
+
fs.writeFileSync(envPath, envContent + `ANTHROPIC_API_KEY=${apiKey}\n`);
|
|
75
|
+
p.log.success("Saved to .env");
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return apiKey;
|
|
79
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function validate(agentName?: string): void;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import * as path from "path";
|
|
2
|
+
import { loadConfig } from "../config/index.js";
|
|
3
|
+
import { validateAgent } from "../scripts/validate-agent.js";
|
|
4
|
+
const PASS = "\u2713";
|
|
5
|
+
const FAIL = "\u2717";
|
|
6
|
+
const CONFIG_PATH = path.join(process.cwd(), "agent-kit.json");
|
|
7
|
+
const SKILLS_DIR = path.join(process.cwd(), "skills");
|
|
8
|
+
const DATA_DIR = path.join(process.cwd(), "data");
|
|
9
|
+
function printResult(result) {
|
|
10
|
+
for (const check of result.checks) {
|
|
11
|
+
const icon = check.passed ? PASS : FAIL;
|
|
12
|
+
console.log(` ${icon} [${check.name}] ${check.message}`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export function validate(agentName) {
|
|
16
|
+
let config;
|
|
17
|
+
try {
|
|
18
|
+
config = loadConfig(CONFIG_PATH);
|
|
19
|
+
}
|
|
20
|
+
catch (err) {
|
|
21
|
+
console.error(`${FAIL} Config failed to load: ${err instanceof Error ? err.message : err}`);
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
const opts = { skillsDir: SKILLS_DIR, dataDir: DATA_DIR };
|
|
25
|
+
// Validate all agents if no name given
|
|
26
|
+
const names = agentName ? [agentName] : Object.keys(config.agents);
|
|
27
|
+
if (names.length === 0) {
|
|
28
|
+
console.log("No agents configured.");
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
let allPassed = true;
|
|
32
|
+
for (const name of names) {
|
|
33
|
+
console.log(`\n Validating: ${name}`);
|
|
34
|
+
const result = validateAgent(name, config, opts);
|
|
35
|
+
printResult(result);
|
|
36
|
+
if (!result.success)
|
|
37
|
+
allPassed = false;
|
|
38
|
+
}
|
|
39
|
+
console.log();
|
|
40
|
+
if (allPassed) {
|
|
41
|
+
console.log(` All checks passed.`);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
console.log(` Some checks failed.`);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
}
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
const command = process.argv[2];
|
|
4
|
+
const args = process.argv.slice(3);
|
|
5
|
+
async function main() {
|
|
6
|
+
switch (command) {
|
|
7
|
+
case "init": {
|
|
8
|
+
const { init } = await import("./cli/init.js");
|
|
9
|
+
await init();
|
|
10
|
+
break;
|
|
11
|
+
}
|
|
12
|
+
case "start": {
|
|
13
|
+
const { start } = await import("./cli/start.js");
|
|
14
|
+
await start();
|
|
15
|
+
break;
|
|
16
|
+
}
|
|
17
|
+
case "create": {
|
|
18
|
+
const { create } = await import("./cli/create.js");
|
|
19
|
+
await create();
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
case "list": {
|
|
23
|
+
const { list } = await import("./cli/list.js");
|
|
24
|
+
list();
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
case "chat": {
|
|
28
|
+
const { chat } = await import("./cli/chat.js");
|
|
29
|
+
await chat(args[0]);
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
case "validate": {
|
|
33
|
+
const { validate } = await import("./cli/validate.js");
|
|
34
|
+
validate(args[0]);
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
default: {
|
|
38
|
+
console.log(`
|
|
39
|
+
agent-kit — personal AI agent framework
|
|
40
|
+
|
|
41
|
+
Usage:
|
|
42
|
+
agent-kit init AI-powered setup wizard
|
|
43
|
+
agent-kit start Start all services + REPL
|
|
44
|
+
agent-kit create AI-powered agent creation
|
|
45
|
+
agent-kit list Show configured agents
|
|
46
|
+
agent-kit chat <agent> Lightweight single-agent chat
|
|
47
|
+
agent-kit validate [agent] Validate config
|
|
48
|
+
|
|
49
|
+
Options:
|
|
50
|
+
--help Show this help
|
|
51
|
+
`);
|
|
52
|
+
process.exit(command === "--help" || command === "-h" ? 0 : 1);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
main().catch((err) => {
|
|
57
|
+
console.error(err instanceof Error ? err.message : err);
|
|
58
|
+
process.exit(1);
|
|
59
|
+
});
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { ConfigSchema, type Config, type AgentDef, type CronJobDef, type SandboxDef, type ModelEntry, type SpawnTarget } from "./schema.js";
|
|
2
|
+
export { loadConfig } from "./loader.js";
|
|
3
|
+
export { resolveAgent, resolveModelAlias, buildFallbacks, type ResolvedAgent } from "./resolve.js";
|
|
4
|
+
export { type SkillManifest } from "../skills/index.js";
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import { ConfigSchema } from "./schema.js";
|
|
3
|
+
export function loadConfig(configPath) {
|
|
4
|
+
if (!fs.existsSync(configPath)) {
|
|
5
|
+
return ConfigSchema.parse({});
|
|
6
|
+
}
|
|
7
|
+
const raw = fs.readFileSync(configPath, "utf-8");
|
|
8
|
+
const json = JSON.parse(raw);
|
|
9
|
+
return ConfigSchema.parse(json);
|
|
10
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Config, SandboxDef, ModelEntry, SpawnTarget, WebSearchConfig } from "./schema.js";
|
|
2
|
+
import type { ToolRegistry } from "../tools/registry.js";
|
|
3
|
+
import type { Tool } from "../tools/types.js";
|
|
4
|
+
import { type SkillManifest } from "../skills/index.js";
|
|
5
|
+
export interface ResolvedAgent {
|
|
6
|
+
model: string;
|
|
7
|
+
fallbacks: string[];
|
|
8
|
+
tools: Tool[];
|
|
9
|
+
skills: SkillManifest[];
|
|
10
|
+
canSpawn: SpawnTarget[];
|
|
11
|
+
maxIterations: number;
|
|
12
|
+
maxTokens: number;
|
|
13
|
+
compactionThreshold: number;
|
|
14
|
+
commandTimeout: number;
|
|
15
|
+
maxToolResultSize: number;
|
|
16
|
+
spawn_only: boolean;
|
|
17
|
+
sandbox?: SandboxDef;
|
|
18
|
+
}
|
|
19
|
+
export declare function resolveWebSearch(agentName: string, config: Config): WebSearchConfig;
|
|
20
|
+
export declare function resolveModelAlias(alias: string, models?: ModelEntry[]): string;
|
|
21
|
+
export declare function buildFallbacks(primaryModel: string, models?: ModelEntry[]): string[];
|
|
22
|
+
export declare function resolveAgent(name: string, config: Config, toolRegistry: ToolRegistry, skillsDir?: string): ResolvedAgent;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { loadAllSkillManifests } from "../skills/index.js";
|
|
2
|
+
export function resolveWebSearch(agentName, config) {
|
|
3
|
+
const agentDef = config.agents[agentName];
|
|
4
|
+
return agentDef?.webSearch ?? config.defaults.webSearch;
|
|
5
|
+
}
|
|
6
|
+
export function resolveModelAlias(alias, models) {
|
|
7
|
+
if (!models)
|
|
8
|
+
return alias;
|
|
9
|
+
const entry = models.find((m) => m.alias === alias);
|
|
10
|
+
if (!entry)
|
|
11
|
+
throw new Error(`Unknown model alias "${alias}"`);
|
|
12
|
+
return entry.model;
|
|
13
|
+
}
|
|
14
|
+
export function buildFallbacks(primaryModel, models) {
|
|
15
|
+
if (!models)
|
|
16
|
+
return [];
|
|
17
|
+
return models
|
|
18
|
+
.map((m) => m.model)
|
|
19
|
+
.filter((m) => m !== primaryModel);
|
|
20
|
+
}
|
|
21
|
+
export function resolveAgent(name, config, toolRegistry, skillsDir) {
|
|
22
|
+
const agentDef = config.agents[name];
|
|
23
|
+
if (!agentDef)
|
|
24
|
+
throw new Error(`Unknown agent "${name}"`);
|
|
25
|
+
const modelAlias = agentDef.model ?? config.defaults.model;
|
|
26
|
+
const model = resolveModelAlias(modelAlias, config.models);
|
|
27
|
+
const fallbacks = buildFallbacks(model, config.models);
|
|
28
|
+
const skills = agentDef.skills && agentDef.skills.length > 0 && skillsDir
|
|
29
|
+
? loadAllSkillManifests(agentDef.skills, skillsDir)
|
|
30
|
+
: [];
|
|
31
|
+
return {
|
|
32
|
+
model,
|
|
33
|
+
fallbacks,
|
|
34
|
+
tools: toolRegistry.resolve(agentDef.tools),
|
|
35
|
+
skills,
|
|
36
|
+
canSpawn: agentDef.can_spawn,
|
|
37
|
+
maxIterations: agentDef.maxIterations ?? config.defaults.maxIterations,
|
|
38
|
+
maxTokens: agentDef.maxTokens ?? config.defaults.maxTokens,
|
|
39
|
+
compactionThreshold: config.defaults.compactionThreshold,
|
|
40
|
+
commandTimeout: config.defaults.commandTimeout,
|
|
41
|
+
maxToolResultSize: config.defaults.maxToolResultSize,
|
|
42
|
+
spawn_only: agentDef.spawn_only,
|
|
43
|
+
sandbox: agentDef.sandbox ?? config.defaults.sandbox,
|
|
44
|
+
};
|
|
45
|
+
}
|