diff --git a/src/vs/workbench/contrib/void/browser/chatThreadService.ts b/src/vs/workbench/contrib/void/browser/chatThreadService.ts index ff04587d..8bdbc6b6 100644 --- a/src/vs/workbench/contrib/void/browser/chatThreadService.ts +++ b/src/vs/workbench/contrib/void/browser/chatThreadService.ts @@ -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(); } } diff --git a/src/vs/workbench/contrib/void/browser/editCodeService.ts b/src/vs/workbench/contrib/void/browser/editCodeService.ts index 0a111386..70a83048 100644 --- a/src/vs/workbench/contrib/void/browser/editCodeService.ts +++ b/src/vs/workbench/contrib/void/browser/editCodeService.ts @@ -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)) diff --git a/src/vs/workbench/contrib/void/browser/toolsService.ts b/src/vs/workbench/contrib/void/browser/toolsService.ts index 739e9bf6..8c0a8187 100644 --- a/src/vs/workbench/contrib/void/browser/toolsService.ts +++ b/src/vs/workbench/contrib/void/browser/toolsService.ts @@ -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, diff --git a/src/vs/workbench/contrib/void/common/toolsServiceTypes.ts b/src/vs/workbench/contrib/void/common/toolsServiceTypes.ts index d5eaca1e..2c8e72da 100644 --- a/src/vs/workbench/contrib/void/common/toolsServiceTypes.ts +++ b/src/vs/workbench/contrib/void/common/toolsServiceTypes.ts @@ -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,