Add basic system prompt

This commit is contained in:
mp 2024-11-08 21:57:33 -08:00
parent 9b878a9fc0
commit 652f64cd14
5 changed files with 32 additions and 166 deletions

View file

@ -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<string>((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<string>((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
}

View file

@ -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,
})
})
}

View file

@ -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

View file

@ -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: {

View file

@ -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. */
}
}
}