@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,100 @@
|
|
|
1
|
+
import * as readline from "readline";
|
|
2
|
+
import { runAgentLoop } from "../../agent/loop.js";
|
|
3
|
+
import { ToolRegistry } from "../../tools/registry.js";
|
|
4
|
+
import { createSetupTools } from "./tools.js";
|
|
5
|
+
import { SETUP_SOUL, CREATE_SOUL } from "./soul.js";
|
|
6
|
+
import { dateContext } from "../../text.js";
|
|
7
|
+
export async function runSetupAgent(opts) {
|
|
8
|
+
// Ensure the API key is available for the Anthropic provider
|
|
9
|
+
process.env.ANTHROPIC_API_KEY = opts.apiKey;
|
|
10
|
+
const model = "anthropic:claude-sonnet-4-6";
|
|
11
|
+
return new Promise((resolve) => {
|
|
12
|
+
let finished = false;
|
|
13
|
+
const toolRegistry = new ToolRegistry();
|
|
14
|
+
const tools = createSetupTools({
|
|
15
|
+
configPath: opts.configPath,
|
|
16
|
+
dataDir: opts.dataDir,
|
|
17
|
+
skillsDir: opts.skillsDir,
|
|
18
|
+
basePath: opts.basePath,
|
|
19
|
+
onFinish: (summary) => {
|
|
20
|
+
finished = true;
|
|
21
|
+
resolve(summary);
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
for (const tool of tools) {
|
|
25
|
+
toolRegistry.register(tool);
|
|
26
|
+
}
|
|
27
|
+
const soul = opts.mode === "init" ? SETUP_SOUL : CREATE_SOUL;
|
|
28
|
+
const systemPrompt = [soul, dateContext()].join("\n\n");
|
|
29
|
+
const messages = [];
|
|
30
|
+
const rl = readline.createInterface({
|
|
31
|
+
input: process.stdin,
|
|
32
|
+
output: process.stdout,
|
|
33
|
+
});
|
|
34
|
+
const ask = (prompt) => {
|
|
35
|
+
if (finished) {
|
|
36
|
+
rl.close();
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
rl.question(prompt ?? "You: ", async (input) => {
|
|
40
|
+
const trimmed = input.trim();
|
|
41
|
+
if (trimmed === "/quit" || trimmed === "/exit") {
|
|
42
|
+
rl.close();
|
|
43
|
+
resolve("Setup cancelled.");
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (!trimmed) {
|
|
47
|
+
ask();
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
messages.push({ role: "user", content: trimmed });
|
|
51
|
+
try {
|
|
52
|
+
const result = await runAgentLoop(messages, {
|
|
53
|
+
model,
|
|
54
|
+
systemPrompt,
|
|
55
|
+
toolRegistry,
|
|
56
|
+
maxIterations: 30,
|
|
57
|
+
source: "cli",
|
|
58
|
+
});
|
|
59
|
+
messages.push(...result.messages.slice(messages.length));
|
|
60
|
+
if (!finished) {
|
|
61
|
+
console.log(`\n${result.text}\n`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
console.error(`\n Error: ${err instanceof Error ? err.message : err}\n`);
|
|
66
|
+
}
|
|
67
|
+
if (!finished) {
|
|
68
|
+
ask();
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
rl.close();
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
// Kick off with an initial greeting from the agent
|
|
76
|
+
(async () => {
|
|
77
|
+
try {
|
|
78
|
+
const greeting = opts.mode === "init"
|
|
79
|
+
? "The user just ran `agent-kit init`. Greet them, then call check_environment to see what's available. After that, ask what kind of agent they'd like to create first."
|
|
80
|
+
: "The user wants to add a new agent to their existing setup. Greet them, call check_environment and list_available_skills to see the current state, then ask what kind of agent they'd like to create.";
|
|
81
|
+
messages.push({ role: "user", content: greeting });
|
|
82
|
+
const result = await runAgentLoop(messages, {
|
|
83
|
+
model,
|
|
84
|
+
systemPrompt,
|
|
85
|
+
toolRegistry,
|
|
86
|
+
maxIterations: 10,
|
|
87
|
+
source: "cli",
|
|
88
|
+
});
|
|
89
|
+
messages.push(...result.messages.slice(messages.length));
|
|
90
|
+
console.log(`\n${result.text}\n`);
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
console.error(`\n Error starting setup agent: ${err instanceof Error ? err.message : err}\n`);
|
|
94
|
+
}
|
|
95
|
+
if (!finished) {
|
|
96
|
+
ask();
|
|
97
|
+
}
|
|
98
|
+
})();
|
|
99
|
+
});
|
|
100
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const SETUP_SOUL = "You are the Agent Kit Setup Wizard \u2014 an AI assistant that helps users create AI agents through natural conversation.\n\n## Your Role\n\nYou help users design and configure AI agents for their personal use. You're friendly, opinionated (in a helpful way), and efficient. You ask smart questions to understand what the user wants, then create agents tailored to their needs.\n\n## How You Work\n\n1. **Ask about the agent** \u2014 What should it do? What's its personality? What communication style should it have?\n2. **Explore available tools and skills** \u2014 Use list_builtin_tools and list_available_skills to see what's available. Suggest appropriate ones based on the user's description.\n3. **Optionally read files** \u2014 If the user wants custom tools that integrate with their codebase, use read_file to understand their code, then use create_skill to build custom tools.\n4. **Generate a rich SOUL.md** \u2014 This is the agent's personality and instructions. Make it detailed and tailored: include personality traits, communication style, specific workflows, and behavioral guidelines. A good SOUL makes all the difference.\n5. **Configure the agent** \u2014 Use save_agent with the full spec: name, displayName, emoji, model, tools, skills, soul, and any advanced features (sandbox, slack, heartbeat, webSearch).\n6. **Add cron jobs** \u2014 If the user mentions scheduled tasks, use add_cron_job to set them up.\n7. **Confirm before saving** \u2014 Always show the user what you'll create before calling save_agent.\n\n## Agent Design Guidelines\n\n- **Names**: Use kebab-case for agent names (e.g., \"fitness-coach\", \"code-reviewer\")\n- **Emoji**: Pick a single emoji that represents the agent's role\n- **Model**: Default to \"sonnet\" unless the user specifies otherwise. Use \"haiku\" for simple/fast tasks.\n- **Tools**: Only include tools the agent actually needs. Less is more.\n- **Skills**: Suggest existing skills when they fit. Create new ones for custom functionality.\n- **SOUL.md**: Write 200-500 words. Include personality, tone, specific instructions, and example interactions. Make each agent feel unique.\n- **Sandbox**: Recommend sandboxing when agents have file/command access. Set allowedPaths to the agent's data directory.\n- **Cron**: Help design good cron schedules. Explain the schedule syntax if asked.\n\n## Creating Custom Tools\n\nWhen the user needs functionality beyond built-in tools, you can create custom skills with tools:\n\n1. Use read_file to explore their codebase and understand patterns\n2. Design tools that fit their stack\n3. Use create_skill to write the skill manifest, SKILL.md instructions, and tool implementations\n4. Tool execute functions receive `args: Record<string, unknown>` and must return a string\n5. Keep tool implementations focused and minimal\n6. Never generate tools that execute arbitrary shell commands without sandbox restrictions\n7. Show the user the generated code and explain what it does before saving\n\n## Conversation Style\n\n- Be conversational but efficient \u2014 don't ask too many questions at once\n- After 2-3 questions, you usually have enough to create the agent\n- Suggest reasonable defaults and let the user override\n- If unsure, propose two options and let the user pick\n- Celebrate when agents are created \u2014 this is fun!\n\n## Multiple Agents\n\nYou can create multiple agents in one session. After saving an agent, ask if the user wants to create another. When they're done, call finish_setup.\n\n## Important\n\n- Always call check_environment at the start to understand the setup\n- Always confirm the full agent spec before calling save_agent\n- Call finish_setup when the user is done (they say \"done\", \"that's all\", etc.)\n";
|
|
2
|
+
export declare const CREATE_SOUL = "You are the Agent Kit Setup Wizard \u2014 an AI assistant that helps users add a new agent to their existing setup.\n\n## Context\n\nThe user already has agent-kit configured with agents. You're helping them add one more.\n\n## How You Work\n\n1. **Ask about the new agent** \u2014 What should it do? Personality? Communication style?\n2. **Explore available tools and skills** \u2014 Check what's available with list_builtin_tools and list_available_skills.\n3. **Optionally create custom tools** \u2014 If needed, read_file to explore their code, then create_skill.\n4. **Generate a rich SOUL.md** \u2014 Detailed personality and instructions (200-500 words).\n5. **Save the agent** \u2014 Use save_agent with the full config.\n6. **Add cron jobs** \u2014 If the user mentions scheduled tasks, use add_cron_job.\n7. **Call finish_setup** \u2014 When the agent is created and the user is satisfied.\n\n## Guidelines\n\nSame as the full setup wizard \u2014 use kebab-case names, pick good emojis, default to \"sonnet\", recommend sandboxing for file/command access, generate rich SOUL.md content. Always confirm before saving.\n\nBe efficient \u2014 you're adding a single agent, not setting up the whole system.\n";
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
export const SETUP_SOUL = `You are the Agent Kit Setup Wizard — an AI assistant that helps users create AI agents through natural conversation.
|
|
2
|
+
|
|
3
|
+
## Your Role
|
|
4
|
+
|
|
5
|
+
You help users design and configure AI agents for their personal use. You're friendly, opinionated (in a helpful way), and efficient. You ask smart questions to understand what the user wants, then create agents tailored to their needs.
|
|
6
|
+
|
|
7
|
+
## How You Work
|
|
8
|
+
|
|
9
|
+
1. **Ask about the agent** — What should it do? What's its personality? What communication style should it have?
|
|
10
|
+
2. **Explore available tools and skills** — Use list_builtin_tools and list_available_skills to see what's available. Suggest appropriate ones based on the user's description.
|
|
11
|
+
3. **Optionally read files** — If the user wants custom tools that integrate with their codebase, use read_file to understand their code, then use create_skill to build custom tools.
|
|
12
|
+
4. **Generate a rich SOUL.md** — This is the agent's personality and instructions. Make it detailed and tailored: include personality traits, communication style, specific workflows, and behavioral guidelines. A good SOUL makes all the difference.
|
|
13
|
+
5. **Configure the agent** — Use save_agent with the full spec: name, displayName, emoji, model, tools, skills, soul, and any advanced features (sandbox, slack, heartbeat, webSearch).
|
|
14
|
+
6. **Add cron jobs** — If the user mentions scheduled tasks, use add_cron_job to set them up.
|
|
15
|
+
7. **Confirm before saving** — Always show the user what you'll create before calling save_agent.
|
|
16
|
+
|
|
17
|
+
## Agent Design Guidelines
|
|
18
|
+
|
|
19
|
+
- **Names**: Use kebab-case for agent names (e.g., "fitness-coach", "code-reviewer")
|
|
20
|
+
- **Emoji**: Pick a single emoji that represents the agent's role
|
|
21
|
+
- **Model**: Default to "sonnet" unless the user specifies otherwise. Use "haiku" for simple/fast tasks.
|
|
22
|
+
- **Tools**: Only include tools the agent actually needs. Less is more.
|
|
23
|
+
- **Skills**: Suggest existing skills when they fit. Create new ones for custom functionality.
|
|
24
|
+
- **SOUL.md**: Write 200-500 words. Include personality, tone, specific instructions, and example interactions. Make each agent feel unique.
|
|
25
|
+
- **Sandbox**: Recommend sandboxing when agents have file/command access. Set allowedPaths to the agent's data directory.
|
|
26
|
+
- **Cron**: Help design good cron schedules. Explain the schedule syntax if asked.
|
|
27
|
+
|
|
28
|
+
## Creating Custom Tools
|
|
29
|
+
|
|
30
|
+
When the user needs functionality beyond built-in tools, you can create custom skills with tools:
|
|
31
|
+
|
|
32
|
+
1. Use read_file to explore their codebase and understand patterns
|
|
33
|
+
2. Design tools that fit their stack
|
|
34
|
+
3. Use create_skill to write the skill manifest, SKILL.md instructions, and tool implementations
|
|
35
|
+
4. Tool execute functions receive \`args: Record<string, unknown>\` and must return a string
|
|
36
|
+
5. Keep tool implementations focused and minimal
|
|
37
|
+
6. Never generate tools that execute arbitrary shell commands without sandbox restrictions
|
|
38
|
+
7. Show the user the generated code and explain what it does before saving
|
|
39
|
+
|
|
40
|
+
## Conversation Style
|
|
41
|
+
|
|
42
|
+
- Be conversational but efficient — don't ask too many questions at once
|
|
43
|
+
- After 2-3 questions, you usually have enough to create the agent
|
|
44
|
+
- Suggest reasonable defaults and let the user override
|
|
45
|
+
- If unsure, propose two options and let the user pick
|
|
46
|
+
- Celebrate when agents are created — this is fun!
|
|
47
|
+
|
|
48
|
+
## Multiple Agents
|
|
49
|
+
|
|
50
|
+
You can create multiple agents in one session. After saving an agent, ask if the user wants to create another. When they're done, call finish_setup.
|
|
51
|
+
|
|
52
|
+
## Important
|
|
53
|
+
|
|
54
|
+
- Always call check_environment at the start to understand the setup
|
|
55
|
+
- Always confirm the full agent spec before calling save_agent
|
|
56
|
+
- Call finish_setup when the user is done (they say "done", "that's all", etc.)
|
|
57
|
+
`;
|
|
58
|
+
export const CREATE_SOUL = `You are the Agent Kit Setup Wizard — an AI assistant that helps users add a new agent to their existing setup.
|
|
59
|
+
|
|
60
|
+
## Context
|
|
61
|
+
|
|
62
|
+
The user already has agent-kit configured with agents. You're helping them add one more.
|
|
63
|
+
|
|
64
|
+
## How You Work
|
|
65
|
+
|
|
66
|
+
1. **Ask about the new agent** — What should it do? Personality? Communication style?
|
|
67
|
+
2. **Explore available tools and skills** — Check what's available with list_builtin_tools and list_available_skills.
|
|
68
|
+
3. **Optionally create custom tools** — If needed, read_file to explore their code, then create_skill.
|
|
69
|
+
4. **Generate a rich SOUL.md** — Detailed personality and instructions (200-500 words).
|
|
70
|
+
5. **Save the agent** — Use save_agent with the full config.
|
|
71
|
+
6. **Add cron jobs** — If the user mentions scheduled tasks, use add_cron_job.
|
|
72
|
+
7. **Call finish_setup** — When the agent is created and the user is satisfied.
|
|
73
|
+
|
|
74
|
+
## Guidelines
|
|
75
|
+
|
|
76
|
+
Same as the full setup wizard — use kebab-case names, pick good emojis, default to "sonnet", recommend sandboxing for file/command access, generate rich SOUL.md content. Always confirm before saving.
|
|
77
|
+
|
|
78
|
+
Be efficient — you're adding a single agent, not setting up the whole system.
|
|
79
|
+
`;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Tool } from "../../tools/types.js";
|
|
2
|
+
export interface SetupToolsOptions {
|
|
3
|
+
configPath: string;
|
|
4
|
+
dataDir: string;
|
|
5
|
+
skillsDir: string;
|
|
6
|
+
basePath: string;
|
|
7
|
+
onFinish: (summary: string) => void;
|
|
8
|
+
}
|
|
9
|
+
export declare function createSetupTools(opts: SetupToolsOptions): Tool[];
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import { checkOllama } from "../ollama.js";
|
|
4
|
+
import { upsertAgent, addCronJob, ensureAgentDirs } from "../config-writer.js";
|
|
5
|
+
export function createSetupTools(opts) {
|
|
6
|
+
const created = {
|
|
7
|
+
agents: [],
|
|
8
|
+
skills: [],
|
|
9
|
+
crons: [],
|
|
10
|
+
};
|
|
11
|
+
const checkEnvironment = {
|
|
12
|
+
name: "check_environment",
|
|
13
|
+
description: "Check the current environment: Node version, Ollama status, detected API keys, and existing config.",
|
|
14
|
+
parameters: { type: "object", properties: {}, required: [] },
|
|
15
|
+
execute: async () => {
|
|
16
|
+
const nodeVersion = process.version;
|
|
17
|
+
const ollamaStatus = await checkOllama();
|
|
18
|
+
const keys = {
|
|
19
|
+
ANTHROPIC_API_KEY: !!process.env.ANTHROPIC_API_KEY,
|
|
20
|
+
OPENAI_API_KEY: !!process.env.OPENAI_API_KEY,
|
|
21
|
+
BRAVE_API_KEY: !!process.env.BRAVE_API_KEY,
|
|
22
|
+
XAI_API_KEY: !!process.env.XAI_API_KEY,
|
|
23
|
+
};
|
|
24
|
+
const configExists = fs.existsSync(opts.configPath);
|
|
25
|
+
return JSON.stringify({
|
|
26
|
+
nodeVersion,
|
|
27
|
+
ollama: ollamaStatus,
|
|
28
|
+
apiKeys: keys,
|
|
29
|
+
configExists,
|
|
30
|
+
basePath: opts.basePath,
|
|
31
|
+
});
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
const listAvailableSkills = {
|
|
35
|
+
name: "list_available_skills",
|
|
36
|
+
description: "List all available skills in the skills directory with their names and descriptions.",
|
|
37
|
+
parameters: { type: "object", properties: {}, required: [] },
|
|
38
|
+
execute: async () => {
|
|
39
|
+
if (!fs.existsSync(opts.skillsDir)) {
|
|
40
|
+
return JSON.stringify({ skills: [] });
|
|
41
|
+
}
|
|
42
|
+
const entries = fs.readdirSync(opts.skillsDir, { withFileTypes: true });
|
|
43
|
+
const skills = [];
|
|
44
|
+
for (const entry of entries) {
|
|
45
|
+
if (!entry.isDirectory())
|
|
46
|
+
continue;
|
|
47
|
+
const manifestPath = path.join(opts.skillsDir, entry.name, "skill.json");
|
|
48
|
+
if (!fs.existsSync(manifestPath))
|
|
49
|
+
continue;
|
|
50
|
+
try {
|
|
51
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
|
|
52
|
+
skills.push({
|
|
53
|
+
name: manifest.name ?? entry.name,
|
|
54
|
+
description: manifest.description ?? "(no description)",
|
|
55
|
+
tools: manifest.tools ?? [],
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// Skip malformed manifests
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return JSON.stringify({ skills });
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
const listBuiltinTools = {
|
|
66
|
+
name: "list_builtin_tools",
|
|
67
|
+
description: "List all built-in tools available to agents with their names and descriptions.",
|
|
68
|
+
parameters: { type: "object", properties: {}, required: [] },
|
|
69
|
+
execute: async () => {
|
|
70
|
+
return JSON.stringify({
|
|
71
|
+
tools: [
|
|
72
|
+
{ name: "read_file", description: "Read the contents of a file from the filesystem" },
|
|
73
|
+
{ name: "write_file", description: "Write content to a file on the filesystem" },
|
|
74
|
+
{ name: "run_command", description: "Execute a shell command and return stdout/stderr" },
|
|
75
|
+
{ name: "web_search", description: "Search the web using Brave Search or Grok" },
|
|
76
|
+
{ name: "store_memory", description: "Store a memory with content and metadata" },
|
|
77
|
+
{ name: "search_memory", description: "Semantic search across stored memories" },
|
|
78
|
+
{ name: "get_memory", description: "Retrieve a specific memory by ID" },
|
|
79
|
+
{ name: "update_memory", description: "Update an existing memory's content or metadata" },
|
|
80
|
+
{ name: "forget_memory", description: "Delete a memory by ID" },
|
|
81
|
+
{ name: "list_memories", description: "List all stored memories with optional filtering" },
|
|
82
|
+
],
|
|
83
|
+
});
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
const readFile = {
|
|
87
|
+
name: "read_file",
|
|
88
|
+
description: "Read a file from the user's project. Use this to understand their codebase when creating custom tools.",
|
|
89
|
+
parameters: {
|
|
90
|
+
type: "object",
|
|
91
|
+
properties: {
|
|
92
|
+
path: {
|
|
93
|
+
type: "string",
|
|
94
|
+
description: "Path to the file (relative to project root or absolute)",
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
required: ["path"],
|
|
98
|
+
},
|
|
99
|
+
execute: async (args) => {
|
|
100
|
+
const filePath = args.path;
|
|
101
|
+
const resolved = path.isAbsolute(filePath) ? filePath : path.join(opts.basePath, filePath);
|
|
102
|
+
// Basic safety: don't read outside basePath
|
|
103
|
+
const realBase = fs.realpathSync(opts.basePath);
|
|
104
|
+
try {
|
|
105
|
+
const realPath = fs.realpathSync(resolved);
|
|
106
|
+
if (!realPath.startsWith(realBase)) {
|
|
107
|
+
return `Error: path is outside the project directory`;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return `Error: file not found: ${filePath}`;
|
|
112
|
+
}
|
|
113
|
+
try {
|
|
114
|
+
const content = fs.readFileSync(resolved, "utf-8");
|
|
115
|
+
if (content.length > 10_000) {
|
|
116
|
+
return content.slice(0, 10_000) + "\n\n... (truncated, file is " + content.length + " chars)";
|
|
117
|
+
}
|
|
118
|
+
return content;
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
return `Error: ${err instanceof Error ? err.message : String(err)}`;
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
const createSkill = {
|
|
126
|
+
name: "create_skill",
|
|
127
|
+
description: "Create a new skill with its manifest, prompt, and tool implementations. The skill will be written to the skills/ directory.",
|
|
128
|
+
parameters: {
|
|
129
|
+
type: "object",
|
|
130
|
+
properties: {
|
|
131
|
+
name: { type: "string", description: "Skill name (kebab-case, e.g. 'db-monitor')" },
|
|
132
|
+
description: { type: "string", description: "Short description of what this skill does" },
|
|
133
|
+
prompt: { type: "string", description: "Full SKILL.md content — instructions for the agent using this skill" },
|
|
134
|
+
tools: {
|
|
135
|
+
type: "array",
|
|
136
|
+
description: "Array of tool definitions to create",
|
|
137
|
+
items: {
|
|
138
|
+
type: "object",
|
|
139
|
+
properties: {
|
|
140
|
+
name: { type: "string", description: "Tool name (snake_case)" },
|
|
141
|
+
description: { type: "string", description: "What this tool does" },
|
|
142
|
+
parameters: { type: "object", description: "JSON Schema for tool parameters" },
|
|
143
|
+
code: { type: "string", description: "TypeScript implementation of the execute function body. Receives `args: Record<string, unknown>` and must return a string." },
|
|
144
|
+
},
|
|
145
|
+
required: ["name", "description", "parameters", "code"],
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
required: ["name", "description", "prompt", "tools"],
|
|
150
|
+
},
|
|
151
|
+
execute: async (args) => {
|
|
152
|
+
const skillName = args.name;
|
|
153
|
+
const description = args.description;
|
|
154
|
+
const prompt = args.prompt;
|
|
155
|
+
const tools = args.tools;
|
|
156
|
+
const skillDir = path.join(opts.skillsDir, skillName);
|
|
157
|
+
const toolsDir = path.join(skillDir, "tools");
|
|
158
|
+
fs.mkdirSync(toolsDir, { recursive: true });
|
|
159
|
+
// Write skill.json
|
|
160
|
+
const manifest = {
|
|
161
|
+
name: skillName,
|
|
162
|
+
description,
|
|
163
|
+
tools: tools.map((t) => t.name),
|
|
164
|
+
prompt: "SKILL.md",
|
|
165
|
+
};
|
|
166
|
+
fs.writeFileSync(path.join(skillDir, "skill.json"), JSON.stringify(manifest, null, 2) + "\n");
|
|
167
|
+
// Write SKILL.md
|
|
168
|
+
fs.writeFileSync(path.join(skillDir, "SKILL.md"), prompt + "\n");
|
|
169
|
+
// Write tool files
|
|
170
|
+
for (const tool of tools) {
|
|
171
|
+
const toolContent = `import type { Tool } from "../../../src/tools/types.js";
|
|
172
|
+
|
|
173
|
+
const tool: Tool = {
|
|
174
|
+
name: "${tool.name}",
|
|
175
|
+
description: "${tool.description.replace(/"/g, '\\"')}",
|
|
176
|
+
parameters: ${JSON.stringify(tool.parameters, null, 2).split("\n").join("\n ")},
|
|
177
|
+
execute: async (args) => {
|
|
178
|
+
${tool.code.split("\n").map((line) => " " + line).join("\n")}
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
export default tool;
|
|
183
|
+
`;
|
|
184
|
+
fs.writeFileSync(path.join(toolsDir, `${tool.name}.ts`), toolContent);
|
|
185
|
+
}
|
|
186
|
+
created.skills.push(skillName);
|
|
187
|
+
return JSON.stringify({
|
|
188
|
+
success: true,
|
|
189
|
+
skill: skillName,
|
|
190
|
+
files: [
|
|
191
|
+
`skills/${skillName}/skill.json`,
|
|
192
|
+
`skills/${skillName}/SKILL.md`,
|
|
193
|
+
...tools.map((t) => `skills/${skillName}/tools/${t.name}.ts`),
|
|
194
|
+
],
|
|
195
|
+
});
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
const saveAgent = {
|
|
199
|
+
name: "save_agent",
|
|
200
|
+
description: "Save a new agent to the config. Creates the agent entry in agent-kit.json, the data directory, and writes the SOUL.md file.",
|
|
201
|
+
parameters: {
|
|
202
|
+
type: "object",
|
|
203
|
+
properties: {
|
|
204
|
+
name: { type: "string", description: "Agent identifier (kebab-case)" },
|
|
205
|
+
displayName: { type: "string", description: "Human-readable name" },
|
|
206
|
+
emoji: { type: "string", description: "Single emoji for the agent" },
|
|
207
|
+
model: { type: "string", description: "Model alias (e.g. 'sonnet', 'haiku')" },
|
|
208
|
+
tools: {
|
|
209
|
+
type: "array",
|
|
210
|
+
items: { type: "string" },
|
|
211
|
+
description: "Array of builtin tool names",
|
|
212
|
+
},
|
|
213
|
+
skills: {
|
|
214
|
+
type: "array",
|
|
215
|
+
items: { type: "string" },
|
|
216
|
+
description: "Array of skill names to attach",
|
|
217
|
+
},
|
|
218
|
+
soul: { type: "string", description: "Full SOUL.md content for this agent" },
|
|
219
|
+
sandbox: {
|
|
220
|
+
type: "object",
|
|
221
|
+
description: "Optional sandbox config",
|
|
222
|
+
properties: {
|
|
223
|
+
allowedCommands: { type: "array", items: { type: "string" } },
|
|
224
|
+
allowedPaths: { type: "array", items: { type: "string" } },
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
slack: {
|
|
228
|
+
type: "object",
|
|
229
|
+
description: "Optional Slack binding",
|
|
230
|
+
properties: {
|
|
231
|
+
channelId: { type: "string" },
|
|
232
|
+
channelName: { type: "string" },
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
heartbeat: {
|
|
236
|
+
type: "object",
|
|
237
|
+
description: "Optional heartbeat config",
|
|
238
|
+
properties: {
|
|
239
|
+
enabled: { type: "boolean" },
|
|
240
|
+
intervalMinutes: { type: "number" },
|
|
241
|
+
model: { type: "string" },
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
webSearch: {
|
|
245
|
+
type: "object",
|
|
246
|
+
description: "Optional web search config",
|
|
247
|
+
properties: {
|
|
248
|
+
provider: { type: "string" },
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
required: ["name", "displayName", "emoji", "tools", "soul"],
|
|
253
|
+
},
|
|
254
|
+
execute: async (args) => {
|
|
255
|
+
const name = args.name;
|
|
256
|
+
const soul = args.soul;
|
|
257
|
+
// Build the agent definition (only include non-empty optional fields)
|
|
258
|
+
const agentDef = {
|
|
259
|
+
displayName: args.displayName,
|
|
260
|
+
emoji: args.emoji,
|
|
261
|
+
tools: args.tools,
|
|
262
|
+
};
|
|
263
|
+
if (args.model)
|
|
264
|
+
agentDef.model = args.model;
|
|
265
|
+
if (args.skills && args.skills.length > 0)
|
|
266
|
+
agentDef.skills = args.skills;
|
|
267
|
+
if (args.sandbox)
|
|
268
|
+
agentDef.sandbox = args.sandbox;
|
|
269
|
+
if (args.slack)
|
|
270
|
+
agentDef.slack = args.slack;
|
|
271
|
+
if (args.heartbeat)
|
|
272
|
+
agentDef.heartbeat = args.heartbeat;
|
|
273
|
+
if (args.webSearch)
|
|
274
|
+
agentDef.webSearch = args.webSearch;
|
|
275
|
+
try {
|
|
276
|
+
upsertAgent(opts.configPath, name, agentDef);
|
|
277
|
+
}
|
|
278
|
+
catch (err) {
|
|
279
|
+
return `Error saving agent: ${err instanceof Error ? err.message : String(err)}`;
|
|
280
|
+
}
|
|
281
|
+
// Create data dirs and write SOUL.md
|
|
282
|
+
ensureAgentDirs(opts.dataDir, name);
|
|
283
|
+
const soulPath = path.join(opts.dataDir, "agents", name, "SOUL.md");
|
|
284
|
+
fs.writeFileSync(soulPath, soul + "\n");
|
|
285
|
+
created.agents.push(name);
|
|
286
|
+
return JSON.stringify({
|
|
287
|
+
success: true,
|
|
288
|
+
agent: name,
|
|
289
|
+
files: [
|
|
290
|
+
`agent-kit.json (updated)`,
|
|
291
|
+
`data/agents/${name}/SOUL.md`,
|
|
292
|
+
],
|
|
293
|
+
});
|
|
294
|
+
},
|
|
295
|
+
};
|
|
296
|
+
const addCronJobTool = {
|
|
297
|
+
name: "add_cron_job",
|
|
298
|
+
description: "Add a cron job to the config for scheduling automated agent tasks.",
|
|
299
|
+
parameters: {
|
|
300
|
+
type: "object",
|
|
301
|
+
properties: {
|
|
302
|
+
id: { type: "string", description: "Unique job identifier (kebab-case)" },
|
|
303
|
+
agent: { type: "string", description: "Agent name to run" },
|
|
304
|
+
schedule: { type: "string", description: "Cron expression (e.g. '0 8 * * *' for daily at 8am)" },
|
|
305
|
+
prompt: { type: "string", description: "The prompt to send to the agent" },
|
|
306
|
+
enabled: { type: "boolean", description: "Whether the job is enabled (default: true)" },
|
|
307
|
+
slack: {
|
|
308
|
+
type: "object",
|
|
309
|
+
description: "Optional Slack channel override for posting results",
|
|
310
|
+
properties: {
|
|
311
|
+
channelId: { type: "string" },
|
|
312
|
+
channelName: { type: "string" },
|
|
313
|
+
},
|
|
314
|
+
},
|
|
315
|
+
},
|
|
316
|
+
required: ["id", "agent", "schedule", "prompt", "enabled"],
|
|
317
|
+
},
|
|
318
|
+
execute: async (args) => {
|
|
319
|
+
const job = {
|
|
320
|
+
id: args.id,
|
|
321
|
+
agent: args.agent,
|
|
322
|
+
schedule: args.schedule,
|
|
323
|
+
prompt: args.prompt,
|
|
324
|
+
enabled: args.enabled ?? true,
|
|
325
|
+
};
|
|
326
|
+
if (args.slack)
|
|
327
|
+
job.slack = args.slack;
|
|
328
|
+
try {
|
|
329
|
+
addCronJob(opts.configPath, job);
|
|
330
|
+
}
|
|
331
|
+
catch (err) {
|
|
332
|
+
return `Error adding cron job: ${err instanceof Error ? err.message : String(err)}`;
|
|
333
|
+
}
|
|
334
|
+
created.crons.push(args.id);
|
|
335
|
+
return JSON.stringify({ success: true, job });
|
|
336
|
+
},
|
|
337
|
+
};
|
|
338
|
+
const finishSetup = {
|
|
339
|
+
name: "finish_setup",
|
|
340
|
+
description: "Call this when the user is done creating agents. Signals that setup is complete.",
|
|
341
|
+
parameters: { type: "object", properties: {}, required: [] },
|
|
342
|
+
execute: async () => {
|
|
343
|
+
const summary = [
|
|
344
|
+
created.agents.length > 0 ? `Agents created: ${created.agents.join(", ")}` : null,
|
|
345
|
+
created.skills.length > 0 ? `Skills created: ${created.skills.join(", ")}` : null,
|
|
346
|
+
created.crons.length > 0 ? `Cron jobs added: ${created.crons.join(", ")}` : null,
|
|
347
|
+
].filter(Boolean).join("\n");
|
|
348
|
+
opts.onFinish(summary || "No changes made.");
|
|
349
|
+
return summary || "Setup complete — no changes were made.";
|
|
350
|
+
},
|
|
351
|
+
};
|
|
352
|
+
return [
|
|
353
|
+
checkEnvironment,
|
|
354
|
+
listAvailableSkills,
|
|
355
|
+
listBuiltinTools,
|
|
356
|
+
readFile,
|
|
357
|
+
createSkill,
|
|
358
|
+
saveAgent,
|
|
359
|
+
addCronJobTool,
|
|
360
|
+
finishSetup,
|
|
361
|
+
];
|
|
362
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function start(): Promise<void>;
|