@opensumi/ide-ai-native 3.0.3 → 3.0.4-next-1716367246.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/lib/browser/inline-completions/completeProvider.d.ts +5 -3
  2. package/lib/browser/inline-completions/completeProvider.d.ts.map +1 -1
  3. package/lib/browser/inline-completions/completeProvider.js +16 -30
  4. package/lib/browser/inline-completions/completeProvider.js.map +1 -1
  5. package/lib/browser/inline-completions/constants.d.ts +2 -6
  6. package/lib/browser/inline-completions/constants.d.ts.map +1 -1
  7. package/lib/browser/inline-completions/constants.js +81 -4
  8. package/lib/browser/inline-completions/constants.js.map +1 -1
  9. package/lib/browser/inline-completions/prompt/const.d.ts +9 -0
  10. package/lib/browser/inline-completions/prompt/const.d.ts.map +1 -0
  11. package/lib/browser/inline-completions/prompt/const.js +284 -0
  12. package/lib/browser/inline-completions/prompt/const.js.map +1 -0
  13. package/lib/browser/inline-completions/prompt/importedFiles.d.ts +6 -0
  14. package/lib/browser/inline-completions/prompt/importedFiles.d.ts.map +1 -0
  15. package/lib/browser/inline-completions/prompt/importedFiles.js +77 -0
  16. package/lib/browser/inline-completions/prompt/importedFiles.js.map +1 -0
  17. package/lib/browser/inline-completions/prompt/jaccardMatcher.d.ts +31 -0
  18. package/lib/browser/inline-completions/prompt/jaccardMatcher.d.ts.map +1 -0
  19. package/lib/browser/inline-completions/prompt/jaccardMatcher.js +75 -0
  20. package/lib/browser/inline-completions/prompt/jaccardMatcher.js.map +1 -0
  21. package/lib/browser/inline-completions/prompt/languages.d.ts +4 -0
  22. package/lib/browser/inline-completions/prompt/languages.d.ts.map +1 -0
  23. package/lib/browser/inline-completions/prompt/languages.js +67 -0
  24. package/lib/browser/inline-completions/prompt/languages.js.map +1 -0
  25. package/lib/browser/inline-completions/prompt/matcher.d.ts +42 -0
  26. package/lib/browser/inline-completions/prompt/matcher.d.ts.map +1 -0
  27. package/lib/browser/inline-completions/prompt/matcher.js +279 -0
  28. package/lib/browser/inline-completions/prompt/matcher.js.map +1 -0
  29. package/lib/browser/inline-completions/prompt/prompt.d.ts +24 -0
  30. package/lib/browser/inline-completions/prompt/prompt.d.ts.map +1 -0
  31. package/lib/browser/inline-completions/prompt/prompt.js +242 -0
  32. package/lib/browser/inline-completions/prompt/prompt.js.map +1 -0
  33. package/lib/browser/inline-completions/prompt/similarSnippets.d.ts +9 -0
  34. package/lib/browser/inline-completions/prompt/similarSnippets.d.ts.map +1 -0
  35. package/lib/browser/inline-completions/prompt/similarSnippets.js +110 -0
  36. package/lib/browser/inline-completions/prompt/similarSnippets.js.map +1 -0
  37. package/lib/browser/inline-completions/prompt/tokenizer.d.ts +4 -0
  38. package/lib/browser/inline-completions/prompt/tokenizer.d.ts.map +1 -0
  39. package/lib/browser/inline-completions/prompt/tokenizer.js +18 -0
  40. package/lib/browser/inline-completions/prompt/tokenizer.js.map +1 -0
  41. package/lib/browser/inline-completions/provider.d.ts +5 -12
  42. package/lib/browser/inline-completions/provider.d.ts.map +1 -1
  43. package/lib/browser/inline-completions/provider.js +79 -44
  44. package/lib/browser/inline-completions/provider.js.map +1 -1
  45. package/lib/browser/inline-completions/types.d.ts +154 -0
  46. package/lib/browser/inline-completions/types.d.ts.map +1 -0
  47. package/lib/browser/inline-completions/types.js +59 -0
  48. package/lib/browser/inline-completions/types.js.map +1 -0
  49. package/lib/browser/languages/parser.d.ts +6 -0
  50. package/lib/browser/languages/parser.d.ts.map +1 -1
  51. package/lib/browser/languages/parser.js +140 -1
  52. package/lib/browser/languages/parser.js.map +1 -1
  53. package/lib/browser/languages/tree-sitter/language-facts/types.d.ts +1 -1
  54. package/lib/browser/languages/tree-sitter/wasm-manager.d.ts +2 -2
  55. package/lib/browser/languages/tree-sitter/wasm-manager.d.ts.map +1 -1
  56. package/lib/browser/languages/tree-sitter/wasm-manager.js +2 -2
  57. package/lib/browser/languages/tree-sitter/wasm-manager.js.map +1 -1
  58. package/lib/common/utils.d.ts +5 -0
  59. package/lib/common/utils.d.ts.map +1 -0
  60. package/lib/common/utils.js +26 -0
  61. package/lib/common/utils.js.map +1 -0
  62. package/package.json +20 -19
  63. package/src/browser/inline-completions/completeProvider.ts +26 -35
  64. package/src/browser/inline-completions/constants.ts +87 -7
  65. package/src/browser/inline-completions/prompt/const.ts +286 -0
  66. package/src/browser/inline-completions/prompt/importedFiles.ts +92 -0
  67. package/src/browser/inline-completions/prompt/jaccardMatcher.ts +98 -0
  68. package/src/browser/inline-completions/prompt/languages.ts +65 -0
  69. package/src/browser/inline-completions/prompt/matcher.ts +328 -0
  70. package/src/browser/inline-completions/prompt/prompt.ts +297 -0
  71. package/src/browser/inline-completions/prompt/similarSnippets.ts +130 -0
  72. package/src/browser/inline-completions/prompt/tokenizer.ts +16 -0
  73. package/src/browser/inline-completions/provider.ts +107 -42
  74. package/src/browser/inline-completions/types.ts +169 -0
  75. package/src/browser/languages/parser.ts +147 -0
  76. package/src/browser/languages/tree-sitter/wasm-manager.ts +3 -3
  77. package/src/common/utils.ts +23 -0
@@ -0,0 +1,98 @@
1
+ import { ResourceDocument, TokenizerName } from '../types';
2
+
3
+ import { WindowedMatcher, computeScore } from './matcher';
4
+ import { getTokenizer } from './tokenizer';
5
+
6
+ export interface CursorContextOptions {
7
+ maxLineCount?: number;
8
+ maxTokenLength?: number;
9
+ tokenizerName?: TokenizerName;
10
+ extensionPath?: string;
11
+ }
12
+
13
+ export const getCursorContext = (
14
+ resource: ResourceDocument,
15
+ option: CursorContextOptions = {},
16
+ ): {
17
+ context: string;
18
+ lineCount: number;
19
+ tokenLength: number;
20
+ tokenizerName: TokenizerName;
21
+ } => {
22
+ const baseOptions = {
23
+ tokenizerName: TokenizerName.cl100k_base,
24
+ ...option,
25
+ };
26
+ const tokenizer = getTokenizer(baseOptions.tokenizerName);
27
+ if (baseOptions.maxLineCount && baseOptions.maxLineCount < 0) {
28
+ throw new Error('maxLineCount must be non-negative if defined');
29
+ }
30
+ if (baseOptions.maxTokenLength && baseOptions.maxTokenLength < 0) {
31
+ throw new Error('maxTokenLength must be non-negative if defined');
32
+ }
33
+ if (baseOptions.maxLineCount === 0 || baseOptions.maxTokenLength === 0) {
34
+ return {
35
+ context: '',
36
+ lineCount: 0,
37
+ tokenLength: 0,
38
+ tokenizerName: baseOptions.tokenizerName,
39
+ };
40
+ }
41
+ let context = resource.source.slice(0, resource.offset);
42
+ if (baseOptions.maxLineCount) {
43
+ context = context.split('\n').slice(-baseOptions.maxLineCount).join('\n');
44
+ }
45
+ return {
46
+ context,
47
+ lineCount: context.split('\n').length,
48
+ tokenLength: tokenizer.encode(context).length,
49
+ tokenizerName: baseOptions.tokenizerName,
50
+ };
51
+ };
52
+
53
+ const getBasicWindowDelineations = (windowSize: number, lineArrays: string[]): [number, number][] => {
54
+ const ranges: [number, number][] = [];
55
+ const arrayLength = lineArrays.length;
56
+ if (arrayLength === 0) {
57
+ return [];
58
+ }
59
+ if (arrayLength < windowSize) {
60
+ return [[0, arrayLength]];
61
+ }
62
+ for (let i = 0; i < arrayLength - windowSize + 1; i++) {
63
+ ranges.push([i, i + windowSize]);
64
+ }
65
+ return ranges;
66
+ };
67
+
68
+ // 固定窗口大小的 Jaccard 匹配器
69
+ export class FixedWindowSizeJaccardMatcher extends WindowedMatcher {
70
+ static factory(windowSize: number) {
71
+ return {
72
+ to: (doc: ResourceDocument) => new FixedWindowSizeJaccardMatcher(doc, windowSize),
73
+ };
74
+ }
75
+
76
+ private readonly windowLength: number;
77
+
78
+ constructor(doc: ResourceDocument, windowSize: number) {
79
+ super(doc);
80
+ this.windowLength = windowSize;
81
+ }
82
+
83
+ id() {
84
+ return `fixed:${this.windowLength}`;
85
+ }
86
+
87
+ getWindowsDelineations(lines: string[]) {
88
+ return getBasicWindowDelineations(this.windowLength, lines);
89
+ }
90
+
91
+ getCursorContextInfo(resource: ResourceDocument) {
92
+ return getCursorContext(resource, { maxLineCount: this.windowLength });
93
+ }
94
+
95
+ similarityScore(set1: Set<string>, set2: Set<string>) {
96
+ return computeScore(set1, set2);
97
+ }
98
+ }
@@ -0,0 +1,65 @@
1
+ export const LANGUAGE_TO_SUFFIX: {
2
+ [key: string]: string;
3
+ } = {
4
+ abap: '.abap',
5
+ bat: '.bat',
6
+ bibtex: '.bib',
7
+ c: '.c',
8
+ clojure: '.clj',
9
+ coffeescript: '.coffee',
10
+ cpp: '.cpp',
11
+ csharp: '.cs',
12
+ css: '.css',
13
+ 'cuda-cpp': '.cu',
14
+ dart: '.dart',
15
+ diff: '.diff',
16
+ dockerfile: '.dockerfile',
17
+ fsharp: '.fs',
18
+ go: '.go',
19
+ groovy: '.groovy',
20
+ haml: '.haml',
21
+ handlebars: '.handlebars',
22
+ hlsl: '.hlsl',
23
+ html: '.html',
24
+ ini: '.ini',
25
+ jade: '.jade',
26
+ java: '.java',
27
+ javascript: '.js',
28
+ javascriptreact: '.jsx',
29
+ json: '.json',
30
+ julia: '.jl',
31
+ latex: '.tex',
32
+ less: '.less',
33
+ lua: '.lua',
34
+ makefile: '.make',
35
+ markdown: '.md',
36
+ 'objective-c': '.m',
37
+ 'objective-cpp': '.mm',
38
+ perl: '.pl',
39
+ perl6: '.6pl',
40
+ php: '.php',
41
+ plaintext: '.txt',
42
+ powershell: '.ps1',
43
+ pug: '.pug',
44
+ python: '.py',
45
+ r: '.r',
46
+ razor: '.cshtml',
47
+ ruby: '.rb',
48
+ rust: '.rs',
49
+ sass: '.sass',
50
+ scss: '.scss',
51
+ shaderlab: '.shader',
52
+ shellscript: '.sh',
53
+ slim: '.slim',
54
+ sql: '.sql',
55
+ stylus: '.styl',
56
+ swift: '.swift',
57
+ tex: '.tex',
58
+ typescript: '.ts',
59
+ typescriptreact: '.tsx',
60
+ vb: '.vb',
61
+ vue: '.vue',
62
+ xml: '.xml',
63
+ xsl: '.xsl',
64
+ yaml: '.yaml',
65
+ };
@@ -0,0 +1,328 @@
1
+ import {
2
+ CursorContext,
3
+ MatchSimilarSnippet,
4
+ ResourceDocument,
5
+ SimilarSnippet,
6
+ SnippetSelectionOption,
7
+ SnippetSemantics,
8
+ SortOption,
9
+ } from '../types';
10
+
11
+ export class TokensCache {
12
+ private readonly size: number;
13
+
14
+ private readonly keys: string[] = [];
15
+
16
+ private readonly cache: {
17
+ [key: string]: Set<string>[];
18
+ } = {};
19
+
20
+ constructor(size: number) {
21
+ this.size = size;
22
+ }
23
+
24
+ put(id: string, tokens: Set<string>[]) {
25
+ this.cache[id] = tokens;
26
+ if (!this.keys.includes(id)) {
27
+ this.keys.push(id);
28
+ }
29
+ if (this.keys.length > this.size) {
30
+ const key = this.keys.shift() ?? '';
31
+ delete this.cache[key];
32
+ }
33
+ }
34
+
35
+ get(id: string) {
36
+ return this.cache[id];
37
+ }
38
+ }
39
+
40
+ const englishStopWords = new Set([
41
+ 'we',
42
+ 'our',
43
+ 'you',
44
+ 'it',
45
+ 'its',
46
+ 'they',
47
+ 'them',
48
+ 'their',
49
+ 'this',
50
+ 'that',
51
+ 'these',
52
+ 'those',
53
+ 'is',
54
+ 'are',
55
+ 'was',
56
+ 'were',
57
+ 'be',
58
+ 'been',
59
+ 'being',
60
+ 'have',
61
+ 'has',
62
+ 'had',
63
+ 'having',
64
+ 'do',
65
+ 'does',
66
+ 'did',
67
+ 'doing',
68
+ 'can',
69
+ 'don',
70
+ 't',
71
+ 's',
72
+ 'will',
73
+ 'would',
74
+ 'should',
75
+ 'what',
76
+ 'which',
77
+ 'who',
78
+ 'when',
79
+ 'where',
80
+ 'why',
81
+ 'how',
82
+ 'a',
83
+ 'an',
84
+ 'the',
85
+ 'and',
86
+ 'or',
87
+ 'not',
88
+ 'no',
89
+ 'but',
90
+ 'because',
91
+ 'as',
92
+ 'until',
93
+ 'again',
94
+ 'further',
95
+ 'then',
96
+ 'once',
97
+ 'here',
98
+ 'there',
99
+ 'all',
100
+ 'any',
101
+ 'both',
102
+ 'each',
103
+ 'few',
104
+ 'more',
105
+ 'most',
106
+ 'other',
107
+ 'some',
108
+ 'such',
109
+ 'above',
110
+ 'below',
111
+ 'to',
112
+ 'during',
113
+ 'before',
114
+ 'after',
115
+ 'of',
116
+ 'at',
117
+ 'by',
118
+ 'about',
119
+ 'between',
120
+ 'into',
121
+ 'through',
122
+ 'from',
123
+ 'up',
124
+ 'down',
125
+ 'in',
126
+ 'out',
127
+ 'on',
128
+ 'off',
129
+ 'over',
130
+ 'under',
131
+ 'only',
132
+ 'own',
133
+ 'same',
134
+ 'so',
135
+ 'than',
136
+ 'too',
137
+ 'very',
138
+ 'just',
139
+ 'now',
140
+ ]);
141
+ const programmingStopWords = new Set([
142
+ 'if',
143
+ 'then',
144
+ 'else',
145
+ 'for',
146
+ 'while',
147
+ 'with',
148
+ 'def',
149
+ 'function',
150
+ 'return',
151
+ 'TODO',
152
+ 'import',
153
+ 'try',
154
+ 'catch',
155
+ 'raise',
156
+ 'finally',
157
+ 'repeat',
158
+ 'switch',
159
+ 'case',
160
+ 'match',
161
+ 'assert',
162
+ 'continue',
163
+ 'break',
164
+ 'const',
165
+ 'class',
166
+ 'enum',
167
+ 'struct',
168
+ 'static',
169
+ 'new',
170
+ 'super',
171
+ 'this',
172
+ 'var',
173
+ ]);
174
+ const allStopWords = new Set([...englishStopWords, ...programmingStopWords]);
175
+
176
+ const languageStopWords = new Map();
177
+
178
+ function splitIntoWords(text: string) {
179
+ return text.split(/[^a-zA-Z0-9]/).filter((word: string) => word.length > 0);
180
+ }
181
+
182
+ class DocumentTokenizer {
183
+ private readonly stopsForLanguage: Set<string>;
184
+
185
+ constructor(resource: ResourceDocument) {
186
+ this.stopsForLanguage = languageStopWords.get(resource.languageId) ?? allStopWords;
187
+ }
188
+
189
+ tokenize(text: string) {
190
+ return new Set(splitIntoWords(text).filter((word) => !this.stopsForLanguage.has(word)));
191
+ }
192
+ }
193
+
194
+ const tokensCache = new TokensCache(20);
195
+
196
+ export abstract class WindowedMatcher {
197
+ private referenceDoc: ResourceDocument;
198
+
199
+ private tokenizer: DocumentTokenizer;
200
+
201
+ abstract getCursorContextInfo(doc: ResourceDocument): CursorContext;
202
+ abstract getWindowsDelineations(lines: string[]): [number, number][];
203
+ abstract similarityScore(tokens1: Set<string>, tokens2: Set<string>): number;
204
+ abstract id(): string;
205
+
206
+ private referenceTokensCache?: Set<string>;
207
+
208
+ constructor(doc: ResourceDocument) {
209
+ this.referenceDoc = doc;
210
+ this.tokenizer = new DocumentTokenizer(doc);
211
+ }
212
+
213
+ get referenceTokens() {
214
+ if (!this.referenceTokensCache) {
215
+ this.referenceTokensCache = new Set(
216
+ this.tokenizer.tokenize(this.getCursorContextInfo(this.referenceDoc).context),
217
+ );
218
+ }
219
+ return this.referenceTokensCache;
220
+ }
221
+
222
+ sortScoredSnippets(snippets: SimilarSnippet[], sortRule = SortOption.Descending) {
223
+ // eslint-disable-next-line no-nested-ternary
224
+ return sortRule === SortOption.Ascending
225
+ ? snippets.sort((snippet1, snippet2) => (snippet1.score > snippet2.score ? 1 : -1))
226
+ : sortRule === SortOption.Descending
227
+ ? snippets.sort((snippet1, snippet2) => (snippet1.score > snippet2.score ? -1 : 1))
228
+ : snippets;
229
+ }
230
+
231
+ retrieveAllSnippets(resource: ResourceDocument, sortRule = SortOption.Descending) {
232
+ const snippets: SimilarSnippet[] = [];
233
+ if (!resource.source.length || !this.referenceTokens.size) {
234
+ return snippets;
235
+ }
236
+ const sourceArray = resource.source.split('\n');
237
+ const key = `${this.id()}:${resource.source}`;
238
+ const cache: Set<string>[] = tokensCache.get(key) ?? [];
239
+ const noCache = !cache.length;
240
+ const tokens = noCache ? sourceArray.map((text) => this.tokenizer.tokenize(text), this.tokenizer) : [];
241
+ for (const [index, [startLine, endLine]] of this.getWindowsDelineations(sourceArray).entries()) {
242
+ if (noCache) {
243
+ const size: Set<string> = new Set();
244
+ tokens.slice(startLine, endLine).forEach((token) => token.forEach((word) => size.add(word)));
245
+ cache.push(size);
246
+ }
247
+ const traget = cache[index];
248
+ const score = this.similarityScore(traget, this.referenceTokens);
249
+ snippets.push({
250
+ score,
251
+ startLine,
252
+ endLine,
253
+ });
254
+ }
255
+ if (noCache) {
256
+ tokensCache.put(key, cache);
257
+ }
258
+ return this.sortScoredSnippets(snippets, sortRule);
259
+ }
260
+
261
+ findMatches(
262
+ resource: ResourceDocument,
263
+ mode = SnippetSelectionOption.BestMatch,
264
+ size?: number,
265
+ ): MatchSimilarSnippet[] | undefined {
266
+ if (mode === SnippetSelectionOption.BestMatch) {
267
+ const snippet = this.findBestMatch(resource);
268
+ return snippet ? [snippet] : [];
269
+ }
270
+ return mode === SnippetSelectionOption.TopK ? this.findTopKMatches(resource, size) : [];
271
+ }
272
+
273
+ /**
274
+ * 获取所有匹配的片段
275
+ * @param resource 文档资源
276
+ */
277
+ findBestMatch(resource: ResourceDocument) {
278
+ if (!resource.source.length || !this.referenceTokens.size) {
279
+ return;
280
+ }
281
+ const lines = resource.source.split('\n');
282
+ const snippets = this.retrieveAllSnippets(resource, SortOption.Descending);
283
+ return snippets.length !== 0 && snippets[0].score !== 0
284
+ ? {
285
+ snippet: lines.slice(snippets[0].startLine, snippets[0].endLine).join('\n'),
286
+ semantics: SnippetSemantics.Snippet,
287
+ ...snippets[0],
288
+ }
289
+ : null;
290
+ }
291
+
292
+ /**
293
+ * 获取最高匹配片段
294
+ * @param resource 文档资源
295
+ * @param size 取前几位,默认取前一位
296
+ */
297
+ findTopKMatches(resource: ResourceDocument, size = 1): MatchSimilarSnippet[] | undefined {
298
+ if (!resource.source.length || !this.referenceTokens.size || size < 1) {
299
+ return;
300
+ }
301
+ const lines = resource.source.split('\n');
302
+ const snippets = this.retrieveAllSnippets(resource, SortOption.Descending);
303
+ if (!snippets.length || !snippets[0].score) {
304
+ return;
305
+ }
306
+ const topSnippets = [snippets[0]];
307
+ for (let i = 1; i < snippets.length && topSnippets.length < size; i++) {
308
+ if (topSnippets.findIndex((t) => snippets[i].startLine < t.endLine && snippets[i].endLine > t.startLine) === -1) {
309
+ topSnippets.push(snippets[i]);
310
+ }
311
+ }
312
+ return topSnippets.map((snippet) => ({
313
+ snippet: lines.slice(snippet.startLine, snippet.endLine).join('\n'),
314
+ semantics: SnippetSemantics.Snippet,
315
+ ...snippet,
316
+ }));
317
+ }
318
+ }
319
+
320
+ export function computeScore(set1: Set<string>, set2: Set<string>) {
321
+ let intersectionSize = 0;
322
+ for (const element of set1) {
323
+ if (set2.has(element)) {
324
+ intersectionSize++;
325
+ }
326
+ }
327
+ return intersectionSize / (set1.size + set2.size - intersectionSize);
328
+ }