kimi-vercel-ai-sdk-provider 0.4.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.
@@ -0,0 +1,319 @@
1
+ /**
2
+ * Language detection and code extraction utilities.
3
+ * @module
4
+ */
5
+
6
+ import type { CodeBlock, CodeExtractionResult, LanguageDetectionResult, SupportedLanguage } from './types';
7
+
8
+ // ============================================================================
9
+ // Language Detection
10
+ // ============================================================================
11
+
12
+ /**
13
+ * Language detection patterns with confidence weights.
14
+ */
15
+ const LANGUAGE_PATTERNS: Array<{
16
+ language: SupportedLanguage;
17
+ patterns: Array<{ pattern: RegExp; weight: number; name: string }>;
18
+ }> = [
19
+ {
20
+ language: 'typescript',
21
+ patterns: [
22
+ { pattern: /:\s*(string|number|boolean|void|any|unknown|never)\b/, weight: 0.9, name: 'type_annotation' },
23
+ { pattern: /interface\s+\w+\s*{/, weight: 0.95, name: 'interface' },
24
+ { pattern: /type\s+\w+\s*=/, weight: 0.9, name: 'type_alias' },
25
+ { pattern: /<\w+>/, weight: 0.5, name: 'generics' },
26
+ { pattern: /import\s+.*\s+from\s+['"]/, weight: 0.7, name: 'import_from' },
27
+ { pattern: /export\s+(interface|type|enum)\b/, weight: 0.95, name: 'export_type' },
28
+ { pattern: /as\s+(string|number|boolean|any)\b/, weight: 0.85, name: 'type_assertion' }
29
+ ]
30
+ },
31
+ {
32
+ language: 'javascript',
33
+ patterns: [
34
+ { pattern: /\bfunction\s+\w+\s*\(/, weight: 0.6, name: 'function_decl' },
35
+ { pattern: /\bconst\s+\w+\s*=/, weight: 0.5, name: 'const' },
36
+ { pattern: /\blet\s+\w+\s*=/, weight: 0.5, name: 'let' },
37
+ { pattern: /=>\s*{/, weight: 0.6, name: 'arrow_function' },
38
+ { pattern: /require\s*\(['"]/, weight: 0.7, name: 'require' },
39
+ { pattern: /module\.exports\s*=/, weight: 0.85, name: 'module_exports' },
40
+ { pattern: /console\.(log|error|warn)\(/, weight: 0.5, name: 'console' }
41
+ ]
42
+ },
43
+ {
44
+ language: 'python',
45
+ patterns: [
46
+ { pattern: /\bdef\s+\w+\s*\([^)]*\)\s*:/, weight: 0.9, name: 'def' },
47
+ { pattern: /\bclass\s+\w+.*:/, weight: 0.85, name: 'class' },
48
+ { pattern: /\bimport\s+\w+/, weight: 0.6, name: 'import' },
49
+ { pattern: /\bfrom\s+\w+\s+import\b/, weight: 0.85, name: 'from_import' },
50
+ { pattern: /\bif\s+__name__\s*==\s*['"]__main__['"]\s*:/, weight: 0.95, name: 'main_guard' },
51
+ { pattern: /\bprint\s*\(/, weight: 0.5, name: 'print' },
52
+ { pattern: /\bself\.\w+/, weight: 0.85, name: 'self' },
53
+ { pattern: /#.*$/, weight: 0.3, name: 'comment' }
54
+ ]
55
+ },
56
+ {
57
+ language: 'java',
58
+ patterns: [
59
+ { pattern: /public\s+class\s+\w+/, weight: 0.95, name: 'public_class' },
60
+ { pattern: /public\s+static\s+void\s+main/, weight: 0.98, name: 'main_method' },
61
+ { pattern: /System\.out\.println/, weight: 0.9, name: 'sysout' },
62
+ { pattern: /\bpackage\s+[\w.]+;/, weight: 0.95, name: 'package' },
63
+ { pattern: /\bimport\s+[\w.]+;/, weight: 0.8, name: 'import' },
64
+ { pattern: /@Override\b/, weight: 0.9, name: 'override' },
65
+ { pattern: /\bprivate\s+\w+\s+\w+;/, weight: 0.7, name: 'private_field' }
66
+ ]
67
+ },
68
+ {
69
+ language: 'go',
70
+ patterns: [
71
+ { pattern: /\bpackage\s+main\b/, weight: 0.95, name: 'package_main' },
72
+ { pattern: /\bfunc\s+\w+\s*\(/, weight: 0.85, name: 'func' },
73
+ { pattern: /\bfmt\.Print/, weight: 0.9, name: 'fmt_print' },
74
+ { pattern: /\bimport\s+\(/, weight: 0.85, name: 'import_block' },
75
+ { pattern: /:=/, weight: 0.7, name: 'short_var_decl' },
76
+ { pattern: /\bgo\s+\w+\(/, weight: 0.9, name: 'goroutine' },
77
+ { pattern: /\bchan\s+\w+/, weight: 0.9, name: 'channel' }
78
+ ]
79
+ },
80
+ {
81
+ language: 'rust',
82
+ patterns: [
83
+ { pattern: /\bfn\s+\w+\s*\(/, weight: 0.9, name: 'fn' },
84
+ { pattern: /\blet\s+mut\s+\w+/, weight: 0.95, name: 'let_mut' },
85
+ { pattern: /\bimpl\s+\w+\s+for\s+\w+/, weight: 0.95, name: 'impl_for' },
86
+ { pattern: /\buse\s+[\w:]+;/, weight: 0.85, name: 'use' },
87
+ { pattern: /\bpub\s+(fn|struct|enum|mod)\b/, weight: 0.9, name: 'pub' },
88
+ { pattern: /->.*{/, weight: 0.7, name: 'return_type' },
89
+ { pattern: /\bprintln!\(/, weight: 0.95, name: 'println_macro' }
90
+ ]
91
+ },
92
+ {
93
+ language: 'ruby',
94
+ patterns: [
95
+ { pattern: /\bdef\s+\w+/, weight: 0.8, name: 'def' },
96
+ { pattern: /\bclass\s+\w+/, weight: 0.7, name: 'class' },
97
+ { pattern: /\bend\s*$/, weight: 0.4, name: 'end' },
98
+ { pattern: /\brequire\s+['"]/, weight: 0.85, name: 'require' },
99
+ { pattern: /\bputs\s+/, weight: 0.8, name: 'puts' },
100
+ { pattern: /@\w+/, weight: 0.5, name: 'instance_var' },
101
+ { pattern: /\.each\s+do\s*\|/, weight: 0.85, name: 'each_block' }
102
+ ]
103
+ },
104
+ {
105
+ language: 'php',
106
+ patterns: [
107
+ { pattern: /<\?php/, weight: 0.98, name: 'php_tag' },
108
+ { pattern: /\$\w+\s*=/, weight: 0.75, name: 'php_var' },
109
+ { pattern: /\bfunction\s+\w+\s*\(/, weight: 0.5, name: 'function' },
110
+ { pattern: /\becho\s+/, weight: 0.7, name: 'echo' },
111
+ { pattern: /->(\w+)\(/, weight: 0.6, name: 'method_call' },
112
+ { pattern: /\buse\s+[\w\\]+;/, weight: 0.8, name: 'use' }
113
+ ]
114
+ },
115
+ {
116
+ language: 'cpp',
117
+ patterns: [
118
+ { pattern: /#include\s*<[\w.]+>/, weight: 0.9, name: 'include_angle' },
119
+ { pattern: /#include\s*"[\w.]+"/, weight: 0.85, name: 'include_quote' },
120
+ { pattern: /\bstd::\w+/, weight: 0.9, name: 'std_namespace' },
121
+ { pattern: /\bint\s+main\s*\(/, weight: 0.95, name: 'main' },
122
+ { pattern: /\bcout\s*<</, weight: 0.95, name: 'cout' },
123
+ { pattern: /\bnamespace\s+\w+/, weight: 0.85, name: 'namespace' },
124
+ { pattern: /\btemplate\s*</, weight: 0.9, name: 'template' }
125
+ ]
126
+ }
127
+ ];
128
+
129
+ /**
130
+ * Detect the programming language of a code snippet.
131
+ *
132
+ * @param code - The code to analyze
133
+ * @returns Detection result with language, confidence, and indicators
134
+ */
135
+ export function detectLanguage(code: string): LanguageDetectionResult {
136
+ const scores: Map<SupportedLanguage, { score: number; indicators: string[] }> = new Map();
137
+
138
+ // Initialize scores
139
+ for (const { language } of LANGUAGE_PATTERNS) {
140
+ scores.set(language, { score: 0, indicators: [] });
141
+ }
142
+
143
+ // Check each language's patterns
144
+ for (const { language, patterns } of LANGUAGE_PATTERNS) {
145
+ const langScore = scores.get(language)!;
146
+
147
+ for (const { pattern, weight, name } of patterns) {
148
+ if (pattern.test(code)) {
149
+ langScore.score += weight;
150
+ langScore.indicators.push(name);
151
+ }
152
+ }
153
+ }
154
+
155
+ // Find the best match
156
+ let bestLanguage: SupportedLanguage = 'javascript'; // default
157
+ let bestScore = 0;
158
+ let bestIndicators: string[] = [];
159
+
160
+ for (const [language, { score, indicators }] of scores) {
161
+ if (score > bestScore) {
162
+ bestScore = score;
163
+ bestLanguage = language;
164
+ bestIndicators = indicators;
165
+ }
166
+ }
167
+
168
+ // Handle TypeScript vs JavaScript ambiguity
169
+ const tsScore = scores.get('typescript')!.score;
170
+ const jsScore = scores.get('javascript')!.score;
171
+
172
+ // If both have similar scores but TS has type-specific indicators, prefer TS
173
+ if (
174
+ tsScore > 0 &&
175
+ jsScore > 0 &&
176
+ Math.abs(tsScore - jsScore) < 0.5 &&
177
+ scores
178
+ .get('typescript')!
179
+ .indicators.some((i) => ['type_annotation', 'interface', 'type_alias', 'export_type'].includes(i))
180
+ ) {
181
+ bestLanguage = 'typescript';
182
+ bestScore = tsScore;
183
+ bestIndicators = scores.get('typescript')!.indicators;
184
+ }
185
+
186
+ // Calculate confidence (normalize score)
187
+ const maxPossibleScore =
188
+ LANGUAGE_PATTERNS.find((l) => l.language === bestLanguage)?.patterns.reduce((sum, p) => sum + p.weight, 0) ?? 1;
189
+
190
+ const confidence = Math.min(1, bestScore / Math.max(1, maxPossibleScore * 0.5));
191
+
192
+ return {
193
+ language: bestLanguage,
194
+ confidence,
195
+ indicators: bestIndicators
196
+ };
197
+ }
198
+
199
+ // ============================================================================
200
+ // Code Extraction
201
+ // ============================================================================
202
+
203
+ /**
204
+ * Extract code blocks from text (including markdown code fences).
205
+ *
206
+ * @param text - Text that may contain code blocks
207
+ * @returns Extraction result with code blocks
208
+ */
209
+ export function extractCodeBlocks(text: string): CodeExtractionResult {
210
+ const blocks: CodeBlock[] = [];
211
+
212
+ // Match markdown code fences
213
+ const fenceRegex = /```(\w*)\n([\s\S]*?)```/g;
214
+ let match: RegExpExecArray | null = fenceRegex.exec(text);
215
+
216
+ while (match !== null) {
217
+ blocks.push({
218
+ code: match[2].trim(),
219
+ language: match[1] || undefined,
220
+ startIndex: match.index,
221
+ endIndex: match.index + match[0].length
222
+ });
223
+ match = fenceRegex.exec(text);
224
+ }
225
+
226
+ // If no fenced blocks, check for inline code or treat entire text as code
227
+ if (blocks.length === 0) {
228
+ // Check if text looks like code (has significant code patterns)
229
+ const { confidence } = detectLanguage(text);
230
+ if (confidence > 0.3) {
231
+ blocks.push({
232
+ code: text.trim(),
233
+ startIndex: 0,
234
+ endIndex: text.length
235
+ });
236
+ }
237
+ }
238
+
239
+ return {
240
+ blocks,
241
+ hasCode: blocks.length > 0
242
+ };
243
+ }
244
+
245
+ /**
246
+ * Extract the primary code block from text.
247
+ * Returns the largest/most significant code block.
248
+ *
249
+ * @param text - Text that may contain code blocks
250
+ * @returns The primary code or undefined if no code found
251
+ */
252
+ export function extractPrimaryCode(text: string): string | undefined {
253
+ const { blocks, hasCode } = extractCodeBlocks(text);
254
+
255
+ if (!hasCode) {
256
+ return undefined;
257
+ }
258
+
259
+ // Return the largest block
260
+ return blocks.reduce((largest, block) => (block.code.length > largest.code.length ? block : largest)).code;
261
+ }
262
+
263
+ /**
264
+ * Check if text contains code.
265
+ *
266
+ * @param text - Text to check
267
+ * @returns True if text contains code
268
+ */
269
+ export function containsCode(text: string): boolean {
270
+ // Check for code fences
271
+ if (/```[\s\S]*```/.test(text)) {
272
+ return true;
273
+ }
274
+
275
+ // Check for common code patterns directly (quick check before full language detection)
276
+ const quickCodePatterns = [
277
+ /\bfunction\s+\w+\s*\([^)]*\)\s*\{/, // function declarations
278
+ /\bconst\s+\w+\s*=\s*\([^)]*\)\s*=>/, // arrow functions
279
+ /\bclass\s+\w+\s*(\s+extends\s+\w+)?\s*\{/, // class declarations
280
+ /\bdef\s+\w+\s*\([^)]*\)\s*:/, // Python functions
281
+ /\bimport\s+.*\s+from\s+['"]/, // ES imports
282
+ /\b(if|for|while)\s*\([^)]*\)\s*\{/, // Control structures with braces
283
+ /=>\s*\{[\s\S]*\}/, // Arrow function bodies
284
+ /\breturn\s+[\w"'`{[<]/ // Return statements
285
+ ];
286
+
287
+ for (const pattern of quickCodePatterns) {
288
+ if (pattern.test(text)) {
289
+ return true;
290
+ }
291
+ }
292
+
293
+ // Check for code-like patterns via language detection
294
+ const { confidence } = detectLanguage(text);
295
+ return confidence > 0.4;
296
+ }
297
+
298
+ /**
299
+ * Get file extension for a language.
300
+ *
301
+ * @param language - The programming language
302
+ * @returns File extension (without dot)
303
+ */
304
+ export function getFileExtension(language: SupportedLanguage): string {
305
+ const extensions: Record<SupportedLanguage, string> = {
306
+ javascript: 'js',
307
+ typescript: 'ts',
308
+ python: 'py',
309
+ java: 'java',
310
+ cpp: 'cpp',
311
+ go: 'go',
312
+ rust: 'rs',
313
+ ruby: 'rb',
314
+ php: 'php',
315
+ auto: 'txt'
316
+ };
317
+
318
+ return extensions[language] || 'txt';
319
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Code validation module exports.
3
+ * @module
4
+ */
5
+
6
+ export type {
7
+ CodeBlock,
8
+ CodeExtractionResult,
9
+ CodeValidationConfig,
10
+ FixAttempt,
11
+ LanguageDetectionResult,
12
+ SupportedLanguage,
13
+ ValidationError,
14
+ ValidationErrorType,
15
+ ValidationResult,
16
+ ValidationSeverity,
17
+ ValidationStrictness
18
+ } from './types';
19
+ export type { CodeValidatorOptions, GenerateTextFunction } from './validator';
20
+ export {
21
+ containsCode,
22
+ detectLanguage,
23
+ extractCodeBlocks,
24
+ extractPrimaryCode,
25
+ getFileExtension
26
+ } from './detector';
27
+ export {
28
+ CodeValidator,
29
+ createFailedValidationResult,
30
+ createPassedValidationResult
31
+ } from './validator';
@@ -0,0 +1,291 @@
1
+ /**
2
+ * Types for code validation functionality.
3
+ * @module
4
+ */
5
+
6
+ // ============================================================================
7
+ // Configuration Types
8
+ // ============================================================================
9
+
10
+ /**
11
+ * Supported programming languages for code validation.
12
+ */
13
+ export type SupportedLanguage =
14
+ | 'javascript'
15
+ | 'typescript'
16
+ | 'python'
17
+ | 'java'
18
+ | 'cpp'
19
+ | 'go'
20
+ | 'rust'
21
+ | 'ruby'
22
+ | 'php'
23
+ | 'auto';
24
+
25
+ /**
26
+ * Validation strictness levels.
27
+ */
28
+ export type ValidationStrictness = 'lenient' | 'strict' | 'maximum';
29
+
30
+ /**
31
+ * Configuration for code validation.
32
+ */
33
+ export interface CodeValidationConfig {
34
+ /**
35
+ * Enable automatic code validation.
36
+ * @default false
37
+ */
38
+ enabled: boolean;
39
+
40
+ /**
41
+ * Maximum number of attempts to fix errors.
42
+ * @default 3
43
+ */
44
+ maxAttempts?: number;
45
+
46
+ /**
47
+ * Language to validate (auto-detected if not specified).
48
+ * @default 'auto'
49
+ */
50
+ language?: SupportedLanguage;
51
+
52
+ /**
53
+ * Timeout for each code execution attempt (ms).
54
+ * @default 30000
55
+ */
56
+ executionTimeoutMs?: number;
57
+
58
+ /**
59
+ * Whether to include test cases in validation.
60
+ * If true, the provider will look for test patterns in the prompt.
61
+ * @default true
62
+ */
63
+ includeTests?: boolean;
64
+
65
+ /**
66
+ * Validation strictness.
67
+ * - 'lenient': Check for runtime errors only
68
+ * - 'strict': Check syntax + runtime + style
69
+ * - 'maximum': Also verify output correctness
70
+ * @default 'strict'
71
+ */
72
+ strictness?: ValidationStrictness;
73
+
74
+ /**
75
+ * Custom validation function for specialized needs.
76
+ */
77
+ customValidator?: (code: string, language: string) => Promise<ValidationResult>;
78
+
79
+ /**
80
+ * Whether to return the fixed code even if validation fails.
81
+ * @default true
82
+ */
83
+ returnPartialFix?: boolean;
84
+ }
85
+
86
+ // ============================================================================
87
+ // Error Types
88
+ // ============================================================================
89
+
90
+ /**
91
+ * Types of validation errors.
92
+ */
93
+ export type ValidationErrorType = 'syntax' | 'runtime' | 'timeout' | 'test' | 'style' | 'logic';
94
+
95
+ /**
96
+ * Severity of validation errors.
97
+ */
98
+ export type ValidationSeverity = 'error' | 'warning' | 'info';
99
+
100
+ /**
101
+ * A single validation error.
102
+ */
103
+ export interface ValidationError {
104
+ /**
105
+ * Type of the error.
106
+ */
107
+ type: ValidationErrorType;
108
+
109
+ /**
110
+ * Error message.
111
+ */
112
+ message: string;
113
+
114
+ /**
115
+ * Line number where the error occurred (1-indexed).
116
+ */
117
+ line?: number;
118
+
119
+ /**
120
+ * Column number where the error occurred (1-indexed).
121
+ */
122
+ column?: number;
123
+
124
+ /**
125
+ * Severity of the error.
126
+ */
127
+ severity: ValidationSeverity;
128
+
129
+ /**
130
+ * The problematic code snippet.
131
+ */
132
+ snippet?: string;
133
+
134
+ /**
135
+ * Suggested fix (if available).
136
+ */
137
+ suggestion?: string;
138
+ }
139
+
140
+ // ============================================================================
141
+ // Result Types
142
+ // ============================================================================
143
+
144
+ /**
145
+ * Result of validating and potentially fixing code.
146
+ */
147
+ export interface ValidationResult {
148
+ /**
149
+ * Whether the final code is valid.
150
+ */
151
+ valid: boolean;
152
+
153
+ /**
154
+ * All errors encountered during validation.
155
+ */
156
+ errors: ValidationError[];
157
+
158
+ /**
159
+ * Warnings that don't prevent execution.
160
+ */
161
+ warnings: ValidationError[];
162
+
163
+ /**
164
+ * Output from successful execution (if any).
165
+ */
166
+ output?: string;
167
+
168
+ /**
169
+ * Time taken for execution (ms).
170
+ */
171
+ executionTimeMs?: number;
172
+
173
+ /**
174
+ * Number of validation/fix attempts made.
175
+ */
176
+ attempts: number;
177
+
178
+ /**
179
+ * The final code after any fixes.
180
+ */
181
+ finalCode: string;
182
+
183
+ /**
184
+ * The original code before any fixes.
185
+ */
186
+ originalCode: string;
187
+
188
+ /**
189
+ * Language that was detected/used.
190
+ */
191
+ language: string;
192
+
193
+ /**
194
+ * History of code changes during fix attempts.
195
+ */
196
+ fixHistory?: FixAttempt[];
197
+ }
198
+
199
+ /**
200
+ * A single fix attempt.
201
+ */
202
+ export interface FixAttempt {
203
+ /**
204
+ * Attempt number (1-indexed).
205
+ */
206
+ attempt: number;
207
+
208
+ /**
209
+ * The code before this fix.
210
+ */
211
+ codeBefore: string;
212
+
213
+ /**
214
+ * The code after this fix.
215
+ */
216
+ codeAfter: string;
217
+
218
+ /**
219
+ * Errors that were addressed.
220
+ */
221
+ errorsAddressed: ValidationError[];
222
+
223
+ /**
224
+ * Whether this fix resolved all errors.
225
+ */
226
+ success: boolean;
227
+ }
228
+
229
+ // ============================================================================
230
+ // Detection Types
231
+ // ============================================================================
232
+
233
+ /**
234
+ * Result of language detection.
235
+ */
236
+ export interface LanguageDetectionResult {
237
+ /**
238
+ * Detected language.
239
+ */
240
+ language: SupportedLanguage;
241
+
242
+ /**
243
+ * Confidence score (0-1).
244
+ */
245
+ confidence: number;
246
+
247
+ /**
248
+ * Indicators that led to this detection.
249
+ */
250
+ indicators: string[];
251
+ }
252
+
253
+ /**
254
+ * Result of code extraction from text.
255
+ */
256
+ export interface CodeExtractionResult {
257
+ /**
258
+ * Extracted code blocks.
259
+ */
260
+ blocks: CodeBlock[];
261
+
262
+ /**
263
+ * Whether any code was found.
264
+ */
265
+ hasCode: boolean;
266
+ }
267
+
268
+ /**
269
+ * A code block extracted from text.
270
+ */
271
+ export interface CodeBlock {
272
+ /**
273
+ * The code content.
274
+ */
275
+ code: string;
276
+
277
+ /**
278
+ * Language annotation (if provided).
279
+ */
280
+ language?: string;
281
+
282
+ /**
283
+ * Start position in the original text.
284
+ */
285
+ startIndex: number;
286
+
287
+ /**
288
+ * End position in the original text.
289
+ */
290
+ endIndex: number;
291
+ }