@lakitu/sdk 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/README.md +166 -0
- package/convex/_generated/api.d.ts +45 -0
- package/convex/_generated/api.js +23 -0
- package/convex/_generated/dataModel.d.ts +58 -0
- package/convex/_generated/server.d.ts +143 -0
- package/convex/_generated/server.js +93 -0
- package/convex/cloud/CLAUDE.md +238 -0
- package/convex/cloud/_generated/api.ts +84 -0
- package/convex/cloud/_generated/component.ts +861 -0
- package/convex/cloud/_generated/dataModel.ts +60 -0
- package/convex/cloud/_generated/server.ts +156 -0
- package/convex/cloud/convex.config.ts +16 -0
- package/convex/cloud/index.ts +29 -0
- package/convex/cloud/intentSchema/generate.ts +447 -0
- package/convex/cloud/intentSchema/index.ts +16 -0
- package/convex/cloud/intentSchema/types.ts +418 -0
- package/convex/cloud/ksaPolicy.ts +554 -0
- package/convex/cloud/mail.ts +92 -0
- package/convex/cloud/schema.ts +322 -0
- package/convex/cloud/utils/kanbanContext.ts +229 -0
- package/convex/cloud/workflows/agentBoard.ts +451 -0
- package/convex/cloud/workflows/agentPrompt.ts +272 -0
- package/convex/cloud/workflows/agentThread.ts +374 -0
- package/convex/cloud/workflows/compileSandbox.ts +146 -0
- package/convex/cloud/workflows/crudBoard.ts +217 -0
- package/convex/cloud/workflows/crudKSAs.ts +262 -0
- package/convex/cloud/workflows/crudLorobeads.ts +371 -0
- package/convex/cloud/workflows/crudSkills.ts +205 -0
- package/convex/cloud/workflows/crudThreads.ts +708 -0
- package/convex/cloud/workflows/lifecycleSandbox.ts +1396 -0
- package/convex/cloud/workflows/sandboxConvex.ts +1046 -0
- package/convex/sandbox/README.md +90 -0
- package/convex/sandbox/_generated/api.d.ts +2934 -0
- package/convex/sandbox/_generated/api.js +23 -0
- package/convex/sandbox/_generated/dataModel.d.ts +60 -0
- package/convex/sandbox/_generated/server.d.ts +143 -0
- package/convex/sandbox/_generated/server.js +93 -0
- package/convex/sandbox/actions/bash.ts +130 -0
- package/convex/sandbox/actions/browser.ts +282 -0
- package/convex/sandbox/actions/file.ts +336 -0
- package/convex/sandbox/actions/lsp.ts +325 -0
- package/convex/sandbox/actions/pdf.ts +119 -0
- package/convex/sandbox/agent/codeExecLoop.ts +535 -0
- package/convex/sandbox/agent/decisions.ts +284 -0
- package/convex/sandbox/agent/index.ts +515 -0
- package/convex/sandbox/agent/subagents.ts +651 -0
- package/convex/sandbox/brandResearch/index.ts +417 -0
- package/convex/sandbox/context/index.ts +7 -0
- package/convex/sandbox/context/session.ts +402 -0
- package/convex/sandbox/convex.config.ts +17 -0
- package/convex/sandbox/index.ts +51 -0
- package/convex/sandbox/nodeActions/codeExec.ts +130 -0
- package/convex/sandbox/planning/beads.ts +187 -0
- package/convex/sandbox/planning/index.ts +8 -0
- package/convex/sandbox/planning/sync.ts +194 -0
- package/convex/sandbox/prompts/codeExec.ts +852 -0
- package/convex/sandbox/prompts/modes.ts +231 -0
- package/convex/sandbox/prompts/system.ts +142 -0
- package/convex/sandbox/schema.ts +510 -0
- package/convex/sandbox/state/artifacts.ts +99 -0
- package/convex/sandbox/state/checkpoints.ts +341 -0
- package/convex/sandbox/state/files.ts +383 -0
- package/convex/sandbox/state/index.ts +10 -0
- package/convex/sandbox/state/verification.actions.ts +268 -0
- package/convex/sandbox/state/verification.ts +101 -0
- package/convex/sandbox/tsconfig.json +25 -0
- package/convex/sandbox/utils/codeExecHelpers.ts +52 -0
- package/dist/cli/commands/build.d.ts +19 -0
- package/dist/cli/commands/build.d.ts.map +1 -0
- package/dist/cli/commands/build.js +223 -0
- package/dist/cli/commands/init.d.ts +16 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +148 -0
- package/dist/cli/commands/publish.d.ts +12 -0
- package/dist/cli/commands/publish.d.ts.map +1 -0
- package/dist/cli/commands/publish.js +33 -0
- package/dist/cli/index.d.ts +14 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +40 -0
- package/dist/sdk/builders.d.ts +104 -0
- package/dist/sdk/builders.d.ts.map +1 -0
- package/dist/sdk/builders.js +214 -0
- package/dist/sdk/index.d.ts +29 -0
- package/dist/sdk/index.d.ts.map +1 -0
- package/dist/sdk/index.js +38 -0
- package/dist/sdk/types.d.ts +107 -0
- package/dist/sdk/types.d.ts.map +1 -0
- package/dist/sdk/types.js +6 -0
- package/ksa/README.md +263 -0
- package/ksa/_generated/REFERENCE.md +2954 -0
- package/ksa/_generated/registry.ts +257 -0
- package/ksa/_shared/configReader.ts +302 -0
- package/ksa/_shared/configSchemas.ts +649 -0
- package/ksa/_shared/gateway.ts +175 -0
- package/ksa/_shared/ksaBehaviors.ts +411 -0
- package/ksa/_shared/ksaProxy.ts +248 -0
- package/ksa/_shared/localDb.ts +302 -0
- package/ksa/index.ts +134 -0
- package/package.json +93 -0
- package/runtime/browser/agent-browser.ts +330 -0
- package/runtime/entrypoint.ts +194 -0
- package/runtime/lsp/manager.ts +366 -0
- package/runtime/pdf/pdf-generator.ts +50 -0
- package/runtime/pdf/renderer.ts +357 -0
- package/runtime/pdf/schema.ts +97 -0
- package/runtime/services/file-watcher.ts +191 -0
- package/template/build.ts +307 -0
- package/template/e2b/Dockerfile +69 -0
- package/template/e2b/e2b.toml +13 -0
- package/template/e2b/prebuild.sh +68 -0
- package/template/e2b/start.sh +14 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lakitu build
|
|
3
|
+
*
|
|
4
|
+
* Build E2B sandbox template with pre-deployed Convex functions.
|
|
5
|
+
*
|
|
6
|
+
* Strategy:
|
|
7
|
+
* 1. Start local convex-backend
|
|
8
|
+
* 2. Deploy sandbox functions with `convex dev --once`
|
|
9
|
+
* 3. Capture the state directory
|
|
10
|
+
* 4. Build E2B template with pre-built state baked in
|
|
11
|
+
*/
|
|
12
|
+
import { Template, defaultBuildLogger, waitForPort } from "e2b";
|
|
13
|
+
import { mkdirSync, rmSync, cpSync, writeFileSync, readFileSync } from "fs";
|
|
14
|
+
import { join, dirname } from "path";
|
|
15
|
+
import { execSync, spawn } from "child_process";
|
|
16
|
+
import { fileURLToPath } from "url";
|
|
17
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
18
|
+
const PACKAGE_ROOT = join(__dirname, "../..");
|
|
19
|
+
async function getApiKey() {
|
|
20
|
+
if (process.env.E2B_API_KEY)
|
|
21
|
+
return process.env.E2B_API_KEY;
|
|
22
|
+
// Check .env.local files
|
|
23
|
+
const envPaths = [
|
|
24
|
+
join(process.cwd(), ".env.local"),
|
|
25
|
+
join(process.cwd(), ".env"),
|
|
26
|
+
];
|
|
27
|
+
for (const path of envPaths) {
|
|
28
|
+
try {
|
|
29
|
+
const content = readFileSync(path, "utf-8");
|
|
30
|
+
const match = content.match(/E2B_API_KEY=(.+)/);
|
|
31
|
+
if (match)
|
|
32
|
+
return match[1].trim();
|
|
33
|
+
}
|
|
34
|
+
catch { /* not found */ }
|
|
35
|
+
}
|
|
36
|
+
// Check E2B config
|
|
37
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE || "";
|
|
38
|
+
try {
|
|
39
|
+
const configPath = join(homeDir, ".e2b/config.json");
|
|
40
|
+
const config = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
41
|
+
if (config.teamApiKey)
|
|
42
|
+
return config.teamApiKey;
|
|
43
|
+
if (config.accessToken)
|
|
44
|
+
return config.accessToken;
|
|
45
|
+
}
|
|
46
|
+
catch { /* not found */ }
|
|
47
|
+
throw new Error("E2B_API_KEY not found. Set in .env.local or run 'e2b auth login'");
|
|
48
|
+
}
|
|
49
|
+
async function sleep(ms) {
|
|
50
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Pre-build Convex locally: start backend, deploy functions, capture state
|
|
54
|
+
*/
|
|
55
|
+
async function prebuildConvex() {
|
|
56
|
+
const stateDir = "/tmp/lakitu-convex-state";
|
|
57
|
+
const sandboxConvexDir = join(PACKAGE_ROOT, "convex/sandbox");
|
|
58
|
+
console.log("=== Pre-building Convex locally ===");
|
|
59
|
+
// Clean up any existing state
|
|
60
|
+
rmSync(stateDir, { recursive: true, force: true });
|
|
61
|
+
mkdirSync(stateDir, { recursive: true });
|
|
62
|
+
// Kill any existing convex-backend
|
|
63
|
+
try {
|
|
64
|
+
execSync("pkill -f convex-backend", { stdio: "ignore" });
|
|
65
|
+
await sleep(1000);
|
|
66
|
+
}
|
|
67
|
+
catch { /* not running */ }
|
|
68
|
+
console.log("Starting local convex-backend...");
|
|
69
|
+
// Start convex-backend in background
|
|
70
|
+
const backend = spawn("convex-backend", [
|
|
71
|
+
join(stateDir, "convex_local_backend.sqlite3"),
|
|
72
|
+
"--port", "3210",
|
|
73
|
+
"--site-proxy-port", "3211",
|
|
74
|
+
"--local-storage", stateDir,
|
|
75
|
+
], {
|
|
76
|
+
cwd: stateDir,
|
|
77
|
+
stdio: "pipe",
|
|
78
|
+
});
|
|
79
|
+
// Wait for backend to be ready
|
|
80
|
+
console.log("Waiting for backend to be ready...");
|
|
81
|
+
for (let i = 0; i < 30; i++) {
|
|
82
|
+
try {
|
|
83
|
+
const res = await fetch("http://127.0.0.1:3210/version");
|
|
84
|
+
if (res.ok) {
|
|
85
|
+
console.log(`Backend ready after ${i + 1} seconds`);
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch { /* not ready yet */ }
|
|
90
|
+
if (i === 29) {
|
|
91
|
+
backend.kill();
|
|
92
|
+
throw new Error("Backend failed to start after 30 seconds");
|
|
93
|
+
}
|
|
94
|
+
await sleep(1000);
|
|
95
|
+
}
|
|
96
|
+
// Deploy functions using convex dev --once
|
|
97
|
+
console.log("Deploying functions with convex dev --once...");
|
|
98
|
+
const tempEnvFile = "/tmp/lakitu-convex-env";
|
|
99
|
+
writeFileSync(tempEnvFile, `CONVEX_SELF_HOSTED_URL=http://127.0.0.1:3210
|
|
100
|
+
CONVEX_SELF_HOSTED_ADMIN_KEY=0135d8598650f8f5cb0f30c34ec2e2bb62793bc28717c8eb6fb577996d50be5f4281b59181095065c5d0f86a2c31ddbe9b597ec62b47ded69782cd
|
|
101
|
+
`);
|
|
102
|
+
try {
|
|
103
|
+
execSync(`npx convex dev --once --typecheck disable --env-file ${tempEnvFile}`, {
|
|
104
|
+
cwd: sandboxConvexDir,
|
|
105
|
+
stdio: "inherit",
|
|
106
|
+
env: { ...process.env, CONVEX_DEPLOYMENT: undefined },
|
|
107
|
+
});
|
|
108
|
+
console.log("Functions deployed successfully!");
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
backend.kill();
|
|
112
|
+
throw new Error("Convex deploy failed");
|
|
113
|
+
}
|
|
114
|
+
// Give backend a moment to flush state
|
|
115
|
+
await sleep(2000);
|
|
116
|
+
// Stop backend gracefully
|
|
117
|
+
console.log("Stopping backend...");
|
|
118
|
+
backend.kill("SIGTERM");
|
|
119
|
+
await sleep(1000);
|
|
120
|
+
console.log("=== Pre-build complete ===\n");
|
|
121
|
+
return stateDir;
|
|
122
|
+
}
|
|
123
|
+
// Base template: Ubuntu + Bun + Convex Backend + Node.js
|
|
124
|
+
const baseTemplate = Template()
|
|
125
|
+
.fromImage("e2bdev/code-interpreter:latest")
|
|
126
|
+
.runCmd("sudo apt-get update && sudo apt-get install -y git curl sqlite3 libsqlite3-dev build-essential unzip")
|
|
127
|
+
.runCmd(`export HOME=/home/user && curl -fsSL https://bun.sh/install | bash`)
|
|
128
|
+
.runCmd(`curl -fsSL https://deb.nodesource.com/setup_20.x | sudo bash - && sudo apt-get install -y nodejs`)
|
|
129
|
+
.runCmd(`
|
|
130
|
+
curl -L -o /tmp/convex.zip "https://github.com/get-convex/convex-backend/releases/download/precompiled-2026-01-08-272e7f4/convex-local-backend-x86_64-unknown-linux-gnu.zip" && \
|
|
131
|
+
unzip /tmp/convex.zip -d /tmp && \
|
|
132
|
+
sudo mv /tmp/convex-local-backend /usr/local/bin/convex-backend && \
|
|
133
|
+
sudo chmod +x /usr/local/bin/convex-backend && \
|
|
134
|
+
rm /tmp/convex.zip
|
|
135
|
+
`)
|
|
136
|
+
.runCmd(`mkdir -p /home/user/workspace /home/user/.convex/convex-backend-state/lakitu /home/user/artifacts && chown -R user:user /home/user`)
|
|
137
|
+
.setEnvs({
|
|
138
|
+
HOME: "/home/user",
|
|
139
|
+
PATH: "/home/user/.bun/bin:/usr/local/bin:/usr/bin:/bin",
|
|
140
|
+
CONVEX_URL: "http://localhost:3210",
|
|
141
|
+
});
|
|
142
|
+
// Custom template: Add Lakitu code + PRE-BUILT Convex state + AUTO-START backend
|
|
143
|
+
function customTemplate(baseId, buildDir) {
|
|
144
|
+
return Template()
|
|
145
|
+
.fromTemplate(baseId)
|
|
146
|
+
.copy(`${buildDir}/lakitu`, "/home/user/lakitu")
|
|
147
|
+
.copy(`${buildDir}/start.sh`, "/home/user/start.sh")
|
|
148
|
+
.copy(`${buildDir}/convex-state`, "/home/user/.convex/convex-backend-state/lakitu")
|
|
149
|
+
.runCmd(`
|
|
150
|
+
sudo chown -R user:user /home/user/lakitu /home/user/start.sh /home/user/.convex && \
|
|
151
|
+
chmod +x /home/user/start.sh && \
|
|
152
|
+
export HOME=/home/user && \
|
|
153
|
+
export PATH="/home/user/.bun/bin:/usr/local/bin:/usr/bin:/bin" && \
|
|
154
|
+
cd /home/user/lakitu && bun install && \
|
|
155
|
+
echo '#!/bin/bash\nbun run /home/user/lakitu/runtime/pdf/pdf-generator.ts "$@"' | sudo tee /usr/local/bin/generate-pdf && \
|
|
156
|
+
sudo chmod +x /usr/local/bin/generate-pdf && \
|
|
157
|
+
cp -r /home/user/lakitu/ksa /home/user/ksa && \
|
|
158
|
+
chown -R user:user /home/user/ksa
|
|
159
|
+
`)
|
|
160
|
+
.setEnvs({
|
|
161
|
+
HOME: "/home/user",
|
|
162
|
+
PATH: "/home/user/.bun/bin:/usr/local/bin:/usr/bin:/bin",
|
|
163
|
+
CONVEX_URL: "http://localhost:3210",
|
|
164
|
+
CONVEX_LOCAL_STORAGE: "/home/user/.convex/convex-backend-state/lakitu",
|
|
165
|
+
})
|
|
166
|
+
.setStartCmd("/home/user/start.sh", waitForPort(3210));
|
|
167
|
+
}
|
|
168
|
+
async function buildBase(apiKey) {
|
|
169
|
+
console.log("🔧 Building Lakitu base template...\n");
|
|
170
|
+
const result = await Template.build(baseTemplate, {
|
|
171
|
+
alias: "lakitu-base",
|
|
172
|
+
apiKey,
|
|
173
|
+
onBuildLogs: defaultBuildLogger(),
|
|
174
|
+
});
|
|
175
|
+
console.log(`\n✅ Base template: ${result.templateId}`);
|
|
176
|
+
return result.templateId;
|
|
177
|
+
}
|
|
178
|
+
async function buildCustom(apiKey, baseId) {
|
|
179
|
+
const buildDir = "/tmp/lakitu-build";
|
|
180
|
+
// Step 1: Pre-build Convex locally
|
|
181
|
+
const stateDir = await prebuildConvex();
|
|
182
|
+
// Step 2: Prepare build context
|
|
183
|
+
console.log("📦 Preparing build context...");
|
|
184
|
+
rmSync(buildDir, { recursive: true, force: true });
|
|
185
|
+
mkdirSync(buildDir, { recursive: true });
|
|
186
|
+
// Copy lakitu source (excluding node_modules, .git, template, cli)
|
|
187
|
+
const excludes = ["node_modules", ".git", "template", "cli", "dist"];
|
|
188
|
+
cpSync(PACKAGE_ROOT, join(buildDir, "lakitu"), {
|
|
189
|
+
recursive: true,
|
|
190
|
+
filter: (src) => !excludes.some(ex => src.includes(`/${ex}`)),
|
|
191
|
+
});
|
|
192
|
+
// Copy start script
|
|
193
|
+
cpSync(join(PACKAGE_ROOT, "template/e2b/start.sh"), join(buildDir, "start.sh"));
|
|
194
|
+
// Copy pre-built Convex state
|
|
195
|
+
cpSync(stateDir, join(buildDir, "convex-state"), { recursive: true });
|
|
196
|
+
console.log(" ✓ Build context ready\n");
|
|
197
|
+
// Step 3: Build E2B template with pre-built state
|
|
198
|
+
console.log(`🔧 Building Lakitu custom template on ${baseId}...\n`);
|
|
199
|
+
const result = await Template.build(customTemplate(baseId, buildDir), {
|
|
200
|
+
alias: "lakitu",
|
|
201
|
+
apiKey,
|
|
202
|
+
onBuildLogs: defaultBuildLogger(),
|
|
203
|
+
});
|
|
204
|
+
console.log(`\n✅ Custom template: ${result.templateId}`);
|
|
205
|
+
console.log(" Functions are PRE-DEPLOYED - sandbox starts instantly!");
|
|
206
|
+
return result.templateId;
|
|
207
|
+
}
|
|
208
|
+
export async function build(options) {
|
|
209
|
+
console.log("🍄 Lakitu Template Builder\n");
|
|
210
|
+
const apiKey = await getApiKey();
|
|
211
|
+
if (options.base) {
|
|
212
|
+
await buildBase(apiKey);
|
|
213
|
+
}
|
|
214
|
+
else if (options.custom) {
|
|
215
|
+
await buildCustom(apiKey, options.baseId || "lakitu-base");
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
// Build both
|
|
219
|
+
const baseId = await buildBase(apiKey);
|
|
220
|
+
await buildCustom(apiKey, baseId);
|
|
221
|
+
}
|
|
222
|
+
console.log("\n🎉 Build complete!");
|
|
223
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lakitu init
|
|
3
|
+
*
|
|
4
|
+
* Initialize lakitu in a Convex project:
|
|
5
|
+
* 1. Install @lakitu/sdk as a dependency
|
|
6
|
+
* 2. Create convex/lakitu.config.ts
|
|
7
|
+
* 3. Add lakitu component to convex.config.ts
|
|
8
|
+
* 4. Create example KSA file
|
|
9
|
+
*/
|
|
10
|
+
interface InitOptions {
|
|
11
|
+
dir: string;
|
|
12
|
+
skipInstall?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare function init(options: InitOptions): Promise<void>;
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=init.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../cli/commands/init.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,UAAU,WAAW;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAuED,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW,iBA6E9C"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lakitu init
|
|
3
|
+
*
|
|
4
|
+
* Initialize lakitu in a Convex project:
|
|
5
|
+
* 1. Install @lakitu/sdk as a dependency
|
|
6
|
+
* 2. Create convex/lakitu.config.ts
|
|
7
|
+
* 3. Add lakitu component to convex.config.ts
|
|
8
|
+
* 4. Create example KSA file
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync } from "fs";
|
|
11
|
+
import { join } from "path";
|
|
12
|
+
import { execSync } from "child_process";
|
|
13
|
+
const LAKITU_CONFIG = `/**
|
|
14
|
+
* Lakitu Configuration
|
|
15
|
+
*
|
|
16
|
+
* Configure your AI agent's capabilities here.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { Lakitu } from "@lakitu/sdk";
|
|
20
|
+
|
|
21
|
+
export default Lakitu.configure({
|
|
22
|
+
// E2B template to use (build with: npx lakitu build)
|
|
23
|
+
template: "lakitu",
|
|
24
|
+
|
|
25
|
+
// Default model for agent
|
|
26
|
+
model: "anthropic/claude-sonnet-4-20250514",
|
|
27
|
+
|
|
28
|
+
// KSA modules to enable
|
|
29
|
+
ksas: [
|
|
30
|
+
// Built-in KSAs
|
|
31
|
+
"file",
|
|
32
|
+
"shell",
|
|
33
|
+
"browser",
|
|
34
|
+
"beads",
|
|
35
|
+
|
|
36
|
+
// Custom KSAs (define in convex/lakitu/)
|
|
37
|
+
// "./example",
|
|
38
|
+
],
|
|
39
|
+
|
|
40
|
+
// Sandbox pool settings
|
|
41
|
+
pool: {
|
|
42
|
+
min: 0,
|
|
43
|
+
max: 5,
|
|
44
|
+
idleTimeout: 300_000, // 5 minutes
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
`;
|
|
48
|
+
const EXAMPLE_KSA = `/**
|
|
49
|
+
* Example Custom KSA
|
|
50
|
+
*
|
|
51
|
+
* KSAs (Knowledge, Skills, Abilities) are capability modules
|
|
52
|
+
* that the AI agent can use via code execution.
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
import { defineKSA, fn, service } from "@lakitu/sdk";
|
|
56
|
+
|
|
57
|
+
export const exampleKSA = defineKSA("example")
|
|
58
|
+
.description("Example KSA showing how to define custom capabilities")
|
|
59
|
+
.category("skills")
|
|
60
|
+
|
|
61
|
+
// Simple function that calls a Convex service
|
|
62
|
+
.fn("greet", fn()
|
|
63
|
+
.description("Generate a greeting")
|
|
64
|
+
.param("name", { type: "string", required: true })
|
|
65
|
+
.impl(service("myService.greet")
|
|
66
|
+
.mapArgs(({ name }) => ({ userName: name }))
|
|
67
|
+
)
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
.build();
|
|
71
|
+
|
|
72
|
+
export default exampleKSA;
|
|
73
|
+
`;
|
|
74
|
+
const CONVEX_CONFIG_ADDITION = `
|
|
75
|
+
// Lakitu agent component
|
|
76
|
+
import lakitu from "@lakitu/sdk/component";
|
|
77
|
+
app.use(lakitu);
|
|
78
|
+
`;
|
|
79
|
+
export async function init(options) {
|
|
80
|
+
const cwd = process.cwd();
|
|
81
|
+
const convexDir = join(cwd, options.dir);
|
|
82
|
+
console.log("🍄 Initializing Lakitu...\n");
|
|
83
|
+
// Check if convex directory exists
|
|
84
|
+
if (!existsSync(convexDir)) {
|
|
85
|
+
console.error(`❌ Convex directory not found: ${convexDir}`);
|
|
86
|
+
console.log(" Run this command from a Convex project root.");
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
// Step 1: Install dependency
|
|
90
|
+
if (!options.skipInstall) {
|
|
91
|
+
console.log("📦 Installing @lakitu/sdk...");
|
|
92
|
+
try {
|
|
93
|
+
// Detect package manager
|
|
94
|
+
const useBun = existsSync(join(cwd, "bun.lockb"));
|
|
95
|
+
const usePnpm = existsSync(join(cwd, "pnpm-lock.yaml"));
|
|
96
|
+
const useYarn = existsSync(join(cwd, "yarn.lock"));
|
|
97
|
+
const pm = useBun ? "bun" : usePnpm ? "pnpm" : useYarn ? "yarn" : "npm";
|
|
98
|
+
const addCmd = pm === "yarn" ? "add" : "install";
|
|
99
|
+
execSync(`${pm} ${addCmd} @lakitu/sdk`, { stdio: "inherit" });
|
|
100
|
+
console.log(" ✓ Installed\n");
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
console.warn(" ⚠ Could not auto-install. Run: npm install @lakitu/sdk\n");
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Step 2: Create convex/lakitu/ directory and config
|
|
107
|
+
const lakituDir = join(convexDir, "lakitu");
|
|
108
|
+
if (!existsSync(lakituDir)) {
|
|
109
|
+
mkdirSync(lakituDir, { recursive: true });
|
|
110
|
+
}
|
|
111
|
+
const configPath = join(lakituDir, "config.ts");
|
|
112
|
+
if (!existsSync(configPath)) {
|
|
113
|
+
console.log("📝 Creating convex/lakitu/config.ts...");
|
|
114
|
+
writeFileSync(configPath, LAKITU_CONFIG);
|
|
115
|
+
console.log(" ✓ Created\n");
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
console.log("📝 convex/lakitu/config.ts already exists, skipping.\n");
|
|
119
|
+
}
|
|
120
|
+
// Step 3: Create example KSA in convex/lakitu/
|
|
121
|
+
const examplePath = join(lakituDir, "example.ts");
|
|
122
|
+
if (!existsSync(examplePath)) {
|
|
123
|
+
console.log("📝 Creating example KSA...");
|
|
124
|
+
if (!existsSync(lakituDir)) {
|
|
125
|
+
mkdirSync(lakituDir, { recursive: true });
|
|
126
|
+
}
|
|
127
|
+
writeFileSync(examplePath, EXAMPLE_KSA);
|
|
128
|
+
console.log(" ✓ Created convex/lakitu/example.ts\n");
|
|
129
|
+
}
|
|
130
|
+
// Step 4: Check convex.config.ts
|
|
131
|
+
const convexConfigPath = join(convexDir, "convex.config.ts");
|
|
132
|
+
if (existsSync(convexConfigPath)) {
|
|
133
|
+
const content = readFileSync(convexConfigPath, "utf-8");
|
|
134
|
+
if (!content.includes("@lakitu/sdk")) {
|
|
135
|
+
console.log("📝 Add this to your convex.config.ts:\n");
|
|
136
|
+
console.log(" " + CONVEX_CONFIG_ADDITION.trim().split("\n").join("\n "));
|
|
137
|
+
console.log("");
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Done
|
|
141
|
+
console.log("✅ Lakitu initialized!\n");
|
|
142
|
+
console.log("Next steps:");
|
|
143
|
+
console.log(" 1. Add lakitu component to convex.config.ts (see above)");
|
|
144
|
+
console.log(" 2. Define KSAs in convex/lakitu/");
|
|
145
|
+
console.log(" 3. Build template: npx lakitu build");
|
|
146
|
+
console.log(" 4. Publish to E2B: npx lakitu publish");
|
|
147
|
+
console.log("");
|
|
148
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lakitu publish
|
|
3
|
+
*
|
|
4
|
+
* Publish your built template to E2B.
|
|
5
|
+
* This is mostly a convenience wrapper - the build command already publishes.
|
|
6
|
+
*/
|
|
7
|
+
interface PublishOptions {
|
|
8
|
+
alias?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function publish(options: PublishOptions): Promise<void>;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=publish.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../../cli/commands/publish.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,UAAU,cAAc;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,OAAO,CAAC,OAAO,EAAE,cAAc,iBA2BpD"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lakitu publish
|
|
3
|
+
*
|
|
4
|
+
* Publish your built template to E2B.
|
|
5
|
+
* This is mostly a convenience wrapper - the build command already publishes.
|
|
6
|
+
*/
|
|
7
|
+
import { execSync } from "child_process";
|
|
8
|
+
export async function publish(options) {
|
|
9
|
+
console.log("🍄 Publishing Lakitu template to E2B...\n");
|
|
10
|
+
const alias = options.alias || "lakitu";
|
|
11
|
+
// The build command already publishes, so this is mainly for
|
|
12
|
+
// re-publishing or updating an existing template
|
|
13
|
+
console.log(`Template alias: ${alias}`);
|
|
14
|
+
console.log("");
|
|
15
|
+
console.log("To publish a new template, run:");
|
|
16
|
+
console.log(" npx lakitu build");
|
|
17
|
+
console.log("");
|
|
18
|
+
console.log("To manage templates directly:");
|
|
19
|
+
console.log(" e2b template list");
|
|
20
|
+
console.log(" e2b template delete <template-id>");
|
|
21
|
+
console.log("");
|
|
22
|
+
// Check if e2b CLI is available
|
|
23
|
+
try {
|
|
24
|
+
const templates = execSync("e2b template list", { encoding: "utf-8" });
|
|
25
|
+
console.log("Your E2B templates:");
|
|
26
|
+
console.log(templates);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
console.log("💡 Install E2B CLI for more template management:");
|
|
30
|
+
console.log(" npm install -g @e2b/cli");
|
|
31
|
+
console.log(" e2b auth login");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Lakitu CLI
|
|
4
|
+
*
|
|
5
|
+
* Self-hosted AI agent framework for Convex + E2B.
|
|
6
|
+
*
|
|
7
|
+
* Commands:
|
|
8
|
+
* init - Initialize lakitu in a Convex project
|
|
9
|
+
* build - Build E2B sandbox template
|
|
10
|
+
* publish - Publish template to E2B
|
|
11
|
+
* dev - Start local development
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../cli/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;GAUG"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Lakitu CLI
|
|
4
|
+
*
|
|
5
|
+
* Self-hosted AI agent framework for Convex + E2B.
|
|
6
|
+
*
|
|
7
|
+
* Commands:
|
|
8
|
+
* init - Initialize lakitu in a Convex project
|
|
9
|
+
* build - Build E2B sandbox template
|
|
10
|
+
* publish - Publish template to E2B
|
|
11
|
+
* dev - Start local development
|
|
12
|
+
*/
|
|
13
|
+
import { Command } from "commander";
|
|
14
|
+
import { init } from "./commands/init.js";
|
|
15
|
+
import { build } from "./commands/build.js";
|
|
16
|
+
import { publish } from "./commands/publish.js";
|
|
17
|
+
const program = new Command();
|
|
18
|
+
program
|
|
19
|
+
.name("lakitu")
|
|
20
|
+
.description("Self-hosted AI agent framework for Convex + E2B")
|
|
21
|
+
.version("0.1.0");
|
|
22
|
+
program
|
|
23
|
+
.command("init")
|
|
24
|
+
.description("Initialize lakitu in your Convex project")
|
|
25
|
+
.option("-d, --dir <path>", "Convex directory", "convex")
|
|
26
|
+
.option("--skip-install", "Skip npm install")
|
|
27
|
+
.action(init);
|
|
28
|
+
program
|
|
29
|
+
.command("build")
|
|
30
|
+
.description("Build E2B sandbox template")
|
|
31
|
+
.option("--base", "Build base template only")
|
|
32
|
+
.option("--custom", "Build custom template only")
|
|
33
|
+
.option("--base-id <id>", "Base template ID for custom build", "lakitu-base")
|
|
34
|
+
.action(build);
|
|
35
|
+
program
|
|
36
|
+
.command("publish")
|
|
37
|
+
.description("Publish template to E2B")
|
|
38
|
+
.option("--alias <name>", "Template alias", "lakitu")
|
|
39
|
+
.action(publish);
|
|
40
|
+
program.parse();
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KSA SDK Builders
|
|
3
|
+
*
|
|
4
|
+
* Fluent API for defining KSAs with full TypeScript type safety.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { defineKSA, fn, service, primitive } from '@lakitu/sdk';
|
|
9
|
+
*
|
|
10
|
+
* export const webKSA = defineKSA('web')
|
|
11
|
+
* .description('Web search and content extraction')
|
|
12
|
+
* .category('skills')
|
|
13
|
+
* .group('research')
|
|
14
|
+
* .fn('search', fn()
|
|
15
|
+
* .description('Search the web')
|
|
16
|
+
* .param('query', { type: 'string', required: true })
|
|
17
|
+
* .param('maxResults', { type: 'number', default: 10 })
|
|
18
|
+
* .returns<SearchResult[]>()
|
|
19
|
+
* .impl(service('services.Valyu.internal.search')
|
|
20
|
+
* .mapArgs(({ query, maxResults }) => ({ query, maxResults, fastMode: true }))
|
|
21
|
+
* .mapResult(r => r.results || [])
|
|
22
|
+
* )
|
|
23
|
+
* )
|
|
24
|
+
* .build();
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
import type { KSADef, KSACategory, FunctionDef, ParamDef, ParamType, Implementation, ServiceImpl, PrimitiveImpl, CompositeImpl, StepContext } from "./types";
|
|
28
|
+
export declare class ServiceBuilder<TArgs = Record<string, unknown>, TResult = unknown> {
|
|
29
|
+
private _path;
|
|
30
|
+
private _mapArgs?;
|
|
31
|
+
private _mapResult?;
|
|
32
|
+
constructor(path: string);
|
|
33
|
+
/** Map input arguments to service arguments */
|
|
34
|
+
mapArgs<T extends TArgs>(mapper: (args: T) => Record<string, unknown>): ServiceBuilder<T, TResult>;
|
|
35
|
+
/** Map service result to function return type */
|
|
36
|
+
mapResult<T>(mapper: (result: unknown) => T): ServiceBuilder<TArgs, T>;
|
|
37
|
+
build(): ServiceImpl<TArgs, TResult>;
|
|
38
|
+
}
|
|
39
|
+
/** Create a service implementation */
|
|
40
|
+
export declare function service(path: string): ServiceBuilder;
|
|
41
|
+
/** Create a primitive implementation */
|
|
42
|
+
export declare function primitive(name: string): PrimitiveImpl;
|
|
43
|
+
export declare class CompositeBuilder {
|
|
44
|
+
private _steps;
|
|
45
|
+
/** Call another KSA function */
|
|
46
|
+
call(fnPath: string, args?: Record<string, unknown> | ((ctx: StepContext) => Record<string, unknown>), as?: string): CompositeBuilder;
|
|
47
|
+
/** Return a value */
|
|
48
|
+
return(value: unknown | ((ctx: StepContext) => unknown)): CompositeBuilder;
|
|
49
|
+
build(): CompositeImpl;
|
|
50
|
+
}
|
|
51
|
+
/** Create a composite implementation */
|
|
52
|
+
export declare function composite(): CompositeBuilder;
|
|
53
|
+
export declare class FunctionBuilder<TParams extends Record<string, ParamDef> = Record<string, never>, TResult = unknown> {
|
|
54
|
+
private _description;
|
|
55
|
+
private _params;
|
|
56
|
+
private _impl?;
|
|
57
|
+
private _returns?;
|
|
58
|
+
/** Set function description */
|
|
59
|
+
description(desc: string): this;
|
|
60
|
+
/** Add a parameter */
|
|
61
|
+
param<K extends string, T extends ParamType>(name: K, def: ParamDef & {
|
|
62
|
+
type: T;
|
|
63
|
+
}): FunctionBuilder<TParams & Record<K, ParamDef & {
|
|
64
|
+
type: T;
|
|
65
|
+
}>, TResult>;
|
|
66
|
+
/** Set return type info */
|
|
67
|
+
returns<T>(typeInfo?: {
|
|
68
|
+
type: string;
|
|
69
|
+
description?: string;
|
|
70
|
+
}): FunctionBuilder<TParams, T>;
|
|
71
|
+
/** Set implementation */
|
|
72
|
+
impl(implementation: Implementation | ServiceBuilder | CompositeBuilder): this;
|
|
73
|
+
build(name: string): FunctionDef;
|
|
74
|
+
}
|
|
75
|
+
/** Create a function builder */
|
|
76
|
+
export declare function fn(): FunctionBuilder;
|
|
77
|
+
export declare class KSABuilder {
|
|
78
|
+
private _name;
|
|
79
|
+
private _description;
|
|
80
|
+
private _category;
|
|
81
|
+
private _group?;
|
|
82
|
+
private _icon?;
|
|
83
|
+
private _functions;
|
|
84
|
+
constructor(name: string);
|
|
85
|
+
/** Set KSA description */
|
|
86
|
+
description(desc: string): this;
|
|
87
|
+
/** Set KSA category */
|
|
88
|
+
category(cat: KSACategory): this;
|
|
89
|
+
/** Set KSA group (subcategory) */
|
|
90
|
+
group(grp: string): this;
|
|
91
|
+
/** Set KSA icon (MDI icon name) */
|
|
92
|
+
icon(ico: string): this;
|
|
93
|
+
/** Add a function to the KSA */
|
|
94
|
+
fn(name: string, builder: FunctionBuilder): this;
|
|
95
|
+
/** Build the KSA definition */
|
|
96
|
+
build(): KSADef;
|
|
97
|
+
}
|
|
98
|
+
/** Create a KSA builder */
|
|
99
|
+
export declare function defineKSA(name: string): KSABuilder;
|
|
100
|
+
/** Create a registry from KSA definitions */
|
|
101
|
+
export declare function createRegistry(...ksas: KSADef[]): Map<string, KSADef>;
|
|
102
|
+
/** Get a function from a registry */
|
|
103
|
+
export declare function getFunction(registry: Map<string, KSADef>, ksaName: string, fnName: string): FunctionDef | undefined;
|
|
104
|
+
//# sourceMappingURL=builders.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builders.d.ts","sourceRoot":"","sources":["../../sdk/builders.ts"],"names":[],"mappings":"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"}
|