diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index f9c50efa..faadd1cd 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -121,11 +121,11 @@ import { normalizeNFC } from '../../base/common/normalization.js'; import { ICSSDevelopmentService, CSSDevelopmentService } from '../../platform/cssDev/node/cssDevService.js'; import { ExtensionSignatureVerificationService, IExtensionSignatureVerificationService } from '../../platform/extensionManagement/node/extensionSignatureVerificationService.js'; -import { LLMMessageChannel } from '../../platform/void/electron-main/llmMessageChannel.js'; -import { IMetricsService } from '../../platform/void/common/metricsService.js'; -import { MetricsMainService } from '../../platform/void/electron-main/metricsMainService.js'; -import { VoidMainUpdateService } from '../../platform/void/electron-main/voidUpdateMainService.js'; -import { IVoidUpdateService } from '../../platform/void/common/voidUpdateService.js'; +import { LLMMessageChannel } from '../../workbench/contrib/void/electron-main/llmMessageChannel.js'; +import { IMetricsService } from '../../workbench/contrib/void/common/metricsService.js'; +import { MetricsMainService } from '../../workbench/contrib/void/electron-main/metricsMainService.js'; +import { VoidMainUpdateService } from '../../workbench/contrib/void/electron-main/voidUpdateMainService.js'; +import { IVoidUpdateService } from '../../workbench/contrib/void/common/voidUpdateService.js'; /** * The main VS Code application. There will only ever be one instance, * even if the user starts many instances (e.g. from the command line). diff --git a/src/vs/platform/void/browser/void.contribution.ts b/src/vs/platform/void/browser/void.contribution.ts deleted file mode 100644 index 276d6e72..00000000 --- a/src/vs/platform/void/browser/void.contribution.ts +++ /dev/null @@ -1,21 +0,0 @@ -/*-------------------------------------------------------------------------------------- - * Copyright 2025 Glass Devtools, Inc. All rights reserved. - * Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information. - *--------------------------------------------------------------------------------------*/ - -// ---------- common ---------- - -// llmMessage -import '../common/llmMessageService.js' - -// voidSettings -import '../common/voidSettingsService.js' - -// refreshModel -import '../common/refreshModelService.js' - -// metrics -import '../common/metricsService.js' - -// updates -import '../common/voidUpdateService.js' diff --git a/src/vs/platform/void/electron-main/llmMessage/greptile.ts b/src/vs/platform/void/electron-main/llmMessage/greptile.ts deleted file mode 100644 index f61f87af..00000000 --- a/src/vs/platform/void/electron-main/llmMessage/greptile.ts +++ /dev/null @@ -1,68 +0,0 @@ -/*-------------------------------------------------------------------------------------- - * Copyright 2025 Glass Devtools, Inc. All rights reserved. - * Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information. - *--------------------------------------------------------------------------------------*/ - -// // Greptile -// // https://docs.greptile.com/api-reference/query -// // https://docs.greptile.com/quickstart#sample-response-streamed - -// import { SendLLMMessageFnTypeInternal } from '../../common/llmMessageTypes.js'; - -// export const sendGreptileMsg: SendLLMMessageFnTypeInternal = ({ messages, onText, onFinalMessage, onError, settingsOfProvider, _setAborter }) => { - -// let fullText = '' - -// const thisConfig = settingsOfProvider.greptile - -// fetch('https://api.greptile.com/v2/query', { -// method: 'POST', -// headers: { -// 'Authorization': `Bearer ${thisConfig.apikey}`, -// 'X-Github-Token': `${thisConfig.githubPAT}`, -// 'Content-Type': `application/json`, -// }, -// body: JSON.stringify({ -// messages, -// stream: true, -// repositories: [thisConfig.repoinfo], -// }), -// }) -// // this is {message}\n{message}\n{message}...\n -// .then(async response => { -// const text = await response.text() -// console.log('got greptile', text) -// return JSON.parse(`[${text.trim().split('\n').join(',')}]`) -// }) -// // TODO make this actually stream, right now it just sends one message at the end -// // TODO add _setAborter() when add streaming -// .then(async responseArr => { - -// for (const response of responseArr) { -// const type: string = response['type'] -// const message = response['message'] - -// // when receive text -// if (type === 'message') { -// fullText += message -// onText({ newText: message, fullText }) -// } -// else if (type === 'sources') { -// const { filepath, linestart: _, lineend: _2 } = message as { filepath: string; linestart: number | null; lineend: number | null } -// fullText += filepath -// onText({ newText: filepath, fullText }) -// } -// // type: 'status' with an empty 'message' means last message -// else if (type === 'status') { -// if (!message) { -// onFinalMessage({ fullText }) -// } -// } -// } - -// }) -// .catch(error => { -// onError({ error }) -// }); - -// } diff --git a/src/vs/workbench/api/browser/mainThreadInlineDiff.ts b/src/vs/workbench/api/browser/mainThreadInlineDiff.ts index 344458f9..d43fc633 100644 --- a/src/vs/workbench/api/browser/mainThreadInlineDiff.ts +++ b/src/vs/workbench/api/browser/mainThreadInlineDiff.ts @@ -14,6 +14,8 @@ import { WorkspaceEdit } from '../../../editor/common/languages.js'; // import { IHistoryService } from '../../services/history/common/history.js'; +// VOID: THIS FILE IS OUTDATED!!!!!! No longer used anywhere. + @extHostNamedCustomer(MainContext.MainThreadInlineDiff) export class MainThreadInlineDiff extends Disposable implements MainThreadInlineDiffShape { diff --git a/src/vs/workbench/contrib/void/browser/autocompleteService.ts b/src/vs/workbench/contrib/void/browser/autocompleteService.ts index 6b67c6be..aa8902f3 100644 --- a/src/vs/workbench/contrib/void/browser/autocompleteService.ts +++ b/src/vs/workbench/contrib/void/browser/autocompleteService.ts @@ -11,7 +11,6 @@ import { Position } from '../../../../editor/common/core/position.js'; import { InlineCompletion, InlineCompletionContext, } from '../../../../editor/common/languages.js'; import { CancellationToken } from '../../../../base/common/cancellation.js'; import { Range } from '../../../../editor/common/core/range.js'; -import { ILLMMessageService } from '../../../../platform/void/common/llmMessageService.js'; import { IEditorService } from '../../../services/editor/common/editorService.js'; import { isCodeEditor } from '../../../../editor/browser/editorBrowser.js'; import { EditorResourceAccessor } from '../../../common/editor.js'; @@ -19,6 +18,7 @@ import { IModelService } from '../../../../editor/common/services/model.js'; import { extractCodeFromRegular } from './helpers/extractCodeFromResult.js'; import { isWindows } from '../../../../base/common/platform.js'; import { registerWorkbenchContribution2, WorkbenchPhase } from '../../../common/contributions.js'; +import { ILLMMessageService } from '../common/llmMessageService.js'; // import { IContextGatheringService } from './contextGatheringService.js'; // The extension this was called from is here - https://github.com/voideditor/void/blob/autocomplete/extensions/void/src/extension/extension.ts @@ -784,8 +784,7 @@ export class AutocompleteService extends Disposable implements IAutocompleteServ _newlineCount: 0, } - console.log('BB') - console.log('type', predictionType) + console.log('starting autocomplete...', predictionType) // set parameters of `newAutocompletion` appropriately newAutocompletion.llmPromise = new Promise((resolve, reject) => { diff --git a/src/vs/workbench/contrib/void/browser/chatThreadService.ts b/src/vs/workbench/contrib/void/browser/chatThreadService.ts index 03683732..a3452eb2 100644 --- a/src/vs/workbench/contrib/void/browser/chatThreadService.ts +++ b/src/vs/workbench/contrib/void/browser/chatThreadService.ts @@ -11,7 +11,7 @@ import { IStorageService, StorageScope, StorageTarget } from '../../../../platfo import { URI } from '../../../../base/common/uri.js'; import { Emitter, Event } from '../../../../base/common/event.js'; import { IRange } from '../../../../editor/common/core/range.js'; -import { ILLMMessageService } from '../../../../platform/void/common/llmMessageService.js'; +import { ILLMMessageService } from '../common/llmMessageService.js'; import { IModelService } from '../../../../editor/common/services/model.js'; import { chat_userMessage, chat_systemMessage } from './prompt/prompts.js'; diff --git a/src/vs/workbench/contrib/void/browser/helpers/readFile.ts b/src/vs/workbench/contrib/void/browser/helpers/readFile.ts index 60e5dc5c..b0f154d1 100644 --- a/src/vs/workbench/contrib/void/browser/helpers/readFile.ts +++ b/src/vs/workbench/contrib/void/browser/helpers/readFile.ts @@ -1,10 +1,17 @@ import { URI } from '../../../../../base/common/uri' import { EndOfLinePreference } from '../../../../../editor/common/model' import { IModelService } from '../../../../../editor/common/services/model.js' +import { IFileService } from '../../../../../platform/files/common/files' -// read files from VSCode +// read files from VSCode. preferred (but appears to only work if the model of this URI already exists. If it doesn't use the other function.) export const VSReadFile = async (modelService: IModelService, uri: URI): Promise => { const model = modelService.getModel(uri) if (!model) return null return model.getValue(EndOfLinePreference.LF) } + +export const VSReadFileRaw = async (fileService: IFileService, uri: URI) => { + const res = await fileService.readFile(uri) + const str = res.value.toString() + return str +} diff --git a/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts b/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts index 546065e8..998a286f 100644 --- a/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts +++ b/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts @@ -26,14 +26,11 @@ import { Widget } from '../../../../base/browser/ui/widget.js'; import { URI } from '../../../../base/common/uri.js'; import { IConsistentEditorItemService, IConsistentItemService } from './helperServices/consistentItemService.js'; import { voidPrefixAndSuffix, ctrlKStream_userMessage, ctrlKStream_systemMessage, fastApply_rewritewholething_userMessage, fastApply_rewritewholething_systemMessage, defaultFimTags, fastApply_searchreplace_systemMessage, fastApply_searchreplace_userMessage } from './prompt/prompts.js'; -import { ILLMMessageService } from '../../../../platform/void/common/llmMessageService.js'; import { mountCtrlK } from '../browser/react/out/quick-edit-tsx/index.js' import { QuickEditPropsType } from './quickEditActions.js'; -import { errorDetails, LLMChatMessage } from '../../../../platform/void/common/llmMessageTypes.js'; import { IModelContentChangedEvent } from '../../../../editor/common/textModelEvents.js'; import { extractCodeFromFIM, extractCodeFromRegular } from './helpers/extractCodeFromResult.js'; -import { IMetricsService } from '../../../../platform/void/common/metricsService.js'; import { filenameToVscodeLanguage } from './helpers/detectLanguage.js'; import { INotificationService, Severity } from '../../../../platform/notification/common/notification.js'; import { isMacintosh } from '../../../../base/common/platform.js'; @@ -41,6 +38,9 @@ import { EditorOption } from '../../../../editor/common/config/editorOptions.js' import { Emitter } from '../../../../base/common/event.js'; import { VOID_OPEN_SETTINGS_ACTION_ID } from './voidSettingsPane.js'; import { ICommandService } from '../../../../platform/commands/common/commands.js'; +import { ILLMMessageService } from '../common/llmMessageService.js'; +import { LLMChatMessage, errorDetails } from '../common/llmMessageTypes.js'; +import { IMetricsService } from '../common/metricsService.js'; const configOfBG = (color: Color) => { return { dark: color, light: color, hcDark: color, hcLight: color, } diff --git a/src/vs/workbench/contrib/void/browser/prompt/prompts.ts b/src/vs/workbench/contrib/void/browser/prompt/prompts.ts index 44e70e44..b3fb4482 100644 --- a/src/vs/workbench/contrib/void/browser/prompt/prompts.ts +++ b/src/vs/workbench/contrib/void/browser/prompt/prompts.ts @@ -10,6 +10,10 @@ import { CodeSelection, StagingSelectionItem, FileSelection } from '../chatThrea import { VSReadFile } from '../helpers/readFile.js'; import { IModelService } from '../../../../../editor/common/services/model.js'; + +// this is just for ease of readability +const tripleTick = ['```', '```'] + export const chat_systemMessage = `\ You are a coding assistant. You are given a list of instructions to follow \`INSTRUCTIONS\`, and optionally a list of relevant files \`FILES\`, and selections inside of files \`SELECTIONS\`. @@ -29,7 +33,7 @@ Do not tell the user anything about the examples below. ## EXAMPLE 1 FILES math.ts -\`\`\`typescript +${tripleTick[0]}typescript const addNumbers = (a, b) => a + b const multiplyNumbers = (a, b) => a * b const subtractNumbers = (a, b) => a - b @@ -58,21 +62,21 @@ const normalized = (vector: number[]) => { const v2 = [...vector] // clone vector return normalize(v2) } -\`\`\` +${tripleTick[1]} SELECTIONS math.ts (lines 3:3) -\`\`\`typescript +${tripleTick[0]}typescript const subtractNumbers = (a, b) => a - b -\`\`\` +${tripleTick[1]} INSTRUCTIONS add a function that exponentiates a number below this, and use it to make a power function that raises all entries of a vector to a power ACCEPTED OUTPUT We can add the following code to the file: -\`\`\`typescript +${tripleTick[0]}typescript // existing code... const subtractNumbers = (a, b) => a - b const exponentiateNumbers = (a, b) => Math.pow(a, b) @@ -84,13 +88,13 @@ const raiseAll = (vector: number[], power: number) => { vector[i] = exponentiateNumbers(vector[i], power) return vector } -\`\`\` +${tripleTick[1]} ## EXAMPLE 2 FILES fib.ts -\`\`\`typescript +${tripleTick[0]}typescript const dfs = (root) => { if (!root) return; @@ -102,20 +106,20 @@ const fib = (n) => { if (n < 1) return 1 return fib(n - 1) + fib(n - 2) } -\`\`\` +${tripleTick[1]} SELECTIONS fib.ts (lines 10:10) -\`\`\`typescript +${tripleTick[0]}typescript return fib(n - 1) + fib(n - 2) -\`\`\` +${tripleTick[1]} INSTRUCTIONS memoize results ACCEPTED OUTPUT To implement memoization in your Fibonacci function, you can use a JavaScript object to store previously computed results. This will help avoid redundant calculations and improve performance. Here's how you can modify your function: -\`\`\`typescript +${tripleTick[0]}typescript // existing code... const fib = (n, memo = {}) => { if (n < 1) return 1; @@ -123,7 +127,7 @@ const fib = (n, memo = {}) => { memo[n] = fib(n - 1, memo) + fib(n - 2, memo); // Store result in memo return memo[n]; } -\`\`\` +${tripleTick[1]} Explanation: Memoization Object: A memo object is used to store the results of Fibonacci calculations for each n. Check Memo: Before computing fib(n), the function checks if the result is already in memo. If it is, it returns the stored result. @@ -133,21 +137,21 @@ Store Result: After computing fib(n), the result is stored in memo for future re ` -type FileSelnLocal = FileSelection & { content: string } -const stringifyFileSelection = ({ fileURI, selectionStr, range, content }: FileSelnLocal) => { +type FileSelnLocal = { fileURI: URI, content: string } +const stringifyFileSelection = ({ fileURI, content }: FileSelnLocal) => { return `\ ${fileURI.fsPath} -\`\`\`${filenameToVscodeLanguage(fileURI.fsPath) ?? ''} +${tripleTick[0]}${filenameToVscodeLanguage(fileURI.fsPath) ?? ''} ${content} -\`\`\` +${tripleTick[1]} ` } const stringifyCodeSelection = ({ fileURI, selectionStr, range }: CodeSelection) => { return `\ ${fileURI.fsPath} (lines ${range.startLineNumber}:${range.endLineNumber}) -\`\`\`${filenameToVscodeLanguage(fileURI.fsPath) ?? ''} +${tripleTick[0]}${filenameToVscodeLanguage(fileURI.fsPath) ?? ''} ${selectionStr} -\`\`\` +${tripleTick[1]} ` } @@ -201,14 +205,14 @@ export const fastApply_rewritewholething_userMessage = ({ originalCode, applyStr return `\ ORIGINAL_FILE -\`\`\`${language} +${tripleTick[0]}${language} ${originalCode} -\`\`\` +${tripleTick[1]} CHANGE -\`\`\` +${tripleTick[0]} ${applyStr} -\`\`\` +${tripleTick[1]} INSTRUCTIONS Please finish writing the new file by applying the change to the original file. Return ONLY the completion of the file, without any explanation. @@ -345,9 +349,9 @@ export const ctrlKStream_userMessage = ({ selection, prefix, suffix, instruction return `\ CURRENT SELECTION -\`\`\`${language} +${tripleTick[0]}${language} <${midTag}>${selection} -\`\`\` +${tripleTick[1]} INSTRUCTIONS ${instructions} @@ -355,8 +359,8 @@ ${instructions} <${preTag}>${prefix} <${sufTag}>${suffix} -Return only the completion block of code (of the form \`\`\`${language} +Return only the completion block of code (of the form ${tripleTick[0]}${language} <${midTag}>...new code -\`\`\`).` +${tripleTick[1]}).` }; diff --git a/src/vs/workbench/contrib/void/browser/quickEditActions.ts b/src/vs/workbench/contrib/void/browser/quickEditActions.ts index 1498c8f6..1a6e0deb 100644 --- a/src/vs/workbench/contrib/void/browser/quickEditActions.ts +++ b/src/vs/workbench/contrib/void/browser/quickEditActions.ts @@ -7,12 +7,12 @@ import { KeyCode, KeyMod } from '../../../../base/common/keyCodes.js'; import { Action2, registerAction2 } from '../../../../platform/actions/common/actions.js'; import { ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js'; import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js'; -import { IMetricsService } from '../../../../platform/void/common/metricsService.js'; import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js'; import { IInlineDiffsService } from './inlineDiffsService.js'; import { roundRangeToLines } from './sidebarActions.js'; import { VOID_CTRL_K_ACTION_ID } from './actionIDs.js'; import { localize2 } from '../../../../nls.js'; +import { IMetricsService } from '../common/metricsService.js'; export type QuickEditPropsType = { diff --git a/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx b/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx index 7edf1e5b..37dd91bf 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx @@ -12,7 +12,7 @@ import { ModelDropdown } from '../void-settings-tsx/ModelDropdown.js'; import { VOID_CTRL_K_ACTION_ID } from '../../../actionIDs.js'; import { useRefState } from '../util/helpers.js'; import { useScrollbarStyles } from '../util/useScrollbarStyles.js'; -import { isFeatureNameDisabled } from '../../../../../../../platform/void/common/voidSettingsTypes.js'; +import { isFeatureNameDisabled } from '../../../../../../../workbench/contrib/void/common/voidSettingsTypes.js'; export const QuickEditChat = ({ diffareaid, diff --git a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/ErrorDisplay.tsx b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/ErrorDisplay.tsx index 425ce3c9..9aef4b72 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/ErrorDisplay.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/ErrorDisplay.tsx @@ -5,7 +5,7 @@ import React, { useEffect, useState } from 'react'; import { AlertCircle, ChevronDown, ChevronUp, X } from 'lucide-react'; -import { errorDetails } from '../../../../../../../platform/void/common/llmMessageTypes.js'; +import { errorDetails } from '../../../../../../../workbench/contrib/void/common/llmMessageTypes.js'; import { useSettingsState } from '../util/services.js'; diff --git a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx index 791eb634..2aaf9dd2 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx @@ -22,7 +22,7 @@ import { VOID_CTRL_L_ACTION_ID } from '../../../actionIDs.js'; import { filenameToVscodeLanguage } from '../../../helpers/detectLanguage.js'; import { VOID_OPEN_SETTINGS_ACTION_ID } from '../../../voidSettingsPane.js'; import { Pencil, X } from 'lucide-react'; -import { FeatureName, isFeatureNameDisabled } from '../../../../../../../platform/void/common/voidSettingsTypes.js'; +import { FeatureName, isFeatureNameDisabled } from '../../../../../../../workbench/contrib/void/common/voidSettingsTypes.js'; import { WarningBox } from '../void-settings-tsx/WarningBox.js'; import { ChatLocation } from '../../../searchAndReplaceService.js'; @@ -708,7 +708,7 @@ const ChatBubble = ({ chatMessage, isLoading, messageIdx }: { chatMessage: ChatM `} > {chatbubbleContents} - {isLoading && } + {isLoading && } {/* edit button */} diff --git a/src/vs/workbench/contrib/void/browser/react/src/util/services.tsx b/src/vs/workbench/contrib/void/browser/react/src/util/services.tsx index e5280c14..52af76f2 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/util/services.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/util/services.tsx @@ -5,14 +5,14 @@ import React, { useState, useEffect } from 'react' import { ThreadStreamState, ThreadsState } from '../../../chatThreadService.js' -import { RefreshableProviderName, SettingsOfProvider } from '../../../../../../../platform/void/common/voidSettingsTypes.js' +import { RefreshableProviderName, SettingsOfProvider } from '../../../../../../../workbench/contrib/void/common/voidSettingsTypes.js' import { IDisposable } from '../../../../../../../base/common/lifecycle.js' import { VoidSidebarState } from '../../../sidebarStateService.js' -import { VoidSettingsState } from '../../../../../../../platform/void/common/voidSettingsService.js' +import { VoidSettingsState } from '../../../../../../../workbench/contrib/void/common/voidSettingsService.js' import { ColorScheme } from '../../../../../../../platform/theme/common/theme.js' import { VoidUriState } from '../../../voidUriStateService.js'; import { VoidQuickEditState } from '../../../quickEditStateService.js' -import { RefreshModelStateOfProvider } from '../../../../../../../platform/void/common/refreshModelService.js' +import { RefreshModelStateOfProvider } from '../../../../../../../workbench/contrib/void/common/refreshModelService.js' @@ -25,9 +25,9 @@ import { IContextViewService, IContextMenuService } from '../../../../../../../p import { IFileService } from '../../../../../../../platform/files/common/files.js'; import { IHoverService } from '../../../../../../../platform/hover/browser/hover.js'; import { IThemeService } from '../../../../../../../platform/theme/common/themeService.js'; -import { ILLMMessageService } from '../../../../../../../platform/void/common/llmMessageService.js'; -import { IRefreshModelService } from '../../../../../../../platform/void/common/refreshModelService.js'; -import { IVoidSettingsService } from '../../../../../../../platform/void/common/voidSettingsService.js'; +import { ILLMMessageService } from '../../../../../../../workbench/contrib/void/common/llmMessageService.js'; +import { IRefreshModelService } from '../../../../../../../workbench/contrib/void/common/refreshModelService.js'; +import { IVoidSettingsService } from '../../../../../../../workbench/contrib/void/common/voidSettingsService.js'; import { IInlineDiffsService } from '../../../inlineDiffsService.js'; import { IVoidUriStateService } from '../../../voidUriStateService.js'; import { IQuickEditStateService } from '../../../quickEditStateService.js'; @@ -46,7 +46,7 @@ import { IKeybindingService } from '../../../../../../../platform/keybinding/com import { IEnvironmentService } from '../../../../../../../platform/environment/common/environment.js' import { IConfigurationService } from '../../../../../../../platform/configuration/common/configuration.js' import { IPathService } from '../../../../../../../workbench/services/path/common/pathService.js' -import { IMetricsService } from '../../../../../../../platform/void/common/metricsService.js' +import { IMetricsService } from '../../../../../../../workbench/contrib/void/common/metricsService.js' diff --git a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx index 8016b4b8..2931b671 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx @@ -4,13 +4,13 @@ *--------------------------------------------------------------------------------------*/ import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { FeatureName, featureNames, isFeatureNameDisabled, ModelSelection, modelSelectionsEqual, ProviderName, providerNames, SettingsOfProvider } from '../../../../../../../platform/void/common/voidSettingsTypes.js' +import { FeatureName, featureNames, isFeatureNameDisabled, ModelSelection, modelSelectionsEqual, ProviderName, providerNames, SettingsOfProvider } from '../../../../../../../workbench/contrib/void/common/voidSettingsTypes.js' import { useSettingsState, useRefreshModelState, useAccessor } from '../util/services.js' import { _VoidSelectBox, VoidCustomDropdownBox } from '../util/inputs.js' import { SelectBox } from '../../../../../../../base/browser/ui/selectBox/selectBox.js' import { IconWarning } from '../sidebar-tsx/SidebarChat.js' import { VOID_OPEN_SETTINGS_ACTION_ID, VOID_TOGGLE_SETTINGS_ACTION_ID } from '../../../voidSettingsPane.js' -import { ModelOption } from '../../../../../../../platform/void/common/voidSettingsService.js' +import { ModelOption } from '../../../../../../../workbench/contrib/void/common/voidSettingsService.js' import { WarningBox } from './WarningBox.js' const optionsEqual = (m1: ModelOption[], m2: ModelOption[]) => { diff --git a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/Settings.tsx b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/Settings.tsx index 0cd796e4..62511563 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/Settings.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/Settings.tsx @@ -5,7 +5,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { InputBox } from '../../../../../../../base/browser/ui/inputbox/inputBox.js' -import { ProviderName, SettingName, displayInfoOfSettingName, providerNames, VoidModelInfo, globalSettingNames, customSettingNamesOfProvider, RefreshableProviderName, refreshableProviderNames, displayInfoOfProviderName, defaultProviderSettings, nonlocalProviderNames, localProviderNames, GlobalSettingName, featureNames, displayInfoOfFeatureName, isProviderNameDisabled } from '../../../../../../../platform/void/common/voidSettingsTypes.js' +import { ProviderName, SettingName, displayInfoOfSettingName, providerNames, VoidModelInfo, globalSettingNames, customSettingNamesOfProvider, RefreshableProviderName, refreshableProviderNames, displayInfoOfProviderName, defaultProviderSettings, nonlocalProviderNames, localProviderNames, GlobalSettingName, featureNames, displayInfoOfFeatureName, isProviderNameDisabled } from '../../../../common/voidSettingsTypes.js' import ErrorBoundary from '../sidebar-tsx/ErrorBoundary.js' import { VoidButton, VoidCheckBox, VoidCustomDropdownBox, VoidInputBox, VoidInputBox2, VoidSwitch } from '../util/inputs.js' import { useAccessor, useIsDark, useRefreshModelListener, useRefreshModelState, useSettingsState } from '../util/services.js' diff --git a/src/vs/workbench/contrib/void/browser/sidebarActions.ts b/src/vs/workbench/contrib/void/browser/sidebarActions.ts index 0b60ae8f..d65c51a7 100644 --- a/src/vs/workbench/contrib/void/browser/sidebarActions.ts +++ b/src/vs/workbench/contrib/void/browser/sidebarActions.ts @@ -17,7 +17,7 @@ import { ICodeEditorService } from '../../../../editor/browser/services/codeEdit import { IRange } from '../../../../editor/common/core/range.js'; import { ITextModel } from '../../../../editor/common/model.js'; import { VOID_VIEW_CONTAINER_ID, VOID_VIEW_ID } from './sidebarPane.js'; -import { IMetricsService } from '../../../../platform/void/common/metricsService.js'; +import { IMetricsService } from '../common/metricsService.js'; import { ISidebarStateService } from './sidebarStateService.js'; import { ICommandService } from '../../../../platform/commands/common/commands.js'; import { VOID_TOGGLE_SETTINGS_ACTION_ID } from './voidSettingsPane.js'; diff --git a/src/vs/workbench/contrib/void/browser/void.contribution.ts b/src/vs/workbench/contrib/void/browser/void.contribution.ts index 110a5a26..19d20201 100644 --- a/src/vs/workbench/contrib/void/browser/void.contribution.ts +++ b/src/vs/workbench/contrib/void/browser/void.contribution.ts @@ -33,3 +33,26 @@ import './media/void.css' // update (frontend part, also see platform/) import './voidUpdateActions.js' + + + + +// ---------- common (unclear if these actually need to be imported, because they're already imported wherever they're used) ---------- + +// llmMessage +import '../common/llmMessageService.js' + +// voidSettings +import '../common/voidSettingsService.js' + +// refreshModel +import '../common/refreshModelService.js' + +// metrics +import '../common/metricsService.js' + +// updates +import '../common/voidUpdateService.js' + +// tools +import '../common/toolsService.js' diff --git a/src/vs/workbench/contrib/void/browser/voidUpdateActions.ts b/src/vs/workbench/contrib/void/browser/voidUpdateActions.ts index 04b263b4..9d161b4e 100644 --- a/src/vs/workbench/contrib/void/browser/voidUpdateActions.ts +++ b/src/vs/workbench/contrib/void/browser/voidUpdateActions.ts @@ -9,8 +9,8 @@ import { ServicesAccessor } from '../../../../editor/browser/editorExtensions.js import { localize2 } from '../../../../nls.js'; import { Action2, registerAction2 } from '../../../../platform/actions/common/actions.js'; import { INotificationService } from '../../../../platform/notification/common/notification.js'; -import { IMetricsService } from '../../../../platform/void/common/metricsService.js'; -import { IVoidUpdateService } from '../../../../platform/void/common/voidUpdateService.js'; +import { IMetricsService } from '../common/metricsService.js'; +import { IVoidUpdateService } from '../common/voidUpdateService.js'; import { IWorkbenchContribution, registerWorkbenchContribution2, WorkbenchPhase } from '../../../common/contributions.js'; diff --git a/src/vs/platform/void/common/llmMessageService.ts b/src/vs/workbench/contrib/void/common/llmMessageService.ts similarity index 93% rename from src/vs/platform/void/common/llmMessageService.ts rename to src/vs/workbench/contrib/void/common/llmMessageService.ts index 4718e6c2..314031d4 100644 --- a/src/vs/platform/void/common/llmMessageService.ts +++ b/src/vs/workbench/contrib/void/common/llmMessageService.ts @@ -4,13 +4,14 @@ *--------------------------------------------------------------------------------------*/ import { EventLLMMessageOnTextParams, EventLLMMessageOnErrorParams, EventLLMMessageOnFinalMessageParams, ServiceSendLLMMessageParams, MainSendLLMMessageParams, MainLLMMessageAbortParams, ServiceModelListParams, EventModelListOnSuccessParams, EventModelListOnErrorParams, MainModelListParams, OllamaModelResponse, OpenaiCompatibleModelResponse, } from './llmMessageTypes.js'; -import { IChannel } from '../../../base/parts/ipc/common/ipc.js'; -import { IMainProcessService } from '../../ipc/common/mainProcessService.js'; -import { InstantiationType, registerSingleton } from '../../instantiation/common/extensions.js'; -import { generateUuid } from '../../../base/common/uuid.js'; -import { createDecorator } from '../../instantiation/common/instantiation.js'; -import { Event } from '../../../base/common/event.js'; -import { Disposable } from '../../../base/common/lifecycle.js'; + +import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js'; +import { registerSingleton, InstantiationType } from '../../../../platform/instantiation/common/extensions.js'; +import { IChannel } from '../../../../base/parts/ipc/common/ipc.js'; +import { IMainProcessService } from '../../../../platform/ipc/common/mainProcessService.js'; +import { generateUuid } from '../../../../base/common/uuid.js'; +import { Event } from '../../../../base/common/event.js'; +import { Disposable } from '../../../../base/common/lifecycle.js'; import { IVoidSettingsService } from './voidSettingsService.js'; import { displayInfoOfProviderName, isFeatureNameDisabled } from './voidSettingsTypes.js'; // import { INotificationService } from '../../notification/common/notification.js'; diff --git a/src/vs/platform/void/common/llmMessageTypes.ts b/src/vs/workbench/contrib/void/common/llmMessageTypes.ts similarity index 100% rename from src/vs/platform/void/common/llmMessageTypes.ts rename to src/vs/workbench/contrib/void/common/llmMessageTypes.ts diff --git a/src/vs/platform/void/common/metricsService.ts b/src/vs/workbench/contrib/void/common/metricsService.ts similarity index 74% rename from src/vs/platform/void/common/metricsService.ts rename to src/vs/workbench/contrib/void/common/metricsService.ts index a3aeb6a8..d6892dd8 100644 --- a/src/vs/platform/void/common/metricsService.ts +++ b/src/vs/workbench/contrib/void/common/metricsService.ts @@ -3,14 +3,14 @@ * Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information. *--------------------------------------------------------------------------------------*/ -import { createDecorator } from '../../instantiation/common/instantiation.js'; -import { ProxyChannel } from '../../../base/parts/ipc/common/ipc.js'; -import { IMainProcessService } from '../../ipc/common/mainProcessService.js'; -import { InstantiationType, registerSingleton } from '../../instantiation/common/extensions.js'; -import { Action2, registerAction2 } from '../../actions/common/actions.js'; -import { localize2 } from '../../../nls.js'; -import { ServicesAccessor } from '../../../editor/browser/editorExtensions.js'; -import { INotificationService } from '../../notification/common/notification.js'; +import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js'; +import { ProxyChannel } from '../../../../base/parts/ipc/common/ipc.js'; +import { registerSingleton, InstantiationType } from '../../../../platform/instantiation/common/extensions.js'; +import { IMainProcessService } from '../../../../platform/ipc/common/mainProcessService.js'; +import { localize2 } from '../../../../nls.js'; +import { ServicesAccessor } from '../../../../editor/browser/editorExtensions.js'; +import { registerAction2, Action2 } from '../../../../platform/actions/common/actions.js'; +import { INotificationService } from '../../../../platform/notification/common/notification.js'; export interface IMetricsService { readonly _serviceBrand: undefined; diff --git a/src/vs/platform/void/common/refreshModelService.ts b/src/vs/workbench/contrib/void/common/refreshModelService.ts similarity index 95% rename from src/vs/platform/void/common/refreshModelService.ts rename to src/vs/workbench/contrib/void/common/refreshModelService.ts index 7ef6a068..ff61e8a8 100644 --- a/src/vs/platform/void/common/refreshModelService.ts +++ b/src/vs/workbench/contrib/void/common/refreshModelService.ts @@ -3,14 +3,14 @@ * Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information. *--------------------------------------------------------------------------------------*/ -import { createDecorator } from '../../instantiation/common/instantiation.js'; -import { InstantiationType, registerSingleton } from '../../instantiation/common/extensions.js'; import { IVoidSettingsService } from './voidSettingsService.js'; import { ILLMMessageService } from './llmMessageService.js'; -import { Emitter, Event } from '../../../base/common/event.js'; -import { Disposable, IDisposable } from '../../../base/common/lifecycle.js'; +import { Emitter, Event } from '../../../../base/common/event.js'; +import { Disposable, IDisposable } from '../../../../base/common/lifecycle.js'; import { RefreshableProviderName, refreshableProviderNames, SettingsOfProvider } from './voidSettingsTypes.js'; import { OllamaModelResponse, OpenaiCompatibleModelResponse } from './llmMessageTypes.js'; +import { registerSingleton, InstantiationType } from '../../../../platform/instantiation/common/extensions.js'; +import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js'; diff --git a/src/vs/workbench/contrib/void/common/toolsService.ts b/src/vs/workbench/contrib/void/common/toolsService.ts new file mode 100644 index 00000000..8ffd6b9b --- /dev/null +++ b/src/vs/workbench/contrib/void/common/toolsService.ts @@ -0,0 +1,182 @@ +import { CancellationToken } from '../../../../base/common/cancellation.js' +import { URI } from '../../../../base/common/uri.js' +import { IFileService, IFileStat } from '../../../../platform/files/common/files.js' +import { registerSingleton, InstantiationType } from '../../../../platform/instantiation/common/extensions.js' +import { createDecorator, IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js' +import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.js' +import { VSReadFileRaw } from '../../../../workbench/contrib/void/browser/helpers/readFile.js' +import { QueryBuilder } from '../../../../workbench/services/search/common/queryBuilder.js' +import { ISearchService } from '../../../../workbench/services/search/common/search.js' + + +// tool use for AI + + + +// we do this using Anthropic's style and convert to OpenAI style later +export type InternalToolInfo = { + description: string, + params: { + [paramName: string]: { type: string, description: string | undefined } // name -> type + }, + required: string[], // required paramNames +} + +// helper +const pagination = { + desc: `Very large results may be paginated (indicated in the result). Pagination fails gracefully if out of bounds or invalid page number.`, + param: { pageNumber: { type: 'number', description: 'The page number (optional, default is 1).' }, } +} as const + +export const contextTools = { + read_file: { + description: 'Returns file contents of a given URI.', + params: { + uri: { type: 'string', description: undefined }, + }, + required: ['uri'], + }, + + list_dir: { + description: `Returns all file names and folder names in a given URI. ${pagination.desc}`, + params: { + uri: { type: 'string', description: undefined }, + ...pagination.param + }, + required: ['uri'], + }, + + pathname_search: { + description: `Returns all pathnames that match a given grep query. You should use this when looking for a file with a specific name or path. This does NOT search file content. ${pagination.desc}`, + params: { + query: { type: 'string', description: undefined }, + ...pagination.param, + }, + required: ['query'] + }, + + 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. ${pagination.desc}`, + params: { + query: { type: 'string', description: undefined }, + ...pagination.param, + }, + required: ['query'], + }, + + // semantic_search: { + // description: 'Searches files semantically for the given string query.', + // // RAG + // }, + +} as const satisfies { [name: string]: InternalToolInfo } + +export type ContextToolName = keyof typeof contextTools +type ContextToolParamNames = keyof typeof contextTools[T]['params'] +type ContextToolParams = { [paramName in ContextToolParamNames]: unknown } + +type AllContextToolCallFns = { + [ToolName in ContextToolName]: ((p: (ContextToolParams)) => Promise) +} + + + + + + + +// TODO check to make sure in workspace +// TODO check to make sure is not gitignored + + +async function generateDirectoryTreeMd(fileService: IFileService, rootURI: URI): Promise { + let output = '' + function traverseChildren(children: IFileStat[], depth: number) { + const indentation = ' '.repeat(depth); + for (const child of children) { + output += `${indentation}- ${child.name}\n`; + traverseChildren(child.children ?? [], depth + 1); + } + } + const stat = await fileService.resolve(rootURI, { resolveMetadata: false }); + + // kickstart recursion + output += `${stat.name}\n`; + traverseChildren(stat.children ?? [], 1); + + return output; +} + + +const validateURI = (uriStr: unknown) => { + if (typeof uriStr !== 'string') throw new Error('(uri was not a string)') + const uri = URI.file(uriStr) + return uri +} + +export interface IToolService { + readonly _serviceBrand: undefined; + callContextTool: (toolName: T, params: ContextToolParams) => Promise +} + +export const IToolService = createDecorator('ToolService'); + +export class ToolService implements IToolService { + + readonly _serviceBrand: undefined; + + contextToolCallFns: AllContextToolCallFns + + constructor( + @IFileService fileService: IFileService, + @IWorkspaceContextService workspaceContextService: IWorkspaceContextService, + @ISearchService searchService: ISearchService, + @IInstantiationService instantiationService: IInstantiationService, + ) { + + + const queryBuilder = instantiationService.createInstance(QueryBuilder); + + this.contextToolCallFns = { + read_file: async ({ uri: uriStr }) => { + const uri = validateURI(uriStr) + const fileContents = await VSReadFileRaw(fileService, uri) + return fileContents ?? '(could not read file)' + }, + list_dir: async ({ uri: uriStr }) => { + const uri = validateURI(uriStr) + const treeStr = await generateDirectoryTreeMd(fileService, uri) + return treeStr + }, + pathname_search: async ({ query: queryStr }) => { + if (typeof queryStr !== 'string') return '(Error: query was not a string)' + const query = queryBuilder.file(workspaceContextService.getWorkspace().folders.map(f => f.uri), { filePattern: queryStr, }); + + const data = await searchService.fileSearch(query, CancellationToken.None); + const str = data.results.map(({ resource, results }) => resource.fsPath).join('\n') + return str + }, + search: async ({ query: queryStr }) => { + if (typeof queryStr !== 'string') return '(Error: query was not a string)' + const query = queryBuilder.text({ pattern: queryStr, }, workspaceContextService.getWorkspace().folders.map(f => f.uri)); + + const data = await searchService.textSearch(query, CancellationToken.None); + const str = data.results.map(({ resource, results }) => resource.fsPath).join('\n') + return str + }, + + } + + + + } + + callContextTool: IToolService['callContextTool'] = (toolName, params) => { + return this.contextToolCallFns[toolName](params) + } + + +} + +registerSingleton(IToolService, ToolService, InstantiationType.Eager); + diff --git a/src/vs/platform/void/common/voidSettingsService.ts b/src/vs/workbench/contrib/void/common/voidSettingsService.ts similarity index 95% rename from src/vs/platform/void/common/voidSettingsService.ts rename to src/vs/workbench/contrib/void/common/voidSettingsService.ts index e9c57aa2..4322eaf4 100644 --- a/src/vs/platform/void/common/voidSettingsService.ts +++ b/src/vs/workbench/contrib/void/common/voidSettingsService.ts @@ -3,13 +3,13 @@ * Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information. *--------------------------------------------------------------------------------------*/ -import { Emitter, Event } from '../../../base/common/event.js'; -import { Disposable } from '../../../base/common/lifecycle.js'; -import { deepClone } from '../../../base/common/objects.js'; -import { IEncryptionService } from '../../encryption/common/encryptionService.js'; -import { registerSingleton, InstantiationType } from '../../instantiation/common/extensions.js'; -import { createDecorator } from '../../instantiation/common/instantiation.js'; -import { IStorageService, StorageScope, StorageTarget } from '../../storage/common/storage.js'; +import { Emitter, Event } from '../../../../base/common/event.js'; +import { Disposable } from '../../../../base/common/lifecycle.js'; +import { deepClone } from '../../../../base/common/objects.js'; +import { IEncryptionService } from '../../../../platform/encryption/common/encryptionService.js'; +import { registerSingleton, InstantiationType } from '../../../../platform/instantiation/common/extensions.js'; +import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js'; +import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js'; import { IMetricsService } from './metricsService.js'; import { defaultSettingsOfProvider, FeatureName, ProviderName, ModelSelectionOfFeature, SettingsOfProvider, SettingName, providerNames, ModelSelection, modelSelectionsEqual, featureNames, modelInfoOfDefaultModelNames, VoidModelInfo, GlobalSettings, GlobalSettingName, defaultGlobalSettings, displayInfoOfProviderName, defaultProviderSettings } from './voidSettingsTypes.js'; diff --git a/src/vs/platform/void/common/voidSettingsTypes.ts b/src/vs/workbench/contrib/void/common/voidSettingsTypes.ts similarity index 99% rename from src/vs/platform/void/common/voidSettingsTypes.ts rename to src/vs/workbench/contrib/void/common/voidSettingsTypes.ts index c9eadefd..0a5bdc64 100644 --- a/src/vs/platform/void/common/voidSettingsTypes.ts +++ b/src/vs/workbench/contrib/void/common/voidSettingsTypes.ts @@ -253,7 +253,7 @@ export const displayInfoOfProviderName = (providerName: ProviderName): DisplayIn } else if (providerName === 'groq') { return { - title: 'Groq API', + title: 'Groq.com API', } } else if (providerName === 'mistral') { diff --git a/src/vs/platform/void/common/voidUpdateService.ts b/src/vs/workbench/contrib/void/common/voidUpdateService.ts similarity index 78% rename from src/vs/platform/void/common/voidUpdateService.ts rename to src/vs/workbench/contrib/void/common/voidUpdateService.ts index fd3467dd..f552594f 100644 --- a/src/vs/platform/void/common/voidUpdateService.ts +++ b/src/vs/workbench/contrib/void/common/voidUpdateService.ts @@ -3,10 +3,10 @@ * Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information. *--------------------------------------------------------------------------------------*/ -import { createDecorator } from '../../instantiation/common/instantiation.js'; -import { ProxyChannel } from '../../../base/parts/ipc/common/ipc.js'; -import { IMainProcessService } from '../../ipc/common/mainProcessService.js'; -import { InstantiationType, registerSingleton } from '../../instantiation/common/extensions.js'; +import { ProxyChannel } from '../../../../base/parts/ipc/common/ipc.js'; +import { registerSingleton, InstantiationType } from '../../../../platform/instantiation/common/extensions.js'; +import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js'; +import { IMainProcessService } from '../../../../platform/ipc/common/mainProcessService.js'; diff --git a/src/vs/platform/void/electron-main/llmMessage/anthropic.ts b/src/vs/workbench/contrib/void/electron-main/llmMessage/anthropic.ts similarity index 84% rename from src/vs/platform/void/electron-main/llmMessage/anthropic.ts rename to src/vs/workbench/contrib/void/electron-main/llmMessage/anthropic.ts index ea220eed..91461b16 100644 --- a/src/vs/platform/void/electron-main/llmMessage/anthropic.ts +++ b/src/vs/workbench/contrib/void/electron-main/llmMessage/anthropic.ts @@ -6,6 +6,27 @@ import Anthropic from '@anthropic-ai/sdk'; import { _InternalSendLLMChatMessageFnType } from '../../common/llmMessageTypes.js'; import { anthropicMaxPossibleTokens } from '../../common/voidSettingsTypes.js'; +import { InternalToolInfo } from '../../common/toolsService.js'; + + + + +export const toAnthropicTool = (toolName: string, toolInfo: InternalToolInfo) => { + const { description, params, required } = toolInfo + return { + name: toolName, + description: description, + input_schema: { + type: 'object', + properties: params, + required: required, + } + } satisfies Anthropic.Messages.Tool +} + + + + export const sendAnthropicChat: _InternalSendLLMChatMessageFnType = ({ messages, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter }) => { diff --git a/src/vs/platform/void/electron-main/llmMessage/gemini.ts b/src/vs/workbench/contrib/void/electron-main/llmMessage/gemini.ts similarity index 100% rename from src/vs/platform/void/electron-main/llmMessage/gemini.ts rename to src/vs/workbench/contrib/void/electron-main/llmMessage/gemini.ts diff --git a/src/vs/platform/void/electron-main/llmMessage/groq.ts b/src/vs/workbench/contrib/void/electron-main/llmMessage/groq.ts similarity index 93% rename from src/vs/platform/void/electron-main/llmMessage/groq.ts rename to src/vs/workbench/contrib/void/electron-main/llmMessage/groq.ts index b8c29981..8f7efd14 100644 --- a/src/vs/platform/void/electron-main/llmMessage/groq.ts +++ b/src/vs/workbench/contrib/void/electron-main/llmMessage/groq.ts @@ -22,8 +22,6 @@ export const sendGroqChat: _InternalSendLLMChatMessageFnType = async ({ messages messages: messages, model: modelName, stream: true, - // temperature: 0.7, - // max_tokens: parseMaxTokensStr(thisConfig.maxTokens), }) .then(async response => { _setAborter(() => response.controller.abort()) diff --git a/src/vs/platform/void/electron-main/llmMessage/mistral.ts b/src/vs/workbench/contrib/void/electron-main/llmMessage/mistral.ts similarity index 97% rename from src/vs/platform/void/electron-main/llmMessage/mistral.ts rename to src/vs/workbench/contrib/void/electron-main/llmMessage/mistral.ts index 8fddaf2e..cfddc2a5 100644 --- a/src/vs/platform/void/electron-main/llmMessage/mistral.ts +++ b/src/vs/workbench/contrib/void/electron-main/llmMessage/mistral.ts @@ -21,8 +21,6 @@ export const sendMistralChat: _InternalSendLLMChatMessageFnType = async ({ messa messages: messages, model: modelName, stream: true, - // temperature: 0.7, - // maxTokens: 2048, }) .then(async response => { // Mistral has a really nonstandard API - no interrupt and weird stream types diff --git a/src/vs/platform/void/electron-main/llmMessage/ollama.ts b/src/vs/workbench/contrib/void/electron-main/llmMessage/ollama.ts similarity index 100% rename from src/vs/platform/void/electron-main/llmMessage/ollama.ts rename to src/vs/workbench/contrib/void/electron-main/llmMessage/ollama.ts diff --git a/src/vs/platform/void/electron-main/llmMessage/openai.ts b/src/vs/workbench/contrib/void/electron-main/llmMessage/openai.ts similarity index 75% rename from src/vs/platform/void/electron-main/llmMessage/openai.ts rename to src/vs/workbench/contrib/void/electron-main/llmMessage/openai.ts index 268eadfb..df4d2322 100644 --- a/src/vs/platform/void/electron-main/llmMessage/openai.ts +++ b/src/vs/workbench/contrib/void/electron-main/llmMessage/openai.ts @@ -6,43 +6,34 @@ import OpenAI from 'openai'; import { _InternalModelListFnType, _InternalSendLLMFIMMessageFnType, _InternalSendLLMChatMessageFnType } from '../../common/llmMessageTypes.js'; import { Model } from 'openai/resources/models.js'; +import { InternalToolInfo } from '../../common/toolsService.js'; // import { parseMaxTokensStr } from './util.js'; +// developer command - https://cdn.openai.com/spec/model-spec-2024-05-08.html#follow-the-chain-of-command +// prompting - https://platform.openai.com/docs/guides/reasoning#advice-on-prompting -export const openaiCompatibleList: _InternalModelListFnType = async ({ onSuccess: onSuccess_, onError: onError_, settingsOfProvider }) => { - const onSuccess = ({ models }: { models: Model[] }) => { - onSuccess_({ models }) - } - const onError = ({ error }: { error: string }) => { - onError_({ error }) - } - - try { - const thisConfig = settingsOfProvider.openAICompatible - const openai = new OpenAI({ baseURL: thisConfig.endpoint, apiKey: thisConfig.apiKey, dangerouslyAllowBrowser: true }) - - openai.models.list() - .then(async (response) => { - const models: Model[] = [] - models.push(...response.data) - while (response.hasNextPage()) { - models.push(...(await response.getNextPage()).data) - } - onSuccess({ models }) - }) - .catch((error) => { - onError({ error: error + '' }) - }) - } - catch (error) { - onError({ error: error + '' }) - } +export const toOpenAITool = (toolName: string, toolInfo: InternalToolInfo) => { + const { description, params, required } = toolInfo + return { + type: 'function', + function: { + name: toolName, + description: description, + parameters: { + type: 'object', + properties: params, + required: required, + } + } + } satisfies OpenAI.Chat.Completions.ChatCompletionTool } + + type NewParams = Pick[0] & Parameters<_InternalSendLLMFIMMessageFnType>[0], 'settingsOfProvider' | 'providerName'> const newOpenAI = ({ settingsOfProvider, providerName }: NewParams) => { @@ -81,26 +72,46 @@ const newOpenAI = ({ settingsOfProvider, providerName }: NewParams) => { +// might not currently be used in the code +export const openaiCompatibleList: _InternalModelListFnType = async ({ onSuccess: onSuccess_, onError: onError_, settingsOfProvider }) => { + const onSuccess = ({ models }: { models: Model[] }) => { + onSuccess_({ models }) + } + + const onError = ({ error }: { error: string }) => { + onError_({ error }) + } + + try { + const openai = newOpenAI({ providerName: 'openAICompatible', settingsOfProvider }) + + openai.models.list() + .then(async (response) => { + const models: Model[] = [] + models.push(...response.data) + while (response.hasNextPage()) { + models.push(...(await response.getNextPage()).data) + } + onSuccess({ models }) + }) + .catch((error) => { + onError({ error: error + '' }) + }) + } + catch (error) { + onError({ error: error + '' }) + } +} + + + + export const sendOpenAIFIM: _InternalSendLLMFIMMessageFnType = ({ messages, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, providerName }) => { - const openai: OpenAI = newOpenAI({ providerName, settingsOfProvider }) + // openai.completions has a FIM parameter called `suffix`, but it's deprecated and only works for ~GPT 3 era models - const options: OpenAI.Completions.CompletionCreateParamsStreaming = { - prompt: messages.prefix, - suffix: messages.suffix, - model: modelName, - stream: true, - // max_completion_tokens: parseMaxTokensStr(thisConfig.maxTokens) - } - - - openai.completions - .create(options) - .then(async response => { - // TODO!!! - console.log('RESPONSE', response) - }) + onFinalMessage({ fullText: 'TODO' }) } @@ -116,7 +127,7 @@ export const sendOpenAIChat: _InternalSendLLMChatMessageFnType = ({ messages, on model: modelName, messages: messages, stream: true, - // max_completion_tokens: parseMaxTokensStr(thisConfig.maxTokens) + // tools: Object.keys(contextTools).map(name => toOpenAITool(name, contextTools[name as ContextToolName])), } openai.chat.completions @@ -125,7 +136,11 @@ export const sendOpenAIChat: _InternalSendLLMChatMessageFnType = ({ messages, on _setAborter(() => response.controller.abort()) // when receive text for await (const chunk of response) { - const newText = chunk.choices[0]?.delta?.content || ''; + + 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 }); } diff --git a/src/vs/platform/void/electron-main/llmMessage/sendLLMMessage.ts b/src/vs/workbench/contrib/void/electron-main/llmMessage/sendLLMMessage.ts similarity index 85% rename from src/vs/platform/void/electron-main/llmMessage/sendLLMMessage.ts rename to src/vs/workbench/contrib/void/electron-main/llmMessage/sendLLMMessage.ts index 7cea9d5a..1364e251 100644 --- a/src/vs/platform/void/electron-main/llmMessage/sendLLMMessage.ts +++ b/src/vs/workbench/contrib/void/electron-main/llmMessage/sendLLMMessage.ts @@ -8,7 +8,7 @@ import { IMetricsService } from '../../common/metricsService.js'; import { sendAnthropicChat } from './anthropic.js'; import { sendOllamaFIM, sendOllamaChat } from './ollama.js'; -import { sendOpenAIChat } from './openai.js'; +import { sendOpenAIChat, sendOpenAIFIM } from './openai.js'; import { sendGeminiChat } from './gemini.js'; import { sendGroqChat } from './groq.js'; import { sendMistralChat } from './mistral.js'; @@ -65,9 +65,14 @@ export const sendLLMMessage = ({ metricsService: IMetricsService ) => { - // messages.unshift({ role: 'system', content: aiInstructions }) - const messagesArr = messagesType === 'chatMessages' ? cleanChatMessages(messages_) : [] + let messagesArr: _InternalLLMChatMessage[] = [] + if (messagesType === 'chatMessages') { + messagesArr = cleanChatMessages([ + { role: 'system', content: aiInstructions }, + ...messages_ + ]) + } // only captures number of messages and message "shape", no actual code, instructions, prompts, etc const captureLLMEvent = (eventId: string, extras?: object) => { @@ -138,21 +143,16 @@ export const sendLLMMessage = ({ case 'openRouter': case 'deepseek': case 'openAICompatible': - sendOpenAIChat({ messages: messagesArr, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, providerName }); + if (messagesType === 'FIMMessage') sendOpenAIFIM({ messages: messages_, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, providerName }); + else /* */ sendOpenAIChat({ messages: messagesArr, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, providerName }); + break; + case 'ollama': + if (messagesType === 'FIMMessage') sendOllamaFIM({ messages: messages_, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, providerName }) + else /* */ sendOllamaChat({ messages: messagesArr, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, providerName }) break; case 'gemini': sendGeminiChat({ messages: messagesArr, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, providerName }); break; - case 'ollama': - if ( // TODO @andrew in future we want to use our own templates instead of using ollamaFIM - messagesType === 'FIMMessage' - && settingsOfProvider['ollama']._didFillInProviderSettings - && settingsOfProvider['ollama'].models.some(m => !m.isHidden) - ) - sendOllamaFIM({ messages: messages_, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, providerName }) - else - sendOllamaChat({ messages: messagesArr, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, providerName }); - break; case 'groq': sendGroqChat({ messages: messagesArr, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, providerName }); break; diff --git a/src/vs/platform/void/electron-main/llmMessageChannel.ts b/src/vs/workbench/contrib/void/electron-main/llmMessageChannel.ts similarity index 95% rename from src/vs/platform/void/electron-main/llmMessageChannel.ts rename to src/vs/workbench/contrib/void/electron-main/llmMessageChannel.ts index 2c44e2ec..98725631 100644 --- a/src/vs/platform/void/electron-main/llmMessageChannel.ts +++ b/src/vs/workbench/contrib/void/electron-main/llmMessageChannel.ts @@ -6,8 +6,8 @@ // registered in app.ts // code convention is to make a service responsible for this stuff, and not a channel, but having fewer files is simpler... -import { IServerChannel } from '../../../base/parts/ipc/common/ipc.js'; -import { Emitter, Event } from '../../../base/common/event.js'; +import { IServerChannel } from '../../../../base/parts/ipc/common/ipc.js'; +import { Emitter, Event } from '../../../../base/common/event.js'; import { EventLLMMessageOnTextParams, EventLLMMessageOnErrorParams, EventLLMMessageOnFinalMessageParams, MainSendLLMMessageParams, AbortRef, SendLLMMessageParams, MainLLMMessageAbortParams, MainModelListParams, ModelListParams, EventModelListOnSuccessParams, EventModelListOnErrorParams, OllamaModelResponse, OpenaiCompatibleModelResponse, } from '../common/llmMessageTypes.js'; import { sendLLMMessage } from './llmMessage/sendLLMMessage.js' import { IMetricsService } from '../common/metricsService.js'; @@ -66,7 +66,7 @@ export class LLMMessageChannel implements IServerChannel { } } - // browser uses this to call + // browser uses this to call (see this.channel.call() in llmMessageService.ts for all usages) async call(_: unknown, command: string, params: any): Promise { try { if (command === 'sendLLMMessage') { diff --git a/src/vs/platform/void/electron-main/metricsMainService.ts b/src/vs/workbench/contrib/void/electron-main/metricsMainService.ts similarity index 86% rename from src/vs/platform/void/electron-main/metricsMainService.ts rename to src/vs/workbench/contrib/void/electron-main/metricsMainService.ts index cd8abf2b..592f79c4 100644 --- a/src/vs/platform/void/electron-main/metricsMainService.ts +++ b/src/vs/workbench/contrib/void/electron-main/metricsMainService.ts @@ -3,14 +3,13 @@ * Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information. *--------------------------------------------------------------------------------------*/ -import { Disposable } from '../../../base/common/lifecycle.js'; -import { isLinux, isMacintosh, isWindows } from '../../../base/common/platform.js'; -import { generateUuid } from '../../../base/common/uuid.js'; -import { IEnvironmentMainService } from '../../environment/electron-main/environmentMainService.js'; - -import { IProductService } from '../../product/common/productService.js'; -import { StorageScope, StorageTarget } from '../../storage/common/storage.js'; -import { IApplicationStorageMainService } from '../../storage/electron-main/storageMainService.js'; +import { Disposable } from '../../../../base/common/lifecycle.js'; +import { isLinux, isMacintosh, isWindows } from '../../../../base/common/platform.js'; +import { generateUuid } from '../../../../base/common/uuid.js'; +import { IEnvironmentMainService } from '../../../../platform/environment/electron-main/environmentMainService.js'; +import { IProductService } from '../../../../platform/product/common/productService.js'; +import { StorageTarget, StorageScope } from '../../../../platform/storage/common/storage.js'; +import { IApplicationStorageMainService } from '../../../../platform/storage/electron-main/storageMainService.js'; import { IMetricsService } from '../common/metricsService.js'; import { PostHog } from 'posthog-node' diff --git a/src/vs/workbench/contrib/void/electron-main/templates/templates.ts b/src/vs/workbench/contrib/void/electron-main/templates/templates.ts new file mode 100644 index 00000000..138f7be3 --- /dev/null +++ b/src/vs/workbench/contrib/void/electron-main/templates/templates.ts @@ -0,0 +1,13 @@ +/* + +modelName -> { + system_message_type: 'system' | 'developer' (openai) | null // if null, we will just do a string of system message + supports_tools: boolean // we will just do a string of tool use if it doesn't support + supports_autocomplete_FIM (suffix) // we will just do a description of FIM if it doens't support <|fim_hole|> + + supports_streaming: boolean // (o1 does NOT) we will just dump the final result if doesn't support it + max_tokens: number // required, DEFAULT is Infinity + +} + +*/ diff --git a/src/vs/platform/void/electron-main/voidUpdateMainService.ts b/src/vs/workbench/contrib/void/electron-main/voidUpdateMainService.ts similarity index 82% rename from src/vs/platform/void/electron-main/voidUpdateMainService.ts rename to src/vs/workbench/contrib/void/electron-main/voidUpdateMainService.ts index 029db5f4..c691ff56 100644 --- a/src/vs/platform/void/electron-main/voidUpdateMainService.ts +++ b/src/vs/workbench/contrib/void/electron-main/voidUpdateMainService.ts @@ -3,10 +3,9 @@ * Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information. *--------------------------------------------------------------------------------------*/ -import { Disposable } from '../../../base/common/lifecycle.js'; -import { IEnvironmentMainService } from '../../environment/electron-main/environmentMainService.js'; - -import { IProductService } from '../../product/common/productService.js'; +import { Disposable } from '../../../../base/common/lifecycle.js'; +import { IEnvironmentMainService } from '../../../../platform/environment/electron-main/environmentMainService.js'; +import { IProductService } from '../../../../platform/product/common/productService.js'; import { IVoidUpdateService } from '../common/voidUpdateService.js'; diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index 14f3fec1..394da127 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -17,7 +17,6 @@ import './browser/workbench.contribution.js'; //#region --- Void // Void added this: import './contrib/void/browser/void.contribution.js'; -import '../platform/void/browser/void.contribution.js'; //#endregion