new WORKING Version

This commit is contained in:
Falko Victor Habel 2024-08-21 12:46:48 +02:00
parent f0c5bb0685
commit e160fee3f9
2 changed files with 21 additions and 78 deletions

View File

@ -2,16 +2,13 @@
"name": "fabelous-autocoder", "name": "fabelous-autocoder",
"displayName": "Fabelous Autocoder", "displayName": "Fabelous Autocoder",
"description": "A simple to use Ollama autocompletion engine with options exposed and streaming functionality", "description": "A simple to use Ollama autocompletion engine with options exposed and streaming functionality",
"version": "0.1.69", "version": "0.1.764",
"icon": "icon.png", "icon": "icon.png",
"publisher": "fabel", "publisher": "fabel",
"license": "CC BY-ND 4.0", "license": "CC BY-ND 4.0",
"bugs": { "bugs": {
"url": "https://gitea.fabelous.app/fabel/Fabelous-Autocoder/issues" "url": "https://gitea.fabelous.app/fabel/Fabelous-Autocoder/issues"
}, },
"sponsor": {
"url": "https://ko-fi.com/natehedge"
},
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://gitea.fabelous.app/fabel/Fabelous-Autocoder" "url": "https://gitea.fabelous.app/fabel/Fabelous-Autocoder"
@ -26,7 +23,6 @@
], ],
"keywords": [ "keywords": [
"ollama", "ollama",
"gpt",
"coding", "coding",
"autocomplete", "autocomplete",
"open source", "open source",
@ -35,7 +31,7 @@
"llm" "llm"
], ],
"galleryBanner": { "galleryBanner": {
"color": "#f5ead1" "color": "#133773"
}, },
"activationEvents": [ "activationEvents": [
"onStartupFinished" "onStartupFinished"
@ -60,12 +56,6 @@
"default": "", "default": "",
"description": "The model to use for generating completions" "description": "The model to use for generating completions"
}, },
"fabelous-autocoder.message header": {
"type": "string",
"editPresentation": "multilineText",
"default": "The following is a complete {LANG} file named {FILE_NAME} in the project {PROJECT_NAME}. Anything NOT code is written as a CODE COMMENT. \n\n```\n",
"description": "Pseudo-system prompt, optimized for code completion. It is recommended to keep the format the same if modified. Leave blank for no formatting (raw)."
},
"fabelous-autocoder.max tokens predicted": { "fabelous-autocoder.max tokens predicted": {
"type": "integer", "type": "integer",
"default": 1000, "default": 1000,

View File

@ -38,10 +38,8 @@ vscode.workspace.onDidChangeConfiguration(updateVSConfig);
function getContextLines(document: vscode.TextDocument, position: vscode.Position): string { function getContextLines(document: vscode.TextDocument, position: vscode.Position): string {
const lines = []; const lines = [];
const lineCount = document.lineCount; const startLine = Math.max(0, position.line - 1);
const endLine = position.line;
const startLine = Math.max(0, position.line - promptWindowSize / 2);
const endLine = Math.min(lineCount - 1, position.line + promptWindowSize / 2);
for (let i = startLine; i <= endLine; i++) { for (let i = startLine; i <= endLine; i++) {
lines.push(document.lineAt(i).text); lines.push(document.lineAt(i).text);
@ -50,53 +48,19 @@ function getContextLines(document: vscode.TextDocument, position: vscode.Positio
return lines.join("\n"); return lines.join("\n");
} }
function createFIMPrompt(prefix: string, suffix: string, language: string): string {
return `<fim_prefix>${prefix}<fim_middle><fim_suffix>${suffix}\n\`\`\`${language}\n`; function createFIMPrompt(prefix: string, language: string): string {
return `<fim_prefix>${prefix}<fim_middle><fim_suffix>${language}\n`;
} }
function removeMatchingPrefix(generatedContent: string): string {
const functionHeaderPatterns = [
// Java, C#, TypeScript, JavaScript
/^(public|private|protected)?\s*(static\s+)?(async\s+)?\w+(\s*<[^>]+>)?\s+\w+\s*\([^)]*\)\s*{/m,
// Python
/^def\s+\w+\s*\([^)]*\):/m,
// C++, C
/^(\w+\s+)*\w+\s+\w+\s*\([^)]*\)\s*{/m,
// Go
/^func\s+\w+\s*\([^)]*\)(\s+\w+)?\s*{/m,
// Rust
/^(pub\s+)?(fn|async fn)\s+\w+\s*(<[^>]+>)?\s*\([^)]*\)(\s*->\s*\w+)?\s*{/m
];
const lines = generatedContent.split('\n');
const firstNonEmptyLineIndex = lines.findIndex(line => line.trim() !== '');
if (firstNonEmptyLineIndex === -1) {
return '\n' + generatedContent;
}
const firstLine = lines[firstNonEmptyLineIndex];
for (const pattern of functionHeaderPatterns) {
if (pattern.test(firstLine)) {
lines.splice(firstNonEmptyLineIndex, 1);
return '\n' + lines.join('\n');
}
}
return '\n' + generatedContent;
}
async function autocompleteCommand(textEditor: vscode.TextEditor, cancellationToken?: vscode.CancellationToken) { async function autocompleteCommand(textEditor: vscode.TextEditor, cancellationToken?: vscode.CancellationToken) {
const document = textEditor.document; const document = textEditor.document;
const position = textEditor.selection.active; const position = textEditor.selection.active;
const context = getContextLines(document, position); const context = getContextLines(document, position);
const lines = context.split("\n");
const currentLineIndex = position.line - Math.max(0, position.line - promptWindowSize / 2);
const prefix = lines.slice(0, currentLineIndex + 1).join("\n");
const suffix = lines.slice(currentLineIndex + 1).join("\n");
const fimPrompt = createFIMPrompt(prefix, suffix, document.languageId); const fimPrompt = createFIMPrompt(context, document.languageId);
vscode.window.withProgress( vscode.window.withProgress(
{ {
@ -141,16 +105,21 @@ async function autocompleteCommand(textEditor: vscode.TextEditor, cancellationTo
// Remove any FIM tags and leading/trailing whitespace // Remove any FIM tags and leading/trailing whitespace
completionText = completionText.replace(/<fim_middle>|<fim_suffix>|<fim_prefix>/g, '').trim(); completionText = completionText.replace(/<fim_middle>|<fim_suffix>|<fim_prefix>/g, '').trim();
// Remove the context lines
completionText = removeMatchingPrefix(completionText); const startLine = Math.max(0, position.line - 1);
const endLine = position.line;
const rangeToReplace = new vscode.Range(
new vscode.Position(startLine, 0),
new vscode.Position(endLine, document.lineAt(endLine).text.length)
);
// Apply the edit // Apply the edit
const edit = new vscode.WorkspaceEdit(); const edit = new vscode.WorkspaceEdit();
edit.insert(document.uri, position, completionText); edit.replace(document.uri, rangeToReplace, completionText);
await vscode.workspace.applyEdit(edit); await vscode.workspace.applyEdit(edit);
// Move the cursor to the end of the inserted text // Move the cursor to the end of the inserted text
const newPosition = position.translate(0, completionText.length); const newPosition = new vscode.Position(startLine + completionText.split('\n').length - 1, completionText.split('\n').pop()!.length);
textEditor.selection = new vscode.Selection(newPosition, newPosition); textEditor.selection = new vscode.Selection(newPosition, newPosition);
progress.report({ message: "Fabelous completion finished." }); progress.report({ message: "Fabelous completion finished." });
@ -165,6 +134,7 @@ async function autocompleteCommand(textEditor: vscode.TextEditor, cancellationTo
); );
} }
async function provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, cancellationToken: vscode.CancellationToken) { async function provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, cancellationToken: vscode.CancellationToken) {
const item = new vscode.CompletionItem("Fabelous autocompletion"); const item = new vscode.CompletionItem("Fabelous autocompletion");
item.insertText = new vscode.SnippetString('${1:}'); item.insertText = new vscode.SnippetString('${1:}');
@ -176,11 +146,7 @@ async function provideCompletionItems(document: vscode.TextDocument, position: v
} }
const context = getContextLines(document, position); const context = getContextLines(document, position);
const lines = context.split("\n"); const fimPrompt = createFIMPrompt(context, document.languageId);
const currentLineIndex = position.line - Math.max(0, position.line - promptWindowSize / 2);
const prefix = lines.slice(0, currentLineIndex + 1).join("\n");
const suffix = lines.slice(currentLineIndex + 1).join("\n");
const fimPrompt = createFIMPrompt(prefix, suffix, document.languageId);
try { try {
const response_preview = await axios.post(apiEndpoint, { const response_preview = await axios.post(apiEndpoint, {
@ -200,19 +166,6 @@ async function provideCompletionItems(document: vscode.TextDocument, position: v
cancellationToken.onCancellationRequested(() => c("Autocompletion request terminated by completion cancel")); cancellationToken.onCancellationRequested(() => c("Autocompletion request terminated by completion cancel"));
}) })
}); });
if (response_preview.data.response.trim() !== "") {
let previewText = response_preview.data.response.replace(/<fim_middle>|<fim_suffix>|<fim_prefix>/g, '').trimStart();
// Remove matching prefix and repeated function header
const existingContent = document.getText();
previewText = removeMatchingPrefix(existingContent);
if (previewText.trim() !== "") {
item.label = previewText;
item.insertText = previewText;
}
}
} catch (error) { } catch (error) {
console.error("Error fetching preview:", error); console.error("Error fetching preview:", error);
} }