mirror of
https://github.com/voideditor/void
synced 2026-05-24 09:58:23 +00:00
extract code works! ignore </MID> etc
This commit is contained in:
parent
dd133d2cd5
commit
f19e579ce9
6 changed files with 136 additions and 63 deletions
|
|
@ -204,7 +204,7 @@ export const displayInfoOfProviderName = (providerName: ProviderName): DisplayIn
|
|||
}
|
||||
else if (providerName === 'openAICompatible') {
|
||||
return {
|
||||
title: 'Other',
|
||||
title: 'OpenAI-Compatible',
|
||||
}
|
||||
}
|
||||
else if (providerName === 'gemini') {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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]*?)?<MID>([\s\S]*?)(?:<MID\/>|`{1,3}|$)/;
|
||||
|
||||
// const regex = /[\s\S]*?(?:`{1,3}\s*([a-zA-Z_]+[\w]*)?[\s\S]*?)?<MID>([\s\S]*?)(?:<\/MID>|`{1,3}|$)/;
|
||||
const regex = new RegExp(
|
||||
`[\\s\\S]*?(?:\`{1,3}\\s*([a-zA-Z_]+[\\w]*)?[\\s\\S]*?)?<${midTag}>([\\s\\S]*?)(?:</${midTag}>|\`{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<code>```
|
||||
// 2. ```<code>```
|
||||
|
|
|
|||
|
|
@ -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<DiffZone, 'diffareaid'> = {
|
||||
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 }
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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}</${preTag}>
|
|||
}
|
||||
// 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:
|
||||
\`\`\`
|
||||
|
|
|
|||
|
|
@ -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 <>
|
||||
<h2 className={`text-3xl mb-2`}>Local Providers</h2>
|
||||
{/* <h3 className={`opacity-50 mb-2`}>{`Keep your data private by hosting AI locally on your computer.`}</h3> */}
|
||||
{/* <h3 className={`opacity-50 mb-2`}>{`Instructions:`}</h3> */}
|
||||
{/* <h3 className={`mb-2`}>{`Void can access any model that you host locally. We automatically detect your local models by default.`}</h3> */}
|
||||
<h3 className={`text-void-fg-3 mb-2`}>{`Void can access any model that you host locally. We automatically detect your local models by default.`}</h3>
|
||||
<div className='pl-4 select-text opacity-50'>
|
||||
<span className={`text-sm mb-2`}><ChatMarkdownRender string={`1. Download [Ollama](https://ollama.com/download).`} /></span>
|
||||
<span className={`text-sm mb-2`}><ChatMarkdownRender string={`2. Open your terminal.`} /></span>
|
||||
<span className={`text-sm mb-2`}><ChatMarkdownRender string={`3. Run \`ollama run llama3.1\`. This installs Meta's llama3.1 model which is best for chat and inline edits. Requires 5GB of memory.`} /></span>
|
||||
<span className={`text-sm mb-2`}><ChatMarkdownRender string={`4. Run \`ollama run qwen2.5-coder:1.5b\`. This installs a faster autocomplete model. Requires 1GB of memory.`} /></span>
|
||||
<span className={`text-sm mb-2`}><ChatMarkdownRender string={`Void automatically detects locally running models and enables them.`} /></span>
|
||||
{/* TODO we should create UI for downloading models without user going into terminal */}
|
||||
</div>
|
||||
|
||||
<ErrorBoundary>
|
||||
<VoidProviderSettings providerNames={localProviderNames} />
|
||||
</ErrorBoundary>
|
||||
|
||||
<h2 className={`text-3xl mb-2 mt-16`}>Providers</h2>
|
||||
<h3 className={`text-void-fg-3 mb-2`}>{`Void can access models from Anthropic, OpenAI, OpenRouter, and more.`}</h3>
|
||||
{/* <h3 className={`opacity-50 mb-2`}>{`Access models like ChatGPT and Claude. We recommend using Anthropic or OpenAI as providers, or Groq as a faster alternative.`}</h3> */}
|
||||
<ErrorBoundary>
|
||||
<VoidProviderSettings providerNames={nonlocalProviderNames} />
|
||||
</ErrorBoundary>
|
||||
|
||||
<h2 className={`text-3xl mb-2 mt-16`}>Models</h2>
|
||||
<ErrorBoundary>
|
||||
<VoidFeatureFlagSettings />
|
||||
<RefreshableModels />
|
||||
<ModelDump />
|
||||
<AddModelMenuFull />
|
||||
</ErrorBoundary>
|
||||
</>
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const OneClickSwitch = () => {
|
||||
|
||||
}
|
||||
|
||||
|
||||
const GeneralTab = () => {
|
||||
return <>
|
||||
{/* <VoidFeatureFlagSettings /> */}
|
||||
|
||||
{/* keyboard shortcuts */}
|
||||
|
||||
<h2 className={`text-3xl mb-2`}>General Settings</h2>
|
||||
<h3 className={`text-void-fg-3 mb-2`}>{`VS Code's built-in settings.`}</h3>
|
||||
|
||||
<h2 className={`text-3xl mb-2`}>Keyboard Settings</h2>
|
||||
<h3 className={`text-void-fg-3 mb-2`}>{`Void can access models from Anthropic, OpenAI, OpenRouter, and more.`}</h3>
|
||||
|
||||
|
||||
<h2 className={`text-3xl mb-2`}>One-click Switch</h2>
|
||||
|
||||
Transfer your VS Code settings to Void.
|
||||
|
||||
<h2 className={`text-3xl mb-2`}>Theme</h2>
|
||||
|
||||
|
||||
<h2 className={`text-3xl mb-2`}>Rules for AI</h2>
|
||||
|
||||
|
||||
</>
|
||||
}
|
||||
|
||||
// full settings
|
||||
|
||||
export const Settings = () => {
|
||||
const isDark = useIsDark()
|
||||
|
||||
const [tab, setTab] = useState<'models' | 'features'>('models')
|
||||
const [tab, setTab] = useState<TabName>('models')
|
||||
|
||||
return <div className={`@@void-scope ${isDark ? 'dark' : ''}`}>
|
||||
<div className='w-full h-full px-10 py-10 select-none'>
|
||||
|
|
@ -407,9 +481,9 @@ export const Settings = () => {
|
|||
<button className={`text-left p-1 px-3 my-0.5 rounded-sm overflow-hidden ${tab === 'models' ? 'bg-black/10 dark:bg-gray-200/10' : ''} hover:bg-black/10 hover:dark:bg-gray-200/10 active:bg-black/10 active:dark:bg-gray-200/10 `}
|
||||
onClick={() => { setTab('models') }}
|
||||
>Models</button>
|
||||
{/* <button className={`text-left p-1 px-3 my-0.5 rounded-sm overflow-hidden ${tab === 'features' ? 'bg-black/10 dark:bg-gray-200/10' : ''} hover:bg-black/10 hover:dark:bg-gray-200/10 active:bg-black/10 active:dark:bg-gray-200/10 `}
|
||||
onClick={() => { setTab('features') }}
|
||||
>Features</button> */}
|
||||
<button className={`text-left p-1 px-3 my-0.5 rounded-sm overflow-hidden ${tab === 'general' ? 'bg-black/10 dark:bg-gray-200/10' : ''} hover:bg-black/10 hover:dark:bg-gray-200/10 active:bg-black/10 active:dark:bg-gray-200/10 `}
|
||||
onClick={() => { setTab('general') }}
|
||||
>General</button>
|
||||
</div>
|
||||
|
||||
{/* separator */}
|
||||
|
|
@ -420,43 +494,11 @@ export const Settings = () => {
|
|||
<div className='w-full overflow-y-auto'>
|
||||
|
||||
<div className={`${tab !== 'models' ? 'hidden' : ''}`}>
|
||||
<h2 className={`text-3xl mb-2`}>Local Providers</h2>
|
||||
{/* <h3 className={`opacity-50 mb-2`}>{`Keep your data private by hosting AI locally on your computer.`}</h3> */}
|
||||
{/* <h3 className={`opacity-50 mb-2`}>{`Instructions:`}</h3> */}
|
||||
{/* <h3 className={`mb-2`}>{`Void can access any model that you host locally. We automatically detect your local models by default.`}</h3> */}
|
||||
<h3 className={`text-void-fg-3 mb-2`}>{`Void can access any model that you host locally. We automatically detect your local models by default.`}</h3>
|
||||
<div className='pl-4 select-text opacity-50'>
|
||||
<h4 className={`text-sm mb-2`}><ChatMarkdownRender string={`1. Download [Ollama](https://ollama.com/download).`} /></h4>
|
||||
<h4 className={`text-sm mb-2`}><ChatMarkdownRender string={`2. Open your terminal.`} /></h4>
|
||||
<h4 className={`text-sm mb-2`}><ChatMarkdownRender string={`3. Run \`ollama run llama3.1\`. This installs Meta's llama3.1 model which is best for chat and inline edits. Requires 5GB of memory.`} /></h4>
|
||||
<h4 className={`text-sm mb-2`}><ChatMarkdownRender string={`4. Run \`ollama run qwen2.5-coder:1.5b\`. This installs a faster autocomplete model. Requires 1GB of memory.`} /></h4>
|
||||
<h4 className={`text-sm mb-2`}><ChatMarkdownRender string={`Void automatically detects locally running models and enables them.`} /></h4>
|
||||
{/* TODO we should create UI for downloading models without user going into terminal */}
|
||||
</div>
|
||||
|
||||
<ErrorBoundary>
|
||||
<VoidProviderSettings providerNames={localProviderNames} />
|
||||
</ErrorBoundary>
|
||||
|
||||
<h2 className={`text-3xl mb-2 mt-16`}>More Providers</h2>
|
||||
<h3 className={`text-void-fg-3 mb-2`}>{`Void can also access models from Anthropic, OpenAI, OpenRouter, and more.`}</h3>
|
||||
{/* <h3 className={`opacity-50 mb-2`}>{`Access models like ChatGPT and Claude. We recommend using Anthropic or OpenAI as providers, or Groq as a faster alternative.`}</h3> */}
|
||||
<ErrorBoundary>
|
||||
<VoidProviderSettings providerNames={nonlocalProviderNames} />
|
||||
</ErrorBoundary>
|
||||
|
||||
<h2 className={`text-3xl mb-2 mt-16`}>Models</h2>
|
||||
<ErrorBoundary>
|
||||
<VoidFeatureFlagSettings />
|
||||
<RefreshableModels />
|
||||
<ModelDump />
|
||||
<AddModelMenuFull />
|
||||
</ErrorBoundary>
|
||||
<FeaturesTab />
|
||||
</div>
|
||||
|
||||
<div className={`${tab !== 'features' ? 'hidden' : ''}`}>
|
||||
<h2 className={`text-3xl mb-2`} onClick={() => { setTab('features') }}>Features</h2>
|
||||
{/* <VoidFeatureFlagSettings /> */}
|
||||
<div className={`${tab !== 'general' ? 'hidden' : ''}`}>
|
||||
<GeneralTab />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in a new issue