mirror of
https://github.com/voideditor/void
synced 2026-05-24 09:58:23 +00:00
add FIM streaming + instructions
This commit is contained in:
parent
a9b2ff631d
commit
6e40a92315
5 changed files with 151 additions and 44 deletions
|
|
@ -27,13 +27,14 @@ import * as dom from '../../../../base/browser/dom.js';
|
|||
import { Widget } from '../../../../base/browser/ui/widget.js';
|
||||
import { URI } from '../../../../base/common/uri.js';
|
||||
import { IConsistentItemService } from './helperServices/consistentItemService.js';
|
||||
import { inlineDiff_systemMessage } from './prompt/prompts.js';
|
||||
import { ctrlKStream_prefixAndSuffix, ctrlKStream_prompt, ctrlKStream_systemMessage, ctrlLStream_prompt, ctrlLStream_systemMessage } from './prompt/prompts.js';
|
||||
import { ILLMMessageService } from '../../../../platform/void/common/llmMessageService.js';
|
||||
import { IPosition } from '../../../../editor/common/core/position.js';
|
||||
|
||||
import { mountCtrlK } from '../browser/react/out/ctrl-k-tsx/index.js'
|
||||
import { QuickEditPropsType } from './quickEditActions.js';
|
||||
import { InputBox } from '../../../../base/browser/ui/inputbox/inputBox.js';
|
||||
import { LLMMessage } from '../../../../platform/void/common/llmMessageTypes.js';
|
||||
|
||||
const configOfBG = (color: Color) => {
|
||||
return { dark: color, light: color, hcDark: color, hcLight: color, }
|
||||
|
|
@ -302,6 +303,7 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService {
|
|||
const viewZone: IViewZone = {
|
||||
afterLineNumber: ctrlKZone.startLine - 1,
|
||||
domNode: domNode,
|
||||
heightInPx: 0,
|
||||
suppressMouseDown: false,
|
||||
};
|
||||
|
||||
|
|
@ -640,7 +642,7 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService {
|
|||
// changes the start/line locations of all DiffAreas on the page (adjust their start/end based on the change) based on the change that was recently made
|
||||
private _realignAllDiffAreasLines(uri: URI, text: string, recentChange: { startLineNumber: number; endLineNumber: number }) {
|
||||
|
||||
console.log('recent change', recentChange)
|
||||
// console.log('recent change', recentChange)
|
||||
|
||||
const model = this._getModel(uri)
|
||||
if (!model) return
|
||||
|
|
@ -930,9 +932,9 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService {
|
|||
|
||||
const adding: Omit<DiffZone, 'diffareaid'> = {
|
||||
type: 'DiffZone',
|
||||
originalCode: originalCode,
|
||||
startLine: startLine,
|
||||
endLine: endLine, // starts out the same as the current file
|
||||
originalCode,
|
||||
startLine,
|
||||
endLine,
|
||||
_URI: uri,
|
||||
_streamState: {
|
||||
isStreaming: true,
|
||||
|
|
@ -944,40 +946,38 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService {
|
|||
}
|
||||
const diffZone = this._addDiffArea(adding)
|
||||
|
||||
// actually call the LLM
|
||||
const userContent = featureName === 'Ctrl+L' ? `\
|
||||
ORIGINAL_CODE
|
||||
\`\`\`
|
||||
${originalCode}
|
||||
\`\`\`
|
||||
|
||||
DIFF
|
||||
\`\`\`
|
||||
${userMessage}
|
||||
\`\`\`
|
||||
|
||||
INSTRUCTIONS
|
||||
Please finish writing the new file by applying the diff to the original file. Return ONLY the completion of the file, without any explanation.
|
||||
`
|
||||
: `\
|
||||
CTRL K MESSAGE GOES HERE __TODO__!
|
||||
${userMessage}
|
||||
`
|
||||
let messages: LLMMessage[]
|
||||
|
||||
if (featureName === 'Ctrl+L') {
|
||||
const userContent = ctrlLStream_prompt({ originalCode, userMessage })
|
||||
messages = [
|
||||
// TODO include more context too
|
||||
{ role: 'system', content: ctrlLStream_systemMessage, },
|
||||
{ role: 'user', content: userContent, }
|
||||
]
|
||||
}
|
||||
else if (featureName === 'Ctrl+K') {
|
||||
const { prefix, suffix } = ctrlKStream_prefixAndSuffix({ fullFileStr: currentFileStr, startLine, endLine })
|
||||
const userContent = ctrlKStream_prompt({ selection: originalCode, userMessage, prefix, suffix })
|
||||
console.log('PREFIX:\n', prefix)
|
||||
console.log('SUFFIX:\n', suffix)
|
||||
console.log('USER CONTENT:\n', userContent)
|
||||
messages = [
|
||||
// TODO include more context too (LSP, file history, etc)
|
||||
{ role: 'system', content: ctrlKStream_systemMessage, },
|
||||
{ role: 'user', content: userContent, }
|
||||
]
|
||||
}
|
||||
else { throw new Error(`featureName ${featureName} is invalid`) }
|
||||
|
||||
// __TODO__ make these only move forward
|
||||
|
||||
const latestCurrentFileEnd: IPosition = { lineNumber: 1, column: 1 }
|
||||
const latestOriginalFileStart: IPosition = { lineNumber: 1, column: 1 }
|
||||
|
||||
streamRequestIdRef.current = this._llmMessageService.sendLLMMessage({
|
||||
featureName,
|
||||
logging: { loggingName: 'streamChunk' },
|
||||
messages: [
|
||||
{ role: 'system', content: inlineDiff_systemMessage, },
|
||||
// TODO include more context too
|
||||
{ role: 'user', content: userContent, }
|
||||
],
|
||||
messages,
|
||||
onText: ({ newText, fullText }) => {
|
||||
this._writeDiffZoneLLMText(diffZone, fullText, latestCurrentFileEnd, latestOriginalFileStart)
|
||||
this._refreshStylesAndDiffsInURI(uri)
|
||||
|
|
|
|||
|
|
@ -121,10 +121,7 @@ export const chat_prompt = (instructions: string, selections: CodeSelection[] |
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export const inlineDiff_systemMessage = `
|
||||
export const ctrlLStream_systemMessage = `
|
||||
You are a coding assistant that applies a diff to a file. You are given the original file \`original_file\`, a diff \`diff\`, and a new file that you are applying the diff to \`new_file\`.
|
||||
|
||||
Please finish writing the new file \`new_file\`, according to the diff \`diff\`. You must completely re-write the whole file, using the diff.
|
||||
|
|
@ -255,14 +252,106 @@ export default Sidebar;\`\`\`
|
|||
|
||||
|
||||
|
||||
export const generateCtrlKPrompt = ({ selection, prefix, suffix, instructions, }: { selection: string, prefix: string, suffix: string, instructions: string, }) => `\
|
||||
export const ctrlLStream_prompt = ({ originalCode, userMessage }: { originalCode: string, userMessage: string }) => {
|
||||
return `\
|
||||
ORIGINAL_CODE
|
||||
\`\`\`
|
||||
${originalCode}
|
||||
\`\`\`
|
||||
|
||||
DIFF
|
||||
\`\`\`
|
||||
${userMessage}
|
||||
\`\`\`
|
||||
|
||||
INSTRUCTIONS
|
||||
Please finish writing the new file by applying the diff to the original file. Return ONLY the completion of the file, without any explanation.
|
||||
`
|
||||
}
|
||||
|
||||
|
||||
|
||||
export const ctrlKStream_systemMessage = `\
|
||||
`
|
||||
|
||||
|
||||
export const ctrlKStream_prefixAndSuffix = ({ fullFileStr, startLine, endLine }: { fullFileStr: string, startLine: number, endLine: number }) => {
|
||||
|
||||
const fullFileLines = fullFileStr.split('\n')
|
||||
|
||||
// we can optimize this later
|
||||
const MAX_CHARS = 1024
|
||||
/*
|
||||
|
||||
a
|
||||
a
|
||||
a <-- final i (prefix = a\na\n)
|
||||
a
|
||||
|b <-- startLine-1 (middle = b\nc\nd\n) <-- initial i (moves up)
|
||||
c
|
||||
d| <-- endLine-1 <-- initial j (moves down)
|
||||
e
|
||||
e <-- final j (suffix = e\ne\n)
|
||||
e
|
||||
e
|
||||
*/
|
||||
|
||||
let prefix = ''
|
||||
let i = startLine - 1 // 0-indexed exclusive
|
||||
// we'll include fullFileLines[i...(startLine-1)-1].join('\n') in the prefix.
|
||||
while (i !== 0) {
|
||||
const newLine = fullFileLines[i - 1]
|
||||
if (newLine.length + 1 + prefix.length <= MAX_CHARS) { // +1 to include the \n
|
||||
prefix = `${newLine}\n${prefix}`
|
||||
i -= 1
|
||||
}
|
||||
else break
|
||||
}
|
||||
|
||||
let suffix = ''
|
||||
let j = endLine - 1
|
||||
while (j !== fullFileLines.length - 1) {
|
||||
const newLine = fullFileLines[j + 1]
|
||||
if (newLine.length + 1 + suffix.length <= MAX_CHARS) { // +1 to include the \n
|
||||
suffix = `${suffix}\n${newLine}`
|
||||
j += 1
|
||||
}
|
||||
else break
|
||||
}
|
||||
|
||||
return { prefix, suffix }
|
||||
|
||||
}
|
||||
|
||||
export const ctrlKStream_prompt = ({ selection, prefix, suffix, userMessage }: { selection: string, prefix: string, suffix: string, userMessage: string, }) => {
|
||||
const onlySpeaksFIM = false
|
||||
|
||||
if (onlySpeaksFIM) {
|
||||
const preTag = 'PRE'
|
||||
const sufTag = 'SUF'
|
||||
const midTag = 'MID'
|
||||
return `\
|
||||
<${preTag}>
|
||||
/* Original Selection:
|
||||
${selection}*/
|
||||
/* Instructions: ${userMessage}*/
|
||||
${prefix}</${preTag}>
|
||||
<${sufTag}>${suffix}</${sufTag}>
|
||||
<${midTag}>`
|
||||
}
|
||||
// prompt the model on how to do FIM
|
||||
else {
|
||||
const preTag = 'PRE'
|
||||
const sufTag = 'SUF'
|
||||
const midTag = 'MID'
|
||||
return `\
|
||||
Here is the user's original selection:
|
||||
\`\`\`
|
||||
<MID>${selection}</MID>
|
||||
<${midTag}>${selection}</${midTag}>
|
||||
\`\`\`
|
||||
|
||||
The user wants to apply the following instructions to the selection:
|
||||
${instructions}
|
||||
${userMessage}
|
||||
|
||||
Please rewrite the selection following the user's instructions.
|
||||
|
||||
|
|
@ -273,10 +362,11 @@ Instructions to follow:
|
|||
3. Be careful not to duplicate or remove variables, comments, or other syntax by mistake
|
||||
|
||||
Complete the following:
|
||||
\`\`\`
|
||||
<PRE>${prefix}</PRE>
|
||||
<SUF>${suffix}</SUF>
|
||||
<MID>`;
|
||||
<${preTag}>${prefix}</${preTag}>
|
||||
<${sufTag}>${suffix}</${sufTag}>
|
||||
<${midTag}>`
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Glass Devtools, Inc. All rights reserved.
|
||||
* Void Editor additions licensed under the AGPL 3.0 License.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useIsDark, useSidebarState } from '../util/services.js'
|
||||
import ErrorBoundary from '../sidebar-tsx/ErrorBoundary.js'
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Glass Devtools, Inc. All rights reserved.
|
||||
* Void Editor additions licensed under the AGPL 3.0 License.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import React, { FormEvent, useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useSettingsState, useSidebarState, useThreadsState, useQuickEditState, useAccessor } from '../util/services.js';
|
||||
|
|
@ -20,9 +24,13 @@ export const CtrlKChat = ({ diffareaid, onGetInputBox, onUserUpdateText, onChang
|
|||
const inputContainer = sizerRef.current
|
||||
if (!inputContainer) return;
|
||||
|
||||
|
||||
// inputBoxRef.current?.onDidHeightChange(height => {
|
||||
// console.log('NEW HEIGHT',height)
|
||||
// onChangeHeight(height + 40)
|
||||
// })
|
||||
// only observing 1 element
|
||||
let resizeObserver: ResizeObserver | undefined
|
||||
|
||||
resizeObserver = new ResizeObserver((entries) => {
|
||||
const height = entries[0].borderBoxSize[0].blockSize
|
||||
console.log('NEW HEIGHT', height)
|
||||
|
|
@ -105,7 +113,7 @@ export const CtrlKChat = ({ diffareaid, onGetInputBox, onUserUpdateText, onChang
|
|||
>
|
||||
|
||||
<div // this div is used to position the input box properly
|
||||
className={`w-full m-2 z-[999]`}
|
||||
className={`w-full p-2 z-[999]`}
|
||||
>
|
||||
<div className='flex flex-row justify-between items-end gap-1'>
|
||||
{/* left (input) */}
|
||||
|
|
@ -126,7 +134,7 @@ export const CtrlKChat = ({ diffareaid, onGetInputBox, onUserUpdateText, onChang
|
|||
</div>
|
||||
|
||||
{/* right (button) */}
|
||||
<div className='flex flex-row items-end w-10'>
|
||||
<div className='flex flex-row items-end'>
|
||||
{/* submit / stop button */}
|
||||
{isStreaming ?
|
||||
// stop button
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Glass Devtools, Inc. All rights reserved.
|
||||
* Void Editor additions licensed under the AGPL 3.0 License.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { mountFnGenerator } from '../util/mountFnGenerator.js'
|
||||
import { CtrlK } from './CtrlK.js'
|
||||
|
|
|
|||
Loading…
Reference in a new issue