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.
- package/README.md +567 -17
- package/dist/index.d.mts +1750 -3
- package/dist/index.d.ts +1750 -3
- package/dist/index.js +2317 -161
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2292 -160
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/auto-detect.test.ts +140 -0
- package/src/__tests__/code-validation.test.ts +267 -0
- package/src/__tests__/ensemble.test.ts +242 -0
- package/src/__tests__/file-cache.test.ts +310 -0
- package/src/__tests__/model-config.test.ts +120 -0
- package/src/__tests__/multi-agent.test.ts +201 -0
- package/src/__tests__/project-tools.test.ts +181 -0
- package/src/__tests__/reasoning-utils.test.ts +164 -0
- package/src/__tests__/tools.test.ts +76 -8
- package/src/chat/kimi-chat-language-model.ts +21 -2
- package/src/chat/kimi-chat-settings.ts +15 -1
- package/src/code-validation/detector.ts +319 -0
- package/src/code-validation/index.ts +31 -0
- package/src/code-validation/types.ts +291 -0
- package/src/code-validation/validator.ts +547 -0
- package/src/core/errors.ts +91 -0
- package/src/core/index.ts +15 -3
- package/src/core/types.ts +57 -2
- package/src/core/utils.ts +138 -0
- package/src/ensemble/index.ts +17 -0
- package/src/ensemble/multi-sampler.ts +433 -0
- package/src/ensemble/types.ts +279 -0
- package/src/files/attachment-processor.ts +51 -4
- package/src/files/file-cache.ts +260 -0
- package/src/files/index.ts +16 -1
- package/src/index.ts +102 -3
- package/src/kimi-provider.ts +354 -1
- package/src/multi-agent/index.ts +21 -0
- package/src/multi-agent/types.ts +312 -0
- package/src/multi-agent/workflows.ts +539 -0
- package/src/project-tools/index.ts +16 -0
- package/src/project-tools/scaffolder.ts +494 -0
- package/src/project-tools/types.ts +244 -0
- package/src/tools/auto-detect.ts +276 -0
- package/src/tools/index.ts +6 -2
- 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:
|
|
360
|
-
|
|
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
|
-
|
|
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
|
|
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:
|
|
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/
|
|
1327
|
-
var
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
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
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
"
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
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
|
|
1433
|
-
|
|
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
|
|
1436
|
-
|
|
1437
|
-
|
|
1789
|
+
function extractPrimaryCode(text) {
|
|
1790
|
+
const { blocks, hasCode } = extractCodeBlocks(text);
|
|
1791
|
+
if (!hasCode) {
|
|
1792
|
+
return void 0;
|
|
1438
1793
|
}
|
|
1439
|
-
|
|
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
|
-
|
|
1443
|
-
|
|
1444
|
-
function
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
"
|
|
1452
|
-
|
|
1453
|
-
|
|
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
|
-
|
|
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
|
|
1458
|
-
|
|
1459
|
-
|
|
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
|
-
|
|
1462
|
-
|
|
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
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
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
|
|
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.
|
|
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
|