kimi-vercel-ai-sdk-provider 0.3.0 → 0.5.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 (44) hide show
  1. package/README.md +567 -17
  2. package/dist/index.d.mts +1750 -3
  3. package/dist/index.d.ts +1750 -3
  4. package/dist/index.js +2317 -161
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +2292 -160
  7. package/dist/index.mjs.map +1 -1
  8. package/package.json +1 -1
  9. package/src/__tests__/auto-detect.test.ts +140 -0
  10. package/src/__tests__/code-validation.test.ts +267 -0
  11. package/src/__tests__/ensemble.test.ts +242 -0
  12. package/src/__tests__/file-cache.test.ts +310 -0
  13. package/src/__tests__/model-config.test.ts +120 -0
  14. package/src/__tests__/multi-agent.test.ts +201 -0
  15. package/src/__tests__/project-tools.test.ts +181 -0
  16. package/src/__tests__/reasoning-utils.test.ts +164 -0
  17. package/src/__tests__/tools.test.ts +76 -8
  18. package/src/chat/kimi-chat-language-model.ts +21 -2
  19. package/src/chat/kimi-chat-settings.ts +15 -1
  20. package/src/code-validation/detector.ts +319 -0
  21. package/src/code-validation/index.ts +31 -0
  22. package/src/code-validation/types.ts +291 -0
  23. package/src/code-validation/validator.ts +547 -0
  24. package/src/core/errors.ts +91 -0
  25. package/src/core/index.ts +15 -3
  26. package/src/core/types.ts +57 -2
  27. package/src/core/utils.ts +138 -0
  28. package/src/ensemble/index.ts +17 -0
  29. package/src/ensemble/multi-sampler.ts +433 -0
  30. package/src/ensemble/types.ts +279 -0
  31. package/src/files/attachment-processor.ts +51 -4
  32. package/src/files/file-cache.ts +260 -0
  33. package/src/files/index.ts +16 -1
  34. package/src/index.ts +102 -3
  35. package/src/kimi-provider.ts +354 -1
  36. package/src/multi-agent/index.ts +21 -0
  37. package/src/multi-agent/types.ts +312 -0
  38. package/src/multi-agent/workflows.ts +539 -0
  39. package/src/project-tools/index.ts +16 -0
  40. package/src/project-tools/scaffolder.ts +494 -0
  41. package/src/project-tools/types.ts +244 -0
  42. package/src/tools/auto-detect.ts +276 -0
  43. package/src/tools/index.ts +6 -2
  44. package/src/tools/prepare-tools.ts +179 -4
package/dist/index.mjs CHANGED
@@ -96,8 +96,51 @@ var KimiContextLengthError = class extends KimiError {
96
96
  this.name = "KimiContextLengthError";
97
97
  }
98
98
  };
99
+ var KimiEnsembleValidationError = class extends KimiError {
100
+ constructor(message, config, modelId) {
101
+ super(message, "ensemble_validation_error", 400);
102
+ this.name = "KimiEnsembleValidationError";
103
+ this.config = config;
104
+ this.modelId = modelId;
105
+ }
106
+ };
107
+ var KimiEnsembleTimeoutError = class extends KimiError {
108
+ constructor(message, completedSamples, requestedSamples) {
109
+ super(message, "ensemble_timeout", 408);
110
+ this.name = "KimiEnsembleTimeoutError";
111
+ this.completedSamples = completedSamples;
112
+ this.requestedSamples = requestedSamples;
113
+ }
114
+ };
115
+ var KimiMultiAgentError = class extends KimiError {
116
+ constructor(message, workflow, step, stepError) {
117
+ super(message, "multi_agent_error", 500);
118
+ this.name = "KimiMultiAgentError";
119
+ this.workflow = workflow;
120
+ this.step = step;
121
+ this.stepError = stepError;
122
+ }
123
+ };
124
+ var KimiCodeValidationError = class extends KimiError {
125
+ constructor(message, validationErrors, attempts) {
126
+ super(message, "code_validation_error", 400);
127
+ this.name = "KimiCodeValidationError";
128
+ this.validationErrors = validationErrors;
129
+ this.attempts = attempts;
130
+ }
131
+ };
132
+ var KimiScaffoldError = class extends KimiError {
133
+ constructor(message, projectType) {
134
+ super(message, "scaffold_error", 500);
135
+ this.name = "KimiScaffoldError";
136
+ this.projectType = projectType;
137
+ }
138
+ };
99
139
 
100
140
  // src/core/types.ts
141
+ var THINKING_MODEL_TEMPERATURE = 1;
142
+ var THINKING_MODEL_DEFAULT_MAX_TOKENS = 32768;
143
+ var STANDARD_MODEL_DEFAULT_MAX_TOKENS = 4096;
101
144
  function inferModelCapabilities(modelId) {
102
145
  const isThinkingModel = modelId.includes("-thinking");
103
146
  const isK25Model = modelId.includes("k2.5") || modelId.includes("k2-5");
@@ -112,7 +155,12 @@ function inferModelCapabilities(modelId) {
112
155
  // 256k context window
113
156
  toolCalling: true,
114
157
  jsonMode: true,
115
- structuredOutputs: true
158
+ structuredOutputs: true,
159
+ // Thinking models require temperature=1.0 for optimal reasoning
160
+ defaultTemperature: isThinkingModel ? THINKING_MODEL_TEMPERATURE : void 0,
161
+ temperatureLocked: isThinkingModel,
162
+ // Thinking models need higher token limits to avoid truncated reasoning
163
+ defaultMaxOutputTokens: isThinkingModel ? THINKING_MODEL_DEFAULT_MAX_TOKENS : STANDARD_MODEL_DEFAULT_MAX_TOKENS
116
164
  };
117
165
  }
118
166
 
@@ -231,6 +279,131 @@ function extractMessageContent(message) {
231
279
  return { text, reasoning };
232
280
  }
233
281
 
282
+ // src/tools/auto-detect.ts
283
+ var WEB_SEARCH_PATTERNS = [
284
+ // Direct search requests
285
+ { pattern: /search\s+(for|the\s+web|online|internet)/i, weight: 1, name: "direct_search" },
286
+ { pattern: /look\s+up\b/i, weight: 0.9, name: "look_up" },
287
+ { pattern: /find\s+(information|info|data|details)\s+(about|on|regarding)/i, weight: 0.9, name: "find_info" },
288
+ // Real-time/current information
289
+ {
290
+ pattern: /\b(latest|current|recent|today'?s?|now)\b.*\b(news|price|weather|update|version|status)/i,
291
+ weight: 1,
292
+ name: "current_info"
293
+ },
294
+ { pattern: /what\s+(is|are)\s+the\s+(latest|current|newest)/i, weight: 0.95, name: "what_latest" },
295
+ { pattern: /\b(right\s+now|at\s+the\s+moment|currently)\b/i, weight: 0.7, name: "temporal" },
296
+ // News and events
297
+ { pattern: /\bnews\b.*\b(about|on|regarding)\b/i, weight: 0.85, name: "news_about" },
298
+ { pattern: /what('?s|\s+is)\s+happening\b/i, weight: 0.8, name: "happening" },
299
+ { pattern: /\b(headline|breaking|trending)\b/i, weight: 0.85, name: "headlines" },
300
+ // Prices and markets
301
+ { pattern: /\b(price|cost|rate)\s+of\b/i, weight: 0.7, name: "price" },
302
+ { pattern: /\b(stock|crypto|bitcoin|ethereum|btc|eth)\s+(price|value|market)/i, weight: 0.95, name: "crypto_stock" },
303
+ { pattern: /how\s+much\s+(does|is|are).*\b(cost|worth)\b/i, weight: 0.7, name: "how_much" },
304
+ // Weather
305
+ { pattern: /\bweather\b.*\b(in|at|for|today|tomorrow|forecast)\b/i, weight: 0.95, name: "weather" },
306
+ // Documentation and APIs
307
+ { pattern: /\bdocumentation\b.*\b(for|of|about)\b/i, weight: 0.6, name: "documentation" },
308
+ { pattern: /official\s+(website|docs|documentation|guide)/i, weight: 0.7, name: "official_docs" },
309
+ // Verification needs
310
+ { pattern: /\b(verify|confirm|check|fact-check)\b.*\b(true|accurate|correct|real)\b/i, weight: 0.75, name: "verify" },
311
+ // Comparisons with external data
312
+ { pattern: /\bcompare\b.*\b(prices|reviews|ratings|options)\b/i, weight: 0.65, name: "compare" }
313
+ ];
314
+ var CODE_INTERPRETER_PATTERNS = [
315
+ // Direct code requests
316
+ { pattern: /write\s+(a\s+)?(function|code|script|program|algorithm)/i, weight: 0.95, name: "write_code" },
317
+ { pattern: /\b(code|implement|program)\s+(this|that|the|a)/i, weight: 0.85, name: "code_this" },
318
+ { pattern: /create\s+(a\s+)?(script|function|class|module)/i, weight: 0.9, name: "create_script" },
319
+ // Mathematical calculations
320
+ { pattern: /\bcalculate\b.*\d+/i, weight: 0.9, name: "calculate" },
321
+ { pattern: /\b(compute|evaluate|solve)\b.*\b(equation|expression|formula|problem)\b/i, weight: 0.9, name: "compute" },
322
+ { pattern: /what\s+(is|are)\s+\d+[\s+\-*/^]+\d+/i, weight: 0.95, name: "arithmetic" },
323
+ { pattern: /\b(factorial|fibonacci|prime|sqrt|power|exponent)\b/i, weight: 0.85, name: "math_functions" },
324
+ // Data processing
325
+ {
326
+ pattern: /\b(parse|process|transform|convert)\s+(this\s+)?(data|json|csv|xml)/i,
327
+ weight: 0.85,
328
+ name: "data_processing"
329
+ },
330
+ { pattern: /\b(analyze|process)\s+(this\s+)?(file|dataset|table)/i, weight: 0.8, name: "analyze_data" },
331
+ // Debugging
332
+ { pattern: /\bdebug\b.*\b(this|my|the)\s+(code|function|script|program)/i, weight: 0.9, name: "debug" },
333
+ { pattern: /\b(fix|correct|repair)\s+(this|my|the)\s+(error|bug|issue|problem)\b/i, weight: 0.85, name: "fix_error" },
334
+ {
335
+ pattern: /why\s+(is|does)\s+(this|my)\s+(code|function)\s+(not\s+work|fail|error)/i,
336
+ weight: 0.9,
337
+ name: "why_not_work"
338
+ },
339
+ // Testing
340
+ {
341
+ pattern: /\b(test|verify|validate)\s+(this|my|the)\s+(code|function|implementation)/i,
342
+ weight: 0.85,
343
+ name: "test_code"
344
+ },
345
+ { pattern: /\brun\s+(this|my|the)\s+(code|script|program)/i, weight: 0.95, name: "run_code" },
346
+ { pattern: /\bexecute\b.*\b(code|script|command)/i, weight: 0.95, name: "execute" },
347
+ // Code blocks in input (handles various markdown formats)
348
+ { pattern: /```[\w]*[\s\S]*?```/, weight: 0.7, name: "code_block" },
349
+ // Algorithm requests
350
+ { pattern: /\b(sort|search|traverse|optimize)\s+(algorithm|function|method)/i, weight: 0.85, name: "algorithm" },
351
+ // Regex
352
+ { pattern: /\b(regex|regular\s+expression)\b/i, weight: 0.75, name: "regex" },
353
+ // File operations
354
+ { pattern: /\b(read|write|create|delete)\s+(a\s+)?(file|directory|folder)/i, weight: 0.7, name: "file_ops" }
355
+ ];
356
+ function detectToolsFromPrompt(prompt, config = {}) {
357
+ const { confidenceThreshold = 0.3, includePartialMatches = true } = config;
358
+ const webSearchResult = detectPatterns(prompt, WEB_SEARCH_PATTERNS, includePartialMatches);
359
+ const codeInterpreterResult = detectPatterns(prompt, CODE_INTERPRETER_PATTERNS, includePartialMatches);
360
+ return {
361
+ webSearch: webSearchResult.confidence >= confidenceThreshold,
362
+ codeInterpreter: codeInterpreterResult.confidence >= confidenceThreshold,
363
+ webSearchConfidence: webSearchResult.confidence,
364
+ codeInterpreterConfidence: codeInterpreterResult.confidence,
365
+ webSearchMatches: webSearchResult.matches,
366
+ codeInterpreterMatches: codeInterpreterResult.matches
367
+ };
368
+ }
369
+ function shouldAutoEnableTools(prompt) {
370
+ const result = detectToolsFromPrompt(prompt);
371
+ return {
372
+ webSearch: result.webSearch,
373
+ codeInterpreter: result.codeInterpreter
374
+ };
375
+ }
376
+ function detectPatterns(text, patterns, includePartial) {
377
+ const matches = [];
378
+ let maxWeight = 0;
379
+ let matchCount = 0;
380
+ for (const { pattern, weight, name } of patterns) {
381
+ if (pattern.test(text)) {
382
+ matches.push(name);
383
+ maxWeight = Math.max(maxWeight, weight);
384
+ matchCount++;
385
+ }
386
+ }
387
+ let confidence = 0;
388
+ if (matchCount > 0) {
389
+ if (includePartial) {
390
+ const boost = Math.min(0.15, (matchCount - 1) * 0.05);
391
+ confidence = Math.min(1, maxWeight + boost);
392
+ } else {
393
+ confidence = maxWeight;
394
+ }
395
+ }
396
+ return { confidence, matches };
397
+ }
398
+ function hasToolOptOut(prompt) {
399
+ const webSearchOptOut = /(don'?t|do\s+not|without|no)\s+(search(ing)?|web|internet|online)/i.test(prompt);
400
+ const codeOptOut = /(don'?t|do\s+not|without|no)\s+(run(ning)?|execut(e|ing)|cod(e|ing))/i.test(prompt) || /without\s+[\w\s]*running\s+code/i.test(prompt) || /(or|and)\s+running\s+code/i.test(prompt);
401
+ return {
402
+ webSearch: webSearchOptOut,
403
+ codeInterpreter: codeOptOut
404
+ };
405
+ }
406
+
234
407
  // src/tools/builtin-tools.ts
235
408
  var KIMI_WEB_SEARCH_TOOL_NAME = "$web_search";
236
409
  var KIMI_CODE_INTERPRETER_TOOL_NAME = "$code";
@@ -351,13 +524,15 @@ function prepareKimiTools({
351
524
  });
352
525
  continue;
353
526
  }
527
+ const sanitizedSchema = sanitizeToolSchema(tool.inputSchema);
354
528
  kimiTools2.push({
355
529
  type: "function",
356
530
  function: {
357
531
  name: tool.name,
358
532
  description: tool.description,
359
- parameters: tool.inputSchema,
360
- ...tool.strict != null ? { strict: tool.strict } : {}
533
+ parameters: sanitizedSchema
534
+ // Don't pass strict mode to Kimi - it may cause issues
535
+ // ...(tool.strict != null ? { strict: tool.strict } : {})
361
536
  }
362
537
  });
363
538
  }
@@ -425,11 +600,104 @@ function prepareKimiTools({
425
600
  }
426
601
  }
427
602
  }
603
+ var TOOL_DESCRIPTIONS = {
604
+ $web_search: "Search the web for up-to-date information, current events, facts, news, prices, weather, or any data not available in your training",
605
+ $code: "Execute code to perform calculations, data processing, algorithmic tasks, or verify code correctness"
606
+ };
607
+ function generateToolGuidanceMessage(options) {
608
+ const { toolNames, choiceType, targetTool, promptContext, includeDescriptions = true } = options;
609
+ const lines = ["=== TOOL USAGE GUIDANCE ===", ""];
610
+ if (includeDescriptions && toolNames.length > 0) {
611
+ lines.push("Available tools:");
612
+ for (const toolName of toolNames) {
613
+ const description = TOOL_DESCRIPTIONS[toolName] || "Execute this tool";
614
+ lines.push(`- ${toolName}: ${description}`);
615
+ }
616
+ lines.push("");
617
+ }
618
+ if (choiceType === "required") {
619
+ lines.push("\u26A0\uFE0F IMPORTANT: You MUST use at least one of the available tools to respond.");
620
+ lines.push("Do NOT provide a direct text response without first calling a tool.");
621
+ } else if (choiceType === "tool" && targetTool) {
622
+ lines.push(`\u26A0\uFE0F IMPORTANT: You MUST use the "${targetTool}" tool to respond.`);
623
+ lines.push("Do NOT use any other tool or provide a direct text response.");
624
+ }
625
+ if (promptContext) {
626
+ lines.push("");
627
+ lines.push(`Task context: ${promptContext.slice(0, 200)}${promptContext.length > 200 ? "..." : ""}`);
628
+ }
629
+ return lines.join("\n");
630
+ }
428
631
  function generateRequiredToolMessage(toolNames) {
429
- return `IMPORTANT INSTRUCTION: You MUST use one of the available tools (${toolNames}) to respond to the user's request. Do NOT provide a direct text response without first calling a tool. Always invoke a tool to complete this task.`;
632
+ const tools = toolNames.split(", ");
633
+ return generateToolGuidanceMessage({
634
+ toolNames: tools,
635
+ choiceType: "required",
636
+ includeDescriptions: true
637
+ });
430
638
  }
431
639
  function generateSpecificToolMessage(toolName) {
432
- return `IMPORTANT INSTRUCTION: You MUST use the "${toolName}" tool to respond to this request. Do NOT use any other tool or provide a direct text response. Call the "${toolName}" tool with appropriate parameters.`;
640
+ return generateToolGuidanceMessage({
641
+ toolNames: [toolName],
642
+ choiceType: "tool",
643
+ targetTool: toolName,
644
+ includeDescriptions: true
645
+ });
646
+ }
647
+ var UNSUPPORTED_SCHEMA_KEYWORDS = [
648
+ "$schema",
649
+ "$id",
650
+ "$ref",
651
+ "$defs",
652
+ "definitions",
653
+ "if",
654
+ "then",
655
+ "else",
656
+ "allOf",
657
+ "anyOf",
658
+ "oneOf",
659
+ "not",
660
+ "patternProperties",
661
+ "additionalItems",
662
+ "contains",
663
+ "propertyNames",
664
+ "const",
665
+ "contentMediaType",
666
+ "contentEncoding",
667
+ "examples",
668
+ "$comment"
669
+ ];
670
+ function sanitizeToolSchema(schema) {
671
+ if (schema === null || schema === void 0) {
672
+ return schema;
673
+ }
674
+ if (Array.isArray(schema)) {
675
+ return schema.map(sanitizeToolSchema);
676
+ }
677
+ if (typeof schema !== "object") {
678
+ return schema;
679
+ }
680
+ const sanitized = {};
681
+ const schemaObj = schema;
682
+ for (const [key, value] of Object.entries(schemaObj)) {
683
+ if (UNSUPPORTED_SCHEMA_KEYWORDS.includes(key)) {
684
+ continue;
685
+ }
686
+ if (key === "properties" && typeof value === "object" && value !== null) {
687
+ const props = {};
688
+ for (const [propKey, propValue] of Object.entries(value)) {
689
+ props[propKey] = sanitizeToolSchema(propValue);
690
+ }
691
+ sanitized[key] = props;
692
+ } else if (key === "items" && typeof value === "object") {
693
+ sanitized[key] = sanitizeToolSchema(value);
694
+ } else if (key === "additionalProperties" && typeof value === "object") {
695
+ sanitized[key] = sanitizeToolSchema(value);
696
+ } else {
697
+ sanitized[key] = value;
698
+ }
699
+ }
700
+ return sanitized;
433
701
  }
434
702
  function tryConvertToKimiBuiltinTool(tool) {
435
703
  if (!tool.id.startsWith("kimi.")) {
@@ -720,7 +988,11 @@ var kimiProviderOptionsSchema = z2.object({
720
988
  /**
721
989
  * Enable tool choice polyfill for this request.
722
990
  */
723
- toolChoicePolyfill: z2.boolean().optional()
991
+ toolChoicePolyfill: z2.boolean().optional(),
992
+ /**
993
+ * Auto-enable tools based on prompt content analysis.
994
+ */
995
+ autoEnableTools: z2.boolean().optional()
724
996
  });
725
997
 
726
998
  // src/chat/kimi-chat-language-model.ts
@@ -834,11 +1106,24 @@ var KimiChatLanguageModel = class {
834
1106
  if (toolChoiceSystemMessage) {
835
1107
  messages.unshift({ role: "system", content: toolChoiceSystemMessage });
836
1108
  }
1109
+ const caps = this.capabilities;
1110
+ let resolvedTemperature = temperature;
1111
+ if (caps.temperatureLocked && caps.defaultTemperature !== void 0) {
1112
+ if (temperature !== void 0 && temperature !== caps.defaultTemperature) {
1113
+ warnings.push({
1114
+ type: "compatibility",
1115
+ feature: "temperature",
1116
+ details: `Thinking models require temperature=${caps.defaultTemperature}. Your value (${temperature}) will be overridden.`
1117
+ });
1118
+ }
1119
+ resolvedTemperature = caps.defaultTemperature;
1120
+ }
1121
+ const resolvedMaxTokens = maxOutputTokens ?? caps.defaultMaxOutputTokens;
837
1122
  const body = removeUndefinedEntries({
838
1123
  model: this.modelId,
839
1124
  messages,
840
- max_tokens: maxOutputTokens,
841
- temperature,
1125
+ max_tokens: resolvedMaxTokens,
1126
+ temperature: resolvedTemperature,
842
1127
  top_p: topP,
843
1128
  frequency_penalty: frequencyPenalty,
844
1129
  presence_penalty: presencePenalty,
@@ -1323,163 +1608,1145 @@ var kimiChatChunkBaseSchema = z3.looseObject({
1323
1608
  });
1324
1609
  var kimiChatChunkSchema = z3.union([kimiChatChunkBaseSchema, kimiErrorSchema]);
1325
1610
 
1326
- // src/files/file-utils.ts
1327
- var SUPPORTED_FILE_EXTENSIONS = [
1328
- // Documents
1329
- ".pdf",
1330
- ".txt",
1331
- ".csv",
1332
- ".doc",
1333
- ".docx",
1334
- ".xls",
1335
- ".xlsx",
1336
- ".ppt",
1337
- ".pptx",
1338
- ".md",
1339
- ".epub",
1340
- ".mobi",
1341
- ".html",
1342
- ".json",
1343
- ".log",
1344
- ".dot",
1345
- ".ini",
1346
- ".conf",
1347
- ".yaml",
1348
- ".yml",
1349
- // Images
1350
- ".jpeg",
1351
- ".jpg",
1352
- ".png",
1353
- ".bmp",
1354
- ".gif",
1355
- ".svg",
1356
- ".svgz",
1357
- ".webp",
1358
- ".ico",
1359
- ".xbm",
1360
- ".dib",
1361
- ".pjp",
1362
- ".tif",
1363
- ".tiff",
1364
- ".pjpeg",
1365
- ".avif",
1366
- ".apng",
1367
- ".jfif",
1368
- // Code files
1369
- ".go",
1370
- ".h",
1371
- ".c",
1372
- ".cpp",
1373
- ".cxx",
1374
- ".cc",
1375
- ".cs",
1376
- ".java",
1377
- ".js",
1378
- ".css",
1379
- ".jsp",
1380
- ".php",
1381
- ".py",
1382
- ".py3",
1383
- ".asp",
1384
- ".ts",
1385
- ".tsx"
1611
+ // src/code-validation/detector.ts
1612
+ var LANGUAGE_PATTERNS = [
1613
+ {
1614
+ language: "typescript",
1615
+ patterns: [
1616
+ { pattern: /:\s*(string|number|boolean|void|any|unknown|never)\b/, weight: 0.9, name: "type_annotation" },
1617
+ { pattern: /interface\s+\w+\s*{/, weight: 0.95, name: "interface" },
1618
+ { pattern: /type\s+\w+\s*=/, weight: 0.9, name: "type_alias" },
1619
+ { pattern: /<\w+>/, weight: 0.5, name: "generics" },
1620
+ { pattern: /import\s+.*\s+from\s+['"]/, weight: 0.7, name: "import_from" },
1621
+ { pattern: /export\s+(interface|type|enum)\b/, weight: 0.95, name: "export_type" },
1622
+ { pattern: /as\s+(string|number|boolean|any)\b/, weight: 0.85, name: "type_assertion" }
1623
+ ]
1624
+ },
1625
+ {
1626
+ language: "javascript",
1627
+ patterns: [
1628
+ { pattern: /\bfunction\s+\w+\s*\(/, weight: 0.6, name: "function_decl" },
1629
+ { pattern: /\bconst\s+\w+\s*=/, weight: 0.5, name: "const" },
1630
+ { pattern: /\blet\s+\w+\s*=/, weight: 0.5, name: "let" },
1631
+ { pattern: /=>\s*{/, weight: 0.6, name: "arrow_function" },
1632
+ { pattern: /require\s*\(['"]/, weight: 0.7, name: "require" },
1633
+ { pattern: /module\.exports\s*=/, weight: 0.85, name: "module_exports" },
1634
+ { pattern: /console\.(log|error|warn)\(/, weight: 0.5, name: "console" }
1635
+ ]
1636
+ },
1637
+ {
1638
+ language: "python",
1639
+ patterns: [
1640
+ { pattern: /\bdef\s+\w+\s*\([^)]*\)\s*:/, weight: 0.9, name: "def" },
1641
+ { pattern: /\bclass\s+\w+.*:/, weight: 0.85, name: "class" },
1642
+ { pattern: /\bimport\s+\w+/, weight: 0.6, name: "import" },
1643
+ { pattern: /\bfrom\s+\w+\s+import\b/, weight: 0.85, name: "from_import" },
1644
+ { pattern: /\bif\s+__name__\s*==\s*['"]__main__['"]\s*:/, weight: 0.95, name: "main_guard" },
1645
+ { pattern: /\bprint\s*\(/, weight: 0.5, name: "print" },
1646
+ { pattern: /\bself\.\w+/, weight: 0.85, name: "self" },
1647
+ { pattern: /#.*$/, weight: 0.3, name: "comment" }
1648
+ ]
1649
+ },
1650
+ {
1651
+ language: "java",
1652
+ patterns: [
1653
+ { pattern: /public\s+class\s+\w+/, weight: 0.95, name: "public_class" },
1654
+ { pattern: /public\s+static\s+void\s+main/, weight: 0.98, name: "main_method" },
1655
+ { pattern: /System\.out\.println/, weight: 0.9, name: "sysout" },
1656
+ { pattern: /\bpackage\s+[\w.]+;/, weight: 0.95, name: "package" },
1657
+ { pattern: /\bimport\s+[\w.]+;/, weight: 0.8, name: "import" },
1658
+ { pattern: /@Override\b/, weight: 0.9, name: "override" },
1659
+ { pattern: /\bprivate\s+\w+\s+\w+;/, weight: 0.7, name: "private_field" }
1660
+ ]
1661
+ },
1662
+ {
1663
+ language: "go",
1664
+ patterns: [
1665
+ { pattern: /\bpackage\s+main\b/, weight: 0.95, name: "package_main" },
1666
+ { pattern: /\bfunc\s+\w+\s*\(/, weight: 0.85, name: "func" },
1667
+ { pattern: /\bfmt\.Print/, weight: 0.9, name: "fmt_print" },
1668
+ { pattern: /\bimport\s+\(/, weight: 0.85, name: "import_block" },
1669
+ { pattern: /:=/, weight: 0.7, name: "short_var_decl" },
1670
+ { pattern: /\bgo\s+\w+\(/, weight: 0.9, name: "goroutine" },
1671
+ { pattern: /\bchan\s+\w+/, weight: 0.9, name: "channel" }
1672
+ ]
1673
+ },
1674
+ {
1675
+ language: "rust",
1676
+ patterns: [
1677
+ { pattern: /\bfn\s+\w+\s*\(/, weight: 0.9, name: "fn" },
1678
+ { pattern: /\blet\s+mut\s+\w+/, weight: 0.95, name: "let_mut" },
1679
+ { pattern: /\bimpl\s+\w+\s+for\s+\w+/, weight: 0.95, name: "impl_for" },
1680
+ { pattern: /\buse\s+[\w:]+;/, weight: 0.85, name: "use" },
1681
+ { pattern: /\bpub\s+(fn|struct|enum|mod)\b/, weight: 0.9, name: "pub" },
1682
+ { pattern: /->.*{/, weight: 0.7, name: "return_type" },
1683
+ { pattern: /\bprintln!\(/, weight: 0.95, name: "println_macro" }
1684
+ ]
1685
+ },
1686
+ {
1687
+ language: "ruby",
1688
+ patterns: [
1689
+ { pattern: /\bdef\s+\w+/, weight: 0.8, name: "def" },
1690
+ { pattern: /\bclass\s+\w+/, weight: 0.7, name: "class" },
1691
+ { pattern: /\bend\s*$/, weight: 0.4, name: "end" },
1692
+ { pattern: /\brequire\s+['"]/, weight: 0.85, name: "require" },
1693
+ { pattern: /\bputs\s+/, weight: 0.8, name: "puts" },
1694
+ { pattern: /@\w+/, weight: 0.5, name: "instance_var" },
1695
+ { pattern: /\.each\s+do\s*\|/, weight: 0.85, name: "each_block" }
1696
+ ]
1697
+ },
1698
+ {
1699
+ language: "php",
1700
+ patterns: [
1701
+ { pattern: /<\?php/, weight: 0.98, name: "php_tag" },
1702
+ { pattern: /\$\w+\s*=/, weight: 0.75, name: "php_var" },
1703
+ { pattern: /\bfunction\s+\w+\s*\(/, weight: 0.5, name: "function" },
1704
+ { pattern: /\becho\s+/, weight: 0.7, name: "echo" },
1705
+ { pattern: /->(\w+)\(/, weight: 0.6, name: "method_call" },
1706
+ { pattern: /\buse\s+[\w\\]+;/, weight: 0.8, name: "use" }
1707
+ ]
1708
+ },
1709
+ {
1710
+ language: "cpp",
1711
+ patterns: [
1712
+ { pattern: /#include\s*<[\w.]+>/, weight: 0.9, name: "include_angle" },
1713
+ { pattern: /#include\s*"[\w.]+"/, weight: 0.85, name: "include_quote" },
1714
+ { pattern: /\bstd::\w+/, weight: 0.9, name: "std_namespace" },
1715
+ { pattern: /\bint\s+main\s*\(/, weight: 0.95, name: "main" },
1716
+ { pattern: /\bcout\s*<</, weight: 0.95, name: "cout" },
1717
+ { pattern: /\bnamespace\s+\w+/, weight: 0.85, name: "namespace" },
1718
+ { pattern: /\btemplate\s*</, weight: 0.9, name: "template" }
1719
+ ]
1720
+ }
1386
1721
  ];
1387
- var SUPPORTED_MIME_TYPES = {
1388
- // Documents
1389
- "application/pdf": "file-extract",
1390
- "text/plain": "file-extract",
1391
- "text/csv": "file-extract",
1392
- "application/msword": "file-extract",
1393
- "application/vnd.openxmlformats-officedocument.wordprocessingml.document": "file-extract",
1394
- "application/vnd.ms-excel": "file-extract",
1395
- "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "file-extract",
1396
- "application/vnd.ms-powerpoint": "file-extract",
1397
- "application/vnd.openxmlformats-officedocument.presentationml.presentation": "file-extract",
1398
- "text/markdown": "file-extract",
1399
- "text/html": "file-extract",
1400
- "application/json": "file-extract",
1401
- "application/epub+zip": "file-extract",
1402
- "text/yaml": "file-extract",
1403
- "application/x-yaml": "file-extract",
1404
- // Code files (treated as text)
1405
- "text/javascript": "file-extract",
1406
- "text/typescript": "file-extract",
1407
- "text/x-python": "file-extract",
1408
- "text/x-java": "file-extract",
1409
- "text/x-c": "file-extract",
1410
- "text/x-c++": "file-extract",
1411
- "text/css": "file-extract",
1412
- // Images
1413
- "image/jpeg": "image",
1414
- "image/png": "image",
1415
- "image/gif": "image",
1416
- "image/webp": "image",
1417
- "image/svg+xml": "image",
1418
- "image/bmp": "image",
1419
- "image/tiff": "image",
1420
- "image/avif": "image",
1421
- "image/apng": "image",
1422
- "image/x-icon": "image",
1423
- // Videos
1424
- "video/mp4": "video",
1425
- "video/webm": "video",
1426
- "video/ogg": "video",
1427
- "video/quicktime": "video"
1428
- };
1429
- function isImageMediaType2(mediaType) {
1430
- return mediaType.startsWith("image/");
1722
+ function detectLanguage(code) {
1723
+ const scores = /* @__PURE__ */ new Map();
1724
+ for (const { language } of LANGUAGE_PATTERNS) {
1725
+ scores.set(language, { score: 0, indicators: [] });
1726
+ }
1727
+ for (const { language, patterns } of LANGUAGE_PATTERNS) {
1728
+ const langScore = scores.get(language);
1729
+ for (const { pattern, weight, name } of patterns) {
1730
+ if (pattern.test(code)) {
1731
+ langScore.score += weight;
1732
+ langScore.indicators.push(name);
1733
+ }
1734
+ }
1735
+ }
1736
+ let bestLanguage = "javascript";
1737
+ let bestScore = 0;
1738
+ let bestIndicators = [];
1739
+ for (const [language, { score, indicators }] of scores) {
1740
+ if (score > bestScore) {
1741
+ bestScore = score;
1742
+ bestLanguage = language;
1743
+ bestIndicators = indicators;
1744
+ }
1745
+ }
1746
+ const tsScore = scores.get("typescript").score;
1747
+ const jsScore = scores.get("javascript").score;
1748
+ if (tsScore > 0 && jsScore > 0 && Math.abs(tsScore - jsScore) < 0.5 && scores.get("typescript").indicators.some((i) => ["type_annotation", "interface", "type_alias", "export_type"].includes(i))) {
1749
+ bestLanguage = "typescript";
1750
+ bestScore = tsScore;
1751
+ bestIndicators = scores.get("typescript").indicators;
1752
+ }
1753
+ const maxPossibleScore = LANGUAGE_PATTERNS.find((l) => l.language === bestLanguage)?.patterns.reduce((sum, p) => sum + p.weight, 0) ?? 1;
1754
+ const confidence = Math.min(1, bestScore / Math.max(1, maxPossibleScore * 0.5));
1755
+ return {
1756
+ language: bestLanguage,
1757
+ confidence,
1758
+ indicators: bestIndicators
1759
+ };
1431
1760
  }
1432
- function isVideoMediaType2(mediaType) {
1433
- return mediaType.startsWith("video/");
1761
+ function extractCodeBlocks(text) {
1762
+ const blocks = [];
1763
+ const fenceRegex = /```(\w*)\n([\s\S]*?)```/g;
1764
+ let match = fenceRegex.exec(text);
1765
+ while (match !== null) {
1766
+ blocks.push({
1767
+ code: match[2].trim(),
1768
+ language: match[1] || void 0,
1769
+ startIndex: match.index,
1770
+ endIndex: match.index + match[0].length
1771
+ });
1772
+ match = fenceRegex.exec(text);
1773
+ }
1774
+ if (blocks.length === 0) {
1775
+ const { confidence } = detectLanguage(text);
1776
+ if (confidence > 0.3) {
1777
+ blocks.push({
1778
+ code: text.trim(),
1779
+ startIndex: 0,
1780
+ endIndex: text.length
1781
+ });
1782
+ }
1783
+ }
1784
+ return {
1785
+ blocks,
1786
+ hasCode: blocks.length > 0
1787
+ };
1434
1788
  }
1435
- function isFileExtractMediaType(mediaType) {
1436
- if (mediaType in SUPPORTED_MIME_TYPES) {
1437
- return SUPPORTED_MIME_TYPES[mediaType] === "file-extract";
1789
+ function extractPrimaryCode(text) {
1790
+ const { blocks, hasCode } = extractCodeBlocks(text);
1791
+ if (!hasCode) {
1792
+ return void 0;
1438
1793
  }
1439
- if (mediaType.startsWith("text/") || mediaType === "application/pdf") {
1794
+ return blocks.reduce((largest, block) => block.code.length > largest.code.length ? block : largest).code;
1795
+ }
1796
+ function containsCode(text) {
1797
+ if (/```[\s\S]*```/.test(text)) {
1440
1798
  return true;
1441
1799
  }
1442
- return false;
1443
- }
1444
- function isDocumentMediaType(mediaType) {
1445
- const documentTypes = [
1446
- "application/pdf",
1447
- "application/msword",
1448
- "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
1449
- "application/vnd.ms-excel",
1450
- "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
1451
- "application/vnd.ms-powerpoint",
1452
- "application/vnd.openxmlformats-officedocument.presentationml.presentation",
1453
- "application/epub+zip"
1800
+ const quickCodePatterns = [
1801
+ /\bfunction\s+\w+\s*\([^)]*\)\s*\{/,
1802
+ // function declarations
1803
+ /\bconst\s+\w+\s*=\s*\([^)]*\)\s*=>/,
1804
+ // arrow functions
1805
+ /\bclass\s+\w+\s*(\s+extends\s+\w+)?\s*\{/,
1806
+ // class declarations
1807
+ /\bdef\s+\w+\s*\([^)]*\)\s*:/,
1808
+ // Python functions
1809
+ /\bimport\s+.*\s+from\s+['"]/,
1810
+ // ES imports
1811
+ /\b(if|for|while)\s*\([^)]*\)\s*\{/,
1812
+ // Control structures with braces
1813
+ /=>\s*\{[\s\S]*\}/,
1814
+ // Arrow function bodies
1815
+ /\breturn\s+[\w"'`{[<]/
1816
+ // Return statements
1454
1817
  ];
1455
- return documentTypes.includes(mediaType);
1818
+ for (const pattern of quickCodePatterns) {
1819
+ if (pattern.test(text)) {
1820
+ return true;
1821
+ }
1822
+ }
1823
+ const { confidence } = detectLanguage(text);
1824
+ return confidence > 0.4;
1456
1825
  }
1457
- function getPurposeFromMediaType(mediaType) {
1458
- if (isImageMediaType2(mediaType)) {
1459
- return "image";
1826
+ function getFileExtension(language) {
1827
+ const extensions = {
1828
+ javascript: "js",
1829
+ typescript: "ts",
1830
+ python: "py",
1831
+ java: "java",
1832
+ cpp: "cpp",
1833
+ go: "go",
1834
+ rust: "rs",
1835
+ ruby: "rb",
1836
+ php: "php",
1837
+ auto: "txt"
1838
+ };
1839
+ return extensions[language] || "txt";
1840
+ }
1841
+
1842
+ // src/code-validation/validator.ts
1843
+ var CodeValidator = class {
1844
+ constructor(options) {
1845
+ this.generateText = options.generateText;
1846
+ this.executeCode = options.executeCode;
1460
1847
  }
1461
- if (isVideoMediaType2(mediaType)) {
1462
- return "video";
1848
+ /**
1849
+ * Validate code and optionally fix errors.
1850
+ *
1851
+ * @param code - The code to validate
1852
+ * @param config - Validation configuration
1853
+ * @param originalPrompt - The original user prompt (for context in fixes)
1854
+ * @returns Validation result
1855
+ */
1856
+ async validate(code, config, originalPrompt = "") {
1857
+ const {
1858
+ maxAttempts = 3,
1859
+ language: configLanguage = "auto",
1860
+ executionTimeoutMs = 3e4,
1861
+ strictness = "strict",
1862
+ returnPartialFix = true
1863
+ } = config;
1864
+ const language = configLanguage === "auto" ? detectLanguage(code).language : configLanguage;
1865
+ let currentCode = code;
1866
+ const allErrors = [];
1867
+ const allWarnings = [];
1868
+ const fixHistory = [];
1869
+ let attempts = 0;
1870
+ for (let i = 0; i < maxAttempts; i++) {
1871
+ attempts++;
1872
+ const validationResult = await this.validateCode(currentCode, language, strictness, executionTimeoutMs);
1873
+ const newErrors = validationResult.errors.filter(
1874
+ (e) => !allErrors.some((existing) => existing.message === e.message)
1875
+ );
1876
+ allErrors.push(...newErrors);
1877
+ allWarnings.push(...validationResult.warnings);
1878
+ if (validationResult.valid) {
1879
+ return {
1880
+ valid: true,
1881
+ errors: [],
1882
+ warnings: allWarnings,
1883
+ output: validationResult.output,
1884
+ executionTimeMs: validationResult.executionTimeMs,
1885
+ attempts,
1886
+ finalCode: currentCode,
1887
+ originalCode: code,
1888
+ language,
1889
+ fixHistory
1890
+ };
1891
+ }
1892
+ if (i === maxAttempts - 1) {
1893
+ break;
1894
+ }
1895
+ const fixResult = await this.attemptFix(currentCode, validationResult.errors, language, originalPrompt);
1896
+ fixHistory.push({
1897
+ attempt: attempts,
1898
+ codeBefore: currentCode,
1899
+ codeAfter: fixResult.code,
1900
+ errorsAddressed: validationResult.errors,
1901
+ success: false
1902
+ // Will be updated if next validation passes
1903
+ });
1904
+ if (fixResult.fixed) {
1905
+ currentCode = fixResult.code;
1906
+ } else {
1907
+ break;
1908
+ }
1909
+ }
1910
+ return {
1911
+ valid: false,
1912
+ errors: allErrors,
1913
+ warnings: allWarnings,
1914
+ attempts,
1915
+ finalCode: returnPartialFix ? currentCode : code,
1916
+ originalCode: code,
1917
+ language,
1918
+ fixHistory
1919
+ };
1463
1920
  }
1464
- return "file-extract";
1465
- }
1466
- function getMediaTypeFromExtension(extension) {
1467
- const ext = extension.toLowerCase().startsWith(".") ? extension.toLowerCase() : `.${extension.toLowerCase()}`;
1468
- const extensionToMime = {
1469
- // Documents
1470
- ".pdf": "application/pdf",
1471
- ".txt": "text/plain",
1472
- ".csv": "text/csv",
1473
- ".doc": "application/msword",
1474
- ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
1475
- ".xls": "application/vnd.ms-excel",
1476
- ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
1477
- ".ppt": "application/vnd.ms-powerpoint",
1478
- ".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
1479
- ".md": "text/markdown",
1480
- ".html": "text/html",
1481
- ".json": "application/json",
1482
- ".epub": "application/epub+zip",
1921
+ /**
1922
+ * Validate code without attempting fixes.
1923
+ */
1924
+ async validateCode(code, language, strictness, _timeoutMs) {
1925
+ const errors = [];
1926
+ const warnings = [];
1927
+ const staticErrors = this.performStaticAnalysis(code, language);
1928
+ errors.push(...staticErrors);
1929
+ if (staticErrors.some((e) => e.type === "syntax" && e.severity === "error")) {
1930
+ return { valid: false, errors, warnings };
1931
+ }
1932
+ if (this.executeCode) {
1933
+ try {
1934
+ const startTime = Date.now();
1935
+ const output = await this.executeCode(code, language);
1936
+ const executionTimeMs = Date.now() - startTime;
1937
+ const runtimeErrors = this.detectRuntimeErrors(output);
1938
+ errors.push(...runtimeErrors);
1939
+ if (runtimeErrors.length === 0) {
1940
+ return {
1941
+ valid: true,
1942
+ errors: [],
1943
+ warnings,
1944
+ output,
1945
+ executionTimeMs
1946
+ };
1947
+ }
1948
+ } catch (error) {
1949
+ const message = error instanceof Error ? error.message : "Execution failed";
1950
+ errors.push({
1951
+ type: "runtime",
1952
+ message,
1953
+ severity: "error"
1954
+ });
1955
+ }
1956
+ }
1957
+ if (!this.executeCode && strictness !== "lenient") {
1958
+ const llmValidation = await this.validateWithLLM(code, language);
1959
+ errors.push(...llmValidation.errors);
1960
+ warnings.push(...llmValidation.warnings);
1961
+ }
1962
+ return {
1963
+ valid: errors.length === 0,
1964
+ errors,
1965
+ warnings
1966
+ };
1967
+ }
1968
+ /**
1969
+ * Perform static analysis on code.
1970
+ */
1971
+ performStaticAnalysis(code, language) {
1972
+ const errors = [];
1973
+ switch (language) {
1974
+ case "javascript":
1975
+ case "typescript":
1976
+ errors.push(...this.analyzeJavaScript(code));
1977
+ break;
1978
+ case "python":
1979
+ errors.push(...this.analyzePython(code));
1980
+ break;
1981
+ default:
1982
+ errors.push(...this.analyzeGeneric(code));
1983
+ }
1984
+ return errors;
1985
+ }
1986
+ /**
1987
+ * Analyze JavaScript/TypeScript code.
1988
+ */
1989
+ analyzeJavaScript(code) {
1990
+ const errors = [];
1991
+ const patterns = [
1992
+ { pattern: /\bif\s*\([^)]*\)\s*[^{](?!.*[;{])/, message: "Missing braces after if statement" },
1993
+ { pattern: /\bfor\s*\([^)]*\)\s*[^{](?!.*[;{])/, message: "Missing braces after for loop" },
1994
+ { pattern: /==(?!=)/, message: "Use === instead of == for strict equality", isWarning: true },
1995
+ { pattern: /!=(?!=)/, message: "Use !== instead of != for strict inequality", isWarning: true },
1996
+ { pattern: /\bconsole\.log\(/, message: "Console.log found - remove for production", isWarning: true }
1997
+ ];
1998
+ const bracketBalance = this.checkBracketBalance(code);
1999
+ if (!bracketBalance.valid) {
2000
+ errors.push({
2001
+ type: "syntax",
2002
+ message: bracketBalance.message,
2003
+ severity: "error"
2004
+ });
2005
+ }
2006
+ for (const { pattern, message, isWarning } of patterns) {
2007
+ if (pattern.test(code)) {
2008
+ errors.push({
2009
+ type: isWarning ? "style" : "syntax",
2010
+ message,
2011
+ severity: isWarning ? "warning" : "error"
2012
+ });
2013
+ }
2014
+ }
2015
+ return errors;
2016
+ }
2017
+ /**
2018
+ * Analyze Python code.
2019
+ */
2020
+ analyzePython(code) {
2021
+ const errors = [];
2022
+ const lines = code.split("\n");
2023
+ let indentUnit = null;
2024
+ for (let i = 0; i < lines.length; i++) {
2025
+ const line = lines[i];
2026
+ if (line.trim() === "" || line.trim().startsWith("#")) {
2027
+ continue;
2028
+ }
2029
+ const leadingSpaces = line.match(/^(\s*)/)?.[1].length ?? 0;
2030
+ if (indentUnit === null && leadingSpaces > 0) {
2031
+ indentUnit = leadingSpaces;
2032
+ }
2033
+ if (/^\s*\t/.test(line) && /^\s* /.test(line)) {
2034
+ errors.push({
2035
+ type: "style",
2036
+ message: "Mixed tabs and spaces in indentation",
2037
+ line: i + 1,
2038
+ severity: "warning"
2039
+ });
2040
+ }
2041
+ }
2042
+ if (/\bprint\s+[^(]/.test(code)) {
2043
+ errors.push({
2044
+ type: "syntax",
2045
+ message: "Python 2 print statement syntax - use print() function",
2046
+ severity: "error"
2047
+ });
2048
+ }
2049
+ return errors;
2050
+ }
2051
+ /**
2052
+ * Generic code analysis.
2053
+ */
2054
+ analyzeGeneric(code) {
2055
+ const errors = [];
2056
+ const bracketBalance = this.checkBracketBalance(code);
2057
+ if (!bracketBalance.valid) {
2058
+ errors.push({
2059
+ type: "syntax",
2060
+ message: bracketBalance.message,
2061
+ severity: "error"
2062
+ });
2063
+ }
2064
+ return errors;
2065
+ }
2066
+ /**
2067
+ * Check bracket balance in code.
2068
+ */
2069
+ checkBracketBalance(code) {
2070
+ const stack = [];
2071
+ const pairs = {
2072
+ "(": ")",
2073
+ "[": "]",
2074
+ "{": "}"
2075
+ };
2076
+ const cleanCode = code.replace(/"[^"\\]*(\\.[^"\\]*)*"/g, '""').replace(/'[^'\\]*(\\.[^'\\]*)*'/g, "''").replace(/`[^`\\]*(\\.[^`\\]*)*`/g, "``").replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "").replace(/#.*$/gm, "");
2077
+ for (const char of cleanCode) {
2078
+ if (char in pairs) {
2079
+ stack.push(pairs[char]);
2080
+ } else if (Object.values(pairs).includes(char)) {
2081
+ if (stack.length === 0 || stack.pop() !== char) {
2082
+ return { valid: false, message: `Unmatched bracket: ${char}` };
2083
+ }
2084
+ }
2085
+ }
2086
+ if (stack.length > 0) {
2087
+ return { valid: false, message: `Missing closing bracket: ${stack[stack.length - 1]}` };
2088
+ }
2089
+ return { valid: true, message: "" };
2090
+ }
2091
+ /**
2092
+ * Detect runtime errors from execution output.
2093
+ */
2094
+ detectRuntimeErrors(output) {
2095
+ const errors = [];
2096
+ const errorPatterns = [
2097
+ { pattern: /SyntaxError:\s*(.+)/i, type: "syntax" },
2098
+ { pattern: /ReferenceError:\s*(.+)/i, type: "runtime" },
2099
+ { pattern: /TypeError:\s*(.+)/i, type: "runtime" },
2100
+ { pattern: /RangeError:\s*(.+)/i, type: "runtime" },
2101
+ { pattern: /Error:\s*(.+)/i, type: "runtime" },
2102
+ { pattern: /Exception:\s*(.+)/i, type: "runtime" },
2103
+ { pattern: /Traceback \(most recent call last\)/i, type: "runtime" }
2104
+ ];
2105
+ for (const { pattern, type } of errorPatterns) {
2106
+ const match = output.match(pattern);
2107
+ if (match) {
2108
+ errors.push({
2109
+ type,
2110
+ message: match[1] || match[0],
2111
+ severity: "error"
2112
+ });
2113
+ }
2114
+ }
2115
+ return errors;
2116
+ }
2117
+ /**
2118
+ * Use LLM to validate code.
2119
+ */
2120
+ async validateWithLLM(code, language) {
2121
+ const prompt = `Analyze this ${language} code for errors. Only report actual bugs, not style preferences.
2122
+ Return JSON format: {"errors": [{"message": "...", "line": N, "type": "syntax|runtime|logic"}], "warnings": [{"message": "..."}]}
2123
+ If no errors, return: {"errors": [], "warnings": []}
2124
+
2125
+ Code:
2126
+ \`\`\`${language}
2127
+ ${code}
2128
+ \`\`\`
2129
+
2130
+ Respond ONLY with the JSON object, no other text.`;
2131
+ try {
2132
+ const result = await this.generateText(prompt);
2133
+ const parsed = JSON.parse(result.text);
2134
+ return {
2135
+ errors: (parsed.errors || []).map((e) => {
2136
+ return {
2137
+ type: e.type || "logic",
2138
+ message: e.message,
2139
+ line: e.line,
2140
+ severity: "error"
2141
+ };
2142
+ }),
2143
+ warnings: (parsed.warnings || []).map((w) => {
2144
+ return {
2145
+ type: "style",
2146
+ message: w.message,
2147
+ severity: "warning"
2148
+ };
2149
+ })
2150
+ };
2151
+ } catch {
2152
+ return { errors: [], warnings: [] };
2153
+ }
2154
+ }
2155
+ /**
2156
+ * Attempt to fix errors in code.
2157
+ */
2158
+ async attemptFix(code, errors, language, originalPrompt) {
2159
+ const errorList = errors.map((e) => `- ${e.type}: ${e.message}${e.line ? ` (line ${e.line})` : ""}`).join("\n");
2160
+ const prompt = `Fix the following errors in this ${language} code.
2161
+
2162
+ ${originalPrompt ? `Original request: ${originalPrompt}
2163
+ ` : ""}
2164
+ Errors to fix:
2165
+ ${errorList}
2166
+
2167
+ Current code:
2168
+ \`\`\`${language}
2169
+ ${code}
2170
+ \`\`\`
2171
+
2172
+ Provide ONLY the fixed code wrapped in a code block. No explanations.`;
2173
+ try {
2174
+ const result = await this.generateText(prompt);
2175
+ const extractedCode = extractPrimaryCode(result.text);
2176
+ if (extractedCode && extractedCode !== code) {
2177
+ return { fixed: true, code: extractedCode };
2178
+ }
2179
+ } catch {
2180
+ }
2181
+ return { fixed: false, code };
2182
+ }
2183
+ };
2184
+ function createPassedValidationResult(code, language, output) {
2185
+ return {
2186
+ valid: true,
2187
+ errors: [],
2188
+ warnings: [],
2189
+ output,
2190
+ attempts: 1,
2191
+ finalCode: code,
2192
+ originalCode: code,
2193
+ language
2194
+ };
2195
+ }
2196
+ function createFailedValidationResult(code, language, errors) {
2197
+ return {
2198
+ valid: false,
2199
+ errors,
2200
+ warnings: [],
2201
+ attempts: 1,
2202
+ finalCode: code,
2203
+ originalCode: code,
2204
+ language
2205
+ };
2206
+ }
2207
+
2208
+ // src/ensemble/multi-sampler.ts
2209
+ var MultiSampler = class {
2210
+ constructor(options) {
2211
+ this.modelId = options.modelId;
2212
+ this.baseTemperature = options.baseTemperature ?? 0.7;
2213
+ }
2214
+ /**
2215
+ * Generate multiple samples and select the best one.
2216
+ *
2217
+ * @param generateFn - Function to generate a single response
2218
+ * @param config - Ensemble configuration
2219
+ * @returns The ensemble result
2220
+ */
2221
+ async generate(generateFn, config) {
2222
+ const startTime = Date.now();
2223
+ const {
2224
+ n,
2225
+ selectionStrategy = "best",
2226
+ temperatureVariance = 0.1,
2227
+ scoringHeuristic = "confidence",
2228
+ customScorer,
2229
+ timeoutMs = 6e4,
2230
+ allowPartialFailure = true,
2231
+ minSuccessfulSamples = 1
2232
+ } = config;
2233
+ if (n < 1 || n > 10) {
2234
+ throw new Error("Ensemble n must be between 1 and 10");
2235
+ }
2236
+ const promises = Array.from({ length: n }, async (_, i) => {
2237
+ const temperature = Math.min(this.baseTemperature + i * temperatureVariance, 2);
2238
+ const sampleStart = Date.now();
2239
+ try {
2240
+ const result2 = await generateFn({ temperature, sampleIndex: i });
2241
+ return {
2242
+ text: result2.text,
2243
+ reasoning: result2.reasoning,
2244
+ toolCalls: result2.toolCalls,
2245
+ toolResults: result2.toolResults,
2246
+ usage: result2.usage,
2247
+ sampleIndex: i,
2248
+ temperature,
2249
+ finishReason: result2.finishReason,
2250
+ success: true,
2251
+ durationMs: Date.now() - sampleStart
2252
+ };
2253
+ } catch (error) {
2254
+ return {
2255
+ text: "",
2256
+ sampleIndex: i,
2257
+ temperature,
2258
+ finishReason: "error",
2259
+ success: false,
2260
+ error: error instanceof Error ? error.message : "Unknown error",
2261
+ durationMs: Date.now() - sampleStart
2262
+ };
2263
+ }
2264
+ });
2265
+ let responses;
2266
+ try {
2267
+ responses = await Promise.race([
2268
+ Promise.all(promises),
2269
+ new Promise(
2270
+ (_, reject) => setTimeout(() => reject(new Error("Ensemble generation timed out")), timeoutMs)
2271
+ )
2272
+ ]);
2273
+ } catch (_error) {
2274
+ const partialResponses = await Promise.all(
2275
+ promises.map(
2276
+ (p) => p.catch(
2277
+ () => ({
2278
+ text: "",
2279
+ sampleIndex: -1,
2280
+ temperature: 0,
2281
+ finishReason: "timeout",
2282
+ success: false,
2283
+ error: "Timed out"
2284
+ })
2285
+ )
2286
+ )
2287
+ );
2288
+ responses = partialResponses.filter((r) => r.sampleIndex >= 0);
2289
+ }
2290
+ const successfulResponses = responses.filter((r) => r.success);
2291
+ if (successfulResponses.length < minSuccessfulSamples && !allowPartialFailure) {
2292
+ throw new Error(
2293
+ `Only ${successfulResponses.length} samples succeeded, minimum required is ${minSuccessfulSamples}`
2294
+ );
2295
+ }
2296
+ if (successfulResponses.length === 0) {
2297
+ throw new Error("All ensemble samples failed");
2298
+ }
2299
+ const result = this.selectBest(successfulResponses, responses, {
2300
+ selectionStrategy,
2301
+ scoringHeuristic,
2302
+ customScorer,
2303
+ modelId: this.modelId,
2304
+ startTime
2305
+ });
2306
+ return result;
2307
+ }
2308
+ /**
2309
+ * Select the best response based on the strategy.
2310
+ */
2311
+ selectBest(successfulResponses, allResponses, options) {
2312
+ const { selectionStrategy, scoringHeuristic, customScorer, modelId, startTime } = options;
2313
+ const scored = successfulResponses.map((r) => {
2314
+ return {
2315
+ ...r,
2316
+ score: this.calculateScore(r, scoringHeuristic, customScorer)
2317
+ };
2318
+ });
2319
+ let winner;
2320
+ let alternatives;
2321
+ switch (selectionStrategy) {
2322
+ case "first":
2323
+ winner = scored[0];
2324
+ break;
2325
+ case "vote":
2326
+ winner = this.majorityVote(scored);
2327
+ break;
2328
+ case "best":
2329
+ scored.sort((a, b) => (b.score ?? 0) - (a.score ?? 0));
2330
+ winner = scored[0];
2331
+ break;
2332
+ case "all":
2333
+ winner = scored[0];
2334
+ alternatives = scored;
2335
+ break;
2336
+ default:
2337
+ throw new Error(`Unknown selection strategy: ${selectionStrategy}`);
2338
+ }
2339
+ const metadata = {
2340
+ nRequested: allResponses.length,
2341
+ nCompleted: successfulResponses.length,
2342
+ nFailed: allResponses.filter((r) => !r.success).length,
2343
+ selectionStrategy,
2344
+ winningIndex: winner.sampleIndex,
2345
+ scores: scored.map((r) => r.score ?? 0),
2346
+ durationMs: Date.now() - startTime,
2347
+ modelId,
2348
+ totalUsage: this.aggregateUsage(successfulResponses)
2349
+ };
2350
+ return {
2351
+ text: winner.text,
2352
+ reasoning: winner.reasoning,
2353
+ toolCalls: winner.toolCalls,
2354
+ toolResults: winner.toolResults,
2355
+ usage: winner.usage ?? { promptTokens: 0, completionTokens: 0, totalTokens: 0 },
2356
+ alternatives,
2357
+ metadata
2358
+ };
2359
+ }
2360
+ /**
2361
+ * Calculate score for a response based on the heuristic.
2362
+ */
2363
+ calculateScore(response, heuristic, customScorer) {
2364
+ switch (heuristic) {
2365
+ case "length":
2366
+ return 1e3 / (response.text.length + 1);
2367
+ case "confidence":
2368
+ return response.usage?.completionTokens ?? 0;
2369
+ case "code":
2370
+ return this.scoreCodeQuality(response.text);
2371
+ case "custom":
2372
+ if (!customScorer) {
2373
+ throw new Error("Custom scorer function required for custom heuristic");
2374
+ }
2375
+ return customScorer(response);
2376
+ default:
2377
+ return 0;
2378
+ }
2379
+ }
2380
+ /**
2381
+ * Score code quality based on heuristics.
2382
+ */
2383
+ scoreCodeQuality(text) {
2384
+ let score = 100;
2385
+ const errorPatterns = [
2386
+ { pattern: /SyntaxError/gi, penalty: 25 },
2387
+ { pattern: /ReferenceError/gi, penalty: 20 },
2388
+ { pattern: /TypeError/gi, penalty: 20 },
2389
+ { pattern: /undefined is not/gi, penalty: 15 },
2390
+ { pattern: /cannot read property/gi, penalty: 15 },
2391
+ { pattern: /is not defined/gi, penalty: 15 },
2392
+ { pattern: /unexpected token/gi, penalty: 20 },
2393
+ { pattern: /null is not/gi, penalty: 15 }
2394
+ ];
2395
+ for (const { pattern, penalty } of errorPatterns) {
2396
+ const matches = text.match(pattern);
2397
+ if (matches) {
2398
+ score -= penalty * matches.length;
2399
+ }
2400
+ }
2401
+ if (text.includes("```")) {
2402
+ score += 10;
2403
+ }
2404
+ if (/\/\/.*|\/\*[\s\S]*?\*\/|#.*/.test(text)) {
2405
+ score += 5;
2406
+ }
2407
+ if (/\b(test|spec|assert|expect|describe|it)\b/i.test(text)) {
2408
+ score += 5;
2409
+ }
2410
+ if (/:\s*(string|number|boolean|void|any|unknown|never)\b/.test(text)) {
2411
+ score += 5;
2412
+ }
2413
+ if (/\b(TODO|FIXME|XXX|HACK)\b/i.test(text)) {
2414
+ score -= 5;
2415
+ }
2416
+ return Math.max(0, score);
2417
+ }
2418
+ /**
2419
+ * Select the most common response (majority voting).
2420
+ */
2421
+ majorityVote(responses) {
2422
+ const normalized = responses.map((r) => {
2423
+ return {
2424
+ response: r,
2425
+ key: r.text.toLowerCase().replace(/\s+/g, " ").trim().slice(0, 500)
2426
+ };
2427
+ });
2428
+ const votes = /* @__PURE__ */ new Map();
2429
+ for (const { response, key } of normalized) {
2430
+ const existing = votes.get(key);
2431
+ if (existing) {
2432
+ existing.count++;
2433
+ } else {
2434
+ votes.set(key, { count: 1, response });
2435
+ }
2436
+ }
2437
+ let maxVotes = 0;
2438
+ let winner = responses[0];
2439
+ for (const { count, response } of votes.values()) {
2440
+ if (count > maxVotes) {
2441
+ maxVotes = count;
2442
+ winner = response;
2443
+ }
2444
+ }
2445
+ return winner;
2446
+ }
2447
+ /**
2448
+ * Aggregate usage across all responses.
2449
+ */
2450
+ aggregateUsage(responses) {
2451
+ return responses.reduce(
2452
+ (acc, r) => {
2453
+ return {
2454
+ promptTokens: acc.promptTokens + (r.usage?.promptTokens ?? 0),
2455
+ completionTokens: acc.completionTokens + (r.usage?.completionTokens ?? 0),
2456
+ totalTokens: acc.totalTokens + (r.usage?.totalTokens ?? 0)
2457
+ };
2458
+ },
2459
+ { promptTokens: 0, completionTokens: 0, totalTokens: 0 }
2460
+ );
2461
+ }
2462
+ };
2463
+ function createSingletonEnsembleResult(response, modelId, durationMs) {
2464
+ return {
2465
+ text: response.text,
2466
+ reasoning: response.reasoning,
2467
+ toolCalls: response.toolCalls,
2468
+ toolResults: response.toolResults,
2469
+ usage: response.usage ?? { promptTokens: 0, completionTokens: 0, totalTokens: 0 },
2470
+ metadata: {
2471
+ nRequested: 1,
2472
+ nCompleted: 1,
2473
+ nFailed: 0,
2474
+ selectionStrategy: "first",
2475
+ winningIndex: 0,
2476
+ scores: [100],
2477
+ durationMs,
2478
+ modelId,
2479
+ totalUsage: response.usage ?? { promptTokens: 0, completionTokens: 0, totalTokens: 0 }
2480
+ }
2481
+ };
2482
+ }
2483
+
2484
+ // src/files/file-cache.ts
2485
+ var FileCache = class {
2486
+ constructor(options = {}) {
2487
+ this.maxSize = options.maxSize ?? 100;
2488
+ this.ttlMs = options.ttlMs ?? 36e5;
2489
+ this.cache = /* @__PURE__ */ new Map();
2490
+ }
2491
+ /**
2492
+ * Get a cached entry by content hash.
2493
+ * Returns undefined if not found or expired.
2494
+ * Moves the entry to the end (most recently used).
2495
+ */
2496
+ get(contentHash) {
2497
+ const entry = this.cache.get(contentHash);
2498
+ if (!entry) {
2499
+ return void 0;
2500
+ }
2501
+ if (this.isExpired(entry)) {
2502
+ this.cache.delete(contentHash);
2503
+ return void 0;
2504
+ }
2505
+ this.cache.delete(contentHash);
2506
+ this.cache.set(contentHash, entry);
2507
+ return entry;
2508
+ }
2509
+ /**
2510
+ * Set a cache entry.
2511
+ * Evicts the least recently used entry if cache is full.
2512
+ */
2513
+ set(contentHash, entry) {
2514
+ this.cache.delete(contentHash);
2515
+ while (this.cache.size >= this.maxSize) {
2516
+ const oldestKey = this.cache.keys().next().value;
2517
+ if (oldestKey !== void 0) {
2518
+ this.cache.delete(oldestKey);
2519
+ } else {
2520
+ break;
2521
+ }
2522
+ }
2523
+ this.cache.set(contentHash, entry);
2524
+ }
2525
+ /**
2526
+ * Check if an entry exists and is not expired.
2527
+ */
2528
+ has(contentHash) {
2529
+ return this.get(contentHash) !== void 0;
2530
+ }
2531
+ /**
2532
+ * Delete a specific entry.
2533
+ */
2534
+ delete(contentHash) {
2535
+ return this.cache.delete(contentHash);
2536
+ }
2537
+ /**
2538
+ * Clear all entries.
2539
+ */
2540
+ clear() {
2541
+ this.cache.clear();
2542
+ }
2543
+ /**
2544
+ * Get the current cache size.
2545
+ */
2546
+ get size() {
2547
+ return this.cache.size;
2548
+ }
2549
+ /**
2550
+ * Remove all expired entries.
2551
+ */
2552
+ prune() {
2553
+ let pruned = 0;
2554
+ for (const [key, entry] of this.cache) {
2555
+ if (this.isExpired(entry)) {
2556
+ this.cache.delete(key);
2557
+ pruned++;
2558
+ }
2559
+ }
2560
+ return pruned;
2561
+ }
2562
+ /**
2563
+ * Check if an entry is expired.
2564
+ */
2565
+ isExpired(entry) {
2566
+ return Date.now() - entry.createdAt > this.ttlMs;
2567
+ }
2568
+ };
2569
+ function generateContentHash(data) {
2570
+ const bytes = typeof data === "string" ? new TextEncoder().encode(data) : data;
2571
+ let hash = 2166136261;
2572
+ for (let i = 0; i < bytes.length; i++) {
2573
+ hash ^= bytes[i];
2574
+ hash = Math.imul(hash, 16777619);
2575
+ }
2576
+ hash ^= bytes.length;
2577
+ return (hash >>> 0).toString(16).padStart(8, "0");
2578
+ }
2579
+ function generateCacheKey(data, filename) {
2580
+ const bytes = typeof data === "string" ? new TextEncoder().encode(data) : data;
2581
+ const contentHash = generateContentHash(data);
2582
+ const normalizedFilename = filename.toLowerCase().replace(/[^a-z0-9.]/g, "_");
2583
+ return `${contentHash}_${bytes.length}_${normalizedFilename}`;
2584
+ }
2585
+ var defaultCache = null;
2586
+ function getDefaultFileCache() {
2587
+ if (!defaultCache) {
2588
+ defaultCache = new FileCache();
2589
+ }
2590
+ return defaultCache;
2591
+ }
2592
+
2593
+ // src/files/file-utils.ts
2594
+ var SUPPORTED_FILE_EXTENSIONS = [
2595
+ // Documents
2596
+ ".pdf",
2597
+ ".txt",
2598
+ ".csv",
2599
+ ".doc",
2600
+ ".docx",
2601
+ ".xls",
2602
+ ".xlsx",
2603
+ ".ppt",
2604
+ ".pptx",
2605
+ ".md",
2606
+ ".epub",
2607
+ ".mobi",
2608
+ ".html",
2609
+ ".json",
2610
+ ".log",
2611
+ ".dot",
2612
+ ".ini",
2613
+ ".conf",
2614
+ ".yaml",
2615
+ ".yml",
2616
+ // Images
2617
+ ".jpeg",
2618
+ ".jpg",
2619
+ ".png",
2620
+ ".bmp",
2621
+ ".gif",
2622
+ ".svg",
2623
+ ".svgz",
2624
+ ".webp",
2625
+ ".ico",
2626
+ ".xbm",
2627
+ ".dib",
2628
+ ".pjp",
2629
+ ".tif",
2630
+ ".tiff",
2631
+ ".pjpeg",
2632
+ ".avif",
2633
+ ".apng",
2634
+ ".jfif",
2635
+ // Code files
2636
+ ".go",
2637
+ ".h",
2638
+ ".c",
2639
+ ".cpp",
2640
+ ".cxx",
2641
+ ".cc",
2642
+ ".cs",
2643
+ ".java",
2644
+ ".js",
2645
+ ".css",
2646
+ ".jsp",
2647
+ ".php",
2648
+ ".py",
2649
+ ".py3",
2650
+ ".asp",
2651
+ ".ts",
2652
+ ".tsx"
2653
+ ];
2654
+ var SUPPORTED_MIME_TYPES = {
2655
+ // Documents
2656
+ "application/pdf": "file-extract",
2657
+ "text/plain": "file-extract",
2658
+ "text/csv": "file-extract",
2659
+ "application/msword": "file-extract",
2660
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document": "file-extract",
2661
+ "application/vnd.ms-excel": "file-extract",
2662
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "file-extract",
2663
+ "application/vnd.ms-powerpoint": "file-extract",
2664
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation": "file-extract",
2665
+ "text/markdown": "file-extract",
2666
+ "text/html": "file-extract",
2667
+ "application/json": "file-extract",
2668
+ "application/epub+zip": "file-extract",
2669
+ "text/yaml": "file-extract",
2670
+ "application/x-yaml": "file-extract",
2671
+ // Code files (treated as text)
2672
+ "text/javascript": "file-extract",
2673
+ "text/typescript": "file-extract",
2674
+ "text/x-python": "file-extract",
2675
+ "text/x-java": "file-extract",
2676
+ "text/x-c": "file-extract",
2677
+ "text/x-c++": "file-extract",
2678
+ "text/css": "file-extract",
2679
+ // Images
2680
+ "image/jpeg": "image",
2681
+ "image/png": "image",
2682
+ "image/gif": "image",
2683
+ "image/webp": "image",
2684
+ "image/svg+xml": "image",
2685
+ "image/bmp": "image",
2686
+ "image/tiff": "image",
2687
+ "image/avif": "image",
2688
+ "image/apng": "image",
2689
+ "image/x-icon": "image",
2690
+ // Videos
2691
+ "video/mp4": "video",
2692
+ "video/webm": "video",
2693
+ "video/ogg": "video",
2694
+ "video/quicktime": "video"
2695
+ };
2696
+ function isImageMediaType2(mediaType) {
2697
+ return mediaType.startsWith("image/");
2698
+ }
2699
+ function isVideoMediaType2(mediaType) {
2700
+ return mediaType.startsWith("video/");
2701
+ }
2702
+ function isFileExtractMediaType(mediaType) {
2703
+ if (mediaType in SUPPORTED_MIME_TYPES) {
2704
+ return SUPPORTED_MIME_TYPES[mediaType] === "file-extract";
2705
+ }
2706
+ if (mediaType.startsWith("text/") || mediaType === "application/pdf") {
2707
+ return true;
2708
+ }
2709
+ return false;
2710
+ }
2711
+ function isDocumentMediaType(mediaType) {
2712
+ const documentTypes = [
2713
+ "application/pdf",
2714
+ "application/msword",
2715
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
2716
+ "application/vnd.ms-excel",
2717
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
2718
+ "application/vnd.ms-powerpoint",
2719
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation",
2720
+ "application/epub+zip"
2721
+ ];
2722
+ return documentTypes.includes(mediaType);
2723
+ }
2724
+ function getPurposeFromMediaType(mediaType) {
2725
+ if (isImageMediaType2(mediaType)) {
2726
+ return "image";
2727
+ }
2728
+ if (isVideoMediaType2(mediaType)) {
2729
+ return "video";
2730
+ }
2731
+ return "file-extract";
2732
+ }
2733
+ function getMediaTypeFromExtension(extension) {
2734
+ const ext = extension.toLowerCase().startsWith(".") ? extension.toLowerCase() : `.${extension.toLowerCase()}`;
2735
+ const extensionToMime = {
2736
+ // Documents
2737
+ ".pdf": "application/pdf",
2738
+ ".txt": "text/plain",
2739
+ ".csv": "text/csv",
2740
+ ".doc": "application/msword",
2741
+ ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
2742
+ ".xls": "application/vnd.ms-excel",
2743
+ ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
2744
+ ".ppt": "application/vnd.ms-powerpoint",
2745
+ ".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
2746
+ ".md": "text/markdown",
2747
+ ".html": "text/html",
2748
+ ".json": "application/json",
2749
+ ".epub": "application/epub+zip",
1483
2750
  ".yaml": "text/yaml",
1484
2751
  ".yml": "text/yaml",
1485
2752
  ".log": "text/plain",
@@ -1678,8 +2945,10 @@ async function processAttachments(options) {
1678
2945
  clientConfig,
1679
2946
  autoUploadDocuments = true,
1680
2947
  uploadImages = false,
1681
- cleanupAfterExtract = false
2948
+ cleanupAfterExtract = false,
2949
+ cache = false
1682
2950
  } = options;
2951
+ const cacheInstance = cache === true ? getDefaultFileCache() : cache === false ? null : cache;
1683
2952
  const results = [];
1684
2953
  const client = new KimiFileClient(clientConfig);
1685
2954
  for (const attachment of attachments) {
@@ -1687,7 +2956,8 @@ async function processAttachments(options) {
1687
2956
  const processed = await processAttachment(attachment, client, {
1688
2957
  autoUploadDocuments,
1689
2958
  uploadImages,
1690
- cleanupAfterExtract
2959
+ cleanupAfterExtract,
2960
+ cache: cacheInstance
1691
2961
  });
1692
2962
  results.push(processed);
1693
2963
  } catch (error) {
@@ -1747,12 +3017,35 @@ async function processAttachment(attachment, client, options) {
1747
3017
  error: "No content or URL provided for document attachment"
1748
3018
  };
1749
3019
  }
3020
+ const filename = attachment.name ?? guessFilename(attachment, contentType);
3021
+ if (options.cache) {
3022
+ const cacheKey = generateCacheKey(data, filename);
3023
+ const cached = options.cache.get(cacheKey);
3024
+ if (cached) {
3025
+ return {
3026
+ original: attachment,
3027
+ type: "text-inject",
3028
+ textContent: cached.content,
3029
+ fileId: cached.fileId
3030
+ };
3031
+ }
3032
+ }
1750
3033
  const result = await client.uploadAndExtract({
1751
3034
  data,
1752
- filename: attachment.name ?? guessFilename(attachment, contentType),
3035
+ filename,
1753
3036
  mediaType: contentType,
1754
3037
  purpose: "file-extract"
1755
3038
  });
3039
+ if (options.cache && result.content) {
3040
+ const cacheKey = generateCacheKey(data, filename);
3041
+ const cacheEntry = {
3042
+ fileId: result.file.id,
3043
+ content: result.content,
3044
+ createdAt: Date.now(),
3045
+ purpose: "file-extract"
3046
+ };
3047
+ options.cache.set(cacheKey, cacheEntry);
3048
+ }
1756
3049
  if (options.cleanupAfterExtract && result.file.id) {
1757
3050
  try {
1758
3051
  await client.deleteFile(result.file.id);
@@ -1808,8 +3101,747 @@ function guessFilename(attachment, contentType) {
1808
3101
  return extensionMap[contentType] ?? "file.bin";
1809
3102
  }
1810
3103
 
3104
+ // src/multi-agent/types.ts
3105
+ var DEFAULT_SYSTEM_PROMPTS = {
3106
+ planner: `You are a system architect and planner. Your role is to:
3107
+ 1. Analyze the problem thoroughly
3108
+ 2. Break it down into clear, actionable steps
3109
+ 3. Consider edge cases and potential issues
3110
+ 4. Provide a detailed implementation plan
3111
+
3112
+ Format your response as a numbered list of steps that can be followed to implement the solution.`,
3113
+ executor: `You are an expert implementer. Your role is to:
3114
+ 1. Follow the provided plan precisely
3115
+ 2. Write clean, well-documented code
3116
+ 3. Handle edge cases mentioned in the plan
3117
+ 4. Ensure the implementation is complete and functional
3118
+
3119
+ Provide only the implementation code with necessary comments.`,
3120
+ proposer: `You are a solution architect. Your role is to:
3121
+ 1. Analyze the problem carefully
3122
+ 2. Propose a complete solution
3123
+ 3. Consider best practices and patterns
3124
+ 4. Write clean, maintainable code
3125
+
3126
+ Provide your solution with explanations for key design decisions.`,
3127
+ critic: `You are a code reviewer and critic. Your role is to:
3128
+ 1. Review the proposed solution critically
3129
+ 2. Identify any bugs, errors, or issues
3130
+ 3. Suggest improvements for performance and readability
3131
+ 4. Verify edge cases are handled
3132
+
3133
+ Provide specific, actionable feedback. Be thorough but constructive.`
3134
+ };
3135
+
3136
+ // src/multi-agent/workflows.ts
3137
+ var WorkflowRunner = class {
3138
+ constructor(generateText, validateCode) {
3139
+ this.generateText = generateText;
3140
+ this.validateCode = validateCode;
3141
+ }
3142
+ /**
3143
+ * Run a multi-agent workflow.
3144
+ */
3145
+ async run(prompt, config) {
3146
+ const startTime = Date.now();
3147
+ switch (config.workflow) {
3148
+ case "planner-executor":
3149
+ return this.runPlannerExecutor(prompt, config, startTime);
3150
+ case "proposer-critic":
3151
+ return this.runProposerCritic(prompt, config, startTime);
3152
+ case "debate":
3153
+ return this.runDebate(prompt, config, startTime);
3154
+ case "custom":
3155
+ if (!config.customWorkflow) {
3156
+ throw new Error("Custom workflow requires customWorkflow function");
3157
+ }
3158
+ return this.runCustom(prompt, config, startTime);
3159
+ default:
3160
+ throw new Error(`Unknown workflow type: ${config.workflow}`);
3161
+ }
3162
+ }
3163
+ /**
3164
+ * Planner-Executor workflow.
3165
+ */
3166
+ async runPlannerExecutor(prompt, config, startTime) {
3167
+ const steps = [];
3168
+ let totalUsage = { promptTokens: 0, completionTokens: 0, totalTokens: 0 };
3169
+ const modelA = config.modelA || "kimi-k2.5-thinking";
3170
+ const modelB = config.modelB || "kimi-k2.5";
3171
+ const planStart = Date.now();
3172
+ const plannerPrompt = `${config.systemPrompts?.planner || DEFAULT_SYSTEM_PROMPTS.planner}
3173
+
3174
+ Problem to solve:
3175
+ ${prompt}
3176
+
3177
+ Provide a detailed step-by-step plan.`;
3178
+ const planResult = await this.generateText(modelA, plannerPrompt);
3179
+ steps.push({
3180
+ agent: "A (Planner)",
3181
+ role: "planner",
3182
+ action: "Create implementation plan",
3183
+ input: prompt,
3184
+ output: planResult.text,
3185
+ timestamp: Date.now(),
3186
+ durationMs: Date.now() - planStart,
3187
+ usage: planResult.usage,
3188
+ model: modelA
3189
+ });
3190
+ totalUsage = this.addUsage(totalUsage, planResult.usage);
3191
+ const execStart = Date.now();
3192
+ const executorPrompt = `${config.systemPrompts?.executor || DEFAULT_SYSTEM_PROMPTS.executor}
3193
+
3194
+ Plan to implement:
3195
+ ${planResult.text}
3196
+
3197
+ Original problem: ${prompt}
3198
+
3199
+ Implement the solution following the plan.`;
3200
+ const execResult = await this.generateText(modelB, executorPrompt);
3201
+ steps.push({
3202
+ agent: "B (Executor)",
3203
+ role: "executor",
3204
+ action: "Implement solution",
3205
+ input: planResult.text,
3206
+ output: execResult.text,
3207
+ timestamp: Date.now(),
3208
+ durationMs: Date.now() - execStart,
3209
+ usage: execResult.usage,
3210
+ model: modelB
3211
+ });
3212
+ totalUsage = this.addUsage(totalUsage, execResult.usage);
3213
+ let validation;
3214
+ if (config.validateCode && this.validateCode) {
3215
+ const code = extractPrimaryCode(execResult.text);
3216
+ if (code) {
3217
+ const validStart = Date.now();
3218
+ const validResult = await this.validateCode(code);
3219
+ steps.push({
3220
+ agent: "Validator",
3221
+ role: "validator",
3222
+ action: "Validate code",
3223
+ input: code,
3224
+ output: validResult.valid ? "Code is valid" : `Errors: ${validResult.errors.join(", ")}`,
3225
+ timestamp: Date.now(),
3226
+ durationMs: Date.now() - validStart
3227
+ });
3228
+ validation = {
3229
+ valid: validResult.valid,
3230
+ errors: validResult.errors,
3231
+ finalCode: validResult.fixedCode || code
3232
+ };
3233
+ }
3234
+ }
3235
+ return {
3236
+ text: execResult.text,
3237
+ reasoning: planResult.text,
3238
+ intermediateSteps: steps,
3239
+ usage: totalUsage,
3240
+ metadata: this.buildMetadata(config, steps, startTime, [modelA, modelB]),
3241
+ validation
3242
+ };
3243
+ }
3244
+ /**
3245
+ * Proposer-Critic workflow.
3246
+ */
3247
+ async runProposerCritic(prompt, config, startTime) {
3248
+ const steps = [];
3249
+ let totalUsage = { promptTokens: 0, completionTokens: 0, totalTokens: 0 };
3250
+ const modelA = config.modelA || "kimi-k2.5";
3251
+ const modelB = config.modelB || "kimi-k2.5-thinking";
3252
+ const iterations = config.iterations || 2;
3253
+ let currentSolution = "";
3254
+ let critique = "";
3255
+ for (let i = 0; i < iterations; i++) {
3256
+ const proposeStart = Date.now();
3257
+ const proposerPrompt = i === 0 ? `${config.systemPrompts?.proposer || DEFAULT_SYSTEM_PROMPTS.proposer}
3258
+
3259
+ Problem: ${prompt}
3260
+
3261
+ Provide your solution.` : `${config.systemPrompts?.proposer || DEFAULT_SYSTEM_PROMPTS.proposer}
3262
+
3263
+ Problem: ${prompt}
3264
+
3265
+ Previous solution:
3266
+ ${currentSolution}
3267
+
3268
+ Critique/feedback to address:
3269
+ ${critique}
3270
+
3271
+ Provide an improved solution addressing the feedback.`;
3272
+ const proposeResult = await this.generateText(modelA, proposerPrompt);
3273
+ currentSolution = proposeResult.text;
3274
+ steps.push({
3275
+ agent: "A (Proposer)",
3276
+ role: "proposer",
3277
+ action: `Generate solution (iteration ${i + 1})`,
3278
+ input: i === 0 ? prompt : critique,
3279
+ output: currentSolution,
3280
+ timestamp: Date.now(),
3281
+ durationMs: Date.now() - proposeStart,
3282
+ usage: proposeResult.usage,
3283
+ model: modelA
3284
+ });
3285
+ totalUsage = this.addUsage(totalUsage, proposeResult.usage);
3286
+ if (i < iterations - 1) {
3287
+ const critiqueStart = Date.now();
3288
+ const criticPrompt = `${config.systemPrompts?.critic || DEFAULT_SYSTEM_PROMPTS.critic}
3289
+
3290
+ Original problem: ${prompt}
3291
+
3292
+ Solution to review:
3293
+ ${currentSolution}
3294
+
3295
+ Provide detailed feedback and suggestions for improvement.`;
3296
+ const critiqueResult = await this.generateText(modelB, criticPrompt);
3297
+ critique = critiqueResult.text;
3298
+ steps.push({
3299
+ agent: "B (Critic)",
3300
+ role: "critic",
3301
+ action: `Critique solution (iteration ${i + 1})`,
3302
+ input: currentSolution,
3303
+ output: critique,
3304
+ timestamp: Date.now(),
3305
+ durationMs: Date.now() - critiqueStart,
3306
+ usage: critiqueResult.usage,
3307
+ model: modelB
3308
+ });
3309
+ totalUsage = this.addUsage(totalUsage, critiqueResult.usage);
3310
+ }
3311
+ }
3312
+ let validation;
3313
+ if (config.validateCode && this.validateCode) {
3314
+ const code = extractPrimaryCode(currentSolution);
3315
+ if (code) {
3316
+ const validResult = await this.validateCode(code);
3317
+ validation = {
3318
+ valid: validResult.valid,
3319
+ errors: validResult.errors,
3320
+ finalCode: validResult.fixedCode || code
3321
+ };
3322
+ }
3323
+ }
3324
+ return {
3325
+ text: currentSolution,
3326
+ reasoning: critique,
3327
+ intermediateSteps: steps,
3328
+ usage: totalUsage,
3329
+ metadata: this.buildMetadata(config, steps, startTime, [modelA, modelB]),
3330
+ validation
3331
+ };
3332
+ }
3333
+ /**
3334
+ * Debate workflow.
3335
+ */
3336
+ async runDebate(prompt, config, startTime) {
3337
+ const steps = [];
3338
+ let totalUsage = { promptTokens: 0, completionTokens: 0, totalTokens: 0 };
3339
+ const modelA = config.modelA || "kimi-k2.5";
3340
+ const modelB = config.modelB || "kimi-k2.5";
3341
+ const iterations = config.iterations || 2;
3342
+ let positionA = "";
3343
+ let positionB = "";
3344
+ const initialPrompt = `Problem: ${prompt}
3345
+
3346
+ Provide your solution and reasoning.`;
3347
+ const aStart = Date.now();
3348
+ const aResult = await this.generateText(modelA, initialPrompt);
3349
+ positionA = aResult.text;
3350
+ steps.push({
3351
+ agent: "A",
3352
+ role: "proposer",
3353
+ action: "Initial position",
3354
+ input: prompt,
3355
+ output: positionA,
3356
+ timestamp: Date.now(),
3357
+ durationMs: Date.now() - aStart,
3358
+ usage: aResult.usage,
3359
+ model: modelA
3360
+ });
3361
+ totalUsage = this.addUsage(totalUsage, aResult.usage);
3362
+ const bStart = Date.now();
3363
+ const bResult = await this.generateText(modelB, initialPrompt);
3364
+ positionB = bResult.text;
3365
+ steps.push({
3366
+ agent: "B",
3367
+ role: "proposer",
3368
+ action: "Initial position",
3369
+ input: prompt,
3370
+ output: positionB,
3371
+ timestamp: Date.now(),
3372
+ durationMs: Date.now() - bStart,
3373
+ usage: bResult.usage,
3374
+ model: modelB
3375
+ });
3376
+ totalUsage = this.addUsage(totalUsage, bResult.usage);
3377
+ for (let i = 0; i < iterations - 1; i++) {
3378
+ const aDebateStart = Date.now();
3379
+ const aDebatePrompt = `Problem: ${prompt}
3380
+
3381
+ Your previous position:
3382
+ ${positionA}
3383
+
3384
+ Other perspective:
3385
+ ${positionB}
3386
+
3387
+ Consider the other perspective. Either defend your position with additional reasoning, or revise it based on valid points. Provide your updated solution.`;
3388
+ const aDebateResult = await this.generateText(modelA, aDebatePrompt);
3389
+ positionA = aDebateResult.text;
3390
+ steps.push({
3391
+ agent: "A",
3392
+ role: "proposer",
3393
+ action: `Debate round ${i + 1}`,
3394
+ input: positionB,
3395
+ output: positionA,
3396
+ timestamp: Date.now(),
3397
+ durationMs: Date.now() - aDebateStart,
3398
+ usage: aDebateResult.usage,
3399
+ model: modelA
3400
+ });
3401
+ totalUsage = this.addUsage(totalUsage, aDebateResult.usage);
3402
+ const bDebateStart = Date.now();
3403
+ const bDebatePrompt = `Problem: ${prompt}
3404
+
3405
+ Your previous position:
3406
+ ${positionB}
3407
+
3408
+ Other perspective:
3409
+ ${positionA}
3410
+
3411
+ Consider the other perspective. Either defend your position with additional reasoning, or revise it based on valid points. Provide your updated solution.`;
3412
+ const bDebateResult = await this.generateText(modelB, bDebatePrompt);
3413
+ positionB = bDebateResult.text;
3414
+ steps.push({
3415
+ agent: "B",
3416
+ role: "proposer",
3417
+ action: `Debate round ${i + 1}`,
3418
+ input: positionA,
3419
+ output: positionB,
3420
+ timestamp: Date.now(),
3421
+ durationMs: Date.now() - bDebateStart,
3422
+ usage: bDebateResult.usage,
3423
+ model: modelB
3424
+ });
3425
+ totalUsage = this.addUsage(totalUsage, bDebateResult.usage);
3426
+ }
3427
+ const finalText = positionA.length > positionB.length ? positionA : positionB;
3428
+ return {
3429
+ text: finalText,
3430
+ reasoning: `Debate synthesis from ${iterations} rounds`,
3431
+ intermediateSteps: steps,
3432
+ usage: totalUsage,
3433
+ metadata: this.buildMetadata(config, steps, startTime, [modelA, modelB])
3434
+ };
3435
+ }
3436
+ /**
3437
+ * Custom workflow.
3438
+ */
3439
+ async runCustom(prompt, config, startTime) {
3440
+ const steps = [];
3441
+ const modelA = config.modelA || "kimi-k2.5";
3442
+ const modelB = config.modelB || "kimi-k2.5";
3443
+ const context = {
3444
+ generateWithModelA: (p) => this.generateText(modelA, p),
3445
+ generateWithModelB: (p) => this.generateText(modelB, p),
3446
+ validateCode: this.validateCode,
3447
+ config,
3448
+ addStep: (step) => {
3449
+ steps.push({
3450
+ ...step,
3451
+ timestamp: Date.now(),
3452
+ durationMs: 0
3453
+ });
3454
+ }
3455
+ };
3456
+ const result = await config.customWorkflow(prompt, context);
3457
+ if (result.intermediateSteps.length === 0 && steps.length > 0) {
3458
+ result.intermediateSteps = steps;
3459
+ }
3460
+ result.metadata.durationMs = Date.now() - startTime;
3461
+ return result;
3462
+ }
3463
+ /**
3464
+ * Build metadata for result.
3465
+ */
3466
+ buildMetadata(config, steps, startTime, models) {
3467
+ return {
3468
+ workflow: config.workflow,
3469
+ iterations: steps.length,
3470
+ durationMs: Date.now() - startTime,
3471
+ models: [...new Set(models)],
3472
+ validationEnabled: config.validateCode ?? false,
3473
+ success: true
3474
+ };
3475
+ }
3476
+ /**
3477
+ * Add usage stats.
3478
+ */
3479
+ addUsage(a, b) {
3480
+ if (!b) {
3481
+ return a;
3482
+ }
3483
+ return {
3484
+ promptTokens: a.promptTokens + b.promptTokens,
3485
+ completionTokens: a.completionTokens + b.completionTokens,
3486
+ totalTokens: a.totalTokens + b.totalTokens
3487
+ };
3488
+ }
3489
+ };
3490
+ function createEmptyMultiAgentResult(workflow, error) {
3491
+ return {
3492
+ text: "",
3493
+ intermediateSteps: [],
3494
+ usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },
3495
+ metadata: {
3496
+ workflow,
3497
+ iterations: 0,
3498
+ durationMs: 0,
3499
+ models: [],
3500
+ validationEnabled: false,
3501
+ success: false,
3502
+ error
3503
+ }
3504
+ };
3505
+ }
3506
+
3507
+ // src/project-tools/scaffolder.ts
3508
+ var ProjectScaffolder = class {
3509
+ constructor(options) {
3510
+ this.generateText = options.generateText;
3511
+ }
3512
+ /**
3513
+ * Scaffold a new project based on a description.
3514
+ *
3515
+ * @param description - Description of the project to create
3516
+ * @param config - Scaffold configuration
3517
+ * @returns Scaffold result with files and instructions
3518
+ */
3519
+ async scaffold(description, config = {}) {
3520
+ const {
3521
+ type = "auto",
3522
+ includeTests = true,
3523
+ includeCI = false,
3524
+ includeDocs = true,
3525
+ includeDocker = false,
3526
+ includeLinting = true,
3527
+ outputFormat = "files",
3528
+ useTypeScript = true,
3529
+ features = [],
3530
+ customTemplate
3531
+ } = config;
3532
+ const prompt = this.buildScaffoldPrompt(description, {
3533
+ type,
3534
+ includeTests,
3535
+ includeCI,
3536
+ includeDocs,
3537
+ includeDocker,
3538
+ includeLinting,
3539
+ useTypeScript,
3540
+ features,
3541
+ customTemplate
3542
+ });
3543
+ const result = await this.generateText(prompt);
3544
+ const parsed = this.parseResponse(result.text, type);
3545
+ return this.formatResult(parsed, outputFormat, result.text);
3546
+ }
3547
+ /**
3548
+ * Build the scaffold prompt.
3549
+ */
3550
+ buildScaffoldPrompt(description, config) {
3551
+ const parts = [];
3552
+ parts.push("Generate a complete project structure for the following description:");
3553
+ parts.push(`"${description}"`);
3554
+ parts.push("");
3555
+ if (config.type !== "auto") {
3556
+ parts.push(`Framework/Type: ${config.type}`);
3557
+ }
3558
+ parts.push(`Language: ${config.useTypeScript ? "TypeScript" : "JavaScript/Python/Go (as appropriate)"}`);
3559
+ const includes = [];
3560
+ if (config.includeTests) {
3561
+ includes.push("comprehensive test files");
3562
+ }
3563
+ if (config.includeCI) {
3564
+ includes.push("GitHub Actions CI/CD workflow");
3565
+ }
3566
+ if (config.includeDocs) {
3567
+ includes.push("README with setup instructions");
3568
+ }
3569
+ if (config.includeDocker) {
3570
+ includes.push("Dockerfile and docker-compose.yml");
3571
+ }
3572
+ if (config.includeLinting) {
3573
+ includes.push("ESLint/linting configuration");
3574
+ }
3575
+ if (includes.length > 0) {
3576
+ parts.push(`Include: ${includes.join(", ")}`);
3577
+ }
3578
+ if (config.features.length > 0) {
3579
+ parts.push(`Additional features: ${config.features.join(", ")}`);
3580
+ }
3581
+ if (config.customTemplate) {
3582
+ parts.push("");
3583
+ parts.push("Custom requirements:");
3584
+ parts.push(config.customTemplate);
3585
+ }
3586
+ parts.push("");
3587
+ parts.push("Respond with a JSON object in this exact format:");
3588
+ parts.push("```json");
3589
+ parts.push("{");
3590
+ parts.push(' "projectName": "project-name",');
3591
+ parts.push(' "projectType": "detected-type",');
3592
+ parts.push(' "technologies": ["tech1", "tech2"],');
3593
+ parts.push(' "files": [');
3594
+ parts.push(" {");
3595
+ parts.push(' "path": "relative/path/to/file.ts",');
3596
+ parts.push(' "content": "full file content here",');
3597
+ parts.push(' "description": "what this file does"');
3598
+ parts.push(" }");
3599
+ parts.push(" ],");
3600
+ parts.push(' "setupCommands": ["npm install", "npm run dev"],');
3601
+ parts.push(' "estimatedSetupTime": "5 minutes"');
3602
+ parts.push("}");
3603
+ parts.push("```");
3604
+ parts.push("");
3605
+ parts.push(
3606
+ "Include ALL necessary files for a working project: package.json/requirements.txt, source files, config files, etc."
3607
+ );
3608
+ parts.push("Make sure file contents are complete and functional, not placeholders.");
3609
+ return parts.join("\n");
3610
+ }
3611
+ /**
3612
+ * Parse the model response into structured data.
3613
+ */
3614
+ parseResponse(text, defaultType) {
3615
+ const jsonMatch = text.match(/```json\n?([\s\S]*?)```/) || text.match(/\{[\s\S]*"files"[\s\S]*\}/);
3616
+ if (jsonMatch) {
3617
+ try {
3618
+ const json = JSON.parse(jsonMatch[1] || jsonMatch[0]);
3619
+ const files = (json.files || []).map((f) => {
3620
+ return {
3621
+ path: f.path,
3622
+ content: f.content,
3623
+ description: f.description
3624
+ };
3625
+ });
3626
+ let projectType;
3627
+ if (json.projectType) {
3628
+ projectType = json.projectType;
3629
+ } else if (defaultType === "auto") {
3630
+ projectType = this.detectProjectType(files);
3631
+ } else {
3632
+ projectType = defaultType;
3633
+ }
3634
+ return {
3635
+ files,
3636
+ metadata: {
3637
+ projectType,
3638
+ projectName: json.projectName || "my-project",
3639
+ fileCount: files.length,
3640
+ totalSize: files.reduce((sum, f) => sum + (f.content?.length || 0), 0),
3641
+ estimatedSetupTime: json.estimatedSetupTime || "unknown",
3642
+ technologies: json.technologies || [],
3643
+ features: []
3644
+ },
3645
+ setupCommands: json.setupCommands || []
3646
+ };
3647
+ } catch {
3648
+ }
3649
+ }
3650
+ return this.parseFromCodeBlocks(text, defaultType);
3651
+ }
3652
+ /**
3653
+ * Parse files from markdown code blocks.
3654
+ */
3655
+ parseFromCodeBlocks(text, defaultType) {
3656
+ const files = [];
3657
+ const fileBlockRegex = /```(?:(\w+):)?([\w./-]+)\n([\s\S]*?)```/g;
3658
+ let match = fileBlockRegex.exec(text);
3659
+ while (match !== null) {
3660
+ const path = match[2];
3661
+ const content = match[3].trim();
3662
+ if (path.includes(".")) {
3663
+ files.push({
3664
+ path,
3665
+ content,
3666
+ description: void 0
3667
+ });
3668
+ }
3669
+ match = fileBlockRegex.exec(text);
3670
+ }
3671
+ if (files.length === 0) {
3672
+ const genericBlockRegex = /```(\w*)\n([\s\S]*?)```/g;
3673
+ let blockMatch = genericBlockRegex.exec(text);
3674
+ let index = 0;
3675
+ while (blockMatch !== null) {
3676
+ const lang = blockMatch[1] || "txt";
3677
+ const content = blockMatch[2].trim();
3678
+ if (content.length > 10) {
3679
+ const ext = this.getExtensionForLanguage(lang);
3680
+ files.push({
3681
+ path: `file${index}.${ext}`,
3682
+ content
3683
+ });
3684
+ index++;
3685
+ }
3686
+ blockMatch = genericBlockRegex.exec(text);
3687
+ }
3688
+ }
3689
+ return {
3690
+ files,
3691
+ metadata: {
3692
+ projectType: defaultType === "auto" ? this.detectProjectType(files) : defaultType,
3693
+ projectName: "my-project",
3694
+ fileCount: files.length,
3695
+ totalSize: files.reduce((sum, f) => sum + f.content.length, 0),
3696
+ estimatedSetupTime: "unknown",
3697
+ technologies: [],
3698
+ features: []
3699
+ },
3700
+ setupCommands: []
3701
+ };
3702
+ }
3703
+ /**
3704
+ * Detect project type from files.
3705
+ */
3706
+ detectProjectType(files) {
3707
+ const paths = files.map((f) => f.path.toLowerCase());
3708
+ const contents = files.map((f) => f.content);
3709
+ if (paths.some((p) => p.includes("next.config"))) {
3710
+ return "nextjs";
3711
+ }
3712
+ if (contents.some((c) => c.includes("from fastapi"))) {
3713
+ return "fastapi";
3714
+ }
3715
+ if (contents.some((c) => c.includes("from flask"))) {
3716
+ return "flask";
3717
+ }
3718
+ if (paths.some((p) => p.includes("package.json"))) {
3719
+ const pkgFile = files.find((f) => f.path.includes("package.json"));
3720
+ if (pkgFile) {
3721
+ if (pkgFile.content.includes('"react"')) {
3722
+ return "react";
3723
+ }
3724
+ if (pkgFile.content.includes('"vue"')) {
3725
+ return "vue";
3726
+ }
3727
+ if (pkgFile.content.includes('"express"')) {
3728
+ return "express";
3729
+ }
3730
+ if (pkgFile.content.includes('"fastify"')) {
3731
+ return "fastify";
3732
+ }
3733
+ }
3734
+ return "node";
3735
+ }
3736
+ if (paths.some((p) => p.includes("requirements.txt") || p.endsWith(".py"))) {
3737
+ return "python";
3738
+ }
3739
+ if (paths.some((p) => p.includes("go.mod") || p.endsWith(".go"))) {
3740
+ return "go";
3741
+ }
3742
+ if (paths.some((p) => p.includes("cargo.toml") || p.endsWith(".rs"))) {
3743
+ return "rust";
3744
+ }
3745
+ return "node";
3746
+ }
3747
+ /**
3748
+ * Get file extension for a language.
3749
+ */
3750
+ getExtensionForLanguage(lang) {
3751
+ const map = {
3752
+ typescript: "ts",
3753
+ javascript: "js",
3754
+ python: "py",
3755
+ go: "go",
3756
+ rust: "rs",
3757
+ json: "json",
3758
+ yaml: "yml",
3759
+ markdown: "md",
3760
+ html: "html",
3761
+ css: "css",
3762
+ shell: "sh",
3763
+ bash: "sh",
3764
+ dockerfile: "dockerfile",
3765
+ sql: "sql"
3766
+ };
3767
+ return map[lang.toLowerCase()] || "txt";
3768
+ }
3769
+ /**
3770
+ * Format the result based on output format.
3771
+ */
3772
+ formatResult(parsed, format, rawResponse) {
3773
+ const instructions = this.generateInstructions(parsed);
3774
+ return {
3775
+ files: format === "instructions" ? [] : parsed.files,
3776
+ instructions,
3777
+ setupCommands: parsed.setupCommands,
3778
+ metadata: parsed.metadata,
3779
+ rawResponse: format === "json" ? rawResponse : void 0
3780
+ };
3781
+ }
3782
+ /**
3783
+ * Generate setup instructions.
3784
+ */
3785
+ generateInstructions(parsed) {
3786
+ const lines = [];
3787
+ lines.push(`# ${parsed.metadata.projectName} Setup`);
3788
+ lines.push("");
3789
+ lines.push(`Project type: ${parsed.metadata.projectType}`);
3790
+ lines.push(`Files: ${parsed.metadata.fileCount}`);
3791
+ lines.push("");
3792
+ if (parsed.metadata.technologies.length > 0) {
3793
+ lines.push("## Technologies");
3794
+ lines.push(parsed.metadata.technologies.map((t) => `- ${t}`).join("\n"));
3795
+ lines.push("");
3796
+ }
3797
+ lines.push("## Quick Start");
3798
+ lines.push("");
3799
+ lines.push("1. Create project directory:");
3800
+ lines.push("```bash");
3801
+ lines.push(`mkdir ${parsed.metadata.projectName}`);
3802
+ lines.push(`cd ${parsed.metadata.projectName}`);
3803
+ lines.push("```");
3804
+ lines.push("");
3805
+ lines.push("2. Create the following files:");
3806
+ for (const file of parsed.files.slice(0, 10)) {
3807
+ lines.push(` - \`${file.path}\`${file.description ? `: ${file.description}` : ""}`);
3808
+ }
3809
+ if (parsed.files.length > 10) {
3810
+ lines.push(` - ... and ${parsed.files.length - 10} more files`);
3811
+ }
3812
+ lines.push("");
3813
+ if (parsed.setupCommands.length > 0) {
3814
+ lines.push("3. Run setup commands:");
3815
+ lines.push("```bash");
3816
+ lines.push(parsed.setupCommands.join("\n"));
3817
+ lines.push("```");
3818
+ lines.push("");
3819
+ }
3820
+ if (parsed.metadata.estimatedSetupTime !== "unknown") {
3821
+ lines.push(`Estimated setup time: ${parsed.metadata.estimatedSetupTime}`);
3822
+ }
3823
+ return lines.join("\n");
3824
+ }
3825
+ };
3826
+ function createEmptyScaffoldResult(error) {
3827
+ return {
3828
+ files: [],
3829
+ instructions: `Error: ${error}`,
3830
+ setupCommands: [],
3831
+ metadata: {
3832
+ projectType: "auto",
3833
+ projectName: "unknown",
3834
+ fileCount: 0,
3835
+ totalSize: 0,
3836
+ estimatedSetupTime: "unknown",
3837
+ technologies: [],
3838
+ features: []
3839
+ }
3840
+ };
3841
+ }
3842
+
1811
3843
  // src/version.ts
1812
- var VERSION = "0.3.0".length > 0 ? "0.3.0" : "0.0.0";
3844
+ var VERSION = "0.5.0".length > 0 ? "0.5.0" : "0.0.0";
1813
3845
 
1814
3846
  // src/kimi-provider.ts
1815
3847
  var GLOBAL_BASE_URL = "https://api.moonshot.ai/v1";
@@ -1865,6 +3897,82 @@ function createKimi(options = {}) {
1865
3897
  provider.rerankingModel = (modelId) => {
1866
3898
  throw new NoSuchModelError({ modelId, modelType: "rerankingModel" });
1867
3899
  };
3900
+ provider.ensemble = async (prompt, generateFn, ensembleOptions = {}) => {
3901
+ const { model = "kimi-k2.5", baseTemperature = 0.7, ...config } = ensembleOptions;
3902
+ const sampler = new MultiSampler({
3903
+ modelId: model,
3904
+ baseTemperature
3905
+ });
3906
+ const wrappedGenerateFn = async (options2) => {
3907
+ const languageModel = createChatModel(model, {});
3908
+ const result = await generateFn(languageModel, prompt, { temperature: options2.temperature });
3909
+ return {
3910
+ text: result.text,
3911
+ reasoning: result.reasoning,
3912
+ toolCalls: result.toolCalls,
3913
+ toolResults: result.toolResults,
3914
+ usage: result.usage,
3915
+ finishReason: result.finishReason ?? "stop"
3916
+ };
3917
+ };
3918
+ return sampler.generate(wrappedGenerateFn, {
3919
+ n: config.n ?? 3,
3920
+ selectionStrategy: config.selectionStrategy ?? "best",
3921
+ temperatureVariance: config.temperatureVariance ?? 0.1,
3922
+ scoringHeuristic: config.scoringHeuristic ?? "confidence",
3923
+ customScorer: config.customScorer,
3924
+ timeoutMs: config.timeoutMs ?? 6e4,
3925
+ allowPartialFailure: config.allowPartialFailure ?? true,
3926
+ minSuccessfulSamples: config.minSuccessfulSamples ?? 1
3927
+ });
3928
+ };
3929
+ provider.multiAgent = async (prompt, generateFn, agentOptions = {}) => {
3930
+ const { modelSettings, ...config } = agentOptions;
3931
+ const runner = new WorkflowRunner(generateFn);
3932
+ return runner.run(prompt, {
3933
+ workflow: config.workflow ?? "planner-executor",
3934
+ modelA: config.modelA ?? "kimi-k2.5-thinking",
3935
+ modelB: config.modelB ?? "kimi-k2.5",
3936
+ iterations: config.iterations ?? 2,
3937
+ validateCode: config.validateCode ?? false,
3938
+ timeoutMs: config.timeoutMs ?? 12e4,
3939
+ customWorkflow: config.customWorkflow,
3940
+ verbose: config.verbose ?? false,
3941
+ systemPrompts: config.systemPrompts
3942
+ });
3943
+ };
3944
+ provider.validateCode = async (code, generateFn, validateOptions = {}) => {
3945
+ const { model = "kimi-k2.5", modelSettings, ...config } = validateOptions;
3946
+ const languageModel = createChatModel(model, modelSettings);
3947
+ const llmGenerateFn = generateFn ? async (prompt) => generateFn(languageModel, prompt) : async (_prompt) => {
3948
+ return { text: "" };
3949
+ };
3950
+ const validator = new CodeValidator({
3951
+ generateText: llmGenerateFn
3952
+ });
3953
+ return validator.validate(code, {
3954
+ enabled: true,
3955
+ maxAttempts: config.maxAttempts ?? 3,
3956
+ language: config.language ?? "auto",
3957
+ strictness: config.strictness ?? "strict",
3958
+ executionTimeoutMs: config.executionTimeoutMs ?? 3e4,
3959
+ includeTests: config.includeTests ?? true,
3960
+ returnPartialFix: config.returnPartialFix ?? true
3961
+ });
3962
+ };
3963
+ provider.scaffoldProject = async (description, generateFn, scaffoldOptions = {}) => {
3964
+ const scaffolder = new ProjectScaffolder({
3965
+ generateText: generateFn
3966
+ });
3967
+ return scaffolder.scaffold(description, scaffoldOptions);
3968
+ };
3969
+ provider.detectTools = (prompt) => {
3970
+ const result = detectToolsFromPrompt(prompt);
3971
+ return {
3972
+ webSearch: result.webSearch,
3973
+ codeInterpreter: result.codeInterpreter
3974
+ };
3975
+ };
1868
3976
  return provider;
1869
3977
  }
1870
3978
  var kimi = createKimi();
@@ -2710,6 +4818,8 @@ function createKimiCode(options = {}) {
2710
4818
  }
2711
4819
  var kimiCode = createKimiCode();
2712
4820
  export {
4821
+ CodeValidator,
4822
+ DEFAULT_SYSTEM_PROMPTS,
2713
4823
  KIMI_CODE_BASE_URL,
2714
4824
  KIMI_CODE_DEFAULT_MODEL,
2715
4825
  KIMI_CODE_INTERPRETER_TOOL_NAME,
@@ -2718,22 +4828,43 @@ export {
2718
4828
  KimiAuthenticationError,
2719
4829
  KimiChatLanguageModel,
2720
4830
  KimiCodeLanguageModel,
4831
+ KimiCodeValidationError,
2721
4832
  KimiContentFilterError,
2722
4833
  KimiContextLengthError,
4834
+ KimiEnsembleTimeoutError,
4835
+ KimiEnsembleValidationError,
2723
4836
  KimiError,
2724
4837
  KimiFileClient,
2725
4838
  KimiModelNotFoundError,
4839
+ KimiMultiAgentError,
2726
4840
  KimiRateLimitError,
4841
+ KimiScaffoldError,
2727
4842
  KimiValidationError,
4843
+ MultiSampler,
4844
+ ProjectScaffolder,
2728
4845
  SUPPORTED_FILE_EXTENSIONS,
2729
4846
  SUPPORTED_MIME_TYPES,
4847
+ WorkflowRunner,
4848
+ containsCode,
2730
4849
  createCodeInterpreterTool,
4850
+ createEmptyMultiAgentResult,
4851
+ createEmptyScaffoldResult,
4852
+ createFailedValidationResult,
2731
4853
  createKimi,
2732
4854
  createKimiCode,
2733
4855
  createKimiWebSearchTool,
4856
+ createPassedValidationResult,
4857
+ createSingletonEnsembleResult,
2734
4858
  createWebSearchTool,
4859
+ detectLanguage,
4860
+ detectToolsFromPrompt,
4861
+ extractCodeBlocks,
4862
+ extractPrimaryCode,
4863
+ generateToolGuidanceMessage,
4864
+ getFileExtension,
2735
4865
  getMediaTypeFromExtension,
2736
4866
  getPurposeFromMediaType,
4867
+ hasToolOptOut,
2737
4868
  inferKimiCodeCapabilities,
2738
4869
  inferModelCapabilities,
2739
4870
  isDocumentMediaType,
@@ -2746,6 +4877,7 @@ export {
2746
4877
  kimiCodeProviderOptionsSchema,
2747
4878
  kimiProviderOptionsSchema,
2748
4879
  kimiTools,
2749
- processAttachments
4880
+ processAttachments,
4881
+ shouldAutoEnableTools
2750
4882
  };
2751
4883
  //# sourceMappingURL=index.mjs.map