mirror of
https://github.com/voideditor/void
synced 2026-05-24 09:58:23 +00:00
apply improvements
This commit is contained in:
parent
a320323aa1
commit
b1e50798d8
4 changed files with 100 additions and 84 deletions
|
|
@ -21,7 +21,6 @@ import { ToolName, ToolCallParams, ToolResultType, InternalToolInfo, voidTools,
|
|||
import { IToolsService } from './toolsService.js';
|
||||
import { CancellationToken } from '../../../../base/common/cancellation.js';
|
||||
import { ILanguageFeaturesService } from '../../../../editor/common/services/languageFeatures.js';
|
||||
import { ITextModelService } from '../../../../editor/common/services/resolverService.js';
|
||||
import { ChatMessage, CodespanLocationLink, StagingSelectionItem, ToolMessage, ToolRequestApproval } from '../common/chatThreadServiceTypes.js';
|
||||
import { Position } from '../../../../editor/common/core/position.js';
|
||||
import { ITerminalToolService } from './terminalToolService.js';
|
||||
|
|
@ -207,7 +206,6 @@ class ChatThreadService extends Disposable implements IChatThreadService {
|
|||
@IWorkspaceContextService private readonly _workspaceContextService: IWorkspaceContextService,
|
||||
@IVoidSettingsService private readonly _settingsService: IVoidSettingsService,
|
||||
@ILanguageFeaturesService private readonly _languageFeaturesService: ILanguageFeaturesService,
|
||||
@ITextModelService private readonly _textModelService: ITextModelService,
|
||||
@ITerminalToolService private readonly _terminalToolService: ITerminalToolService,
|
||||
@IMetricsService private readonly _metricsService: IMetricsService,
|
||||
) {
|
||||
|
|
@ -615,6 +613,8 @@ class ChatThreadService extends Disposable implements IChatThreadService {
|
|||
|
||||
const llmCancelToken = this.streamState[threadId]?.streamingToken
|
||||
if (llmCancelToken !== undefined) this._llmMessageService.abort(llmCancelToken)
|
||||
|
||||
this._setStreamState(threadId, {}, 'set')
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -817,6 +817,7 @@ class ChatThreadService extends Disposable implements IChatThreadService {
|
|||
onAbort: () => {
|
||||
// stop the loop to free up the promise, but don't modify state (already handled by whatever stopped it)
|
||||
resMessageIsDonePromise()
|
||||
this._metricsService.capture('Agent Loop Done (Aborted)', { nMessagesSent, chatMode })
|
||||
aborted = true
|
||||
},
|
||||
})
|
||||
|
|
@ -832,10 +833,7 @@ class ChatThreadService extends Disposable implements IChatThreadService {
|
|||
this._setStreamState(threadId, { streamingToken: llmCancelToken }, 'merge') // new stream token for the new message
|
||||
|
||||
await messageIsDonePromise
|
||||
if (aborted) {
|
||||
this._metricsService.capture('Agent Loop Done', { nMessagesSent, chatMode })
|
||||
return
|
||||
}
|
||||
if (aborted) { return }
|
||||
} // end while
|
||||
|
||||
// if awaiting user approval, keep isRunning true, else end isRunning
|
||||
|
|
@ -978,91 +976,87 @@ class ChatThreadService extends Disposable implements IChatThreadService {
|
|||
// check all prevUris for the target
|
||||
for (const uri of prevUris) {
|
||||
|
||||
const modelRef = await this._textModelService.createModelReference(uri);
|
||||
const model = modelRef.object.textEditorModel;
|
||||
const modelRef = await this._voidModelService.getModelSafe(uri)
|
||||
const { model } = modelRef
|
||||
if (!model) continue
|
||||
|
||||
try {
|
||||
const matches = model.findMatches(
|
||||
target,
|
||||
false, // searchOnlyEditableRange
|
||||
false, // isRegex
|
||||
true, // matchCase
|
||||
' ', // wordSeparators
|
||||
true // captureMatches
|
||||
);
|
||||
const matches = model.findMatches(
|
||||
target,
|
||||
false, // searchOnlyEditableRange
|
||||
false, // isRegex
|
||||
true, // matchCase
|
||||
' ', // wordSeparators
|
||||
true // captureMatches
|
||||
);
|
||||
|
||||
const firstThree = matches.slice(0, 3);
|
||||
const firstThree = matches.slice(0, 3);
|
||||
|
||||
// take first 3 occurences, attempt to goto definition on them
|
||||
for (const match of firstThree) {
|
||||
const position = new Position(match.range.startLineNumber, match.range.startColumn);
|
||||
const definitionProviders = this._languageFeaturesService.definitionProvider.ordered(model);
|
||||
// take first 3 occurences, attempt to goto definition on them
|
||||
for (const match of firstThree) {
|
||||
const position = new Position(match.range.startLineNumber, match.range.startColumn);
|
||||
const definitionProviders = this._languageFeaturesService.definitionProvider.ordered(model);
|
||||
|
||||
for (const provider of definitionProviders) {
|
||||
for (const provider of definitionProviders) {
|
||||
|
||||
const _definitions = await provider.provideDefinition(model, position, CancellationToken.None);
|
||||
const _definitions = await provider.provideDefinition(model, position, CancellationToken.None);
|
||||
|
||||
if (!_definitions) continue;
|
||||
if (!_definitions) continue;
|
||||
|
||||
const definitions = Array.isArray(_definitions) ? _definitions : [_definitions];
|
||||
const definitions = Array.isArray(_definitions) ? _definitions : [_definitions];
|
||||
|
||||
for (const definition of definitions) {
|
||||
for (const definition of definitions) {
|
||||
|
||||
return {
|
||||
uri: definition.uri,
|
||||
selection: {
|
||||
startLineNumber: definition.range.startLineNumber,
|
||||
startColumn: definition.range.startColumn,
|
||||
endLineNumber: definition.range.endLineNumber,
|
||||
endColumn: definition.range.endColumn,
|
||||
},
|
||||
displayText: _codespanStr,
|
||||
};
|
||||
return {
|
||||
uri: definition.uri,
|
||||
selection: {
|
||||
startLineNumber: definition.range.startLineNumber,
|
||||
startColumn: definition.range.startColumn,
|
||||
endLineNumber: definition.range.endLineNumber,
|
||||
endColumn: definition.range.endColumn,
|
||||
},
|
||||
displayText: _codespanStr,
|
||||
};
|
||||
|
||||
// const defModelRef = await this._textModelService.createModelReference(definition.uri);
|
||||
// const defModel = defModelRef.object.textEditorModel;
|
||||
// const defModelRef = await this._textModelService.createModelReference(definition.uri);
|
||||
// const defModel = defModelRef.object.textEditorModel;
|
||||
|
||||
// try {
|
||||
// const symbolProviders = this._languageFeaturesService.documentSymbolProvider.ordered(defModel);
|
||||
// try {
|
||||
// const symbolProviders = this._languageFeaturesService.documentSymbolProvider.ordered(defModel);
|
||||
|
||||
// for (const symbolProvider of symbolProviders) {
|
||||
// const symbols = await symbolProvider.provideDocumentSymbols(
|
||||
// defModel,
|
||||
// CancellationToken.None
|
||||
// );
|
||||
// for (const symbolProvider of symbolProviders) {
|
||||
// const symbols = await symbolProvider.provideDocumentSymbols(
|
||||
// defModel,
|
||||
// CancellationToken.None
|
||||
// );
|
||||
|
||||
// if (symbols) {
|
||||
// const symbol = symbols.find(s => {
|
||||
// const symbolRange = s.range;
|
||||
// return symbolRange.startLineNumber <= definition.range.startLineNumber &&
|
||||
// symbolRange.endLineNumber >= definition.range.endLineNumber &&
|
||||
// (symbolRange.startLineNumber !== definition.range.startLineNumber || symbolRange.startColumn <= definition.range.startColumn) &&
|
||||
// (symbolRange.endLineNumber !== definition.range.endLineNumber || symbolRange.endColumn >= definition.range.endColumn);
|
||||
// });
|
||||
// if (symbols) {
|
||||
// const symbol = symbols.find(s => {
|
||||
// const symbolRange = s.range;
|
||||
// return symbolRange.startLineNumber <= definition.range.startLineNumber &&
|
||||
// symbolRange.endLineNumber >= definition.range.endLineNumber &&
|
||||
// (symbolRange.startLineNumber !== definition.range.startLineNumber || symbolRange.startColumn <= definition.range.startColumn) &&
|
||||
// (symbolRange.endLineNumber !== definition.range.endLineNumber || symbolRange.endColumn >= definition.range.endColumn);
|
||||
// });
|
||||
|
||||
// // if we got to a class/function get the full range and return
|
||||
// if (symbol?.kind === SymbolKind.Function || symbol?.kind === SymbolKind.Method || symbol?.kind === SymbolKind.Class) {
|
||||
// return {
|
||||
// uri: definition.uri,
|
||||
// selection: {
|
||||
// startLineNumber: definition.range.startLineNumber,
|
||||
// startColumn: definition.range.startColumn,
|
||||
// endLineNumber: definition.range.endLineNumber,
|
||||
// endColumn: definition.range.endColumn,
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// } finally {
|
||||
// defModelRef.dispose();
|
||||
// }
|
||||
}
|
||||
// // if we got to a class/function get the full range and return
|
||||
// if (symbol?.kind === SymbolKind.Function || symbol?.kind === SymbolKind.Method || symbol?.kind === SymbolKind.Class) {
|
||||
// return {
|
||||
// uri: definition.uri,
|
||||
// selection: {
|
||||
// startLineNumber: definition.range.startLineNumber,
|
||||
// startColumn: definition.range.startColumn,
|
||||
// endLineNumber: definition.range.endLineNumber,
|
||||
// endColumn: definition.range.endColumn,
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// } finally {
|
||||
// defModelRef.dispose();
|
||||
// }
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
modelRef.object.dispose();
|
||||
modelRef.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1681,6 +1681,7 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
let nMessagesSent = 0
|
||||
let currStreamingBlockNum = 0
|
||||
let aborted = false
|
||||
let weAreAborting = false
|
||||
while (shouldSendAnotherMessage) {
|
||||
shouldSendAnotherMessage = false
|
||||
nMessagesSent += 1
|
||||
|
|
@ -1739,7 +1740,6 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
const originalBounds = findTextInCode(block.orig, originalFileCode)
|
||||
// if error
|
||||
if (typeof originalBounds === 'string') {
|
||||
console.log('TEXT NOT FOUND, RETRYING')
|
||||
const content = errMsgOfInvalidStr(originalBounds, block.orig)
|
||||
messages.push(
|
||||
{ role: 'assistant', content: fullText, anthropicReasoning: null }, // latest output
|
||||
|
|
@ -1751,13 +1751,17 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
latestStreamLocationMutable = null
|
||||
shouldUpdateOrigStreamStyle = true
|
||||
blocks.splice(blockNum, Infinity) // remove all blocks at and after this one
|
||||
oldBlocks = blocks
|
||||
oldBlocks = deepClone(blocks)
|
||||
|
||||
// abort and resolve
|
||||
shouldSendAnotherMessage = true
|
||||
if (streamRequestIdRef.current) this._llmMessageService.abort(streamRequestIdRef.current)
|
||||
if (streamRequestIdRef.current) {
|
||||
weAreAborting = true
|
||||
this._llmMessageService.abort(streamRequestIdRef.current)
|
||||
weAreAborting = false
|
||||
resMessageDonePromise()
|
||||
}
|
||||
this._refreshStylesAndDiffsInURI(uri)
|
||||
resMessageDonePromise()
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -1800,7 +1804,10 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
|
||||
// write the added text to the file
|
||||
if (!latestStreamLocationMutable) continue
|
||||
const deltaFinalText = block.final.substring((oldBlocks[blockNum]?.final ?? '').length, Infinity)
|
||||
const oldBlock = oldBlocks[blockNum]
|
||||
const oldFinalLen = (oldBlock?.final ?? '').length
|
||||
const deltaFinalText = block.final.substring(oldFinalLen, Infinity)
|
||||
|
||||
this._writeStreamedDiffZoneLLMText(uri, block.orig, block.final, deltaFinalText, latestStreamLocationMutable)
|
||||
oldBlocks = blocks // oldblocks is only used if writingFinal
|
||||
|
||||
|
|
@ -1857,6 +1864,7 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
resMessageDonePromise()
|
||||
},
|
||||
onAbort: () => {
|
||||
if (weAreAborting) return
|
||||
// stop the loop to free up the promise, but don't modify state (already handled by whatever stopped it)
|
||||
resMessageDonePromise()
|
||||
aborted = true
|
||||
|
|
@ -1866,7 +1874,9 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
// should never happen, just for safety
|
||||
if (streamRequestIdRef.current === null) { break }
|
||||
|
||||
console.log('awaiting...')
|
||||
await messageDonePromise
|
||||
console.log('done awaiting, aborted=', aborted)
|
||||
if (aborted) { return }
|
||||
|
||||
} // end while
|
||||
|
|
@ -1874,6 +1884,7 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
} // end retryLoop
|
||||
|
||||
retryLoop().then(() => {
|
||||
console.log('resolving Apply Done')
|
||||
resApplyDonePromise();
|
||||
// this._noLongerNeedModelReference(uri)
|
||||
}).catch((e) => rejApplyDonePromise(e))
|
||||
|
|
|
|||
|
|
@ -273,6 +273,7 @@ export class ToolsService implements IToolsService {
|
|||
|
||||
this.callTool = {
|
||||
read_file: async ({ uri, pageNumber }) => {
|
||||
await voidModelService.initializeModel(uri)
|
||||
const { model } = await voidModelService.getModelSafe(uri)
|
||||
if (model === null) { throw new Error(`Contents were empty. There may have been an error, or the file may not exist.`) }
|
||||
const readFileContents = model.getValue(EndOfLinePreference.LF)
|
||||
|
|
@ -281,6 +282,7 @@ export class ToolsService implements IToolsService {
|
|||
const toIdx = MAX_FILE_CHARS_PAGE * pageNumber - 1
|
||||
const fileContents = readFileContents.slice(fromIdx, toIdx + 1) // paginate
|
||||
const hasNextPage = (readFileContents.length - 1) - toIdx >= 1
|
||||
|
||||
return { fileContents, hasNextPage }
|
||||
},
|
||||
|
||||
|
|
@ -290,7 +292,9 @@ export class ToolsService implements IToolsService {
|
|||
},
|
||||
|
||||
pathname_search: async ({ queryStr, pageNumber }) => {
|
||||
const query = queryBuilder.file(workspaceContextService.getWorkspace().folders.map(f => f.uri), { filePattern: queryStr, })
|
||||
const query = queryBuilder.file(workspaceContextService.getWorkspace().folders.map(f => f.uri), {
|
||||
filePattern: queryStr,
|
||||
})
|
||||
const data = await searchService.fileSearch(query, CancellationToken.None)
|
||||
|
||||
const fromIdx = MAX_CHILDREN_URIs_PAGE * (pageNumber - 1)
|
||||
|
|
@ -304,7 +308,11 @@ export class ToolsService implements IToolsService {
|
|||
},
|
||||
|
||||
search: async ({ queryStr, pageNumber }) => {
|
||||
const query = queryBuilder.text({ pattern: queryStr, }, workspaceContextService.getWorkspace().folders.map(f => f.uri))
|
||||
const query = queryBuilder.text({
|
||||
pattern: queryStr,
|
||||
isRegExp: true,
|
||||
}, workspaceContextService.getWorkspace().folders.map(f => f.uri))
|
||||
|
||||
const data = await searchService.textSearch(query, CancellationToken.None)
|
||||
|
||||
const fromIdx = MAX_CHILDREN_URIs_PAGE * (pageNumber - 1)
|
||||
|
|
@ -322,8 +330,10 @@ export class ToolsService implements IToolsService {
|
|||
create_uri: async ({ uri, isFolder }) => {
|
||||
if (isFolder)
|
||||
await fileService.createFolder(uri)
|
||||
else
|
||||
else {
|
||||
await voidModelService.initializeModel(uri)
|
||||
await fileService.createFile(uri)
|
||||
}
|
||||
return {}
|
||||
},
|
||||
|
||||
|
|
@ -333,6 +343,7 @@ export class ToolsService implements IToolsService {
|
|||
},
|
||||
|
||||
edit: async ({ uri, changeDescription }) => {
|
||||
await voidModelService.initializeModel(uri)
|
||||
const res = await editCodeService.startApplying({
|
||||
uri,
|
||||
applyStr: changeDescription,
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ export const voidTools = {
|
|||
|
||||
search: {
|
||||
name: 'search',
|
||||
description: `Returns all code excerpts containing the given string or grep query. This does NOT search pathname. As a follow-up, you may want to use read_file to view the full file contents of the results. ${paginationHelper.desc}`,
|
||||
description: `Returns pathnames of files with an exact match of the query. The query can be any regex. This does NOT search pathname. As a follow-up, you may want to use read_file to view the full file contents of the results. ${paginationHelper.desc}`,
|
||||
params: {
|
||||
query: { type: 'string', description: undefined },
|
||||
...paginationHelper.param,
|
||||
|
|
|
|||
Loading…
Reference in a new issue