diff --git a/src/vs/workbench/contrib/void/browser/aiRegexService.ts b/src/vs/workbench/contrib/void/browser/aiRegexService.ts index 9f96da76..c0ae27fa 100644 --- a/src/vs/workbench/contrib/void/browser/aiRegexService.ts +++ b/src/vs/workbench/contrib/void/browser/aiRegexService.ts @@ -5,10 +5,10 @@ import { Emitter, Event } from '../../../../base/common/event.js'; import { Disposable } from '../../../../base/common/lifecycle.js'; -import { URI } from '../../../../base/common/uri.js'; +// import { URI } from '../../../../base/common/uri.js'; import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js'; import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js'; -import { IToolService, ToolService } from '../common/toolsService.js'; +// import { IToolService, ToolService } from '../common/toolsService.js'; @@ -54,7 +54,7 @@ class VoidFastApplyService extends Disposable implements IFastApplyService { // state: ApplyState constructor( - @IToolService private readonly toolService: ToolService + // @IToolService private readonly toolService: ToolService ) { super() @@ -88,97 +88,97 @@ class VoidFastApplyService extends Disposable implements IFastApplyService { // -iterate on syntax errors (all files can be changed from a syntax error, not just the one with the error) - private async _searchUsingAI({ searchClause }: { searchClause: string }) { + // private async _searchUsingAI({ searchClause }: { searchClause: string }) { - const relevantURIs: URI[] = [] - const gatherPrompt = `\ -asdasdas -` - const filterPrompt = `\ -Is this file relevant? -` + // // const relevantURIs: URI[] = [] + // // const gatherPrompt = `\ + // // asdasdas + // // ` + // // const filterPrompt = `\ + // // Is this file relevant? + // // ` - // optimizations (DO THESE LATER!!!!!!) - // if tool includes a uri in uriSet, skip it obviously - let uriSet = new Set() - // gather - let messages = [] - while (true) { - const result = await new Promise((res, rej) => { - sendLLMMessage({ - messages, - tools: ['search'], - onFinalMessage: ({ result: r, }) => { - res(r) - }, - onError: (error) => { - rej(error) - } - }) - }) + // // // optimizations (DO THESE LATER!!!!!!) + // // // if tool includes a uri in uriSet, skip it obviously + // // let uriSet = new Set() + // // // gather + // // let messages = [] + // // while (true) { + // // const result = await new Promise((res, rej) => { + // // sendLLMMessage({ + // // messages, + // // tools: ['search'], + // // onFinalMessage: ({ result: r, }) => { + // // res(r) + // // }, + // // onError: (error) => { + // // rej(error) + // // } + // // }) + // // }) - messages.push({ role: 'tool', content: turnToString(result) }) + // // messages.push({ role: 'tool', content: turnToString(result) }) - sendLLMMessage({ - messages: { 'Output ': result }, - onFinalMessage: (r) => { - // output is file1\nfile2\nfile3\n... - } - }) + // // sendLLMMessage({ + // // messages: { 'Output ': result }, + // // onFinalMessage: (r) => { + // // // output is file1\nfile2\nfile3\n... + // // } + // // }) - uriSet.add(...) - } + // // uriSet.add(...) + // // } - // writes - if (!replaceClause) return + // // // writes + // // if (!replaceClause) return - for (const uri of uriSet) { - // in future, batch these - applyWorkflow({ uri, applyStr: replaceClause }) - } + // // for (const uri of uriSet) { + // // // in future, batch these + // // applyWorkflow({ uri, applyStr: replaceClause }) + // // } - // while (true) { - // const result = new Promise((res, rej) => { - // sendLLMMessage({ - // messages, - // tools: ['search'], - // onResult: (r) => { - // res(r) - // } - // }) - // }) + // // while (true) { + // // const result = new Promise((res, rej) => { + // // sendLLMMessage({ + // // messages, + // // tools: ['search'], + // // onResult: (r) => { + // // res(r) + // // } + // // }) + // // }) - // messages.push(result) + // // messages.push(result) - // } + // // } - } + // } - private async _replaceUsingAI({ searchClause, replaceClause, relevantURIs }: { searchClause: string, replaceClause: string, relevantURIs: URI[] }) { + // private async _replaceUsingAI({ searchClause, replaceClause, relevantURIs }: { searchClause: string, replaceClause: string, relevantURIs: URI[] }) { - for (const uri of relevantURIs) { + // for (const uri of relevantURIs) { - uri + // uri - } + // } - // should I change this file? - // if so what changes to make? + // // should I change this file? + // // if so what changes to make? - // fast apply the changes - } + // // fast apply the changes + // } diff --git a/src/vs/workbench/contrib/void/browser/helpers/extractCodeFromResult.ts b/src/vs/workbench/contrib/void/browser/helpers/extractCodeFromResult.ts index bb1ed350..b7665eca 100644 --- a/src/vs/workbench/contrib/void/browser/helpers/extractCodeFromResult.ts +++ b/src/vs/workbench/contrib/void/browser/helpers/extractCodeFromResult.ts @@ -3,7 +3,7 @@ * Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information. *--------------------------------------------------------------------------------------*/ -import { DIVIDER, FINAL, ORIGINAL } from '../prompt/prompts' +import { DIVIDER, FINAL, ORIGINAL } from '../prompt/prompts.js' class SurroundingsRemover { readonly originalS: string diff --git a/src/vs/workbench/contrib/void/browser/prompt/prompts.ts b/src/vs/workbench/contrib/void/browser/prompt/prompts.ts index 9185e0dc..45a573ae 100644 --- a/src/vs/workbench/contrib/void/browser/prompt/prompts.ts +++ b/src/vs/workbench/contrib/void/browser/prompt/prompts.ts @@ -224,7 +224,7 @@ Please finish writing the new file by applying the change to the original file. -const aiRegex_computeReplacementsForFile_systemMessage = `\ +export const aiRegex_computeReplacementsForFile_systemMessage = `\ You are a "search and replace" coding assistant. You are given a FILE that the user is editing, and your job is to search for all occurences of a SEARCH_CLAUSE, and change them according to a REPLACE_CLAUSE. @@ -246,7 +246,7 @@ For example, if the user is asking you to "make this variable a better name", ma - Make sure you give enough context in the code block to apply the changes to the correct location in the code` -const aiRegex_computeReplacementsForFile_userMessage = async ({ searchClause, replaceClause, fileURI, modelService }: { searchClause: string, replaceClause: string, fileURI: URI, modelService: IModelService }) => { +export const aiRegex_computeReplacementsForFile_userMessage = async ({ searchClause, replaceClause, fileURI, modelService }: { searchClause: string, replaceClause: string, fileURI: URI, modelService: IModelService }) => { // we may want to do this in batches const fileSelection: FileSelection = { type: 'File', fileURI, selectionStr: null, range: null } @@ -273,7 +273,7 @@ Please return the changes you want to make to the file in a codeblock, or return // don't have to tell it it will be given the history; just give it to it -const aiRegex_search_systemMessage = `\ +export const aiRegex_search_systemMessage = `\ You are a coding assistant that executes the SEARCH part of a user's search and replace query. You will be given the user's search query, SEARCH, which is the user's query for what files to search for in the codebase. You may also be given the user's REPLACE query for additional context. diff --git a/src/vs/workbench/contrib/void/common/toolsService.ts b/src/vs/workbench/contrib/void/common/toolsService.ts index 1eda93d1..c8b8bb2d 100644 --- a/src/vs/workbench/contrib/void/common/toolsService.ts +++ b/src/vs/workbench/contrib/void/common/toolsService.ts @@ -162,7 +162,7 @@ export class ToolService implements IToolService { const data = await searchService.textSearch(query, CancellationToken.None); const str = data.results.map(({ resource, results }) => resource) - return str + return str as any }, } diff --git a/src/vs/workbench/contrib/void/electron-main/llmMessage/anthropic.ts b/src/vs/workbench/contrib/void/electron-main/llmMessage/anthropic.ts index 91461b16..97cd3ed9 100644 --- a/src/vs/workbench/contrib/void/electron-main/llmMessage/anthropic.ts +++ b/src/vs/workbench/contrib/void/electron-main/llmMessage/anthropic.ts @@ -53,11 +53,37 @@ export const sendAnthropicChat: _InternalSendLLMChatMessageFnType = ({ messages, onText({ newText, fullText }) }) + + // can do tool use streaming + const toolCallOfIndex: { [index: string]: { name: string, args: string } } = {} + stream.on('streamEvent', e => { + if (e.type === 'content_block_start') { + if (e.content_block.type !== 'tool_use') return + const index = e.index + const tool = e.content_block + if (!toolCallOfIndex[index]) + toolCallOfIndex[index] = { name: '', args: '' } + toolCallOfIndex[index].name += tool.name ?? '' + toolCallOfIndex[index].args += tool.input ?? '' + + } + else if (e.type === 'content_block_delta') { + if (e.delta.type !== 'input_json_delta') return + toolCallOfIndex[e.index].args += e.delta.partial_json + } + // TODO!!!!! + // onText({}) + }) + // when we get the final message on this stream (or when error/fail) - stream.on('finalMessage', (claude_response) => { + stream.on('finalMessage', (response) => { // stringify the response's content - const content = claude_response.content.map(c => c.type === 'text' ? c.text : c.type).join('\n'); - onFinalMessage({ fullText: content }) + const content = response.content.map(c => c.type === 'text' ? c.text : '').join('\n') + const tools = response.content.map(c => c.type === 'tool_use' ? { name: c.name, input: c.input } : null) + + console.log("TOOLS!!!!", typeof tools[0]?.input, JSON.stringify(tools, null, 2)) + + onFinalMessage({ fullText: content, }) }) stream.on('error', (error) => { diff --git a/src/vs/workbench/contrib/void/electron-main/llmMessage/openai.ts b/src/vs/workbench/contrib/void/electron-main/llmMessage/openai.ts index df4d2322..30e80bc6 100644 --- a/src/vs/workbench/contrib/void/electron-main/llmMessage/openai.ts +++ b/src/vs/workbench/contrib/void/electron-main/llmMessage/openai.ts @@ -121,6 +121,7 @@ export const sendOpenAIFIM: _InternalSendLLMFIMMessageFnType = ({ messages, onTe export const sendOpenAIChat: _InternalSendLLMChatMessageFnType = ({ messages, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, providerName }) => { let fullText = '' + const toolCallOfIndex: { [index: string]: { name: string, args: string } } = {} const openai: OpenAI = newOpenAI({ providerName, settingsOfProvider }) const options: OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming = { @@ -137,11 +138,19 @@ export const sendOpenAIChat: _InternalSendLLMChatMessageFnType = ({ messages, on // when receive text for await (const chunk of response) { + // tool call + for (const tool of chunk.choices[0]?.delta?.tool_calls ?? []) { + const index = tool.index + if (!toolCallOfIndex[index]) toolCallOfIndex[index] = { name: '', args: '' } + toolCallOfIndex[index].name += tool.function?.name ?? '' + toolCallOfIndex[index].args += tool.function?.arguments ?? '' + } + + // message let newText = '' - newText += chunk.choices[0]?.delta?.tool_calls?.[0]?.function?.name ?? '' - newText += chunk.choices[0]?.delta?.tool_calls?.[0]?.function?.arguments ?? '' newText += chunk.choices[0]?.delta?.content ?? '' fullText += newText; + onText({ newText, fullText }); } onFinalMessage({ fullText });