From 652f64cd14e4819bd36831dfae277df95dad40f7 Mon Sep 17 00:00:00 2001 From: mp Date: Fri, 8 Nov 2024 21:57:33 -0800 Subject: [PATCH] Add basic system prompt --- .../void/src/extension/AutcompleteProvider.ts | 59 ++++---- extensions/void/src/extension/autocomplete.ts | 130 ------------------ extensions/void/src/extension/extension.ts | 1 - .../src/webviews/common/contextForConfig.tsx | 4 +- extensions/void/tsconfig.json | 4 +- 5 files changed, 32 insertions(+), 166 deletions(-) delete mode 100644 extensions/void/src/extension/autocomplete.ts diff --git a/extensions/void/src/extension/AutcompleteProvider.ts b/extensions/void/src/extension/AutcompleteProvider.ts index e0f0cc9c..3438d50a 100644 --- a/extensions/void/src/extension/AutcompleteProvider.ts +++ b/extensions/void/src/extension/AutcompleteProvider.ts @@ -14,7 +14,7 @@ type Autocompletion = { result: string, } -const TIMEOUT_TIME = 10000 +const TIMEOUT_TIME = 60000 const toInlineCompletion = ({ prefix, suffix, autocompletion }: { prefix: string, suffix: string, autocompletion: Autocompletion }): vscode.InlineCompletionItem => { @@ -37,13 +37,8 @@ const toInlineCompletion = ({ prefix, suffix, autocompletion }: { prefix: string remainingText = generatedMiddle.substring(index + 1) } - console.log('----') - console.log('fullPrefix', fullPrefix) - console.log('----') - console.log('----') - console.log('prefix', prefix) - console.log('----') - console.log('completion: ', remainingText) + console.log('generated middle: ', JSON.stringify(generatedMiddle)) + console.log('remaining text: ', JSON.stringify(remainingText)) return new vscode.InlineCompletionItem(remainingText) @@ -55,6 +50,10 @@ export class AutocompleteProvider implements vscode.InlineCompletionItemProvider private _autocompletionsOfDocument: { [docUriStr: string]: Autocompletion[] } = {} + constructor(context: vscode.ExtensionContext) { + this._extensionContext = context + } + // used internally by vscode // fires after every keystroke async provideInlineCompletionItems( @@ -66,10 +65,12 @@ export class AutocompleteProvider implements vscode.InlineCompletionItemProvider const docUriStr = document.uri.toString() + console.log('initial _autocompletionsOfDocument', this._autocompletionsOfDocument[docUriStr]) + const fullText = document.getText(); const cursorOffset = document.offsetAt(position); - const prefix = fullText.substring(0, cursorOffset); - const suffix = fullText.substring(cursorOffset); + const prefix = fullText.substring(0, cursorOffset) + const suffix = fullText.substring(cursorOffset) if (!this._autocompletionsOfDocument[docUriStr]) { this._autocompletionsOfDocument[docUriStr] = [] @@ -94,44 +95,45 @@ export class AutocompleteProvider implements vscode.InlineCompletionItemProvider if (cachedAutocompletion) { if (cachedAutocompletion.status === 'finished') { + console.log('AAA1') const inlineCompletion = toInlineCompletion({ autocompletion: cachedAutocompletion, prefix, suffix, }) return [inlineCompletion] } else if (cachedAutocompletion.status === 'pending') { + console.log('AAA2') try { // await the result; if it hasnt resolved in 10 seconds assume the request is dead - await Promise.race([ - cachedAutocompletion.promise, - new Promise((resolve, reject) => setTimeout(() => reject('Request timed out'), TIMEOUT_TIME)), - ]) + await cachedAutocompletion.promise; const inlineCompletion = toInlineCompletion({ autocompletion: cachedAutocompletion, prefix, suffix, }) return [inlineCompletion] } catch (e) { console.error('Error creating autocompletion (1): ' + e) - return [] } - } else { - return [] + } else if (cachedAutocompletion.status === 'error') { + console.log('AAA3') } + return [] } + console.log('BBB') + // if there is no autocomplete for this line, create it and add it to cache let messages: LLMMessage[] = [] switch (voidConfig.default.whichApi) { case 'ollama': messages = [ - { role: 'user', content: `[SUFFIX]${suffix}[PREFIX]${prefix} ` } + { role: 'user', content: `[SUFFIX]${suffix}[PREFIX]${prefix} Fill in the middle between the prefix and suffix. Return only the middle. [MIDDLE]` } ] break; case 'anthropic': case 'openAI': messages = [ - { role: 'system', content: '' }, + { role: 'system', content: 'Fill in the prefix up to the suffix. Return only the result and be very concise.' }, { role: 'user', content: `[SUFFIX]${suffix}[PREFIX]${prefix}` }, ] break; @@ -161,7 +163,6 @@ export class AutocompleteProvider implements vscode.InlineCompletionItemProvider newAutocompletion.result = completionStr }, onFinalMessage: (finalMessage) => { - console.log('finalMessage:', finalMessage); // newAutocompletion.prefix = prefix // newAutocompletion.suffix = suffix @@ -184,16 +185,19 @@ export class AutocompleteProvider implements vscode.InlineCompletionItemProvider voidConfig, abortRef: newAutocompletion.abortRef, }) + + setTimeout(() => { // if the request hasnt resolved in TIMEOUT_TIME seconds, end it + if (newAutocompletion.status === 'pending') { + reject('Timeout') + } + }, TIMEOUT_TIME) }) this._autocompletionsOfDocument[docUriStr]!.push(newAutocompletion) try { - const result = await Promise.race([ - newAutocompletion.promise, - new Promise((resolve, reject) => setTimeout(() => reject('Request timed out'), TIMEOUT_TIME)), - ]) + await newAutocompletion.promise; const inlineCompletion = toInlineCompletion({ autocompletion: newAutocompletion, prefix, suffix, }) return [inlineCompletion] @@ -203,13 +207,6 @@ export class AutocompleteProvider implements vscode.InlineCompletionItemProvider return [] } - - } - - constructor(context: vscode.ExtensionContext) { - - this._extensionContext = context - } diff --git a/extensions/void/src/extension/autocomplete.ts b/extensions/void/src/extension/autocomplete.ts deleted file mode 100644 index abe18e34..00000000 --- a/extensions/void/src/extension/autocomplete.ts +++ /dev/null @@ -1,130 +0,0 @@ -import * as vscode from 'vscode'; -import { AbortRef, OnFinalMessage, OnText, sendLLMMessage } from "../common/sendLLMMessage" -import { VoidConfig } from '../webviews/common/contextForConfig'; - -type AutocompletionStatus = 'pending' | 'complete' | 'error'; -type Autocompletion = { - prefix: string, - suffix: string, - startTime: number, - endTime: number, - abortRef: AbortRef, - status: AutocompletionStatus, - result: string, -} - -const recentEdits = [] -const autocompletionsOfDocument: { [docUriStr: string]: Autocompletion[] } = {} - - -const showRecentAutocompletion = () => { - console.log('showRecentAutocompletion') - const editor = vscode.window.activeTextEditor - if (!editor) return; - - const docUriStr = editor.document.uri.toString(); - const autocompletions = autocompletionsOfDocument[docUriStr] - if (!autocompletions || autocompletions.length === 0) return; - - const completion = autocompletions[autocompletions.length - 1] - if (completion.status === 'pending') return; - if (completion.status === 'error') return; - - const decorationType = vscode.window.createTextEditorDecorationType({ - after: { contentText: completion.result, color: '#888', } - }); - const position = editor.document.positionAt(completion.prefix.length); - const decorationOptions = [{ range: new vscode.Range(position, position) }]; - editor.setDecorations(decorationType, decorationOptions); - - -} - -export const setupAutocomplete = ({ voidConfig, abortRef }: { voidConfig: VoidConfig, abortRef: AbortRef }) => { - - - vscode.workspace.onDidChangeTextDocument(e => { - let shouldAutocomplete = true; - // 1. determine if we should do an autocomplete - // -check that we're not predicting too many changes at a time - // -look at cache and see if current location has already been predicted - // -check if the user's selection has overlap with the current prediction they are selecting - - const editor = vscode.window.activeTextEditor - if (!editor) return; - if (e.document !== editor.document) return; - if (e.contentChanges.length === 0) return; - - const docUriStr = editor.document.uri.toString(); - - // get the prefix + suffix - const change = e.contentChanges[e.contentChanges.length - 1]; - const fullText = editor.document.getText(); - const startOffset = editor.document.offsetAt(change.range.start); - const cursorOffset = startOffset + (change.text.length > 0 ? change.text.length : 0); - const prefix = fullText.substring(0, cursorOffset); - const suffix = fullText.substring(cursorOffset); - - // TODO do checks as mentioned above - - if (!shouldAutocomplete) return; - // 2. if we should do an autocomplete, get the relevant quantities - // -LSP types of variables around the cursor - // -LSP imports of variables around the cursor - // -code context of recent edits - - // 3. create an autocompletion - - if (!autocompletionsOfDocument[docUriStr]) { - autocompletionsOfDocument[docUriStr] = [] - } - - let promptContent = ``; - switch (voidConfig.default.whichApi) { - case 'ollama': - promptContent = `[SUFFIX]${suffix}[PREFIX]${prefix}`; - break; - case 'anthropic': - case 'openAI': - promptContent = `[SUFFIX]${suffix}[PREFIX]${prefix}`; - break; - default: - throw new Error(`We do not recommend using autocomplete with your selected provider (${voidConfig.default.whichApi}).`); - } - - const startTime = Date.now(); - sendLLMMessage({ - messages: [{ role: 'user', content: promptContent, }], - onText: async (tokenStr, completionStr) => { - // TODO filter out bad responses here - }, - onFinalMessage: (finalMessage) => { - console.log('finalMessage:', finalMessage); - const autocompletion: Autocompletion = { - prefix, - suffix, - abortRef, - startTime, - endTime: Date.now(), - status: 'complete', - result: finalMessage, - } - autocompletionsOfDocument[docUriStr].push(autocompletion) - showRecentAutocompletion() - }, - onError: (e) => { - console.error('Error generating autocompletion:', e); - }, - voidConfig, - abortRef, - }) - - - - - - - - }) - -} diff --git a/extensions/void/src/extension/extension.ts b/extensions/void/src/extension/extension.ts index 92a4caba..f54df186 100644 --- a/extensions/void/src/extension/extension.ts +++ b/extensions/void/src/extension/extension.ts @@ -9,7 +9,6 @@ import { DiffProvider } from './DiffProvider'; import { readFileContentOfUri } from './extensionLib/readFileContentOfUri'; import { SidebarWebviewProvider } from './providers/SidebarWebviewProvider'; import { CtrlKWebviewProvider } from './providers/CtrlKWebviewProvider'; -import { setupAutocomplete } from './autocomplete'; import { AutocompleteProvider } from './AutcompleteProvider'; // // this comes from vscode.proposed.editorInsets.d.ts diff --git a/extensions/void/src/webviews/common/contextForConfig.tsx b/extensions/void/src/webviews/common/contextForConfig.tsx index e1333154..47e96e60 100644 --- a/extensions/void/src/webviews/common/contextForConfig.tsx +++ b/extensions/void/src/webviews/common/contextForConfig.tsx @@ -121,8 +121,8 @@ const voidConfigInfo: Record< // TODO we should allow user to select model inside Void, but for now we'll just let them handle the Ollama setup on their own model: configEnum( 'Ollama model to use.', - 'llama3.1', - ["codegemma", "codegemma:2b", "codegemma:7b", "codellama", "codellama:7b", "codellama:13b", "codellama:34b", "codellama:70b", "codellama:code", "codellama:python", "command-r", "command-r:35b", "command-r-plus", "command-r-plus:104b", "deepseek-coder-v2", "deepseek-coder-v2:16b", "deepseek-coder-v2:236b", "falcon2", "falcon2:11b", "firefunction-v2", "firefunction-v2:70b", "gemma", "gemma:2b", "gemma:7b", "gemma2", "gemma2:2b", "gemma2:9b", "gemma2:27b", "llama2", "llama2:7b", "llama2:13b", "llama2:70b", "llama3", "llama3:8b", "llama3:70b", "llama3-chatqa", "llama3-chatqa:8b", "llama3-chatqa:70b", "llama3-gradient", "llama3-gradient:8b", "llama3-gradient:70b", "llama3.1", "llama3.2", "llama3.1:8b", "llama3.1:70b", "llama3.1:405b", "llava", "llava:7b", "llava:13b", "llava:34b", "llava-llama3", "llava-llama3:8b", "llava-phi3", "llava-phi3:3.8b", "mistral", "mistral:7b", "mistral-large", "mistral-large:123b", "mistral-nemo", "mistral-nemo:12b", "mixtral", "mixtral:8x7b", "mixtral:8x22b", "moondream", "moondream:1.8b", "openhermes", "openhermes:v2.5", "phi3", "phi3:3.8b", "phi3:14b", "phi3.5", "phi3.5:3.8b", "qwen", "qwen:7b", "qwen:14b", "qwen:32b", "qwen:72b", "qwen:110b", "qwen2", "qwen2:0.5b", "qwen2:1.5b", "qwen2:7b", "qwen2:72b", "smollm", "smollm:135m", "smollm:360m", "smollm:1.7b"] as const + 'codestral', + ["codestral", "codegemma", "codegemma:2b", "codegemma:7b", "codellama", "codellama:7b", "codellama:13b", "codellama:34b", "codellama:70b", "codellama:code", "codellama:python", "command-r", "command-r:35b", "command-r-plus", "command-r-plus:104b", "deepseek-coder-v2", "deepseek-coder-v2:16b", "deepseek-coder-v2:236b", "falcon2", "falcon2:11b", "firefunction-v2", "firefunction-v2:70b", "gemma", "gemma:2b", "gemma:7b", "gemma2", "gemma2:2b", "gemma2:9b", "gemma2:27b", "llama2", "llama2:7b", "llama2:13b", "llama2:70b", "llama3", "llama3:8b", "llama3:70b", "llama3-chatqa", "llama3-chatqa:8b", "llama3-chatqa:70b", "llama3-gradient", "llama3-gradient:8b", "llama3-gradient:70b", "llama3.1", "llama3.2", "llama3.1:8b", "llama3.1:70b", "llama3.1:405b", "llava", "llava:7b", "llava:13b", "llava:34b", "llava-llama3", "llava-llama3:8b", "llava-phi3", "llava-phi3:3.8b", "mistral", "mistral:7b", "mistral-large", "mistral-large:123b", "mistral-nemo", "mistral-nemo:12b", "mixtral", "mixtral:8x7b", "mixtral:8x22b", "moondream", "moondream:1.8b", "openhermes", "openhermes:v2.5", "phi3", "phi3:3.8b", "phi3:14b", "phi3.5", "phi3.5:3.8b", "qwen", "qwen:7b", "qwen:14b", "qwen:32b", "qwen:72b", "qwen:110b", "qwen2", "qwen2:0.5b", "qwen2:1.5b", "qwen2:7b", "qwen2:72b", "smollm", "smollm:135m", "smollm:360m", "smollm:1.7b"] as const ), }, openRouter: { diff --git a/extensions/void/tsconfig.json b/extensions/void/tsconfig.json index 63e3afa9..79aef824 100644 --- a/extensions/void/tsconfig.json +++ b/extensions/void/tsconfig.json @@ -1,7 +1,7 @@ { "include": [ "src/**/*" - ], +, "../../src/vs/workbench/contrib/welcomeGettingStarted/common/AutcompleteProvider.tsx" ], "exclude": [ "node_modules" ], @@ -27,4 +27,4 @@ // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ // "noUnusedParameters": true, /* Report errors on unused parameters. */ } -} \ No newline at end of file +}