@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.
Files changed (111) hide show
  1. package/README.md +166 -0
  2. package/convex/_generated/api.d.ts +45 -0
  3. package/convex/_generated/api.js +23 -0
  4. package/convex/_generated/dataModel.d.ts +58 -0
  5. package/convex/_generated/server.d.ts +143 -0
  6. package/convex/_generated/server.js +93 -0
  7. package/convex/cloud/CLAUDE.md +238 -0
  8. package/convex/cloud/_generated/api.ts +84 -0
  9. package/convex/cloud/_generated/component.ts +861 -0
  10. package/convex/cloud/_generated/dataModel.ts +60 -0
  11. package/convex/cloud/_generated/server.ts +156 -0
  12. package/convex/cloud/convex.config.ts +16 -0
  13. package/convex/cloud/index.ts +29 -0
  14. package/convex/cloud/intentSchema/generate.ts +447 -0
  15. package/convex/cloud/intentSchema/index.ts +16 -0
  16. package/convex/cloud/intentSchema/types.ts +418 -0
  17. package/convex/cloud/ksaPolicy.ts +554 -0
  18. package/convex/cloud/mail.ts +92 -0
  19. package/convex/cloud/schema.ts +322 -0
  20. package/convex/cloud/utils/kanbanContext.ts +229 -0
  21. package/convex/cloud/workflows/agentBoard.ts +451 -0
  22. package/convex/cloud/workflows/agentPrompt.ts +272 -0
  23. package/convex/cloud/workflows/agentThread.ts +374 -0
  24. package/convex/cloud/workflows/compileSandbox.ts +146 -0
  25. package/convex/cloud/workflows/crudBoard.ts +217 -0
  26. package/convex/cloud/workflows/crudKSAs.ts +262 -0
  27. package/convex/cloud/workflows/crudLorobeads.ts +371 -0
  28. package/convex/cloud/workflows/crudSkills.ts +205 -0
  29. package/convex/cloud/workflows/crudThreads.ts +708 -0
  30. package/convex/cloud/workflows/lifecycleSandbox.ts +1396 -0
  31. package/convex/cloud/workflows/sandboxConvex.ts +1046 -0
  32. package/convex/sandbox/README.md +90 -0
  33. package/convex/sandbox/_generated/api.d.ts +2934 -0
  34. package/convex/sandbox/_generated/api.js +23 -0
  35. package/convex/sandbox/_generated/dataModel.d.ts +60 -0
  36. package/convex/sandbox/_generated/server.d.ts +143 -0
  37. package/convex/sandbox/_generated/server.js +93 -0
  38. package/convex/sandbox/actions/bash.ts +130 -0
  39. package/convex/sandbox/actions/browser.ts +282 -0
  40. package/convex/sandbox/actions/file.ts +336 -0
  41. package/convex/sandbox/actions/lsp.ts +325 -0
  42. package/convex/sandbox/actions/pdf.ts +119 -0
  43. package/convex/sandbox/agent/codeExecLoop.ts +535 -0
  44. package/convex/sandbox/agent/decisions.ts +284 -0
  45. package/convex/sandbox/agent/index.ts +515 -0
  46. package/convex/sandbox/agent/subagents.ts +651 -0
  47. package/convex/sandbox/brandResearch/index.ts +417 -0
  48. package/convex/sandbox/context/index.ts +7 -0
  49. package/convex/sandbox/context/session.ts +402 -0
  50. package/convex/sandbox/convex.config.ts +17 -0
  51. package/convex/sandbox/index.ts +51 -0
  52. package/convex/sandbox/nodeActions/codeExec.ts +130 -0
  53. package/convex/sandbox/planning/beads.ts +187 -0
  54. package/convex/sandbox/planning/index.ts +8 -0
  55. package/convex/sandbox/planning/sync.ts +194 -0
  56. package/convex/sandbox/prompts/codeExec.ts +852 -0
  57. package/convex/sandbox/prompts/modes.ts +231 -0
  58. package/convex/sandbox/prompts/system.ts +142 -0
  59. package/convex/sandbox/schema.ts +510 -0
  60. package/convex/sandbox/state/artifacts.ts +99 -0
  61. package/convex/sandbox/state/checkpoints.ts +341 -0
  62. package/convex/sandbox/state/files.ts +383 -0
  63. package/convex/sandbox/state/index.ts +10 -0
  64. package/convex/sandbox/state/verification.actions.ts +268 -0
  65. package/convex/sandbox/state/verification.ts +101 -0
  66. package/convex/sandbox/tsconfig.json +25 -0
  67. package/convex/sandbox/utils/codeExecHelpers.ts +52 -0
  68. package/dist/cli/commands/build.d.ts +19 -0
  69. package/dist/cli/commands/build.d.ts.map +1 -0
  70. package/dist/cli/commands/build.js +223 -0
  71. package/dist/cli/commands/init.d.ts +16 -0
  72. package/dist/cli/commands/init.d.ts.map +1 -0
  73. package/dist/cli/commands/init.js +148 -0
  74. package/dist/cli/commands/publish.d.ts +12 -0
  75. package/dist/cli/commands/publish.d.ts.map +1 -0
  76. package/dist/cli/commands/publish.js +33 -0
  77. package/dist/cli/index.d.ts +14 -0
  78. package/dist/cli/index.d.ts.map +1 -0
  79. package/dist/cli/index.js +40 -0
  80. package/dist/sdk/builders.d.ts +104 -0
  81. package/dist/sdk/builders.d.ts.map +1 -0
  82. package/dist/sdk/builders.js +214 -0
  83. package/dist/sdk/index.d.ts +29 -0
  84. package/dist/sdk/index.d.ts.map +1 -0
  85. package/dist/sdk/index.js +38 -0
  86. package/dist/sdk/types.d.ts +107 -0
  87. package/dist/sdk/types.d.ts.map +1 -0
  88. package/dist/sdk/types.js +6 -0
  89. package/ksa/README.md +263 -0
  90. package/ksa/_generated/REFERENCE.md +2954 -0
  91. package/ksa/_generated/registry.ts +257 -0
  92. package/ksa/_shared/configReader.ts +302 -0
  93. package/ksa/_shared/configSchemas.ts +649 -0
  94. package/ksa/_shared/gateway.ts +175 -0
  95. package/ksa/_shared/ksaBehaviors.ts +411 -0
  96. package/ksa/_shared/ksaProxy.ts +248 -0
  97. package/ksa/_shared/localDb.ts +302 -0
  98. package/ksa/index.ts +134 -0
  99. package/package.json +93 -0
  100. package/runtime/browser/agent-browser.ts +330 -0
  101. package/runtime/entrypoint.ts +194 -0
  102. package/runtime/lsp/manager.ts +366 -0
  103. package/runtime/pdf/pdf-generator.ts +50 -0
  104. package/runtime/pdf/renderer.ts +357 -0
  105. package/runtime/pdf/schema.ts +97 -0
  106. package/runtime/services/file-watcher.ts +191 -0
  107. package/template/build.ts +307 -0
  108. package/template/e2b/Dockerfile +69 -0
  109. package/template/e2b/e2b.toml +13 -0
  110. package/template/e2b/prebuild.sh +68 -0
  111. package/template/e2b/start.sh +14 -0
@@ -0,0 +1,447 @@
1
+ /**
2
+ * Intent Schema Generation
3
+ *
4
+ * Uses a fast LLM (GROQ via OpenRouter) to pre-analyze user requests
5
+ * and generate structured guidance for the sandbox agent.
6
+ *
7
+ * This runs in parallel with sandbox warm-up for zero latency cost.
8
+ */
9
+
10
+ import { internalAction } from "../_generated/server";
11
+ import { internal } from "../_generated/api";
12
+ import { v } from "convex/values";
13
+ import {
14
+ type IntentSchema,
15
+ type UserAgentPolicy,
16
+ validateIntentSchema,
17
+ applyUserPolicy,
18
+ createDefaultIntentSchema,
19
+ } from "./types";
20
+ import {
21
+ getAllKSAs,
22
+ getKSANames,
23
+ CORE_KSAS,
24
+ type KSAInfo,
25
+ } from "../ksaPolicy";
26
+
27
+ // ============================================================================
28
+ // Configuration
29
+ // ============================================================================
30
+
31
+ /** Model to use for intent schema generation - fast and cheap */
32
+ const INTENT_SCHEMA_MODEL = "groq/llama-3.3-70b-versatile";
33
+
34
+ /** Fallback model if primary fails */
35
+ const FALLBACK_MODEL = "google/gemini-2.0-flash-001";
36
+
37
+ /** Max tokens for schema generation */
38
+ const MAX_TOKENS = 2000;
39
+
40
+ /** Temperature - lower for more structured output */
41
+ const TEMPERATURE = 0.3;
42
+
43
+ // ============================================================================
44
+ // Prompt Building
45
+ // ============================================================================
46
+
47
+ /**
48
+ * Build a compact KSA registry summary for the prompt
49
+ */
50
+ function buildKSARegistrySummary(): string {
51
+ const ksas = getAllKSAs();
52
+
53
+ // Group by category
54
+ const byCategory = new Map<string, KSAInfo[]>();
55
+ for (const ksa of ksas) {
56
+ const cat = ksa.category;
57
+ if (!byCategory.has(cat)) byCategory.set(cat, []);
58
+ byCategory.get(cat)!.push(ksa);
59
+ }
60
+
61
+ const lines: string[] = [];
62
+
63
+ // Core KSAs (always available)
64
+ const core = byCategory.get("core") || [];
65
+ if (core.length > 0) {
66
+ lines.push("## Core KSAs (Always Available)");
67
+ for (const k of core) {
68
+ lines.push(`- **${k.name}**: ${k.description}`);
69
+ lines.push(` Functions: ${k.functions.slice(0, 4).join(", ")}${k.functions.length > 4 ? "..." : ""}`);
70
+ }
71
+ lines.push("");
72
+ }
73
+
74
+ // Skills KSAs
75
+ const skills = byCategory.get("skills") || [];
76
+ if (skills.length > 0) {
77
+ lines.push("## Skills KSAs (Research & Data)");
78
+ for (const k of skills) {
79
+ const group = k.group ? ` [${k.group}]` : "";
80
+ lines.push(`- **${k.name}**${group}: ${k.description}`);
81
+ lines.push(` Functions: ${k.functions.slice(0, 4).join(", ")}${k.functions.length > 4 ? "..." : ""}`);
82
+ }
83
+ lines.push("");
84
+ }
85
+
86
+ // Deliverables KSAs
87
+ const deliverables = byCategory.get("deliverables") || [];
88
+ if (deliverables.length > 0) {
89
+ lines.push("## Deliverables KSAs (Output Formats)");
90
+ for (const k of deliverables) {
91
+ lines.push(`- **${k.name}**: ${k.description}`);
92
+ lines.push(` Functions: ${k.functions.join(", ")}`);
93
+ }
94
+ lines.push("");
95
+ }
96
+
97
+ return lines.join("\n");
98
+ }
99
+
100
+ /**
101
+ * Build the system prompt for intent schema generation
102
+ */
103
+ function buildSchemaGenerationPrompt(
104
+ userPrompt: string,
105
+ threadContext?: string,
106
+ enabledSkills?: string[]
107
+ ): string {
108
+ const ksaRegistry = buildKSARegistrySummary();
109
+ const allKSANames = getKSANames();
110
+
111
+ return `You are an Intent Analyzer for an AI agent system. Your job is to pre-analyze user requests and generate an Intent Schema that guides agent execution.
112
+
113
+ ${ksaRegistry}
114
+
115
+ ## Available KSA Names
116
+ ${allKSANames.join(", ")}
117
+
118
+ ---
119
+
120
+ ## User Request
121
+ ${userPrompt}
122
+
123
+ ${threadContext ? `## Conversation Context\n${threadContext}\n` : ""}
124
+ ${enabledSkills?.length ? `## Pre-selected Skills\n${enabledSkills.join(", ")}\n` : ""}
125
+
126
+ ---
127
+
128
+ ## Your Task
129
+ Analyze the user's request and generate an Intent Schema with:
130
+
131
+ 1. **intent**: Break down what the user wants
132
+ - summary: One-line summary (max 100 chars)
133
+ - objective: What they're trying to accomplish
134
+ - context: Key context elements (entities, constraints, preferences)
135
+ - domain: Topic area (e.g., "research", "content", "automation", "design")
136
+
137
+ 2. **ksas**: Prioritize which KSAs the agent should use
138
+ - priority: Top 3-5 KSAs to use first (ordered)
139
+ - secondary: Other potentially useful KSAs
140
+ - notNeeded: KSAs clearly not relevant
141
+ - reasoning: Brief explanation of your choices
142
+
143
+ 3. **plan**: Suggested execution approach
144
+ - goals: 2-4 goals with importance levels (critical/important/nice-to-have)
145
+ - deliverables: Expected outputs with type (markdown/json/csv/pdf/html/code/email)
146
+ - steps: 3-6 high-level execution steps
147
+
148
+ 4. **policy**: Default access controls
149
+ - enabledKSAs: All KSAs from priority + secondary
150
+ - disabledKSAs: Empty (user can override)
151
+ - allowExternalCalls: true (unless user is asking for local-only work)
152
+
153
+ ## Output Format
154
+ Respond with ONLY valid JSON matching this structure:
155
+
156
+ \`\`\`json
157
+ {
158
+ "intent": {
159
+ "summary": "string",
160
+ "objective": "string",
161
+ "context": ["string"],
162
+ "domain": "string"
163
+ },
164
+ "ksas": {
165
+ "priority": ["ksa_name"],
166
+ "secondary": ["ksa_name"],
167
+ "notNeeded": ["ksa_name"],
168
+ "reasoning": "string"
169
+ },
170
+ "plan": {
171
+ "goals": [
172
+ { "id": "g1", "text": "string", "importance": "critical|important|nice-to-have" }
173
+ ],
174
+ "deliverables": [
175
+ { "id": "d1", "type": "markdown|json|csv|pdf|html|code|email", "name": "string", "description": "string" }
176
+ ],
177
+ "steps": ["string"]
178
+ },
179
+ "policy": {
180
+ "enabledKSAs": ["ksa_name"],
181
+ "disabledKSAs": [],
182
+ "allowExternalCalls": true
183
+ }
184
+ }
185
+ \`\`\`
186
+
187
+ IMPORTANT:
188
+ - Use ONLY KSA names from the Available KSA Names list
189
+ - Be concise - this schema guides execution, not documentation
190
+ - If the request is simple, keep the schema simple
191
+ - If deliverables aren't explicitly needed, use an empty array
192
+ - Respond with ONLY the JSON, no other text`;
193
+ }
194
+
195
+ // ============================================================================
196
+ // Parsing and Validation
197
+ // ============================================================================
198
+
199
+ /**
200
+ * Extract JSON from LLM response (handles markdown code blocks)
201
+ */
202
+ function extractJSON(content: string): string {
203
+ // Try to extract from code block first
204
+ const codeBlockMatch = content.match(/```(?:json)?\s*([\s\S]*?)```/);
205
+ if (codeBlockMatch) {
206
+ return codeBlockMatch[1].trim();
207
+ }
208
+
209
+ // Try to find raw JSON
210
+ const jsonMatch = content.match(/\{[\s\S]*\}/);
211
+ if (jsonMatch) {
212
+ return jsonMatch[0];
213
+ }
214
+
215
+ return content.trim();
216
+ }
217
+
218
+ /**
219
+ * Parse and validate the LLM response into an IntentSchema
220
+ */
221
+ function parseIntentSchemaResponse(
222
+ content: string,
223
+ model: string
224
+ ): IntentSchema {
225
+ const jsonStr = extractJSON(content);
226
+
227
+ let parsed: unknown;
228
+ try {
229
+ parsed = JSON.parse(jsonStr);
230
+ } catch (e) {
231
+ throw new Error(`Failed to parse JSON: ${e}`);
232
+ }
233
+
234
+ // Validate structure
235
+ if (!validateIntentSchema(parsed)) {
236
+ throw new Error("Invalid Intent Schema structure");
237
+ }
238
+
239
+ // Add metadata
240
+ const schema = parsed as IntentSchema;
241
+ schema.meta = {
242
+ model,
243
+ generatedAt: Date.now(),
244
+ confidence: determineConfidence(schema),
245
+ };
246
+
247
+ // Ensure policy.enabledKSAs includes core
248
+ schema.policy.enabledKSAs = [
249
+ ...new Set([...CORE_KSAS, ...schema.policy.enabledKSAs]),
250
+ ];
251
+
252
+ return schema;
253
+ }
254
+
255
+ /**
256
+ * Determine confidence level based on schema quality
257
+ */
258
+ function determineConfidence(schema: IntentSchema): "high" | "medium" | "low" {
259
+ let score = 0;
260
+
261
+ // Check intent completeness
262
+ if (schema.intent.summary.length > 10) score++;
263
+ if (schema.intent.objective.length > 20) score++;
264
+ if (schema.intent.context.length > 0) score++;
265
+
266
+ // Check KSA selection
267
+ if (schema.ksas.priority.length >= 2) score++;
268
+ if (schema.ksas.reasoning.length > 20) score++;
269
+
270
+ // Check plan quality
271
+ if (schema.plan.goals.length >= 2) score++;
272
+ if (schema.plan.steps.length >= 3) score++;
273
+
274
+ if (score >= 6) return "high";
275
+ if (score >= 4) return "medium";
276
+ return "low";
277
+ }
278
+
279
+ // ============================================================================
280
+ // Main Action
281
+ // ============================================================================
282
+
283
+ /**
284
+ * Generate Intent Schema for a user request
285
+ *
286
+ * Calls a fast LLM (GROQ via OpenRouter) to analyze the request and
287
+ * generate structured guidance for the sandbox agent.
288
+ */
289
+ export const generateIntentSchema = internalAction({
290
+ args: {
291
+ /** The user's prompt/request */
292
+ prompt: v.string(),
293
+ /** Optional conversation context from thread history */
294
+ threadContext: v.optional(v.string()),
295
+ /** Pre-selected skill IDs from the UI */
296
+ skillIds: v.optional(v.array(v.string())),
297
+ /** User policy overrides */
298
+ userPolicy: v.optional(v.any()),
299
+ /** Skip generation and return default schema */
300
+ skipGeneration: v.optional(v.boolean()),
301
+ },
302
+ handler: async (ctx, args): Promise<IntentSchema> => {
303
+ const startTime = Date.now();
304
+
305
+ // If skip requested, return default
306
+ if (args.skipGeneration) {
307
+ const enabledKSAs = args.skillIds?.length
308
+ ? [...CORE_KSAS, ...args.skillIds]
309
+ : getKSANames();
310
+ return createDefaultIntentSchema(args.prompt, enabledKSAs);
311
+ }
312
+
313
+ // Build the prompt
314
+ const schemaPrompt = buildSchemaGenerationPrompt(
315
+ args.prompt,
316
+ args.threadContext,
317
+ args.skillIds
318
+ );
319
+
320
+ let schema: IntentSchema;
321
+ let usedModel = INTENT_SCHEMA_MODEL;
322
+
323
+ try {
324
+ // Call GROQ via OpenRouter
325
+ const response = await ctx.runAction(
326
+ internal.services.OpenRouter.internal.chatCompletion,
327
+ {
328
+ model: INTENT_SCHEMA_MODEL,
329
+ messages: [{ role: "user", content: schemaPrompt }],
330
+ maxTokens: MAX_TOKENS,
331
+ temperature: TEMPERATURE,
332
+ }
333
+ );
334
+
335
+ const content = response.choices?.[0]?.message?.content;
336
+ if (!content) {
337
+ throw new Error("Empty response from LLM");
338
+ }
339
+
340
+ schema = parseIntentSchemaResponse(content, INTENT_SCHEMA_MODEL);
341
+ } catch (primaryError) {
342
+ console.error(
343
+ `[IntentSchema] Primary model failed: ${primaryError}, trying fallback`
344
+ );
345
+
346
+ try {
347
+ // Try fallback model
348
+ const response = await ctx.runAction(
349
+ internal.services.OpenRouter.internal.chatCompletion,
350
+ {
351
+ model: FALLBACK_MODEL,
352
+ messages: [{ role: "user", content: schemaPrompt }],
353
+ maxTokens: MAX_TOKENS,
354
+ temperature: TEMPERATURE,
355
+ }
356
+ );
357
+
358
+ const content = response.choices?.[0]?.message?.content;
359
+ if (!content) {
360
+ throw new Error("Empty response from fallback LLM");
361
+ }
362
+
363
+ schema = parseIntentSchemaResponse(content, FALLBACK_MODEL);
364
+ usedModel = FALLBACK_MODEL;
365
+ } catch (fallbackError) {
366
+ console.error(
367
+ `[IntentSchema] Fallback model also failed: ${fallbackError}`
368
+ );
369
+
370
+ // Return default schema as last resort
371
+ const enabledKSAs = args.skillIds?.length
372
+ ? [...CORE_KSAS, ...args.skillIds]
373
+ : getKSANames();
374
+ schema = createDefaultIntentSchema(args.prompt, enabledKSAs);
375
+ schema.meta.confidence = "low";
376
+ }
377
+ }
378
+
379
+ // Apply user policy overrides
380
+ if (args.userPolicy) {
381
+ schema = applyUserPolicy(
382
+ schema,
383
+ args.userPolicy as Partial<UserAgentPolicy>
384
+ );
385
+ }
386
+
387
+ // Add latency to metadata
388
+ schema.meta.latencyMs = Date.now() - startTime;
389
+ schema.meta.model = usedModel;
390
+
391
+ console.log(
392
+ `[IntentSchema] Generated in ${schema.meta.latencyMs}ms using ${usedModel}:`,
393
+ {
394
+ summary: schema.intent.summary,
395
+ priorityKSAs: schema.ksas.priority,
396
+ goals: schema.plan.goals.length,
397
+ deliverables: schema.plan.deliverables.length,
398
+ confidence: schema.meta.confidence,
399
+ }
400
+ );
401
+
402
+ return schema;
403
+ },
404
+ });
405
+
406
+ /**
407
+ * Generate Intent Schema with timeout protection
408
+ *
409
+ * Wraps generateIntentSchema with a timeout to ensure we don't block
410
+ * sandbox startup if LLM is slow.
411
+ */
412
+ export const generateIntentSchemaWithTimeout = internalAction({
413
+ args: {
414
+ prompt: v.string(),
415
+ threadContext: v.optional(v.string()),
416
+ skillIds: v.optional(v.array(v.string())),
417
+ userPolicy: v.optional(v.any()),
418
+ /** Timeout in milliseconds (default: 3000ms) */
419
+ timeoutMs: v.optional(v.number()),
420
+ },
421
+ handler: async (ctx, args): Promise<IntentSchema | null> => {
422
+ const timeout = args.timeoutMs || 3000;
423
+
424
+ try {
425
+ // Create a promise that rejects after timeout
426
+ const timeoutPromise = new Promise<never>((_, reject) => {
427
+ setTimeout(() => reject(new Error("Intent schema generation timed out")), timeout);
428
+ });
429
+
430
+ // Race between generation and timeout
431
+ const schema = await Promise.race([
432
+ ctx.runAction(internal.intentSchema.generateIntentSchema, {
433
+ prompt: args.prompt,
434
+ threadContext: args.threadContext,
435
+ skillIds: args.skillIds,
436
+ userPolicy: args.userPolicy,
437
+ }),
438
+ timeoutPromise,
439
+ ]);
440
+
441
+ return schema;
442
+ } catch (error) {
443
+ console.warn(`[IntentSchema] Generation failed or timed out: ${error}`);
444
+ return null; // Caller should use default schema
445
+ }
446
+ },
447
+ });
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Intent Schema Module
3
+ *
4
+ * Pre-analyzes user requests before sandbox execution to provide:
5
+ * - Prioritized KSA selection
6
+ * - Structured goals and deliverables
7
+ * - User-configurable policies
8
+ *
9
+ * Generated by a fast LLM (GROQ via OpenRouter) while the sandbox warms up.
10
+ */
11
+
12
+ // Re-export types
13
+ export * from "./types";
14
+
15
+ // Re-export actions (will be added)
16
+ export * from "./generate";