mirror of
https://github.com/voideditor/void
synced 2026-05-24 09:58:23 +00:00
model selection is accurate now, and lots of files moved to be more accurate
This commit is contained in:
parent
a42ff2d59a
commit
8b25f80e9b
28 changed files with 462 additions and 438 deletions
|
|
@ -10,6 +10,7 @@
|
|||
"jsdoc",
|
||||
"header",
|
||||
"local"
|
||||
// "react" // Void
|
||||
],
|
||||
"rules": {
|
||||
"constructor-super": "warn",
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@
|
|||
// llmMessage
|
||||
import '../common/llmMessageService.js'
|
||||
|
||||
// voidConfig
|
||||
import '../common/voidConfigService.js'
|
||||
// voidSettings
|
||||
import '../common/voidSettingsService.js'
|
||||
|
||||
// refreshModel
|
||||
import '../common/refreshModelService.js'
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ 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 { IVoidConfigStateService } from './voidConfigService.js';
|
||||
import { IVoidSettingsService } from './voidSettingsService.js';
|
||||
// import { INotificationService } from '../../notification/common/notification.js';
|
||||
|
||||
// calls channel to implement features
|
||||
|
|
@ -42,7 +42,7 @@ export class LLMMessageService extends Disposable implements ILLMMessageService
|
|||
|
||||
constructor(
|
||||
@IMainProcessService private readonly mainProcessService: IMainProcessService, // used as a renderer (only usable on client side)
|
||||
@IVoidConfigStateService private readonly voidConfigStateService: IVoidConfigStateService,
|
||||
@IVoidSettingsService private readonly voidSettingsService: IVoidSettingsService,
|
||||
// @INotificationService private readonly notificationService: INotificationService,
|
||||
) {
|
||||
super()
|
||||
|
|
@ -79,7 +79,7 @@ export class LLMMessageService extends Disposable implements ILLMMessageService
|
|||
const { featureName } = proxyParams
|
||||
|
||||
// end early if no provider
|
||||
const modelSelection = this.voidConfigStateService.state.modelSelectionOfFeature[featureName]
|
||||
const modelSelection = this.voidSettingsService.state.modelSelectionOfFeature[featureName]
|
||||
if (modelSelection === null) {
|
||||
onError({ message: 'Please add a Provider in Settings!', fullError: null })
|
||||
return null
|
||||
|
|
@ -92,7 +92,7 @@ export class LLMMessageService extends Disposable implements ILLMMessageService
|
|||
this.onFinalMessageHooks_llm[requestId_] = onFinalMessage
|
||||
this.onErrorHooks_llm[requestId_] = onError
|
||||
|
||||
const { settingsOfProvider } = this.voidConfigStateService.state
|
||||
const { settingsOfProvider } = this.voidSettingsService.state
|
||||
|
||||
// params will be stripped of all its functions over the IPC channel
|
||||
this.channel.call('sendLLMMessage', {
|
||||
|
|
@ -116,7 +116,7 @@ export class LLMMessageService extends Disposable implements ILLMMessageService
|
|||
ollamaList = (params: ServiceOllamaListParams) => {
|
||||
const { onSuccess, onError, ...proxyParams } = params
|
||||
|
||||
const { settingsOfProvider } = this.voidConfigStateService.state
|
||||
const { settingsOfProvider } = this.voidSettingsService.state
|
||||
|
||||
// add state for request id
|
||||
const requestId_ = generateUuid();
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IRange } from '../../../editor/common/core/range'
|
||||
import { ProviderName, SettingsOfProvider } from './voidConfigTypes'
|
||||
import { ProviderName, SettingsOfProvider } from './voidSettingsTypes.js'
|
||||
|
||||
|
||||
export type OnText = (p: { newText: string, fullText: string }) => void
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import { createDecorator } from '../../instantiation/common/instantiation.js';
|
||||
import { InstantiationType, registerSingleton } from '../../instantiation/common/extensions.js';
|
||||
import { IVoidConfigStateService } from './voidConfigService.js';
|
||||
import { IVoidSettingsService } from './voidSettingsService.js';
|
||||
import { ILLMMessageService } from './llmMessageService.js';
|
||||
import { Emitter, Event } from '../../../base/common/event.js';
|
||||
import { Disposable } from '../../../base/common/lifecycle.js';
|
||||
|
|
@ -38,7 +38,7 @@ export class RefreshModelService extends Disposable implements IRefreshModelServ
|
|||
readonly onDidChangeState: Event<void> = this._onDidChangeState.event; // this is primarily for use in react, so react can listen + update on state changes
|
||||
|
||||
constructor(
|
||||
@IVoidConfigStateService private readonly voidConfigStateService: IVoidConfigStateService,
|
||||
@IVoidSettingsService private readonly voidSettingsService: IVoidSettingsService,
|
||||
@ILLMMessageService private readonly llmMessageService: ILLMMessageService,
|
||||
) {
|
||||
super()
|
||||
|
|
@ -46,11 +46,11 @@ export class RefreshModelService extends Disposable implements IRefreshModelServ
|
|||
// on mount, refresh ollama models
|
||||
this.refreshOllamaModels()
|
||||
|
||||
// every time ollama.enabled changes, refresh ollama models
|
||||
let relevantVals = () => [this.voidConfigStateService.state.settingsOfProvider.ollama.enabled, this.voidConfigStateService.state.settingsOfProvider.ollama.endpoint]
|
||||
// every time ollama.enabled changes, refresh ollama models, like useEffect
|
||||
let relevantVals = () => [this.voidSettingsService.state.settingsOfProvider.ollama.enabled, this.voidSettingsService.state.settingsOfProvider.ollama.endpoint]
|
||||
let prevVals = relevantVals()
|
||||
this._register(
|
||||
this.voidConfigStateService.onDidChangeState(() => { // we might want to debounce this
|
||||
this.voidSettingsService.onDidChangeState(() => { // we might want to debounce this
|
||||
const newVals = relevantVals()
|
||||
if (!eq(prevVals, newVals)) {
|
||||
this.refreshOllamaModels()
|
||||
|
|
@ -75,7 +75,7 @@ export class RefreshModelService extends Disposable implements IRefreshModelServ
|
|||
this._cancelTimeout()
|
||||
|
||||
// if ollama is disabled, obivously done
|
||||
if (this.voidConfigStateService.state.settingsOfProvider.ollama.enabled !== 'true') {
|
||||
if (this.voidSettingsService.state.settingsOfProvider.ollama.enabled !== 'true') {
|
||||
this._setState('done')
|
||||
return
|
||||
}
|
||||
|
|
@ -85,7 +85,7 @@ export class RefreshModelService extends Disposable implements IRefreshModelServ
|
|||
|
||||
this.llmMessageService.ollamaList({
|
||||
onSuccess: ({ models }) => {
|
||||
this.voidConfigStateService.setSettingOfProvider('ollama', 'models', models.map(model => model.name))
|
||||
this.voidSettingsService.setSettingOfProvider('ollama', 'models', models.map(model => model.name))
|
||||
this._setState('done')
|
||||
},
|
||||
onError: ({ error }) => {
|
||||
|
|
|
|||
|
|
@ -1,137 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Glass Devtools, Inc. All rights reserved.
|
||||
* Void Editor additions licensed under the AGPL 3.0 License.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
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 { defaultVoidProviderState, FeatureName, ProviderName, ModelSelectionOfFeature, SettingsOfProvider, SettingName } from './voidConfigTypes.js';
|
||||
|
||||
|
||||
const STORAGE_KEY = 'void.voidConfigStateII'
|
||||
|
||||
type SetSettingOfProviderFn = <S extends SettingName>(
|
||||
providerName: ProviderName,
|
||||
settingName: S,
|
||||
newVal: SettingsOfProvider[ProviderName][S extends keyof SettingsOfProvider[ProviderName] ? S : never],
|
||||
) => Promise<void>;
|
||||
|
||||
type SetModelSelectionOfFeature = <K extends FeatureName>(
|
||||
featureName: K,
|
||||
newVal: ModelSelectionOfFeature[K],
|
||||
) => Promise<void>;
|
||||
|
||||
|
||||
type VoidConfigState = {
|
||||
readonly settingsOfProvider: SettingsOfProvider; // optionsOfProvider
|
||||
readonly modelSelectionOfFeature: ModelSelectionOfFeature; // stateOfFeature
|
||||
}
|
||||
|
||||
export interface IVoidConfigStateService {
|
||||
readonly _serviceBrand: undefined;
|
||||
readonly state: VoidConfigState;
|
||||
onDidChangeState: Event<void>;
|
||||
setSettingOfProvider: SetSettingOfProviderFn;
|
||||
setModelSelectionOfFeature: SetModelSelectionOfFeature;
|
||||
}
|
||||
|
||||
|
||||
const defaultState = () => {
|
||||
const d: VoidConfigState = {
|
||||
settingsOfProvider: deepClone(defaultVoidProviderState),
|
||||
modelSelectionOfFeature: { 'Ctrl+L': null, 'Ctrl+K': null, 'Autocomplete': null }
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
|
||||
export const IVoidConfigStateService = createDecorator<IVoidConfigStateService>('VoidConfigStateService');
|
||||
class VoidConfigService extends Disposable implements IVoidConfigStateService {
|
||||
_serviceBrand: undefined;
|
||||
|
||||
private readonly _onDidChangeState = new Emitter<void>();
|
||||
readonly onDidChangeState: Event<void> = this._onDidChangeState.event; // this is primarily for use in react, so react can listen + update on state changes
|
||||
|
||||
state: VoidConfigState;
|
||||
|
||||
constructor(
|
||||
@IStorageService private readonly _storageService: IStorageService,
|
||||
@IEncryptionService private readonly _encryptionService: IEncryptionService,
|
||||
// could have used this, but it's clearer the way it is (+ slightly different eg StorageTarget.USER)
|
||||
// @ISecretStorageService private readonly _secretStorageService: ISecretStorageService,
|
||||
) {
|
||||
super()
|
||||
|
||||
// at the start, we haven't read the partial config yet, but we need to set state to something
|
||||
this.state = defaultState()
|
||||
|
||||
// read and update the actual state immediately
|
||||
this._readVoidConfigState().then(voidConfigState => {
|
||||
this._setState(voidConfigState)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
private async _readVoidConfigState(): Promise<VoidConfigState> {
|
||||
const encryptedPartialConfig = this._storageService.get(STORAGE_KEY, StorageScope.APPLICATION)
|
||||
|
||||
if (!encryptedPartialConfig)
|
||||
return defaultState()
|
||||
|
||||
const voidConfigStateStr = await this._encryptionService.decrypt(encryptedPartialConfig)
|
||||
return JSON.parse(voidConfigStateStr)
|
||||
}
|
||||
|
||||
|
||||
private async _storeVoidConfigState(voidConfigState: VoidConfigState) {
|
||||
const encryptedVoidConfigStr = await this._encryptionService.encrypt(JSON.stringify(voidConfigState))
|
||||
this._storageService.store(STORAGE_KEY, encryptedVoidConfigStr, StorageScope.APPLICATION, StorageTarget.USER);
|
||||
}
|
||||
|
||||
setSettingOfProvider: SetSettingOfProviderFn = async (providerName, settingName, newVal) => {
|
||||
const newState: VoidConfigState = {
|
||||
...this.state,
|
||||
settingsOfProvider: {
|
||||
...this.state.settingsOfProvider,
|
||||
[providerName]: {
|
||||
...this.state.settingsOfProvider[providerName],
|
||||
[settingName]: newVal,
|
||||
}
|
||||
},
|
||||
}
|
||||
// console.log('NEW STATE I', JSON.stringify(newState, null, 2))
|
||||
|
||||
await this._storeVoidConfigState(newState)
|
||||
this._setState(newState)
|
||||
}
|
||||
|
||||
setModelSelectionOfFeature: SetModelSelectionOfFeature = async (featureName, newVal) => {
|
||||
const newState: VoidConfigState = {
|
||||
...this.state,
|
||||
modelSelectionOfFeature: {
|
||||
...this.state.modelSelectionOfFeature,
|
||||
[featureName]: newVal
|
||||
}
|
||||
}
|
||||
// console.log('NEW STATE II', JSON.stringify(newState, null, 2))
|
||||
|
||||
await this._storeVoidConfigState(newState)
|
||||
this._setState(newState)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// internal function to update state, should be called every time state changes
|
||||
private async _setState(voidConfigState: VoidConfigState) {
|
||||
this.state = voidConfigState
|
||||
this._onDidChangeState.fire()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
registerSingleton(IVoidConfigStateService, VoidConfigService, InstantiationType.Eager);
|
||||
191
src/vs/platform/void/common/voidSettingsService.ts
Normal file
191
src/vs/platform/void/common/voidSettingsService.ts
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Glass Devtools, Inc. All rights reserved.
|
||||
* Void Editor additions licensed under the AGPL 3.0 License.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
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 { defaultSettingsOfProvider, FeatureName, ProviderName, ModelSelectionOfFeature, SettingsOfProvider, SettingName, providerNames, ModelSelection, modelSelectionsEqual, featureNames } from './voidSettingsTypes.js';
|
||||
|
||||
|
||||
const STORAGE_KEY = 'void.voidConfigStateIV'
|
||||
|
||||
type SetSettingOfProviderFn = <S extends SettingName>(
|
||||
providerName: ProviderName,
|
||||
settingName: S,
|
||||
newVal: SettingsOfProvider[ProviderName][S extends keyof SettingsOfProvider[ProviderName] ? S : never],
|
||||
) => Promise<void>;
|
||||
|
||||
type SetModelSelectionOfFeature = <K extends FeatureName>(
|
||||
featureName: K,
|
||||
newVal: ModelSelectionOfFeature[K],
|
||||
options?: { doNotApplyEffects?: true }
|
||||
) => Promise<void>;
|
||||
|
||||
|
||||
|
||||
type ModelOption = { text: string, value: ModelSelection }
|
||||
|
||||
|
||||
|
||||
export type VoidSettingsState = {
|
||||
readonly settingsOfProvider: SettingsOfProvider; // optionsOfProvider
|
||||
readonly modelSelectionOfFeature: ModelSelectionOfFeature; // stateOfFeature
|
||||
|
||||
readonly _modelsList: ModelOption[] // computed based on the two above items
|
||||
}
|
||||
|
||||
|
||||
|
||||
export interface IVoidSettingsService {
|
||||
readonly _serviceBrand: undefined;
|
||||
readonly state: VoidSettingsState;
|
||||
onDidChangeState: Event<void>;
|
||||
setSettingOfProvider: SetSettingOfProviderFn;
|
||||
setModelSelectionOfFeature: SetModelSelectionOfFeature;
|
||||
}
|
||||
|
||||
|
||||
let _computeModelsList = (settingsOfProvider: SettingsOfProvider) => {
|
||||
let modelsList: ModelOption[] = []
|
||||
for (const providerName of providerNames) {
|
||||
const providerConfig = settingsOfProvider[providerName]
|
||||
if (providerConfig.enabled !== 'true') continue
|
||||
providerConfig.models?.forEach(modelName => {
|
||||
modelsList.push({ text: `${modelName} (${providerName})`, value: { providerName, modelName } })
|
||||
})
|
||||
}
|
||||
return modelsList
|
||||
}
|
||||
|
||||
|
||||
const defaultState = () => {
|
||||
const d: VoidSettingsState = {
|
||||
settingsOfProvider: deepClone(defaultSettingsOfProvider),
|
||||
modelSelectionOfFeature: { 'Ctrl+L': null, 'Ctrl+K': null, 'Autocomplete': null },
|
||||
_modelsList: _computeModelsList(defaultSettingsOfProvider),
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
|
||||
export const IVoidSettingsService = createDecorator<IVoidSettingsService>('VoidSettingsService');
|
||||
class VoidSettingsService extends Disposable implements IVoidSettingsService {
|
||||
_serviceBrand: undefined;
|
||||
|
||||
private readonly _onDidChangeState = new Emitter<void>();
|
||||
readonly onDidChangeState: Event<void> = this._onDidChangeState.event; // this is primarily for use in react, so react can listen + update on state changes
|
||||
|
||||
state: VoidSettingsState;
|
||||
|
||||
constructor(
|
||||
@IStorageService private readonly _storageService: IStorageService,
|
||||
@IEncryptionService private readonly _encryptionService: IEncryptionService,
|
||||
// could have used this, but it's clearer the way it is (+ slightly different eg StorageTarget.USER)
|
||||
// @ISecretStorageService private readonly _secretStorageService: ISecretStorageService,
|
||||
) {
|
||||
super()
|
||||
|
||||
// at the start, we haven't read the partial config yet, but we need to set state to something
|
||||
this.state = defaultState()
|
||||
|
||||
// read and update the actual state immediately
|
||||
this._readState().then(s => {
|
||||
this.state = s
|
||||
this._onDidChangeState.fire()
|
||||
})
|
||||
}
|
||||
|
||||
private async _readState(): Promise<VoidSettingsState> {
|
||||
const encryptedState = this._storageService.get(STORAGE_KEY, StorageScope.APPLICATION)
|
||||
|
||||
if (!encryptedState)
|
||||
return defaultState()
|
||||
|
||||
const stateStr = await this._encryptionService.decrypt(encryptedState)
|
||||
return JSON.parse(stateStr)
|
||||
}
|
||||
|
||||
|
||||
private async _storeState() {
|
||||
const state = this.state
|
||||
const encryptedState = await this._encryptionService.encrypt(JSON.stringify(state))
|
||||
this._storageService.store(STORAGE_KEY, encryptedState, StorageScope.APPLICATION, StorageTarget.USER);
|
||||
}
|
||||
|
||||
setSettingOfProvider: SetSettingOfProviderFn = async (providerName, settingName, newVal) => {
|
||||
|
||||
const newModelSelectionOfFeature = this.state.modelSelectionOfFeature
|
||||
|
||||
const newSettingsOfProvider = {
|
||||
...this.state.settingsOfProvider,
|
||||
[providerName]: {
|
||||
...this.state.settingsOfProvider[providerName],
|
||||
[settingName]: newVal,
|
||||
}
|
||||
}
|
||||
|
||||
// if changed models or enabled a provider, recompute models list
|
||||
const modelsListChanged = settingName === 'models' || settingName === 'enabled'
|
||||
const newModelsList = modelsListChanged ? _computeModelsList(newSettingsOfProvider) : this.state._modelsList
|
||||
|
||||
const newState: VoidSettingsState = {
|
||||
modelSelectionOfFeature: newModelSelectionOfFeature,
|
||||
settingsOfProvider: newSettingsOfProvider,
|
||||
_modelsList: newModelsList,
|
||||
}
|
||||
|
||||
// this must go above this.setanythingelse()
|
||||
this.state = newState
|
||||
|
||||
// if the user-selected model is no longer in the list, update the selection for each feature that needs it to something relevant (the 0th model available, or null)
|
||||
if (modelsListChanged) {
|
||||
for (const featureName of featureNames) {
|
||||
|
||||
const currentSelection = newModelSelectionOfFeature[featureName]
|
||||
const selnIdx = currentSelection === null ? -1 : newModelsList.findIndex(m => modelSelectionsEqual(m.value, currentSelection))
|
||||
|
||||
if (selnIdx === -1) {
|
||||
if (newModelsList.length !== 0)
|
||||
this.setModelSelectionOfFeature(featureName, newModelsList[0].value, { doNotApplyEffects: true })
|
||||
else
|
||||
this.setModelSelectionOfFeature(featureName, null, { doNotApplyEffects: true })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await this._storeState()
|
||||
this._onDidChangeState.fire()
|
||||
}
|
||||
|
||||
|
||||
setModelSelectionOfFeature: SetModelSelectionOfFeature = async (featureName, newVal, options) => {
|
||||
const newState: VoidSettingsState = {
|
||||
...this.state,
|
||||
modelSelectionOfFeature: {
|
||||
...this.state.modelSelectionOfFeature,
|
||||
[featureName]: newVal
|
||||
}
|
||||
}
|
||||
|
||||
this.state = newState
|
||||
|
||||
if (options?.doNotApplyEffects)
|
||||
return
|
||||
console.log('NEW STATE II', JSON.stringify(newState, null, 2))
|
||||
|
||||
await this._storeState()
|
||||
this._onDidChangeState.fire()
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
registerSingleton(IVoidSettingsService, VoidSettingsService, InstantiationType.Eager);
|
||||
|
|
@ -76,12 +76,12 @@ export const anthropicMaxPossibleTokens = (modelName: string) => {
|
|||
}
|
||||
|
||||
|
||||
export const dummyModelData = {
|
||||
anthropic: ['claude 3.5'],
|
||||
openAI: ['gpt 4o'],
|
||||
ollama: ['llama 3.2', 'codestral'],
|
||||
openRouter: ['qwen 2.5'],
|
||||
}
|
||||
// export const dummyModelData = {
|
||||
// anthropic: ['claude 3.5'],
|
||||
// openAI: ['gpt 4o'],
|
||||
// ollama: ['llama 3.2', 'codestral'],
|
||||
// openRouter: ['qwen 2.5'],
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
|
@ -234,7 +234,7 @@ export const displayInfoOfSettingName = (providerName: ProviderName, settingName
|
|||
|
||||
|
||||
// used when waiting and for a type reference
|
||||
export const defaultVoidProviderState: SettingsOfProvider = {
|
||||
export const defaultSettingsOfProvider: SettingsOfProvider = {
|
||||
anthropic: {
|
||||
...voidProviderDefaults.anthropic,
|
||||
...voidInitModelOptions.anthropic,
|
||||
|
|
@ -273,21 +273,17 @@ export const defaultVoidProviderState: SettingsOfProvider = {
|
|||
}
|
||||
|
||||
|
||||
export type ModelSelection = { providerName: ProviderName, modelName: string }
|
||||
|
||||
export const modelSelectionsEqual = (m1: ModelSelection, m2: ModelSelection) => {
|
||||
return m1.modelName === m2.modelName && m1.providerName === m2.providerName
|
||||
}
|
||||
|
||||
// this is a state
|
||||
export type ModelSelectionOfFeature = {
|
||||
'Ctrl+L': {
|
||||
providerName: ProviderName,
|
||||
modelName: string,
|
||||
} | null,
|
||||
'Ctrl+K': {
|
||||
providerName: ProviderName,
|
||||
modelName: string,
|
||||
} | null,
|
||||
'Autocomplete': {
|
||||
providerName: ProviderName,
|
||||
modelName: string,
|
||||
} | null,
|
||||
'Ctrl+L': ModelSelection | null,
|
||||
'Ctrl+K': ModelSelection | null,
|
||||
'Autocomplete': ModelSelection | null,
|
||||
}
|
||||
export type FeatureName = keyof ModelSelectionOfFeature
|
||||
export const featureNames = ['Ctrl+L', 'Ctrl+K', 'Autocomplete'] as const
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import Anthropic from '@anthropic-ai/sdk';
|
||||
import { _InternalSendLLMMessageFnType } from '../../common/llmMessageTypes.js';
|
||||
import { anthropicMaxPossibleTokens } from '../../common/voidConfigTypes.js';
|
||||
import { anthropicMaxPossibleTokens } from '../../common/voidSettingsTypes.js';
|
||||
|
||||
// Anthropic
|
||||
type LLMMessageAnthropic = {
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
void-imports/
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* Void Editor additions licensed under the AGPL 3.0 License.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { diffLines } from './react/out/diff/index.js'
|
||||
import { diffLines } from '../react/out/diff/index.js'
|
||||
|
||||
export type ComputedDiff = {
|
||||
type: 'edit';
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* Void Editor additions licensed under the AGPL 3.0 License.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { isMacintosh } from '../../../../base/common/platform.js';
|
||||
import { isMacintosh } from '../../../../../base/common/platform.js';
|
||||
|
||||
// import { OperatingSystem, OS } from '../../../../base/common/platform.js';
|
||||
// OS === OperatingSystem.Macintosh
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
import { ServicesAccessor } from '../../../../../editor/browser/editorExtensions.js';
|
||||
import { IModelService } from '../../../../../editor/common/services/model.js';
|
||||
import { IClipboardService } from '../../../../../platform/clipboard/common/clipboardService.js';
|
||||
import { IContextViewService, IContextMenuService } from '../../../../../platform/contextview/browser/contextView.js';
|
||||
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 { IInlineDiffsService } from '../inlineDiffsService.js';
|
||||
import { ISidebarStateService } from '../sidebarStateService.js';
|
||||
import { IThreadHistoryService } from '../threadHistoryService.js';
|
||||
|
||||
export type ReactServicesType = {
|
||||
sidebarStateService: ISidebarStateService;
|
||||
settingsStateService: IVoidSettingsService;
|
||||
threadsStateService: IThreadHistoryService;
|
||||
fileService: IFileService;
|
||||
modelService: IModelService;
|
||||
inlineDiffService: IInlineDiffsService;
|
||||
llmMessageService: ILLMMessageService;
|
||||
clipboardService: IClipboardService;
|
||||
refreshModelService: IRefreshModelService;
|
||||
|
||||
themeService: IThemeService,
|
||||
hoverService: IHoverService,
|
||||
|
||||
contextViewService: IContextViewService;
|
||||
contextMenuService: IContextMenuService;
|
||||
}
|
||||
|
||||
|
||||
export const getReactServices = (accessor: ServicesAccessor): ReactServicesType => {
|
||||
return {
|
||||
settingsStateService: accessor.get(IVoidSettingsService),
|
||||
sidebarStateService: accessor.get(ISidebarStateService),
|
||||
threadsStateService: accessor.get(IThreadHistoryService),
|
||||
fileService: accessor.get(IFileService),
|
||||
modelService: accessor.get(IModelService),
|
||||
inlineDiffService: accessor.get(IInlineDiffsService),
|
||||
llmMessageService: accessor.get(ILLMMessageService),
|
||||
clipboardService: accessor.get(IClipboardService),
|
||||
themeService: accessor.get(IThemeService),
|
||||
hoverService: accessor.get(IHoverService),
|
||||
refreshModelService: accessor.get(IRefreshModelService),
|
||||
contextViewService: accessor.get(IContextViewService),
|
||||
contextMenuService: accessor.get(IContextMenuService),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -11,9 +11,8 @@ import { ICodeEditor, IOverlayWidget, IViewZone } from '../../../../editor/brows
|
|||
// import { IUndoRedoService } from '../../../../platform/undoRedo/common/undoRedo.js';
|
||||
import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js';
|
||||
// import { throttle } from '../../../../base/common/decorators.js';
|
||||
// import { IVoidConfigStateService } from './registerConfig.js';
|
||||
import { writeFileWithDiffInstructions } from './prompt/systemPrompts.js';
|
||||
import { ComputedDiff, findDiffs } from './findDiffs.js';
|
||||
import { ComputedDiff, findDiffs } from './helpers/findDiffs.js';
|
||||
import { EndOfLinePreference, ITextModel } from '../../../../editor/common/model.js';
|
||||
import { IRange } from '../../../../editor/common/core/range.js';
|
||||
import { registerColor } from '../../../../platform/theme/common/colorUtils.js';
|
||||
|
|
@ -144,7 +143,6 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService {
|
|||
|
||||
constructor(
|
||||
// @IHistoryService private readonly _historyService: IHistoryService, // history service is the history of pressing alt left/right
|
||||
// @IVoidConfigStateService private readonly _voidConfigStateService: IVoidConfigStateService,
|
||||
@ICodeEditorService private readonly _editorService: ICodeEditorService,
|
||||
@IModelService private readonly _modelService: IModelService,
|
||||
@IUndoRedoService private readonly _undoRedoService: IUndoRedoService, // undoRedo service is the history of pressing ctrl+z
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* Void Editor additions licensed under the AGPL 3.0 License.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { CodeSelection } from '../registerThreads.js';
|
||||
import { CodeSelection } from '../threadHistoryService.js';
|
||||
|
||||
export const stringifySelections = (selections: CodeSelection[]) => {
|
||||
|
||||
|
|
|
|||
|
|
@ -6,10 +6,10 @@
|
|||
import React, { FormEvent, Fragment, useCallback, useEffect, useRef, useState } from 'react';
|
||||
|
||||
|
||||
import { useConfigState, useService, useSidebarState, useThreadsState } from '../util/services.js';
|
||||
import { useSettingsState, useService, useSidebarState, useThreadsState } from '../util/services.js';
|
||||
import { generateDiffInstructions } from '../../../prompt/systemPrompts.js';
|
||||
import { userInstructionsStr } from '../../../prompt/stringifySelections.js';
|
||||
import { ChatMessage, CodeSelection, CodeStagingSelection } from '../../../registerThreads.js';
|
||||
import { ChatMessage, CodeSelection, CodeStagingSelection } from '../../../threadHistoryService.js';
|
||||
|
||||
import { BlockCode } from '../markdown/BlockCode.js';
|
||||
import { ChatMarkdownRender } from '../markdown/ChatMarkdownRender.js';
|
||||
|
|
@ -19,7 +19,7 @@ import { EndOfLinePreference } from '../../../../../../../editor/common/model.js
|
|||
import { IDisposable } from '../../../../../../../base/common/lifecycle.js';
|
||||
import { ErrorDisplay } from './ErrorDisplay.js';
|
||||
import { OnError, ServiceSendLLMMessageParams } from '../../../../../../../platform/void/common/llmMessageTypes.js';
|
||||
import { getCmdKey } from '../../../getCmdKey.js'
|
||||
import { getCmdKey } from '../../../helpers/getCmdKey.js'
|
||||
import { HistoryInputBox, InputBox } from '../../../../../../../base/browser/ui/inputbox/inputBox.js';
|
||||
import { VoidInputBox } from './inputs.js';
|
||||
import { ModelSelectionOfFeature } from '../void-settings-tsx/ModelSelectionSettings.js';
|
||||
|
|
@ -277,9 +277,6 @@ export const SidebarChat = () => {
|
|||
return () => disposables.forEach(d => d.dispose())
|
||||
}, [sidebarStateService, inputBoxRef])
|
||||
|
||||
// config state
|
||||
const voidConfigState = useConfigState()
|
||||
|
||||
// threads state
|
||||
const threadsState = useThreadsState()
|
||||
const threadsStateService = useService('threadsStateService')
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import * as ReactDOM from 'react-dom/client'
|
||||
import { _registerServices } from './services.js';
|
||||
import { ReactServicesType } from '../../../reactServices.js';
|
||||
import { ReactServicesType } from '../../../helpers/reactServicesHelper.js';
|
||||
|
||||
|
||||
export const mountFnGenerator = (Component: React.FC) => (rootElement: HTMLElement, services: ReactServicesType) => {
|
||||
|
|
|
|||
|
|
@ -4,35 +4,38 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { useState, useEffect } from 'react'
|
||||
import { VoidSidebarState } from '../../../registerSidebar.js'
|
||||
import { ThreadsState } from '../../../registerThreads.js'
|
||||
import { SettingsOfProvider } from '../../../../../../../platform/void/common/voidConfigTypes.js'
|
||||
import { ThreadsState } from '../../../threadHistoryService.js'
|
||||
import { SettingsOfProvider } from '../../../../../../../platform/void/common/voidSettingsTypes.js'
|
||||
import { RefreshModelState } from '../../../../../../../platform/void/common/refreshModelService.js'
|
||||
import { IDisposable } from '../../../../../../../base/common/lifecycle.js'
|
||||
import { ReactServicesType } from '../../../reactServices.js'
|
||||
import { ReactServicesType } from '../../../helpers/reactServicesHelper.js'
|
||||
import { VoidSidebarState } from '../../../sidebarStateService.js'
|
||||
import { VoidSettingsState } from '../../../../../../../platform/void/common/voidSettingsService.js'
|
||||
|
||||
|
||||
// normally to do this you'd use a useEffect that calls .onDidChangeState(), but useEffect mounts too late and misses initial state changes
|
||||
|
||||
let services: ReactServicesType
|
||||
|
||||
// even if React hasn't mounted yet, these variables are always updated to the latest state:
|
||||
// even if React hasn't mounted yet, the variables are always updated to the latest state.
|
||||
// React listens by adding a setState function to these listeners.
|
||||
let sidebarState: VoidSidebarState
|
||||
let threadsState: ThreadsState
|
||||
let settingsOfProvider: SettingsOfProvider
|
||||
let refreshModelState: RefreshModelState
|
||||
|
||||
// React listens by adding a setState function to these:
|
||||
const sidebarStateListeners: Set<(s: VoidSidebarState) => void> = new Set()
|
||||
|
||||
let threadsState: ThreadsState
|
||||
const threadsStateListeners: Set<(s: ThreadsState) => void> = new Set()
|
||||
const settingsOfProviderListeners: Set<(s: SettingsOfProvider) => void> = new Set()
|
||||
|
||||
let settingsState: VoidSettingsState
|
||||
const settingsStateListeners: Set<(s: VoidSettingsState) => void> = new Set()
|
||||
|
||||
let refreshModelState: RefreshModelState
|
||||
const refreshModelStateListeners: Set<(s: RefreshModelState) => void> = new Set()
|
||||
|
||||
|
||||
|
||||
// must call this before you can use any of the hooks below
|
||||
// this should only be called ONCE! this is the only place you don't need to dispose onDidChange. If you use state.onDidChange anywhere else, make sure to dispose it!
|
||||
|
||||
let wasCalled = false
|
||||
|
||||
export const _registerServices = (services_: ReactServicesType) => {
|
||||
|
||||
const disposables: IDisposable[] = []
|
||||
|
|
@ -41,7 +44,7 @@ export const _registerServices = (services_: ReactServicesType) => {
|
|||
wasCalled = true
|
||||
|
||||
services = services_
|
||||
const { sidebarStateService, configStateService, threadsStateService, refreshModelService } = services
|
||||
const { sidebarStateService, settingsStateService, threadsStateService, refreshModelService } = services
|
||||
|
||||
sidebarState = sidebarStateService.state
|
||||
disposables.push(
|
||||
|
|
@ -59,11 +62,11 @@ export const _registerServices = (services_: ReactServicesType) => {
|
|||
})
|
||||
)
|
||||
|
||||
settingsOfProvider = configStateService.state.settingsOfProvider
|
||||
settingsState = settingsStateService.state
|
||||
disposables.push(
|
||||
configStateService.onDidChangeState(() => {
|
||||
settingsOfProvider = configStateService.state.settingsOfProvider
|
||||
settingsOfProviderListeners.forEach(l => l(settingsOfProvider))
|
||||
settingsStateService.onDidChangeState(() => {
|
||||
settingsState = settingsStateService.state
|
||||
settingsStateListeners.forEach(l => l(settingsState))
|
||||
})
|
||||
)
|
||||
|
||||
|
|
@ -99,12 +102,12 @@ export const useSidebarState = () => {
|
|||
return s
|
||||
}
|
||||
|
||||
export const useConfigState = () => {
|
||||
const [s, ss] = useState(settingsOfProvider)
|
||||
export const useSettingsState = () => {
|
||||
const [s, ss] = useState(settingsState)
|
||||
useEffect(() => {
|
||||
ss(settingsOfProvider)
|
||||
settingsOfProviderListeners.add(ss)
|
||||
return () => { settingsOfProviderListeners.delete(ss) }
|
||||
ss(settingsState)
|
||||
settingsStateListeners.add(ss)
|
||||
return () => { settingsStateListeners.delete(ss) }
|
||||
}, [ss])
|
||||
return s
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,66 +4,44 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { FeatureName, featureNames, ProviderName, providerNames } from '../../../../../../../platform/void/common/voidConfigTypes.js'
|
||||
import { dummyModelData } from '../../../../../../../platform/void/common/voidConfigTypes.js'
|
||||
import { useConfigState, useRefreshModelState, useService } from '../util/services.js'
|
||||
import { FeatureName, featureNames, ModelSelection, modelSelectionsEqual, ProviderName, providerNames } from '../../../../../../../platform/void/common/voidSettingsTypes.js'
|
||||
import { useSettingsState, useRefreshModelState, useService } from '../util/services.js'
|
||||
import { VoidSelectBox } from '../sidebar-tsx/inputs.js'
|
||||
import { SelectBox } from '../../../../../../../base/browser/ui/selectBox/selectBox.js'
|
||||
|
||||
|
||||
export const ModelSelectionOfFeature = ({ featureName }: { featureName: FeatureName }) => {
|
||||
|
||||
const voidConfigService = useService('configStateService')
|
||||
const voidConfigState = useConfigState()
|
||||
|
||||
const modelOptions: { text: string, value: [string, string] }[] = []
|
||||
|
||||
for (const providerName of providerNames) {
|
||||
const providerConfig = voidConfigState[providerName]
|
||||
if (providerConfig.enabled !== 'true') continue
|
||||
providerConfig.models?.forEach(model => {
|
||||
modelOptions.push({ text: `${model} (${providerName})`, value: [providerName, model] })
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
const isDummy = modelOptions.length === 0
|
||||
if (isDummy) {
|
||||
for (const [providerName, models] of Object.entries(dummyModelData)) {
|
||||
for (let model of models) {
|
||||
modelOptions.push({ text: `${model} (${providerName})`, value: ['dummy', 'dummy'] })
|
||||
}
|
||||
}
|
||||
}
|
||||
const voidSettingsService = useService('settingsStateService')
|
||||
const settingsState = useSettingsState()
|
||||
|
||||
let weChangedText = false
|
||||
|
||||
return <>
|
||||
<h2>{featureName}</h2>
|
||||
{
|
||||
<VoidSelectBox
|
||||
options={modelOptions}
|
||||
onChangeSelection={useCallback((newVal: [string, string]) => {
|
||||
if (isDummy) return // don't set state to the dummy value
|
||||
options={settingsState._modelsList}
|
||||
onChangeSelection={useCallback((newVal: ModelSelection) => {
|
||||
if (weChangedText) return
|
||||
|
||||
voidConfigService.setModelSelectionOfFeature(featureName, { providerName: newVal[0] as ProviderName, modelName: newVal[1] })
|
||||
}, [voidConfigService, featureName, isDummy])}
|
||||
voidSettingsService.setModelSelectionOfFeature(featureName, newVal)
|
||||
}, [voidSettingsService, featureName])}
|
||||
// we are responsible for setting the initial state here. always sync instance when state changes.
|
||||
onCreateInstance={useCallback((instance: SelectBox) => {
|
||||
const syncInstance = () => {
|
||||
const settingsAtProvider = voidConfigService.state.modelSelectionOfFeature[featureName]
|
||||
const index = modelOptions.findIndex(v => v.value[0] === settingsAtProvider?.providerName && v.value[1] === settingsAtProvider?.modelName)
|
||||
if (index !== -1) {
|
||||
const modelsListRef = voidSettingsService.state._modelsList // as a ref
|
||||
const settingsAtProvider = voidSettingsService.state.modelSelectionOfFeature[featureName]
|
||||
const selectionIdx = settingsAtProvider === null ? -1 : modelsListRef.findIndex(v => modelSelectionsEqual(v.value, settingsAtProvider))
|
||||
if (selectionIdx !== -1) {
|
||||
weChangedText = true
|
||||
instance.select(index)
|
||||
instance.select(selectionIdx)
|
||||
weChangedText = false
|
||||
}
|
||||
}
|
||||
syncInstance()
|
||||
const disposable = voidConfigService.onDidChangeState(syncInstance)
|
||||
const disposable = voidSettingsService.onDidChangeState(syncInstance)
|
||||
return [disposable]
|
||||
}, [voidConfigService, modelOptions, featureName])}
|
||||
}, [voidSettingsService, featureName])}
|
||||
/>}
|
||||
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import React, { Fragment, useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { titleOfProviderName, displayInfoOfSettingName, ProviderName, providerNames, featureNames, SettingsOfProvider, SettingName, defaultVoidProviderState } from '../../../../../../../platform/void/common/voidConfigTypes.js'
|
||||
import { titleOfProviderName, displayInfoOfSettingName, ProviderName, providerNames, featureNames, SettingsOfProvider, SettingName, defaultSettingsOfProvider } from '../../../../../../../platform/void/common/voidSettingsTypes.js'
|
||||
import { VoidInputBox } from '../sidebar-tsx/inputs.js'
|
||||
import { useConfigState, useService } from '../util/services.js'
|
||||
import { useSettingsState, useService } from '../util/services.js'
|
||||
import { InputBox } from '../../../../../../../base/browser/ui/inputbox/inputBox.js'
|
||||
import ErrorBoundary from '../sidebar-tsx/ErrorBoundary.js'
|
||||
|
||||
|
|
@ -14,41 +14,34 @@ import ErrorBoundary from '../sidebar-tsx/ErrorBoundary.js'
|
|||
const Setting = ({ providerName, settingName }: { providerName: ProviderName, settingName: SettingName }) => {
|
||||
|
||||
const { title, type, placeholder } = displayInfoOfSettingName(providerName, settingName)
|
||||
const voidConfigService = useService('configStateService')
|
||||
const voidSettingsService = useService('settingsStateService')
|
||||
|
||||
|
||||
let weChangedText = false
|
||||
let weChangedTextRef = false
|
||||
|
||||
return <><ErrorBoundary>
|
||||
<label>{title}</label>
|
||||
<VoidInputBox
|
||||
placeholder={placeholder}
|
||||
onChangeText={useCallback((newVal) => {
|
||||
if (weChangedText) return
|
||||
|
||||
voidConfigService.setSettingOfProvider(providerName, settingName, newVal)
|
||||
// if we just disabeld this provider, we should unselect all models that use it
|
||||
if (settingName === 'enabled' && newVal !== 'true') {
|
||||
for (let featureName of featureNames) {
|
||||
if (voidConfigService.state.modelSelectionOfFeature[featureName]?.providerName === providerName)
|
||||
voidConfigService.setModelSelectionOfFeature(featureName, null)
|
||||
}
|
||||
}
|
||||
}, [voidConfigService, providerName, settingName])}
|
||||
if (weChangedTextRef) return
|
||||
voidSettingsService.setSettingOfProvider(providerName, settingName, newVal)
|
||||
}, [voidSettingsService, providerName, settingName])}
|
||||
|
||||
// we are responsible for setting the initial value. always sync the instance whenever there's a change to state.
|
||||
onCreateInstance={useCallback((instance: InputBox) => {
|
||||
const syncInstance = () => {
|
||||
const settingsAtProvider = voidConfigService.state.settingsOfProvider[providerName];
|
||||
const settingsAtProvider = voidSettingsService.state.settingsOfProvider[providerName];
|
||||
const stateVal = settingsAtProvider[settingName as keyof typeof settingsAtProvider]
|
||||
weChangedText = true
|
||||
// console.log('SYNCING TO', providerName, settingName, stateVal)
|
||||
weChangedTextRef = true
|
||||
instance.value = stateVal as string
|
||||
weChangedText = false
|
||||
weChangedTextRef = false
|
||||
}
|
||||
syncInstance()
|
||||
const disposable = voidConfigService.onDidChangeState(syncInstance)
|
||||
const disposable = voidSettingsService.onDidChangeState(syncInstance)
|
||||
return [disposable]
|
||||
}, [voidConfigService, providerName, settingName])}
|
||||
}, [voidSettingsService, providerName, settingName])}
|
||||
multiline={false}
|
||||
/>
|
||||
</ErrorBoundary></>
|
||||
|
|
@ -57,8 +50,8 @@ const Setting = ({ providerName, settingName }: { providerName: ProviderName, se
|
|||
|
||||
|
||||
const SettingsForProvider = ({ providerName }: { providerName: ProviderName }) => {
|
||||
const voidConfigState = useConfigState()
|
||||
const { models, ...others } = voidConfigState[providerName]
|
||||
const voidSettingsState = useSettingsState()
|
||||
const { models, ...others } = voidSettingsState.settingsOfProvider[providerName]
|
||||
|
||||
return <>
|
||||
<h1 className='text-xl'>{titleOfProviderName(providerName)}</h1>
|
||||
|
|
@ -77,7 +70,5 @@ export const VoidProviderSettings = () => {
|
|||
{providerNames.map(providerName =>
|
||||
<SettingsForProvider key={providerName} providerName={providerName} />
|
||||
)}
|
||||
|
||||
|
||||
</>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,51 +0,0 @@
|
|||
import { ServicesAccessor } from '../../../../editor/browser/editorExtensions.js';
|
||||
import { IModelService } from '../../../../editor/common/services/model.js';
|
||||
import { IClipboardService } from '../../../../platform/clipboard/common/clipboardService.js';
|
||||
import { IContextViewService, IContextMenuService } from '../../../../platform/contextview/browser/contextView.js';
|
||||
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 { IVoidConfigStateService } from '../../../../platform/void/common/voidConfigService.js';
|
||||
import { IInlineDiffsService } from './registerInlineDiffs.js';
|
||||
import { IVoidSidebarStateService } from './registerSidebar.js';
|
||||
import { IThreadHistoryService } from './registerThreads.js';
|
||||
|
||||
export type ReactServicesType = {
|
||||
sidebarStateService: IVoidSidebarStateService;
|
||||
configStateService: IVoidConfigStateService;
|
||||
threadsStateService: IThreadHistoryService;
|
||||
fileService: IFileService;
|
||||
modelService: IModelService;
|
||||
inlineDiffService: IInlineDiffsService;
|
||||
llmMessageService: ILLMMessageService;
|
||||
clipboardService: IClipboardService;
|
||||
refreshModelService: IRefreshModelService;
|
||||
|
||||
themeService: IThemeService,
|
||||
hoverService: IHoverService,
|
||||
|
||||
contextViewService: IContextViewService;
|
||||
contextMenuService: IContextMenuService;
|
||||
}
|
||||
|
||||
|
||||
export const getReactServices = (accessor: ServicesAccessor): ReactServicesType => {
|
||||
return {
|
||||
configStateService: accessor.get(IVoidConfigStateService),
|
||||
sidebarStateService: accessor.get(IVoidSidebarStateService),
|
||||
threadsStateService: accessor.get(IThreadHistoryService),
|
||||
fileService: accessor.get(IFileService),
|
||||
modelService: accessor.get(IModelService),
|
||||
inlineDiffService: accessor.get(IInlineDiffsService),
|
||||
llmMessageService: accessor.get(ILLMMessageService),
|
||||
clipboardService: accessor.get(IClipboardService),
|
||||
themeService: accessor.get(IThemeService),
|
||||
hoverService: accessor.get(IHoverService),
|
||||
refreshModelService: accessor.get(IRefreshModelService),
|
||||
contextViewService: accessor.get(IContextViewService),
|
||||
contextMenuService: accessor.get(IContextMenuService),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -11,16 +11,16 @@ import { ServicesAccessor } from '../../../../editor/browser/editorExtensions.js
|
|||
|
||||
import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js';
|
||||
import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js';
|
||||
import { CodeStagingSelection, IThreadHistoryService } from './registerThreads.js';
|
||||
import { CodeStagingSelection, IThreadHistoryService } from './threadHistoryService.js';
|
||||
// import { IEditorService } from '../../../services/editor/common/editorService.js';
|
||||
|
||||
import { IEditorService } from '../../../services/editor/common/editorService.js';
|
||||
import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js';
|
||||
import { IRange } from '../../../../editor/common/core/range.js';
|
||||
import { ITextModel } from '../../../../editor/common/model.js';
|
||||
import { IVoidSidebarStateService, VOID_VIEW_ID } from './registerSidebar.js';
|
||||
import { VOID_VIEW_ID } from './sidebarViewPane.js';
|
||||
import { IMetricsService } from '../../../../platform/void/common/metricsService.js';
|
||||
// import { IClipboardService } from '../../../../platform/clipboard/common/clipboardService.js';
|
||||
import { ISidebarStateService } from './sidebarStateService.js';
|
||||
|
||||
|
||||
// ---------- Register commands and keybindings ----------
|
||||
|
|
@ -61,7 +61,7 @@ registerAction2(class extends Action2 {
|
|||
if (!model)
|
||||
return
|
||||
|
||||
const stateService = accessor.get(IVoidSidebarStateService)
|
||||
const stateService = accessor.get(ISidebarStateService)
|
||||
const metricsService = accessor.get(IMetricsService)
|
||||
|
||||
metricsService.capture('Chat Navigation', { type: 'Ctrl+L' })
|
||||
|
|
@ -126,7 +126,7 @@ registerAction2(class extends Action2 {
|
|||
});
|
||||
}
|
||||
async run(accessor: ServicesAccessor): Promise<void> {
|
||||
const stateService = accessor.get(IVoidSidebarStateService)
|
||||
const stateService = accessor.get(ISidebarStateService)
|
||||
const metricsService = accessor.get(IMetricsService)
|
||||
|
||||
metricsService.capture('Chat Navigation', { type: 'New Chat' })
|
||||
|
|
@ -149,7 +149,7 @@ registerAction2(class extends Action2 {
|
|||
});
|
||||
}
|
||||
async run(accessor: ServicesAccessor): Promise<void> {
|
||||
const stateService = accessor.get(IVoidSidebarStateService)
|
||||
const stateService = accessor.get(ISidebarStateService)
|
||||
const metricsService = accessor.get(IMetricsService)
|
||||
|
||||
metricsService.capture('Chat Navigation', { type: 'History' })
|
||||
|
|
@ -159,7 +159,6 @@ registerAction2(class extends Action2 {
|
|||
}
|
||||
})
|
||||
|
||||
// // Settings (API config) menu button
|
||||
// registerAction2(class extends Action2 {
|
||||
// constructor() {
|
||||
// super({
|
||||
84
src/vs/workbench/contrib/void/browser/sidebarStateService.ts
Normal file
84
src/vs/workbench/contrib/void/browser/sidebarStateService.ts
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
import { Emitter, Event } from '../../../../base/common/event.js';
|
||||
import { Disposable } from '../../../../base/common/lifecycle.js';
|
||||
import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';
|
||||
import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
|
||||
import { IViewsService } from '../../../services/views/common/viewsService.js';
|
||||
import { VOID_VIEW_CONTAINER_ID, VOID_VIEW_ID } from './sidebarViewPane.js';
|
||||
|
||||
|
||||
// service that manages sidebar's state
|
||||
export type VoidSidebarState = {
|
||||
isHistoryOpen: boolean;
|
||||
currentTab: 'chat';
|
||||
}
|
||||
|
||||
export interface ISidebarStateService {
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
readonly state: VoidSidebarState; // readonly to the user
|
||||
setState(newState: Partial<VoidSidebarState>): void;
|
||||
onDidChangeState: Event<void>;
|
||||
|
||||
onDidFocusChat: Event<void>;
|
||||
onDidBlurChat: Event<void>;
|
||||
fireFocusChat(): void;
|
||||
fireBlurChat(): void;
|
||||
|
||||
openSidebarView(): void;
|
||||
}
|
||||
|
||||
export const ISidebarStateService = createDecorator<ISidebarStateService>('voidSidebarStateService');
|
||||
class VoidSidebarStateService extends Disposable implements ISidebarStateService {
|
||||
_serviceBrand: undefined;
|
||||
|
||||
static readonly ID = 'voidSidebarStateService';
|
||||
|
||||
private readonly _onDidChangeState = new Emitter<void>();
|
||||
readonly onDidChangeState: Event<void> = this._onDidChangeState.event;
|
||||
|
||||
private readonly _onFocusChat = new Emitter<void>();
|
||||
readonly onDidFocusChat: Event<void> = this._onFocusChat.event;
|
||||
|
||||
private readonly _onBlurChat = new Emitter<void>();
|
||||
readonly onDidBlurChat: Event<void> = this._onBlurChat.event;
|
||||
|
||||
|
||||
// state
|
||||
state: VoidSidebarState
|
||||
|
||||
constructor(
|
||||
@IViewsService private readonly _viewsService: IViewsService,
|
||||
) {
|
||||
super()
|
||||
|
||||
// initial state
|
||||
this.state = { isHistoryOpen: false, currentTab: 'chat', }
|
||||
}
|
||||
|
||||
|
||||
setState(newState: Partial<VoidSidebarState>) {
|
||||
// make sure view is open if the tab changes
|
||||
if ('currentTab' in newState) {
|
||||
this.openSidebarView()
|
||||
}
|
||||
|
||||
this.state = { ...this.state, ...newState }
|
||||
this._onDidChangeState.fire()
|
||||
}
|
||||
|
||||
fireFocusChat() {
|
||||
this._onFocusChat.fire()
|
||||
}
|
||||
|
||||
fireBlurChat() {
|
||||
this._onBlurChat.fire()
|
||||
}
|
||||
|
||||
openSidebarView() {
|
||||
this._viewsService.openViewContainer(VOID_VIEW_CONTAINER_ID);
|
||||
this._viewsService.openView(VOID_VIEW_ID);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
registerSingleton(ISidebarStateService, VoidSidebarStateService, InstantiationType.Eager);
|
||||
|
|
@ -24,9 +24,8 @@ import { SyncDescriptor } from '../../../../platform/instantiation/common/descri
|
|||
import { IViewPaneOptions, ViewPane } from '../../../browser/parts/views/viewPane.js';
|
||||
|
||||
import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';
|
||||
import { createDecorator, IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
|
||||
import { Disposable, IDisposable } from '../../../../base/common/lifecycle.js';
|
||||
import { Emitter, Event } from '../../../../base/common/event.js';
|
||||
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
|
||||
import { IDisposable } from '../../../../base/common/lifecycle.js';
|
||||
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
|
||||
import { IThemeService } from '../../../../platform/theme/common/themeService.js';
|
||||
import { IContextMenuService } from '../../../../platform/contextview/browser/contextView.js';
|
||||
|
|
@ -37,18 +36,11 @@ import { IHoverService } from '../../../../platform/hover/browser/hover.js';
|
|||
|
||||
import { mountSidebar } from './react/out/sidebar-tsx/index.js';
|
||||
|
||||
import { IViewsService } from '../../../services/views/common/viewsService.js';
|
||||
import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';
|
||||
import { getReactServices } from './reactServices.js';
|
||||
import { getReactServices } from './helpers/reactServicesHelper.js';
|
||||
|
||||
|
||||
// compare against search.contribution.ts and debug.contribution.ts, scm.contribution.ts (source control)
|
||||
|
||||
export type VoidSidebarState = {
|
||||
isHistoryOpen: boolean;
|
||||
currentTab: 'chat';
|
||||
}
|
||||
|
||||
// ---------- Define viewpane ----------
|
||||
|
||||
class VoidSidebarViewPane extends ViewPane {
|
||||
|
|
@ -132,77 +124,3 @@ viewsRegistry.registerViews([{
|
|||
// },
|
||||
}], viewContainer);
|
||||
|
||||
|
||||
|
||||
// ---------- Register service that manages sidebar's state ----------
|
||||
|
||||
export interface IVoidSidebarStateService {
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
readonly state: VoidSidebarState; // readonly to the user
|
||||
setState(newState: Partial<VoidSidebarState>): void;
|
||||
onDidChangeState: Event<void>;
|
||||
|
||||
onDidFocusChat: Event<void>;
|
||||
onDidBlurChat: Event<void>;
|
||||
fireFocusChat(): void;
|
||||
fireBlurChat(): void;
|
||||
|
||||
openSidebarView(): void;
|
||||
}
|
||||
|
||||
export const IVoidSidebarStateService = createDecorator<IVoidSidebarStateService>('voidSidebarStateService');
|
||||
class VoidSidebarStateService extends Disposable implements IVoidSidebarStateService {
|
||||
_serviceBrand: undefined;
|
||||
|
||||
static readonly ID = 'voidSidebarStateService';
|
||||
|
||||
private readonly _onDidChangeState = new Emitter<void>();
|
||||
readonly onDidChangeState: Event<void> = this._onDidChangeState.event;
|
||||
|
||||
private readonly _onFocusChat = new Emitter<void>();
|
||||
readonly onDidFocusChat: Event<void> = this._onFocusChat.event;
|
||||
|
||||
private readonly _onBlurChat = new Emitter<void>();
|
||||
readonly onDidBlurChat: Event<void> = this._onBlurChat.event;
|
||||
|
||||
|
||||
// state
|
||||
state: VoidSidebarState
|
||||
|
||||
constructor(
|
||||
@IViewsService private readonly _viewsService: IViewsService,
|
||||
) {
|
||||
super()
|
||||
|
||||
// initial state
|
||||
this.state = { isHistoryOpen: false, currentTab: 'chat', }
|
||||
}
|
||||
|
||||
|
||||
setState(newState: Partial<VoidSidebarState>) {
|
||||
// make sure view is open if the tab changes
|
||||
if ('currentTab' in newState) {
|
||||
this.openSidebarView()
|
||||
}
|
||||
|
||||
this.state = { ...this.state, ...newState }
|
||||
this._onDidChangeState.fire()
|
||||
}
|
||||
|
||||
fireFocusChat() {
|
||||
this._onFocusChat.fire()
|
||||
}
|
||||
|
||||
fireBlurChat() {
|
||||
this._onBlurChat.fire()
|
||||
}
|
||||
|
||||
openSidebarView() {
|
||||
this._viewsService.openViewContainer(VOID_VIEW_CONTAINER_ID);
|
||||
this._viewsService.openView(VOID_VIEW_ID);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
registerSingleton(IVoidSidebarStateService, VoidSidebarStateService, InstantiationType.Eager);
|
||||
|
|
@ -10,7 +10,7 @@ import { IStorageService, StorageScope, StorageTarget } from '../../../../platfo
|
|||
|
||||
import { URI } from '../../../../base/common/uri.js';
|
||||
import { Emitter, Event } from '../../../../base/common/event.js';
|
||||
import { IAutocompleteService } from './registerAutocomplete.js';
|
||||
import { IAutocompleteService } from './autocompleteService.js';
|
||||
import { IRange } from '../../../../editor/common/core/range.js';
|
||||
|
||||
export type CodeSelection = {
|
||||
|
|
@ -80,7 +80,7 @@ const newThreadObject = () => {
|
|||
}
|
||||
}
|
||||
|
||||
const THREAD_STORAGE_KEY = 'void.threadsHistory'
|
||||
const THREAD_STORAGE_KEY = 'void.threadHistory'
|
||||
|
||||
export interface IThreadHistoryService {
|
||||
readonly _serviceBrand: undefined;
|
||||
|
|
@ -3,23 +3,23 @@
|
|||
* Void Editor additions licensed under the AGPL 3.0 License.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
// register keybinds
|
||||
import './registerActions.js'
|
||||
|
||||
// register inline diffs
|
||||
import './registerInlineDiffs.js'
|
||||
import './inlineDiffsService.js'
|
||||
|
||||
// register Sidebar chat
|
||||
import './registerSidebar.js'
|
||||
// register Sidebar pane, state, actions (keybinds, menus)
|
||||
import './sidebarActions.js'
|
||||
import './sidebarViewPane.js'
|
||||
import './sidebarStateService.js'
|
||||
|
||||
// register Thread History
|
||||
import './registerThreads.js'
|
||||
import './threadHistoryService.js'
|
||||
|
||||
// register Autocomplete
|
||||
import './registerAutocomplete.js'
|
||||
import './autocompleteService.js'
|
||||
|
||||
// register css
|
||||
import './media/void.css'
|
||||
|
||||
// settings pane
|
||||
import './voidSettingsEditorPane.js'
|
||||
import './voidSettingsPane.js'
|
||||
|
|
|
|||
|
|
@ -15,10 +15,8 @@ import { IStorageService } from '../../../../platform/storage/common/storage.js'
|
|||
import { Dimension } from '../../../../base/browser/dom.js';
|
||||
import { EditorPaneDescriptor, IEditorPaneRegistry } from '../../../browser/editor.js';
|
||||
import { SyncDescriptor } from '../../../../platform/instantiation/common/descriptors.js';
|
||||
import { Action2, registerAction2 } from '../../../../platform/actions/common/actions.js';
|
||||
import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js';
|
||||
import { Action2, MenuId, registerAction2 } from '../../../../platform/actions/common/actions.js';
|
||||
import { Registry } from '../../../../platform/registry/common/platform.js';
|
||||
import { KeyCode, KeyMod } from '../../../../base/common/keyCodes.js';
|
||||
import { ServicesAccessor } from '../../../../editor/browser/editorExtensions.js';
|
||||
import { IEditorService } from '../../../services/editor/common/editorService.js';
|
||||
import { URI } from '../../../../base/common/uri.js';
|
||||
|
|
@ -26,12 +24,13 @@ import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextke
|
|||
|
||||
|
||||
import { mountVoidSettings } from './react/out/void-settings-tsx/index.js'
|
||||
import { getReactServices } from './reactServices.js';
|
||||
import { getReactServices } from './helpers/reactServicesHelper.js';
|
||||
import { Codicon } from '../../../../base/common/codicons.js';
|
||||
|
||||
|
||||
// refer to preferences.contribution.ts keybindings editor
|
||||
|
||||
export class VoidEditorInput extends EditorInput {
|
||||
class VoidEditorInput extends EditorInput {
|
||||
|
||||
static readonly ID: string = 'workbench.input.void.settings';
|
||||
|
||||
|
|
@ -93,17 +92,25 @@ Registry.as<IEditorPaneRegistry>(EditorExtensions.EditorPane).registerEditorPane
|
|||
);
|
||||
|
||||
|
||||
// Register the action
|
||||
// Register the gear
|
||||
registerAction2(class extends Action2 {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'workbench.action.openVoidEditor',
|
||||
title: 'Open Void Settings',
|
||||
keybinding: {
|
||||
when: ContextKeyExpr.true(),
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KeyE,
|
||||
weight: KeybindingWeight.WorkbenchContrib
|
||||
}
|
||||
id: 'workbench.action.openVoidSettings',
|
||||
title: nls.localize2('voidSettings', "Void: Settings"),
|
||||
f1: true,
|
||||
icon: Codicon.gear,
|
||||
menu: [
|
||||
{
|
||||
id: MenuId.LayoutControlMenuSubmenu,
|
||||
group: 'z_end',
|
||||
},
|
||||
{
|
||||
id: MenuId.LayoutControlMenu,
|
||||
when: ContextKeyExpr.equals('config.workbench.layoutControl.type', 'both'),
|
||||
group: 'z_end'
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
async run(accessor: ServicesAccessor): Promise<void> {
|
||||
|
|
@ -112,5 +119,4 @@ registerAction2(class extends Action2 {
|
|||
const input = instantiationService.createInstance(VoidEditorInput);
|
||||
await editorService.openEditor(input);
|
||||
}
|
||||
});
|
||||
|
||||
})
|
||||
Loading…
Reference in a new issue