@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,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";
|