Merge remote-tracking branch 'origin/model-selection' into edit-chats

This commit is contained in:
Mathew Pareles 2025-02-11 18:44:20 -08:00
commit efeb85b48b
39 changed files with 428 additions and 257 deletions

View file

@ -121,11 +121,11 @@ import { normalizeNFC } from '../../base/common/normalization.js';
import { ICSSDevelopmentService, CSSDevelopmentService } from '../../platform/cssDev/node/cssDevService.js'; import { ICSSDevelopmentService, CSSDevelopmentService } from '../../platform/cssDev/node/cssDevService.js';
import { ExtensionSignatureVerificationService, IExtensionSignatureVerificationService } from '../../platform/extensionManagement/node/extensionSignatureVerificationService.js'; import { ExtensionSignatureVerificationService, IExtensionSignatureVerificationService } from '../../platform/extensionManagement/node/extensionSignatureVerificationService.js';
import { LLMMessageChannel } from '../../platform/void/electron-main/llmMessageChannel.js'; import { LLMMessageChannel } from '../../workbench/contrib/void/electron-main/llmMessageChannel.js';
import { IMetricsService } from '../../platform/void/common/metricsService.js'; import { IMetricsService } from '../../workbench/contrib/void/common/metricsService.js';
import { MetricsMainService } from '../../platform/void/electron-main/metricsMainService.js'; import { MetricsMainService } from '../../workbench/contrib/void/electron-main/metricsMainService.js';
import { VoidMainUpdateService } from '../../platform/void/electron-main/voidUpdateMainService.js'; import { VoidMainUpdateService } from '../../workbench/contrib/void/electron-main/voidUpdateMainService.js';
import { IVoidUpdateService } from '../../platform/void/common/voidUpdateService.js'; import { IVoidUpdateService } from '../../workbench/contrib/void/common/voidUpdateService.js';
/** /**
* The main VS Code application. There will only ever be one instance, * 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). * even if the user starts many instances (e.g. from the command line).

View file

@ -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'

View file

@ -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 })
// });
// }

View file

@ -14,6 +14,8 @@ import { WorkspaceEdit } from '../../../editor/common/languages.js';
// import { IHistoryService } from '../../services/history/common/history.js'; // import { IHistoryService } from '../../services/history/common/history.js';
// VOID: THIS FILE IS OUTDATED!!!!!! No longer used anywhere.
@extHostNamedCustomer(MainContext.MainThreadInlineDiff) @extHostNamedCustomer(MainContext.MainThreadInlineDiff)
export class MainThreadInlineDiff extends Disposable implements MainThreadInlineDiffShape { export class MainThreadInlineDiff extends Disposable implements MainThreadInlineDiffShape {

View file

@ -11,7 +11,6 @@ import { Position } from '../../../../editor/common/core/position.js';
import { InlineCompletion, InlineCompletionContext, } from '../../../../editor/common/languages.js'; import { InlineCompletion, InlineCompletionContext, } from '../../../../editor/common/languages.js';
import { CancellationToken } from '../../../../base/common/cancellation.js'; import { CancellationToken } from '../../../../base/common/cancellation.js';
import { Range } from '../../../../editor/common/core/range.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 { IEditorService } from '../../../services/editor/common/editorService.js';
import { isCodeEditor } from '../../../../editor/browser/editorBrowser.js'; import { isCodeEditor } from '../../../../editor/browser/editorBrowser.js';
import { EditorResourceAccessor } from '../../../common/editor.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 { extractCodeFromRegular } from './helpers/extractCodeFromResult.js';
import { isWindows } from '../../../../base/common/platform.js'; import { isWindows } from '../../../../base/common/platform.js';
import { registerWorkbenchContribution2, WorkbenchPhase } from '../../../common/contributions.js'; import { registerWorkbenchContribution2, WorkbenchPhase } from '../../../common/contributions.js';
import { ILLMMessageService } from '../common/llmMessageService.js';
// import { IContextGatheringService } from './contextGatheringService.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 // 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, _newlineCount: 0,
} }
console.log('BB') console.log('starting autocomplete...', predictionType)
console.log('type', predictionType)
// set parameters of `newAutocompletion` appropriately // set parameters of `newAutocompletion` appropriately
newAutocompletion.llmPromise = new Promise((resolve, reject) => { newAutocompletion.llmPromise = new Promise((resolve, reject) => {

View file

@ -11,7 +11,7 @@ import { IStorageService, StorageScope, StorageTarget } from '../../../../platfo
import { URI } from '../../../../base/common/uri.js'; import { URI } from '../../../../base/common/uri.js';
import { Emitter, Event } from '../../../../base/common/event.js'; import { Emitter, Event } from '../../../../base/common/event.js';
import { IRange } from '../../../../editor/common/core/range.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 { IModelService } from '../../../../editor/common/services/model.js';
import { chat_userMessage, chat_systemMessage } from './prompt/prompts.js'; import { chat_userMessage, chat_systemMessage } from './prompt/prompts.js';

View file

@ -1,10 +1,17 @@
import { URI } from '../../../../../base/common/uri' import { URI } from '../../../../../base/common/uri'
import { EndOfLinePreference } from '../../../../../editor/common/model' import { EndOfLinePreference } from '../../../../../editor/common/model'
import { IModelService } from '../../../../../editor/common/services/model.js' 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<string | null> => { export const VSReadFile = async (modelService: IModelService, uri: URI): Promise<string | null> => {
const model = modelService.getModel(uri) const model = modelService.getModel(uri)
if (!model) return null if (!model) return null
return model.getValue(EndOfLinePreference.LF) 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
}

View file

@ -26,14 +26,11 @@ import { Widget } from '../../../../base/browser/ui/widget.js';
import { URI } from '../../../../base/common/uri.js'; import { URI } from '../../../../base/common/uri.js';
import { IConsistentEditorItemService, IConsistentItemService } from './helperServices/consistentItemService.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 { 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 { mountCtrlK } from '../browser/react/out/quick-edit-tsx/index.js'
import { QuickEditPropsType } from './quickEditActions.js'; import { QuickEditPropsType } from './quickEditActions.js';
import { errorDetails, LLMChatMessage } from '../../../../platform/void/common/llmMessageTypes.js';
import { IModelContentChangedEvent } from '../../../../editor/common/textModelEvents.js'; import { IModelContentChangedEvent } from '../../../../editor/common/textModelEvents.js';
import { extractCodeFromFIM, extractCodeFromRegular } from './helpers/extractCodeFromResult.js'; import { extractCodeFromFIM, extractCodeFromRegular } from './helpers/extractCodeFromResult.js';
import { IMetricsService } from '../../../../platform/void/common/metricsService.js';
import { filenameToVscodeLanguage } from './helpers/detectLanguage.js'; import { filenameToVscodeLanguage } from './helpers/detectLanguage.js';
import { INotificationService, Severity } from '../../../../platform/notification/common/notification.js'; import { INotificationService, Severity } from '../../../../platform/notification/common/notification.js';
import { isMacintosh } from '../../../../base/common/platform.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 { Emitter } from '../../../../base/common/event.js';
import { VOID_OPEN_SETTINGS_ACTION_ID } from './voidSettingsPane.js'; import { VOID_OPEN_SETTINGS_ACTION_ID } from './voidSettingsPane.js';
import { ICommandService } from '../../../../platform/commands/common/commands.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) => { const configOfBG = (color: Color) => {
return { dark: color, light: color, hcDark: color, hcLight: color, } return { dark: color, light: color, hcDark: color, hcLight: color, }

View file

@ -10,6 +10,10 @@ import { CodeSelection, StagingSelectionItem, FileSelection } from '../chatThrea
import { VSReadFile } from '../helpers/readFile.js'; import { VSReadFile } from '../helpers/readFile.js';
import { IModelService } from '../../../../../editor/common/services/model.js'; import { IModelService } from '../../../../../editor/common/services/model.js';
// this is just for ease of readability
const tripleTick = ['```', '```']
export const chat_systemMessage = `\ 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\`. 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 ## EXAMPLE 1
FILES FILES
math.ts math.ts
\`\`\`typescript ${tripleTick[0]}typescript
const addNumbers = (a, b) => a + b const addNumbers = (a, b) => a + b
const multiplyNumbers = (a, b) => a * b const multiplyNumbers = (a, b) => a * b
const subtractNumbers = (a, b) => a - b const subtractNumbers = (a, b) => a - b
@ -58,21 +62,21 @@ const normalized = (vector: number[]) => {
const v2 = [...vector] // clone vector const v2 = [...vector] // clone vector
return normalize(v2) return normalize(v2)
} }
\`\`\` ${tripleTick[1]}
SELECTIONS SELECTIONS
math.ts (lines 3:3) math.ts (lines 3:3)
\`\`\`typescript ${tripleTick[0]}typescript
const subtractNumbers = (a, b) => a - b const subtractNumbers = (a, b) => a - b
\`\`\` ${tripleTick[1]}
INSTRUCTIONS 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 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 ACCEPTED OUTPUT
We can add the following code to the file: We can add the following code to the file:
\`\`\`typescript ${tripleTick[0]}typescript
// existing code... // existing code...
const subtractNumbers = (a, b) => a - b const subtractNumbers = (a, b) => a - b
const exponentiateNumbers = (a, b) => Math.pow(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) vector[i] = exponentiateNumbers(vector[i], power)
return vector return vector
} }
\`\`\` ${tripleTick[1]}
## EXAMPLE 2 ## EXAMPLE 2
FILES FILES
fib.ts fib.ts
\`\`\`typescript ${tripleTick[0]}typescript
const dfs = (root) => { const dfs = (root) => {
if (!root) return; if (!root) return;
@ -102,20 +106,20 @@ const fib = (n) => {
if (n < 1) return 1 if (n < 1) return 1
return fib(n - 1) + fib(n - 2) return fib(n - 1) + fib(n - 2)
} }
\`\`\` ${tripleTick[1]}
SELECTIONS SELECTIONS
fib.ts (lines 10:10) fib.ts (lines 10:10)
\`\`\`typescript ${tripleTick[0]}typescript
return fib(n - 1) + fib(n - 2) return fib(n - 1) + fib(n - 2)
\`\`\` ${tripleTick[1]}
INSTRUCTIONS INSTRUCTIONS
memoize results memoize results
ACCEPTED OUTPUT 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: 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... // existing code...
const fib = (n, memo = {}) => { const fib = (n, memo = {}) => {
if (n < 1) return 1; 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 memo[n] = fib(n - 1, memo) + fib(n - 2, memo); // Store result in memo
return memo[n]; return memo[n];
} }
\`\`\` ${tripleTick[1]}
Explanation: Explanation:
Memoization Object: A memo object is used to store the results of Fibonacci calculations for each n. 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. 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 } type FileSelnLocal = { fileURI: URI, content: string }
const stringifyFileSelection = ({ fileURI, selectionStr, range, content }: FileSelnLocal) => { const stringifyFileSelection = ({ fileURI, content }: FileSelnLocal) => {
return `\ return `\
${fileURI.fsPath} ${fileURI.fsPath}
\`\`\`${filenameToVscodeLanguage(fileURI.fsPath) ?? ''} ${tripleTick[0]}${filenameToVscodeLanguage(fileURI.fsPath) ?? ''}
${content} ${content}
\`\`\` ${tripleTick[1]}
` `
} }
const stringifyCodeSelection = ({ fileURI, selectionStr, range }: CodeSelection) => { const stringifyCodeSelection = ({ fileURI, selectionStr, range }: CodeSelection) => {
return `\ return `\
${fileURI.fsPath} (lines ${range.startLineNumber}:${range.endLineNumber}) ${fileURI.fsPath} (lines ${range.startLineNumber}:${range.endLineNumber})
\`\`\`${filenameToVscodeLanguage(fileURI.fsPath) ?? ''} ${tripleTick[0]}${filenameToVscodeLanguage(fileURI.fsPath) ?? ''}
${selectionStr} ${selectionStr}
\`\`\` ${tripleTick[1]}
` `
} }
@ -201,14 +205,14 @@ export const fastApply_rewritewholething_userMessage = ({ originalCode, applyStr
return `\ return `\
ORIGINAL_FILE ORIGINAL_FILE
\`\`\`${language} ${tripleTick[0]}${language}
${originalCode} ${originalCode}
\`\`\` ${tripleTick[1]}
CHANGE CHANGE
\`\`\` ${tripleTick[0]}
${applyStr} ${applyStr}
\`\`\` ${tripleTick[1]}
INSTRUCTIONS 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. 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 `\ return `\
CURRENT SELECTION CURRENT SELECTION
\`\`\`${language} ${tripleTick[0]}${language}
<${midTag}>${selection}</${midTag}> <${midTag}>${selection}</${midTag}>
\`\`\` ${tripleTick[1]}
INSTRUCTIONS INSTRUCTIONS
${instructions} ${instructions}
@ -355,8 +359,8 @@ ${instructions}
<${preTag}>${prefix}</${preTag}> <${preTag}>${prefix}</${preTag}>
<${sufTag}>${suffix}</${sufTag}> <${sufTag}>${suffix}</${sufTag}>
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</${midTag}> <${midTag}>...new code</${midTag}>
\`\`\`).` ${tripleTick[1]}).`
}; };

View file

@ -7,12 +7,12 @@ import { KeyCode, KeyMod } from '../../../../base/common/keyCodes.js';
import { Action2, registerAction2 } from '../../../../platform/actions/common/actions.js'; import { Action2, registerAction2 } from '../../../../platform/actions/common/actions.js';
import { ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js'; import { ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js';
import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.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 { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js';
import { IInlineDiffsService } from './inlineDiffsService.js'; import { IInlineDiffsService } from './inlineDiffsService.js';
import { roundRangeToLines } from './sidebarActions.js'; import { roundRangeToLines } from './sidebarActions.js';
import { VOID_CTRL_K_ACTION_ID } from './actionIDs.js'; import { VOID_CTRL_K_ACTION_ID } from './actionIDs.js';
import { localize2 } from '../../../../nls.js'; import { localize2 } from '../../../../nls.js';
import { IMetricsService } from '../common/metricsService.js';
export type QuickEditPropsType = { export type QuickEditPropsType = {

View file

@ -12,7 +12,7 @@ import { ModelDropdown } from '../void-settings-tsx/ModelDropdown.js';
import { VOID_CTRL_K_ACTION_ID } from '../../../actionIDs.js'; import { VOID_CTRL_K_ACTION_ID } from '../../../actionIDs.js';
import { useRefState } from '../util/helpers.js'; import { useRefState } from '../util/helpers.js';
import { useScrollbarStyles } from '../util/useScrollbarStyles.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 = ({ export const QuickEditChat = ({
diffareaid, diffareaid,

View file

@ -5,7 +5,7 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { AlertCircle, ChevronDown, ChevronUp, X } from 'lucide-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'; import { useSettingsState } from '../util/services.js';

View file

@ -22,7 +22,7 @@ import { VOID_CTRL_L_ACTION_ID } from '../../../actionIDs.js';
import { filenameToVscodeLanguage } from '../../../helpers/detectLanguage.js'; import { filenameToVscodeLanguage } from '../../../helpers/detectLanguage.js';
import { VOID_OPEN_SETTINGS_ACTION_ID } from '../../../voidSettingsPane.js'; import { VOID_OPEN_SETTINGS_ACTION_ID } from '../../../voidSettingsPane.js';
import { Pencil, X } from 'lucide-react'; 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 { WarningBox } from '../void-settings-tsx/WarningBox.js';
import { ChatLocation } from '../../../searchAndReplaceService.js'; import { ChatLocation } from '../../../searchAndReplaceService.js';
@ -708,7 +708,7 @@ const ChatBubble = ({ chatMessage, isLoading, messageIdx }: { chatMessage: ChatM
`} `}
> >
{chatbubbleContents} {chatbubbleContents}
{isLoading && <IconLoading className='opacity-50 text-sm' />} {isLoading && <IconLoading className='opacity-50 text-sm px-2' />}
</div> </div>
{/* edit button */} {/* edit button */}

View file

@ -5,14 +5,14 @@
import React, { useState, useEffect } from 'react' import React, { useState, useEffect } from 'react'
import { ThreadStreamState, ThreadsState } from '../../../chatThreadService.js' 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 { IDisposable } from '../../../../../../../base/common/lifecycle.js'
import { VoidSidebarState } from '../../../sidebarStateService.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 { ColorScheme } from '../../../../../../../platform/theme/common/theme.js'
import { VoidUriState } from '../../../voidUriStateService.js'; import { VoidUriState } from '../../../voidUriStateService.js';
import { VoidQuickEditState } from '../../../quickEditStateService.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 { IFileService } from '../../../../../../../platform/files/common/files.js';
import { IHoverService } from '../../../../../../../platform/hover/browser/hover.js'; import { IHoverService } from '../../../../../../../platform/hover/browser/hover.js';
import { IThemeService } from '../../../../../../../platform/theme/common/themeService.js'; import { IThemeService } from '../../../../../../../platform/theme/common/themeService.js';
import { ILLMMessageService } from '../../../../../../../platform/void/common/llmMessageService.js'; import { ILLMMessageService } from '../../../../../../../workbench/contrib/void/common/llmMessageService.js';
import { IRefreshModelService } from '../../../../../../../platform/void/common/refreshModelService.js'; import { IRefreshModelService } from '../../../../../../../workbench/contrib/void/common/refreshModelService.js';
import { IVoidSettingsService } from '../../../../../../../platform/void/common/voidSettingsService.js'; import { IVoidSettingsService } from '../../../../../../../workbench/contrib/void/common/voidSettingsService.js';
import { IInlineDiffsService } from '../../../inlineDiffsService.js'; import { IInlineDiffsService } from '../../../inlineDiffsService.js';
import { IVoidUriStateService } from '../../../voidUriStateService.js'; import { IVoidUriStateService } from '../../../voidUriStateService.js';
import { IQuickEditStateService } from '../../../quickEditStateService.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 { IEnvironmentService } from '../../../../../../../platform/environment/common/environment.js'
import { IConfigurationService } from '../../../../../../../platform/configuration/common/configuration.js' import { IConfigurationService } from '../../../../../../../platform/configuration/common/configuration.js'
import { IPathService } from '../../../../../../../workbench/services/path/common/pathService.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'

View file

@ -4,13 +4,13 @@
*--------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------*/
import { useCallback, useEffect, useMemo, useRef, useState } from 'react' 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 { useSettingsState, useRefreshModelState, useAccessor } from '../util/services.js'
import { _VoidSelectBox, VoidCustomDropdownBox } from '../util/inputs.js' import { _VoidSelectBox, VoidCustomDropdownBox } from '../util/inputs.js'
import { SelectBox } from '../../../../../../../base/browser/ui/selectBox/selectBox.js' import { SelectBox } from '../../../../../../../base/browser/ui/selectBox/selectBox.js'
import { IconWarning } from '../sidebar-tsx/SidebarChat.js' import { IconWarning } from '../sidebar-tsx/SidebarChat.js'
import { VOID_OPEN_SETTINGS_ACTION_ID, VOID_TOGGLE_SETTINGS_ACTION_ID } from '../../../voidSettingsPane.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' import { WarningBox } from './WarningBox.js'
const optionsEqual = (m1: ModelOption[], m2: ModelOption[]) => { const optionsEqual = (m1: ModelOption[], m2: ModelOption[]) => {

View file

@ -5,7 +5,7 @@
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { InputBox } from '../../../../../../../base/browser/ui/inputbox/inputBox.js' 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 ErrorBoundary from '../sidebar-tsx/ErrorBoundary.js'
import { VoidButton, VoidCheckBox, VoidCustomDropdownBox, VoidInputBox, VoidInputBox2, VoidSwitch } from '../util/inputs.js' import { VoidButton, VoidCheckBox, VoidCustomDropdownBox, VoidInputBox, VoidInputBox2, VoidSwitch } from '../util/inputs.js'
import { useAccessor, useIsDark, useRefreshModelListener, useRefreshModelState, useSettingsState } from '../util/services.js' import { useAccessor, useIsDark, useRefreshModelListener, useRefreshModelState, useSettingsState } from '../util/services.js'

View file

@ -17,7 +17,7 @@ import { ICodeEditorService } from '../../../../editor/browser/services/codeEdit
import { IRange } from '../../../../editor/common/core/range.js'; import { IRange } from '../../../../editor/common/core/range.js';
import { ITextModel } from '../../../../editor/common/model.js'; import { ITextModel } from '../../../../editor/common/model.js';
import { VOID_VIEW_CONTAINER_ID, VOID_VIEW_ID } from './sidebarPane.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 { ISidebarStateService } from './sidebarStateService.js';
import { ICommandService } from '../../../../platform/commands/common/commands.js'; import { ICommandService } from '../../../../platform/commands/common/commands.js';
import { VOID_TOGGLE_SETTINGS_ACTION_ID } from './voidSettingsPane.js'; import { VOID_TOGGLE_SETTINGS_ACTION_ID } from './voidSettingsPane.js';

View file

@ -33,3 +33,26 @@ import './media/void.css'
// update (frontend part, also see platform/) // update (frontend part, also see platform/)
import './voidUpdateActions.js' 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'

View file

@ -9,8 +9,8 @@ import { ServicesAccessor } from '../../../../editor/browser/editorExtensions.js
import { localize2 } from '../../../../nls.js'; import { localize2 } from '../../../../nls.js';
import { Action2, registerAction2 } from '../../../../platform/actions/common/actions.js'; import { Action2, registerAction2 } from '../../../../platform/actions/common/actions.js';
import { INotificationService } from '../../../../platform/notification/common/notification.js'; import { INotificationService } from '../../../../platform/notification/common/notification.js';
import { IMetricsService } from '../../../../platform/void/common/metricsService.js'; import { IMetricsService } from '../common/metricsService.js';
import { IVoidUpdateService } from '../../../../platform/void/common/voidUpdateService.js'; import { IVoidUpdateService } from '../common/voidUpdateService.js';
import { IWorkbenchContribution, registerWorkbenchContribution2, WorkbenchPhase } from '../../../common/contributions.js'; import { IWorkbenchContribution, registerWorkbenchContribution2, WorkbenchPhase } from '../../../common/contributions.js';

View file

@ -4,13 +4,14 @@
*--------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------*/
import { EventLLMMessageOnTextParams, EventLLMMessageOnErrorParams, EventLLMMessageOnFinalMessageParams, ServiceSendLLMMessageParams, MainSendLLMMessageParams, MainLLMMessageAbortParams, ServiceModelListParams, EventModelListOnSuccessParams, EventModelListOnErrorParams, MainModelListParams, OllamaModelResponse, OpenaiCompatibleModelResponse, } from './llmMessageTypes.js'; 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 { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
import { InstantiationType, registerSingleton } from '../../instantiation/common/extensions.js'; import { registerSingleton, InstantiationType } from '../../../../platform/instantiation/common/extensions.js';
import { generateUuid } from '../../../base/common/uuid.js'; import { IChannel } from '../../../../base/parts/ipc/common/ipc.js';
import { createDecorator } from '../../instantiation/common/instantiation.js'; import { IMainProcessService } from '../../../../platform/ipc/common/mainProcessService.js';
import { Event } from '../../../base/common/event.js'; import { generateUuid } from '../../../../base/common/uuid.js';
import { Disposable } from '../../../base/common/lifecycle.js'; import { Event } from '../../../../base/common/event.js';
import { Disposable } from '../../../../base/common/lifecycle.js';
import { IVoidSettingsService } from './voidSettingsService.js'; import { IVoidSettingsService } from './voidSettingsService.js';
import { displayInfoOfProviderName, isFeatureNameDisabled } from './voidSettingsTypes.js'; import { displayInfoOfProviderName, isFeatureNameDisabled } from './voidSettingsTypes.js';
// import { INotificationService } from '../../notification/common/notification.js'; // import { INotificationService } from '../../notification/common/notification.js';

View file

@ -3,14 +3,14 @@
* Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information. * Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information.
*--------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------*/
import { createDecorator } from '../../instantiation/common/instantiation.js'; import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
import { ProxyChannel } from '../../../base/parts/ipc/common/ipc.js'; import { ProxyChannel } from '../../../../base/parts/ipc/common/ipc.js';
import { IMainProcessService } from '../../ipc/common/mainProcessService.js'; import { registerSingleton, InstantiationType } from '../../../../platform/instantiation/common/extensions.js';
import { InstantiationType, registerSingleton } from '../../instantiation/common/extensions.js'; import { IMainProcessService } from '../../../../platform/ipc/common/mainProcessService.js';
import { Action2, registerAction2 } from '../../actions/common/actions.js'; import { localize2 } from '../../../../nls.js';
import { localize2 } from '../../../nls.js'; import { ServicesAccessor } from '../../../../editor/browser/editorExtensions.js';
import { ServicesAccessor } from '../../../editor/browser/editorExtensions.js'; import { registerAction2, Action2 } from '../../../../platform/actions/common/actions.js';
import { INotificationService } from '../../notification/common/notification.js'; import { INotificationService } from '../../../../platform/notification/common/notification.js';
export interface IMetricsService { export interface IMetricsService {
readonly _serviceBrand: undefined; readonly _serviceBrand: undefined;

View file

@ -3,14 +3,14 @@
* Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information. * 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 { IVoidSettingsService } from './voidSettingsService.js';
import { ILLMMessageService } from './llmMessageService.js'; import { ILLMMessageService } from './llmMessageService.js';
import { Emitter, Event } from '../../../base/common/event.js'; import { Emitter, Event } from '../../../../base/common/event.js';
import { Disposable, IDisposable } from '../../../base/common/lifecycle.js'; import { Disposable, IDisposable } from '../../../../base/common/lifecycle.js';
import { RefreshableProviderName, refreshableProviderNames, SettingsOfProvider } from './voidSettingsTypes.js'; import { RefreshableProviderName, refreshableProviderNames, SettingsOfProvider } from './voidSettingsTypes.js';
import { OllamaModelResponse, OpenaiCompatibleModelResponse } from './llmMessageTypes.js'; import { OllamaModelResponse, OpenaiCompatibleModelResponse } from './llmMessageTypes.js';
import { registerSingleton, InstantiationType } from '../../../../platform/instantiation/common/extensions.js';
import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';

View file

@ -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<T extends ContextToolName> = keyof typeof contextTools[T]['params']
type ContextToolParams<T extends ContextToolName> = { [paramName in ContextToolParamNames<T>]: unknown }
type AllContextToolCallFns = {
[ToolName in ContextToolName]: ((p: (ContextToolParams<ToolName>)) => Promise<string>)
}
// TODO check to make sure in workspace
// TODO check to make sure is not gitignored
async function generateDirectoryTreeMd(fileService: IFileService, rootURI: URI): Promise<string> {
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: <T extends ContextToolName>(toolName: T, params: ContextToolParams<T>) => Promise<string>
}
export const IToolService = createDecorator<IToolService>('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);

View file

@ -3,13 +3,13 @@
* Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information. * Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information.
*--------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------*/
import { Emitter, Event } from '../../../base/common/event.js'; import { Emitter, Event } from '../../../../base/common/event.js';
import { Disposable } from '../../../base/common/lifecycle.js'; import { Disposable } from '../../../../base/common/lifecycle.js';
import { deepClone } from '../../../base/common/objects.js'; import { deepClone } from '../../../../base/common/objects.js';
import { IEncryptionService } from '../../encryption/common/encryptionService.js'; import { IEncryptionService } from '../../../../platform/encryption/common/encryptionService.js';
import { registerSingleton, InstantiationType } from '../../instantiation/common/extensions.js'; import { registerSingleton, InstantiationType } from '../../../../platform/instantiation/common/extensions.js';
import { createDecorator } from '../../instantiation/common/instantiation.js'; import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
import { IStorageService, StorageScope, StorageTarget } from '../../storage/common/storage.js'; import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js';
import { IMetricsService } from './metricsService.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'; import { defaultSettingsOfProvider, FeatureName, ProviderName, ModelSelectionOfFeature, SettingsOfProvider, SettingName, providerNames, ModelSelection, modelSelectionsEqual, featureNames, modelInfoOfDefaultModelNames, VoidModelInfo, GlobalSettings, GlobalSettingName, defaultGlobalSettings, displayInfoOfProviderName, defaultProviderSettings } from './voidSettingsTypes.js';

View file

@ -253,7 +253,7 @@ export const displayInfoOfProviderName = (providerName: ProviderName): DisplayIn
} }
else if (providerName === 'groq') { else if (providerName === 'groq') {
return { return {
title: 'Groq API', title: 'Groq.com API',
} }
} }
else if (providerName === 'mistral') { else if (providerName === 'mistral') {

View file

@ -3,10 +3,10 @@
* Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information. * 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 { ProxyChannel } from '../../../base/parts/ipc/common/ipc.js'; import { registerSingleton, InstantiationType } from '../../../../platform/instantiation/common/extensions.js';
import { IMainProcessService } from '../../ipc/common/mainProcessService.js'; import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
import { InstantiationType, registerSingleton } from '../../instantiation/common/extensions.js'; import { IMainProcessService } from '../../../../platform/ipc/common/mainProcessService.js';

View file

@ -6,6 +6,27 @@
import Anthropic from '@anthropic-ai/sdk'; import Anthropic from '@anthropic-ai/sdk';
import { _InternalSendLLMChatMessageFnType } from '../../common/llmMessageTypes.js'; import { _InternalSendLLMChatMessageFnType } from '../../common/llmMessageTypes.js';
import { anthropicMaxPossibleTokens } from '../../common/voidSettingsTypes.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 }) => { export const sendAnthropicChat: _InternalSendLLMChatMessageFnType = ({ messages, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter }) => {

View file

@ -22,8 +22,6 @@ export const sendGroqChat: _InternalSendLLMChatMessageFnType = async ({ messages
messages: messages, messages: messages,
model: modelName, model: modelName,
stream: true, stream: true,
// temperature: 0.7,
// max_tokens: parseMaxTokensStr(thisConfig.maxTokens),
}) })
.then(async response => { .then(async response => {
_setAborter(() => response.controller.abort()) _setAborter(() => response.controller.abort())

View file

@ -21,8 +21,6 @@ export const sendMistralChat: _InternalSendLLMChatMessageFnType = async ({ messa
messages: messages, messages: messages,
model: modelName, model: modelName,
stream: true, stream: true,
// temperature: 0.7,
// maxTokens: 2048,
}) })
.then(async response => { .then(async response => {
// Mistral has a really nonstandard API - no interrupt and weird stream types // Mistral has a really nonstandard API - no interrupt and weird stream types

View file

@ -6,43 +6,34 @@
import OpenAI from 'openai'; import OpenAI from 'openai';
import { _InternalModelListFnType, _InternalSendLLMFIMMessageFnType, _InternalSendLLMChatMessageFnType } from '../../common/llmMessageTypes.js'; import { _InternalModelListFnType, _InternalSendLLMFIMMessageFnType, _InternalSendLLMChatMessageFnType } from '../../common/llmMessageTypes.js';
import { Model } from 'openai/resources/models.js'; import { Model } from 'openai/resources/models.js';
import { InternalToolInfo } from '../../common/toolsService.js';
// import { parseMaxTokensStr } from './util.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<Model> = async ({ onSuccess: onSuccess_, onError: onError_, settingsOfProvider }) => {
const onSuccess = ({ models }: { models: Model[] }) => {
onSuccess_({ models })
}
const onError = ({ error }: { error: string }) => { export const toOpenAITool = (toolName: string, toolInfo: InternalToolInfo) => {
onError_({ error }) const { description, params, required } = toolInfo
} return {
type: 'function',
try { function: {
const thisConfig = settingsOfProvider.openAICompatible name: toolName,
const openai = new OpenAI({ baseURL: thisConfig.endpoint, apiKey: thisConfig.apiKey, dangerouslyAllowBrowser: true }) description: description,
parameters: {
openai.models.list() type: 'object',
.then(async (response) => { properties: params,
const models: Model[] = [] required: required,
models.push(...response.data) }
while (response.hasNextPage()) { }
models.push(...(await response.getNextPage()).data) } satisfies OpenAI.Chat.Completions.ChatCompletionTool
}
onSuccess({ models })
})
.catch((error) => {
onError({ error: error + '' })
})
}
catch (error) {
onError({ error: error + '' })
}
} }
type NewParams = Pick<Parameters<_InternalSendLLMChatMessageFnType>[0] & Parameters<_InternalSendLLMFIMMessageFnType>[0], 'settingsOfProvider' | 'providerName'> type NewParams = Pick<Parameters<_InternalSendLLMChatMessageFnType>[0] & Parameters<_InternalSendLLMFIMMessageFnType>[0], 'settingsOfProvider' | 'providerName'>
const newOpenAI = ({ settingsOfProvider, providerName }: NewParams) => { 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<Model> = 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 }) => { 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 = { onFinalMessage({ fullText: 'TODO' })
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)
})
} }
@ -116,7 +127,7 @@ export const sendOpenAIChat: _InternalSendLLMChatMessageFnType = ({ messages, on
model: modelName, model: modelName,
messages: messages, messages: messages,
stream: true, stream: true,
// max_completion_tokens: parseMaxTokensStr(thisConfig.maxTokens) // tools: Object.keys(contextTools).map(name => toOpenAITool(name, contextTools[name as ContextToolName])),
} }
openai.chat.completions openai.chat.completions
@ -125,7 +136,11 @@ export const sendOpenAIChat: _InternalSendLLMChatMessageFnType = ({ messages, on
_setAborter(() => response.controller.abort()) _setAborter(() => response.controller.abort())
// when receive text // when receive text
for await (const chunk of response) { 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; fullText += newText;
onText({ newText, fullText }); onText({ newText, fullText });
} }

View file

@ -8,7 +8,7 @@ import { IMetricsService } from '../../common/metricsService.js';
import { sendAnthropicChat } from './anthropic.js'; import { sendAnthropicChat } from './anthropic.js';
import { sendOllamaFIM, sendOllamaChat } from './ollama.js'; import { sendOllamaFIM, sendOllamaChat } from './ollama.js';
import { sendOpenAIChat } from './openai.js'; import { sendOpenAIChat, sendOpenAIFIM } from './openai.js';
import { sendGeminiChat } from './gemini.js'; import { sendGeminiChat } from './gemini.js';
import { sendGroqChat } from './groq.js'; import { sendGroqChat } from './groq.js';
import { sendMistralChat } from './mistral.js'; import { sendMistralChat } from './mistral.js';
@ -65,9 +65,14 @@ export const sendLLMMessage = ({
metricsService: IMetricsService 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 // only captures number of messages and message "shape", no actual code, instructions, prompts, etc
const captureLLMEvent = (eventId: string, extras?: object) => { const captureLLMEvent = (eventId: string, extras?: object) => {
@ -138,21 +143,16 @@ export const sendLLMMessage = ({
case 'openRouter': case 'openRouter':
case 'deepseek': case 'deepseek':
case 'openAICompatible': 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; break;
case 'gemini': case 'gemini':
sendGeminiChat({ messages: messagesArr, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, providerName }); sendGeminiChat({ messages: messagesArr, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, providerName });
break; 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': case 'groq':
sendGroqChat({ messages: messagesArr, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, providerName }); sendGroqChat({ messages: messagesArr, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, providerName });
break; break;

View file

@ -6,8 +6,8 @@
// registered in app.ts // 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... // 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 { IServerChannel } from '../../../../base/parts/ipc/common/ipc.js';
import { Emitter, Event } from '../../../base/common/event.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 { EventLLMMessageOnTextParams, EventLLMMessageOnErrorParams, EventLLMMessageOnFinalMessageParams, MainSendLLMMessageParams, AbortRef, SendLLMMessageParams, MainLLMMessageAbortParams, MainModelListParams, ModelListParams, EventModelListOnSuccessParams, EventModelListOnErrorParams, OllamaModelResponse, OpenaiCompatibleModelResponse, } from '../common/llmMessageTypes.js';
import { sendLLMMessage } from './llmMessage/sendLLMMessage.js' import { sendLLMMessage } from './llmMessage/sendLLMMessage.js'
import { IMetricsService } from '../common/metricsService.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<any> { async call(_: unknown, command: string, params: any): Promise<any> {
try { try {
if (command === 'sendLLMMessage') { if (command === 'sendLLMMessage') {

View file

@ -3,14 +3,13 @@
* Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information. * Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information.
*--------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------*/
import { Disposable } from '../../../base/common/lifecycle.js'; import { Disposable } from '../../../../base/common/lifecycle.js';
import { isLinux, isMacintosh, isWindows } from '../../../base/common/platform.js'; import { isLinux, isMacintosh, isWindows } from '../../../../base/common/platform.js';
import { generateUuid } from '../../../base/common/uuid.js'; import { generateUuid } from '../../../../base/common/uuid.js';
import { IEnvironmentMainService } from '../../environment/electron-main/environmentMainService.js'; import { IEnvironmentMainService } from '../../../../platform/environment/electron-main/environmentMainService.js';
import { IProductService } from '../../../../platform/product/common/productService.js';
import { IProductService } from '../../product/common/productService.js'; import { StorageTarget, StorageScope } from '../../../../platform/storage/common/storage.js';
import { StorageScope, StorageTarget } from '../../storage/common/storage.js'; import { IApplicationStorageMainService } from '../../../../platform/storage/electron-main/storageMainService.js';
import { IApplicationStorageMainService } from '../../storage/electron-main/storageMainService.js';
import { IMetricsService } from '../common/metricsService.js'; import { IMetricsService } from '../common/metricsService.js';
import { PostHog } from 'posthog-node' import { PostHog } from 'posthog-node'

View file

@ -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
}
*/

View file

@ -3,10 +3,9 @@
* Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information. * Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information.
*--------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------*/
import { Disposable } from '../../../base/common/lifecycle.js'; import { Disposable } from '../../../../base/common/lifecycle.js';
import { IEnvironmentMainService } from '../../environment/electron-main/environmentMainService.js'; import { IEnvironmentMainService } from '../../../../platform/environment/electron-main/environmentMainService.js';
import { IProductService } from '../../../../platform/product/common/productService.js';
import { IProductService } from '../../product/common/productService.js';
import { IVoidUpdateService } from '../common/voidUpdateService.js'; import { IVoidUpdateService } from '../common/voidUpdateService.js';

View file

@ -17,7 +17,6 @@ import './browser/workbench.contribution.js';
//#region --- Void //#region --- Void
// Void added this: // Void added this:
import './contrib/void/browser/void.contribution.js'; import './contrib/void/browser/void.contribution.js';
import '../platform/void/browser/void.contribution.js';
//#endregion //#endregion