From f19e579ce9b6485ebb8d11775b965fe68017e4dd Mon Sep 17 00:00:00 2001 From: Andrew Pareles Date: Mon, 6 Jan 2025 01:19:27 -0800 Subject: [PATCH] extract code works! ignore etc --- .../platform/void/common/voidSettingsTypes.ts | 2 +- .../void/browser/autocompleteService.ts | 4 +- .../browser/helpers/extractCodeFromResult.ts | 18 +-- .../void/browser/inlineDiffsService.ts | 25 +++- .../contrib/void/browser/prompt/prompts.ts | 28 ++-- .../react/src/void-settings-tsx/Settings.tsx | 122 ++++++++++++------ 6 files changed, 136 insertions(+), 63 deletions(-) diff --git a/src/vs/platform/void/common/voidSettingsTypes.ts b/src/vs/platform/void/common/voidSettingsTypes.ts index e4878e6f..3c9b9da0 100644 --- a/src/vs/platform/void/common/voidSettingsTypes.ts +++ b/src/vs/platform/void/common/voidSettingsTypes.ts @@ -204,7 +204,7 @@ export const displayInfoOfProviderName = (providerName: ProviderName): DisplayIn } else if (providerName === 'openAICompatible') { return { - title: 'Other', + title: 'OpenAI-Compatible', } } else if (providerName === 'gemini') { diff --git a/src/vs/workbench/contrib/void/browser/autocompleteService.ts b/src/vs/workbench/contrib/void/browser/autocompleteService.ts index 3bd4d955..bbefb748 100644 --- a/src/vs/workbench/contrib/void/browser/autocompleteService.ts +++ b/src/vs/workbench/contrib/void/browser/autocompleteService.ts @@ -17,7 +17,7 @@ import { IEditorService } from '../../../services/editor/common/editorService.js import { isCodeEditor } from '../../../../editor/browser/editorBrowser.js'; import { EditorResourceAccessor } from '../../../common/editor.js'; import { IModelService } from '../../../../editor/common/services/model.js'; -import { extractCodeFromResult } from './helpers/extractCodeFromResult.js'; +import { extractCodeFromRegular } from './helpers/extractCodeFromResult.js'; // The extension this was called from is here - https://github.com/voideditor/void/blob/autocomplete/extensions/void/src/extension/extension.ts @@ -652,7 +652,7 @@ export class AutocompleteService extends Disposable implements IAutocompleteServ // newAutocompletion.abortRef = { current: () => { } } newAutocompletion.status = 'finished' // newAutocompletion.promise = undefined - newAutocompletion.insertText = postprocessResult(extractCodeFromResult(fullText)) + newAutocompletion.insertText = postprocessResult(extractCodeFromRegular(fullText)) resolve(newAutocompletion.insertText) diff --git a/src/vs/workbench/contrib/void/browser/helpers/extractCodeFromResult.ts b/src/vs/workbench/contrib/void/browser/helpers/extractCodeFromResult.ts index 2573dae4..6ac12fd1 100644 --- a/src/vs/workbench/contrib/void/browser/helpers/extractCodeFromResult.ts +++ b/src/vs/workbench/contrib/void/browser/helpers/extractCodeFromResult.ts @@ -4,9 +4,8 @@ *--------------------------------------------------------------------------------------------*/ - - -export const extractArtificialFIMCodeFromResult = ({ text, preTag, sufTag, midTag }: { text: string, preTag: string, sufTag: string, midTag: string }) => { +// modelWasTrainedOnFIM should be false here +export const extractCodeFromFIM = ({ text, midTag, modelWasTrainedOnFIM }: { text: string, midTag: string, modelWasTrainedOnFIM: false }) => { /* desired matches ` @@ -39,22 +38,25 @@ export const extractArtificialFIMCodeFromResult = ({ text, preTag, sufTag, midTa [optional ` | `` | ```] */ - const regex = /[\s\S]*?(?:`{1,3}\s*([a-zA-Z_]+[\w]*)?[\s\S]*?)?([\s\S]*?)(?:|`{1,3}|$)/; - + // const regex = /[\s\S]*?(?:`{1,3}\s*([a-zA-Z_]+[\w]*)?[\s\S]*?)?([\s\S]*?)(?:<\/MID>|`{1,3}|$)/; + const regex = new RegExp( + `[\\s\\S]*?(?:\`{1,3}\\s*([a-zA-Z_]+[\\w]*)?[\\s\\S]*?)?<${midTag}>([\\s\\S]*?)(?:|\`{1,3}|$)`, + '' + ); const match = text.match(regex); if (match) { const [_, languageName, codeBetweenMidTags] = match; - return [languageName, codeBetweenMidTags] + return [languageName, codeBetweenMidTags] as const } else { - return [undefined, extractCodeFromResult(text)] + return [undefined, extractCodeFromRegular(text)] as const } } -export const extractCodeFromResult = (result: string) => { +export const extractCodeFromRegular = (result: string) => { // Match either: // 1. ```language\n``` // 2. `````` diff --git a/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts b/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts index a7db6e6c..40f4391d 100644 --- a/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts +++ b/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts @@ -27,7 +27,7 @@ import * as dom from '../../../../base/browser/dom.js'; import { Widget } from '../../../../base/browser/ui/widget.js'; import { URI } from '../../../../base/common/uri.js'; import { IConsistentEditorItemService, IConsistentItemService } from './helperServices/consistentItemService.js'; -import { ctrlKStream_prefixAndSuffix, ctrlKStream_prompt, ctrlKStream_systemMessage, ctrlLStream_prompt, ctrlLStream_systemMessage } from './prompt/prompts.js'; +import { ctrlKStream_prefixAndSuffix, ctrlKStream_prompt, ctrlKStream_systemMessage, ctrlLStream_prompt, ctrlLStream_systemMessage, defaultFimTags } from './prompt/prompts.js'; import { ILLMMessageService } from '../../../../platform/void/common/llmMessageService.js'; import { IPosition } from '../../../../editor/common/core/position.js'; @@ -36,6 +36,7 @@ import { QuickEditPropsType } from './quickEditActions.js'; import { InputBox } from '../../../../base/browser/ui/inputbox/inputBox.js'; import { LLMMessage } from '../../../../platform/void/common/llmMessageTypes.js'; import { IModelContentChangedEvent } from '../../../../editor/common/textModelEvents.js'; +import { extractCodeFromFIM, extractCodeFromRegular } from './helpers/extractCodeFromResult.js'; const configOfBG = (color: Color) => { return { dark: color, light: color, hcDark: color, hcLight: color, } @@ -1043,6 +1044,10 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService { // this._deleteDiffArea(ctrlKZone) // } + // TODO ctrl+K case should be replaced with an actual check for model.isFIM + const modelWasTrainedOnFIM = featureName === 'Ctrl+K' ? false : false + const modelFimTags = defaultFimTags + const adding: Omit = { type: 'DiffZone', originalCode, @@ -1071,7 +1076,7 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService { } else if (featureName === 'Ctrl+K') { const { prefix, suffix } = ctrlKStream_prefixAndSuffix({ fullFileStr: currentFileStr, startLine, endLine }) - const userContent = ctrlKStream_prompt({ selection: originalCode, userMessage, prefix, suffix }) + const userContent = ctrlKStream_prompt({ selection: originalCode, userMessage, prefix, suffix, modelWasTrainedOnFIM, fimTags: modelFimTags }) console.log('PREFIX:\n', prefix) console.log('SUFFIX:\n', suffix) console.log('USER CONTENT:\n', userContent) @@ -1102,17 +1107,29 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService { // refresh now in case onText takes a while to get 1st message this._refreshStylesAndDiffsInURI(uri) + + const extractText = (fullText: string) => { + if (featureName === 'Ctrl+K') { + const [_, textSoFar] = extractCodeFromFIM({ text: fullText, midTag: modelFimTags.midTag, modelWasTrainedOnFIM }) + return textSoFar + } + else if (featureName === 'Ctrl+L') { + return extractCodeFromRegular(fullText) + } + throw 1 + } + streamRequestIdRef.current = this._llmMessageService.sendLLMMessage({ featureName, logging: { loggingName: `startApplying - ${featureName}` }, messages, onText: ({ newText, fullText }) => { - this._writeDiffZoneLLMText(diffZone, fullText, latestCurrentFileEnd, latestOriginalFileStart) + this._writeDiffZoneLLMText(diffZone, extractText(fullText), latestCurrentFileEnd, latestOriginalFileStart) this._refreshStylesAndDiffsInURI(uri) }, onFinalMessage: ({ fullText }) => { // at the end, re-write whole thing to make sure no sync errors - this._writeText(uri, fullText, + this._writeText(uri, extractText(fullText), { startLineNumber: diffZone.startLine, startColumn: 1, endLineNumber: diffZone.endLine, endColumn: Number.MAX_SAFE_INTEGER }, // 1-indexed { shouldRealignDiffAreas: false } ) diff --git a/src/vs/workbench/contrib/void/browser/prompt/prompts.ts b/src/vs/workbench/contrib/void/browser/prompt/prompts.ts index f65bfcbe..f2759744 100644 --- a/src/vs/workbench/contrib/void/browser/prompt/prompts.ts +++ b/src/vs/workbench/contrib/void/browser/prompt/prompts.ts @@ -324,13 +324,25 @@ export const ctrlKStream_prefixAndSuffix = ({ fullFileStr, startLine, endLine }: } -export const ctrlKStream_prompt = ({ selection, prefix, suffix, userMessage }: { selection: string, prefix: string, suffix: string, userMessage: string, }) => { - const modelWasTrainedOnFIM = false + +export type FimTagsType = { + preTag: string, + sufTag: string, + midTag: string +} +export const defaultFimTags: FimTagsType = { + preTag: 'BEFORE', + sufTag: 'AFTER', + midTag: 'SELECTION', +} + +export const ctrlKStream_prompt = ({ selection, prefix, suffix, userMessage, modelWasTrainedOnFIM, fimTags }: { selection: string, prefix: string, suffix: string, userMessage: string, modelWasTrainedOnFIM: boolean, fimTags: FimTagsType }) => { + const { preTag, sufTag, midTag } = fimTags if (modelWasTrainedOnFIM) { - const preTag = 'PRE' - const sufTag = 'SUF' - const midTag = 'MID' + // const preTag = 'PRE' + // const sufTag = 'SUF' + // const midTag = 'MID' return `\ <${preTag}> /* Original Selection: @@ -343,9 +355,9 @@ ${prefix} } // prompt the model artifically on how to do FIM else { - const preTag = 'BEFORE' - const sufTag = 'AFTER' - const midTag = 'SELECTION' + // const preTag = 'BEFORE' + // const sufTag = 'AFTER' + // const midTag = 'SELECTION' return `\ The user is selecting this code as their SELECTION: \`\`\` diff --git a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/Settings.tsx b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/Settings.tsx index 8239ef88..f8d07f75 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/Settings.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/Settings.tsx @@ -9,7 +9,7 @@ import { ProviderName, SettingName, displayInfoOfSettingName, providerNames, Voi import ErrorBoundary from '../sidebar-tsx/ErrorBoundary.js' import { VoidCheckBox, VoidInputBox, VoidSelectBox, VoidSwitch } from '../util/inputs.js' import { useAccessor, useIsDark, useRefreshModelListener, useRefreshModelState, useSettingsState } from '../util/services.js' -import { X, RefreshCw, Loader2, Check } from 'lucide-react' +import { X, RefreshCw, Loader2, Check, MoveRight } from 'lucide-react' import { ChatMarkdownRender } from '../markdown/ChatMarkdownRender.js' const SubtleButton = ({ onClick, text, icon, disabled }: { onClick: () => void, text: string, icon: React.ReactNode, disabled: boolean }) => { @@ -360,6 +360,7 @@ export const VoidProviderSettings = ({ providerNames }: { providerNames: Provide // })} // // } +type TabName = 'models' | 'general' export const VoidFeatureFlagSettings = () => { const accessor = useAccessor() @@ -383,12 +384,85 @@ export const VoidFeatureFlagSettings = () => { } +export const FeaturesTab = () => { + return <> +

Local Providers

+ {/*

{`Keep your data private by hosting AI locally on your computer.`}

*/} + {/*

{`Instructions:`}

*/} + {/*

{`Void can access any model that you host locally. We automatically detect your local models by default.`}

*/} +

{`Void can access any model that you host locally. We automatically detect your local models by default.`}

+
+ + + + + + {/* TODO we should create UI for downloading models without user going into terminal */} +
+ + + + + +

Providers

+

{`Void can access models from Anthropic, OpenAI, OpenRouter, and more.`}

+ {/*

{`Access models like ChatGPT and Claude. We recommend using Anthropic or OpenAI as providers, or Groq as a faster alternative.`}

*/} + + + + +

Models

+ + + + + + + +} + + + + + + +const OneClickSwitch = () => { + +} + + +const GeneralTab = () => { + return <> + {/* */} + + {/* keyboard shortcuts */} + +

General Settings

+

{`VS Code's built-in settings.`}

+ +

Keyboard Settings

+

{`Void can access models from Anthropic, OpenAI, OpenRouter, and more.`}

+ + +

One-click Switch

+ + Transfer your VS Code settings to Void. + +

Theme

+ + +

Rules for AI

+ + + +} + // full settings export const Settings = () => { const isDark = useIsDark() - const [tab, setTab] = useState<'models' | 'features'>('models') + const [tab, setTab] = useState('models') return
@@ -407,9 +481,9 @@ export const Settings = () => { - {/* */} +
{/* separator */} @@ -420,43 +494,11 @@ export const Settings = () => {
-

Local Providers

- {/*

{`Keep your data private by hosting AI locally on your computer.`}

*/} - {/*

{`Instructions:`}

*/} - {/*

{`Void can access any model that you host locally. We automatically detect your local models by default.`}

*/} -

{`Void can access any model that you host locally. We automatically detect your local models by default.`}

-
-

-

-

-

-

- {/* TODO we should create UI for downloading models without user going into terminal */} -
- - - - - -

More Providers

-

{`Void can also access models from Anthropic, OpenAI, OpenRouter, and more.`}

- {/*

{`Access models like ChatGPT and Claude. We recommend using Anthropic or OpenAI as providers, or Groq as a faster alternative.`}

*/} - - - - -

Models

- - - - - - +
-
-

{ setTab('features') }}>Features

- {/* */} +
+