mirror of
https://github.com/voideditor/void
synced 2026-05-24 09:58:23 +00:00
ollama refreshes!
This commit is contained in:
parent
1365400f21
commit
e2d39fe4b1
19 changed files with 271 additions and 116 deletions
|
|
@ -1,32 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Glass Devtools, Inc. All rights reserved.
|
||||
* Void Editor additions licensed under the AGPL 3.0 License.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ProxyChannel } from '../../../base/parts/ipc/common/ipc.js';
|
||||
import { IMainProcessService } from '../../ipc/common/mainProcessService.js';
|
||||
import { InstantiationType, registerSingleton } from '../../instantiation/common/extensions.js';
|
||||
import { IMetricsService } from '../common/metricsService.js';
|
||||
|
||||
// BROWSER IMPLEMENTATION, calls channel
|
||||
|
||||
export class MetricsService implements IMetricsService {
|
||||
|
||||
readonly _serviceBrand: undefined;
|
||||
private readonly metricsService: IMetricsService;
|
||||
|
||||
constructor(
|
||||
@IMainProcessService mainProcessService: IMainProcessService // (only usable on client side)
|
||||
) {
|
||||
this.metricsService = ProxyChannel.toService<IMetricsService>(mainProcessService.getChannel('void-channel-metrics'));
|
||||
}
|
||||
|
||||
// call capture on the channel
|
||||
capture(...params: Parameters<IMetricsService['capture']>) {
|
||||
this.metricsService.capture(...params);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
registerSingleton(IMetricsService, MetricsService, InstantiationType.Eager);
|
||||
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
|
||||
// --- browser ---
|
||||
// metrics
|
||||
import '../browser/metricsService.js'
|
||||
|
||||
// --- common ---
|
||||
// llmMessage
|
||||
import '../browser/llmMessageService.js'
|
||||
|
||||
// voidConfig
|
||||
import '../common/voidConfigService.js'
|
||||
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* Void Editor additions licensed under the AGPL 3.0 License.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { EventLLMMessageOnTextParams, EventLLMMessageOnErrorParams, EventLLMMessageOnFinalMessageParams, ServiceSendLLMMessageParams, MainLLMMessageParams, MainLLMMessageAbortParams, ServiceOllamaListParams, EventOllamaListOnSuccessParams, EventOllamaListOnErrorParams, MainOllamaListParams } from '../common/llmMessageTypes.js';
|
||||
import { EventLLMMessageOnTextParams, EventLLMMessageOnErrorParams, EventLLMMessageOnFinalMessageParams, ServiceSendLLMMessageParams, MainLLMMessageParams, MainLLMMessageAbortParams, ServiceOllamaListParams, EventOllamaListOnSuccessParams, EventOllamaListOnErrorParams, MainOllamaListParams } from './llmMessageTypes.js';
|
||||
import { IChannel } from '../../../base/parts/ipc/common/ipc.js';
|
||||
import { IMainProcessService } from '../../ipc/common/mainProcessService.js';
|
||||
import { InstantiationType, registerSingleton } from '../../instantiation/common/extensions.js';
|
||||
|
|
@ -11,21 +11,19 @@ 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 '../common/voidConfigService.js';
|
||||
import { IVoidConfigStateService } from './voidConfigService.js';
|
||||
// import { INotificationService } from '../../notification/common/notification.js';
|
||||
|
||||
|
||||
// BROWSER IMPLEMENTATION
|
||||
// calls channel to implement features
|
||||
export const ILLMMessageService = createDecorator<ILLMMessageService>('llmMessageService');
|
||||
|
||||
// defines an interface that node/ creates and browser/ uses
|
||||
export interface ILLMMessageService {
|
||||
readonly _serviceBrand: undefined;
|
||||
sendLLMMessage: (params: ServiceSendLLMMessageParams) => string | null;
|
||||
abort: (requestId: string) => void;
|
||||
ollamaList: (params: ServiceOllamaListParams) => void;
|
||||
}
|
||||
|
||||
|
||||
export class LLMMessageService extends Disposable implements ILLMMessageService {
|
||||
|
||||
readonly _serviceBrand: undefined;
|
||||
|
|
@ -52,8 +50,7 @@ export class LLMMessageService extends Disposable implements ILLMMessageService
|
|||
// const service = ProxyChannel.toService<LLMMessageChannel>(mainProcessService.getChannel('void-channel-sendLLMMessage')); // lets you call it like a service
|
||||
this.channel = this.mainProcessService.getChannel('void-channel-llmMessageService')
|
||||
|
||||
// this sets up an IPC channel and takes a few ms, so we set up listeners immediately and add hooks to them instead
|
||||
|
||||
// .listen sets up an IPC channel and takes a few ms, so we set up listeners immediately and add hooks to them instead
|
||||
// llm
|
||||
this._register((this.channel.listen('onText_llm') satisfies Event<EventLLMMessageOnTextParams>)(e => {
|
||||
this.onTextHooks_llm[e.requestId]?.(e)
|
||||
|
|
@ -74,6 +71,7 @@ export class LLMMessageService extends Disposable implements ILLMMessageService
|
|||
this._register((this.channel.listen('onError_ollama') satisfies Event<EventOllamaListOnErrorParams>)(e => {
|
||||
this.onError_ollama[e.requestId]?.(e)
|
||||
}))
|
||||
|
||||
}
|
||||
|
||||
sendLLMMessage(params: ServiceSendLLMMessageParams) {
|
||||
|
|
@ -114,6 +112,7 @@ export class LLMMessageService extends Disposable implements ILLMMessageService
|
|||
this._onRequestIdDone(requestId)
|
||||
}
|
||||
|
||||
|
||||
ollamaList = (params: ServiceOllamaListParams) => {
|
||||
const { onSuccess, onError, ...proxyParams } = params
|
||||
|
||||
|
|
@ -132,6 +131,7 @@ export class LLMMessageService extends Disposable implements ILLMMessageService
|
|||
}
|
||||
|
||||
|
||||
|
||||
_onRequestIdDone(requestId: string) {
|
||||
delete this.onTextHooks_llm[requestId]
|
||||
delete this.onFinalMessageHooks_llm[requestId]
|
||||
|
|
@ -142,5 +142,5 @@ export class LLMMessageService extends Disposable implements ILLMMessageService
|
|||
}
|
||||
}
|
||||
|
||||
registerSingleton(ILLMMessageService, LLMMessageService, InstantiationType.Delayed);
|
||||
registerSingleton(ILLMMessageService, LLMMessageService, InstantiationType.Eager);
|
||||
|
||||
|
|
@ -106,7 +106,7 @@ interface ModelDetails {
|
|||
quantization_level: string;
|
||||
}
|
||||
|
||||
type ModelResponse = {
|
||||
export type ModelResponse = {
|
||||
name: string;
|
||||
modified_at: Date;
|
||||
size: number;
|
||||
|
|
@ -121,7 +121,7 @@ type ModelResponse = {
|
|||
export type OllamaListParams = {
|
||||
settingsOfProvider: SettingsOfProvider;
|
||||
onSuccess: (param: { models: ModelResponse[] }) => void;
|
||||
onError: (param: { error: any }) => void;
|
||||
onError: (param: { error: string }) => void;
|
||||
}
|
||||
|
||||
export type ServiceOllamaListParams = {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { createDecorator } from '../../instantiation/common/instantiation.js';
|
||||
import { ProxyChannel } from '../../../base/parts/ipc/common/ipc.js';
|
||||
import { IMainProcessService } from '../../ipc/common/mainProcessService.js';
|
||||
import { InstantiationType, registerSingleton } from '../../instantiation/common/extensions.js';
|
||||
|
||||
export interface IMetricsService {
|
||||
readonly _serviceBrand: undefined;
|
||||
|
|
@ -13,3 +16,24 @@ export interface IMetricsService {
|
|||
export const IMetricsService = createDecorator<IMetricsService>('metricsService');
|
||||
|
||||
|
||||
// implemented by calling channel
|
||||
export class MetricsService implements IMetricsService {
|
||||
|
||||
readonly _serviceBrand: undefined;
|
||||
private readonly metricsService: IMetricsService;
|
||||
|
||||
constructor(
|
||||
@IMainProcessService mainProcessService: IMainProcessService // (only usable on client side)
|
||||
) {
|
||||
this.metricsService = ProxyChannel.toService<IMetricsService>(mainProcessService.getChannel('void-channel-metrics'));
|
||||
}
|
||||
|
||||
// call capture on the channel
|
||||
capture(...params: Parameters<IMetricsService['capture']>) {
|
||||
this.metricsService.capture(...params);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
registerSingleton(IMetricsService, MetricsService, InstantiationType.Eager);
|
||||
|
||||
|
|
|
|||
96
src/vs/platform/void/common/refreshModelService.ts
Normal file
96
src/vs/platform/void/common/refreshModelService.ts
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Glass Devtools, Inc. All rights reserved.
|
||||
* Void Editor additions licensed under the AGPL 3.0 License.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { createDecorator } from '../../instantiation/common/instantiation.js';
|
||||
import { InstantiationType, registerSingleton } from '../../instantiation/common/extensions.js';
|
||||
import { IVoidConfigStateService } from './voidConfigService.js';
|
||||
import { ILLMMessageService } from './llmMessageService.js';
|
||||
import { Emitter, Event } from '../../../base/common/event.js';
|
||||
import { Disposable } from '../../../base/common/lifecycle.js';
|
||||
|
||||
|
||||
export type RefreshModelState = 'done' | 'loading'
|
||||
|
||||
export interface IRefreshModelService {
|
||||
readonly _serviceBrand: undefined;
|
||||
refreshOllamaModels(): void;
|
||||
onDidChangeState: Event<void>;
|
||||
state: RefreshModelState;
|
||||
}
|
||||
|
||||
export const IRefreshModelService = createDecorator<IRefreshModelService>('RefreshModelService');
|
||||
|
||||
export class RefreshModelService extends Disposable implements IRefreshModelService {
|
||||
|
||||
readonly _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
|
||||
|
||||
constructor(
|
||||
@IVoidConfigStateService private readonly voidConfigStateService: IVoidConfigStateService,
|
||||
@ILLMMessageService private readonly llmMessageService: ILLMMessageService,
|
||||
) {
|
||||
super()
|
||||
|
||||
// on mount, refresh ollama models
|
||||
this.refreshOllamaModels()
|
||||
|
||||
// every time ollama.enabled changes, refresh ollama models
|
||||
let prevVal: string = this.voidConfigStateService.state.settingsOfProvider.ollama.enabled
|
||||
this._register(
|
||||
this.voidConfigStateService.onDidChangeState(() => {
|
||||
const newVal = this.voidConfigStateService.state.settingsOfProvider.ollama.enabled
|
||||
if (prevVal !== newVal)
|
||||
this.refreshOllamaModels()
|
||||
prevVal = newVal
|
||||
})
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
state: RefreshModelState = 'done'
|
||||
|
||||
private _timeoutId: NodeJS.Timeout | null = null
|
||||
private _cancelTimeout = () => {
|
||||
if (this._timeoutId) {
|
||||
clearTimeout(this._timeoutId)
|
||||
this._timeoutId = null
|
||||
}
|
||||
}
|
||||
async refreshOllamaModels() {
|
||||
// cancel any existing poll
|
||||
this._cancelTimeout()
|
||||
|
||||
// if ollama is disabled, obivously done
|
||||
if (this.voidConfigStateService.state.settingsOfProvider.ollama.enabled !== 'true') {
|
||||
this._setState('done')
|
||||
return
|
||||
}
|
||||
|
||||
// start loading models
|
||||
this._setState('loading')
|
||||
|
||||
this.llmMessageService.ollamaList({
|
||||
onSuccess: ({ models }) => {
|
||||
this.voidConfigStateService.setSettingOfProvider('ollama', 'models', models.map(model => model.name))
|
||||
this._setState('done')
|
||||
},
|
||||
onError: ({ error }) => {
|
||||
// poll
|
||||
console.log('retrying ollamaList:', error)
|
||||
this._timeoutId = setTimeout(() => this.refreshOllamaModels(), 5000)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private _setState(state: RefreshModelState) {
|
||||
this.state = state
|
||||
this._onDidChangeState.fire()
|
||||
}
|
||||
}
|
||||
|
||||
registerSingleton(IRefreshModelService, RefreshModelService, InstantiationType.Eager);
|
||||
|
||||
11
src/vs/platform/void/common/void.contribution.ts
Normal file
11
src/vs/platform/void/common/void.contribution.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
// llmMessage
|
||||
import './llmMessageService.js'
|
||||
|
||||
// voidConfig
|
||||
import './voidConfigService.js'
|
||||
|
||||
// refreshModel
|
||||
import './refreshModelService.js'
|
||||
|
||||
// metrics
|
||||
import './metricsService.js'
|
||||
|
|
@ -10,15 +10,15 @@ 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 } from './voidConfigTypes.js';
|
||||
import { defaultVoidProviderState, FeatureName, ProviderName, ModelSelectionOfFeature, SettingsOfProvider, SettingName } from './voidConfigTypes.js';
|
||||
|
||||
|
||||
const STORAGE_KEY = 'void.voidConfigStateII'
|
||||
|
||||
type SetSettingOfProviderFn = <K extends ProviderName>(
|
||||
providerName: K,
|
||||
option: keyof SettingsOfProvider[K],
|
||||
newVal: string
|
||||
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>(
|
||||
|
|
@ -52,7 +52,7 @@ const defaultState = () => {
|
|||
|
||||
|
||||
export const IVoidConfigStateService = createDecorator<IVoidConfigStateService>('VoidConfigStateService');
|
||||
class VoidConfigStateService extends Disposable implements IVoidConfigStateService {
|
||||
class VoidConfigService extends Disposable implements IVoidConfigStateService {
|
||||
_serviceBrand: undefined;
|
||||
|
||||
private readonly _onDidChangeState = new Emitter<void>();
|
||||
|
|
@ -75,7 +75,10 @@ class VoidConfigStateService extends Disposable implements IVoidConfigStateServi
|
|||
this.state = defaultState()
|
||||
|
||||
// read and update the actual state immediately
|
||||
this._readVoidConfigState().then(voidConfigState => { this._setState(voidConfigState, 'initialState') })
|
||||
this._readVoidConfigState().then(voidConfigState => {
|
||||
this._setState(voidConfigState)
|
||||
this._onDidGetInitState.fire()
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -95,16 +98,16 @@ class VoidConfigStateService extends Disposable implements IVoidConfigStateServi
|
|||
this._storageService.store(STORAGE_KEY, encryptedVoidConfigStr, StorageScope.APPLICATION, StorageTarget.USER);
|
||||
}
|
||||
|
||||
setSettingOfProvider: SetSettingOfProviderFn = async (providerName, option, newVal) => {
|
||||
setSettingOfProvider: SetSettingOfProviderFn = async (providerName, settingName, newVal) => {
|
||||
const newState: VoidConfigState = {
|
||||
...this.state,
|
||||
settingsOfProvider: {
|
||||
...this.state.settingsOfProvider,
|
||||
[providerName]: {
|
||||
...this.state.settingsOfProvider[providerName],
|
||||
[option]: newVal,
|
||||
[settingName]: newVal,
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
// console.log('NEW STATE I', JSON.stringify(newState, null, 2))
|
||||
|
||||
|
|
@ -129,14 +132,11 @@ class VoidConfigStateService extends Disposable implements IVoidConfigStateServi
|
|||
|
||||
|
||||
// internal function to update state, should be called every time state changes
|
||||
private async _setState(voidConfigState: VoidConfigState, type: 'usual' | 'initialState' = 'usual') {
|
||||
private async _setState(voidConfigState: VoidConfigState) {
|
||||
this.state = voidConfigState
|
||||
if (type === 'usual')
|
||||
this._onDidChangeState.fire()
|
||||
else if (type === 'initialState')
|
||||
this._onDidGetInitState.fire()
|
||||
this._onDidChangeState.fire()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
registerSingleton(IVoidConfigStateService, VoidConfigStateService, InstantiationType.Eager);
|
||||
registerSingleton(IVoidConfigStateService, VoidConfigService, InstantiationType.Eager);
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ export const voidInitModelOptions = {
|
|||
models: defaultOpenAIModels,
|
||||
},
|
||||
ollama: {
|
||||
models: [],//getDefaultOllamaModels,
|
||||
models: [],
|
||||
},
|
||||
openRouter: {
|
||||
models: [], // any string
|
||||
|
|
@ -164,7 +164,7 @@ export const displayInfoOfSettingName = (providerName: ProviderName, settingName
|
|||
}
|
||||
|
||||
|
||||
|
||||
// used when waiting and for a type reference
|
||||
export const defaultVoidProviderState: SettingsOfProvider = {
|
||||
anthropic: {
|
||||
...voidProviderDefaults.anthropic,
|
||||
|
|
|
|||
|
|
@ -4,21 +4,35 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Ollama } from 'ollama';
|
||||
import { _InternalOllamaListFnType, _InternalSendLLMMessageFnType } from '../../common/llmMessageTypes.js';
|
||||
import { _InternalOllamaListFnType, _InternalSendLLMMessageFnType, ModelResponse } from '../../common/llmMessageTypes.js';
|
||||
import { parseMaxTokensStr } from './util.js';
|
||||
|
||||
export const ollamaList: _InternalOllamaListFnType = async ({ onSuccess, onError, settingsOfProvider }) => {
|
||||
const thisConfig = settingsOfProvider.ollama
|
||||
const ollama = new Ollama({ host: thisConfig.endpoint })
|
||||
ollama.list()
|
||||
.then((response) => {
|
||||
const { models } = response
|
||||
onSuccess({ models })
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('getDefaultOllamaModels: error:', error)
|
||||
onError(error)
|
||||
})
|
||||
export const ollamaList: _InternalOllamaListFnType = async ({ onSuccess: onSuccess_, onError: onError_, settingsOfProvider }) => {
|
||||
|
||||
const onSuccess = ({ models }: { models: ModelResponse[] }) => {
|
||||
onSuccess_({ models })
|
||||
}
|
||||
|
||||
const onError = ({ error }: { error: string }) => {
|
||||
onError_({ error })
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
const thisConfig = settingsOfProvider.ollama
|
||||
const ollama = new Ollama({ host: thisConfig.endpoint })
|
||||
ollama.list()
|
||||
.then((response) => {
|
||||
const { models } = response
|
||||
onSuccess({ models })
|
||||
})
|
||||
.catch((error) => {
|
||||
onError({ error: error + '' })
|
||||
})
|
||||
}
|
||||
catch (error) {
|
||||
onError({ error: error + '' })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -31,8 +31,7 @@ export class LLMMessageChannel implements IServerChannel {
|
|||
// stupidly, channels can't take in @IService
|
||||
constructor(
|
||||
private readonly metricsService: IMetricsService,
|
||||
) {
|
||||
}
|
||||
) { }
|
||||
|
||||
// browser uses this to listen for changes
|
||||
listen(_: unknown, event: string): Event<any> {
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
* Void Editor additions licensed under the AGPL 3.0 License.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { useCallback, useEffect, useRef } from 'react'
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { FeatureName, featureNames, ProviderName, providerNames } from '../../../../../../../platform/void/common/voidConfigTypes.js'
|
||||
import { dummyModelData } from '../../../../../../../platform/void/common/voidConfigModelDefaults.js'
|
||||
import { useConfigState, useService } from '../util/services.js'
|
||||
import { useConfigState, useRefreshModelState, useService } from '../util/services.js'
|
||||
import { VoidSelectBox } from './inputs.js'
|
||||
import { SelectBox } from '../../../../../../../base/browser/ui/selectBox/selectBox.js'
|
||||
|
||||
|
|
@ -59,8 +59,18 @@ export const ModelSelectionOfFeature = ({ featureName }: { featureName: FeatureN
|
|||
}, [voidConfigService, modelOptions, featureName])}
|
||||
/>}
|
||||
|
||||
{/* <h1>Settings - {featureName}</h1> */}
|
||||
{/* {models.map(([providerName, model], i) => <p key={i}>{providerName} - {model}</p>)} */}
|
||||
</>
|
||||
}
|
||||
|
||||
const RefreshModels = () => {
|
||||
const refreshModelState = useRefreshModelState()
|
||||
const refreshModelService = useService('refreshModelService')
|
||||
|
||||
return <>
|
||||
<button onClick={() => refreshModelService.refreshOllamaModels()}>
|
||||
refresh
|
||||
</button>
|
||||
{refreshModelState === 'loading' ? 'loading...' : '✅'}
|
||||
</>
|
||||
}
|
||||
|
||||
|
|
@ -70,6 +80,8 @@ export const ModelSelectionSettings = () => {
|
|||
key={featureName}
|
||||
featureName={featureName}
|
||||
/>)}
|
||||
|
||||
<RefreshModels />
|
||||
</>
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,14 +4,14 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import React, { Fragment, useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { titleOfProviderName, displayInfoOfSettingName, ProviderName, providerNames, featureNames } from '../../../../../../../platform/void/common/voidConfigTypes.js'
|
||||
import { titleOfProviderName, displayInfoOfSettingName, ProviderName, providerNames, featureNames, SettingsOfProvider, SettingName, defaultVoidProviderState } from '../../../../../../../platform/void/common/voidConfigTypes.js'
|
||||
import { VoidInputBox } from './inputs.js'
|
||||
import { useConfigState, useService } from '../util/services.js'
|
||||
import { InputBox } from '../../../../../../../base/browser/ui/inputbox/inputBox.js'
|
||||
import ErrorBoundary from './ErrorBoundary.js'
|
||||
|
||||
|
||||
const Setting = ({ providerName, settingName }: { providerName: ProviderName, settingName: any }) => {
|
||||
const Setting = ({ providerName, settingName }: { providerName: ProviderName, settingName: SettingName }) => {
|
||||
|
||||
const { title, type, placeholder } = displayInfoOfSettingName(providerName, settingName)
|
||||
const voidConfigService = useService('configStateService')
|
||||
|
|
@ -22,6 +22,7 @@ const Setting = ({ providerName, settingName }: { providerName: ProviderName, se
|
|||
<VoidInputBox
|
||||
placeholder={placeholder}
|
||||
onChangeText={useCallback((newVal) => {
|
||||
|
||||
voidConfigService.setSettingOfProvider(providerName, settingName, newVal)
|
||||
// if we just disabeld this provider, we should unselect all models that use it
|
||||
if (settingName === 'enabled' && newVal !== 'true') {
|
||||
|
|
@ -54,10 +55,12 @@ const Setting = ({ providerName, settingName }: { providerName: ProviderName, se
|
|||
const SettingsForProvider = ({ providerName }: { providerName: ProviderName }) => {
|
||||
const voidConfigState = useConfigState()
|
||||
const { models, ...others } = voidConfigState[providerName]
|
||||
|
||||
return <>
|
||||
<h1 className='text-xl'>{titleOfProviderName(providerName)}</h1>
|
||||
{/* settings besides models (e.g. api key) */}
|
||||
{Object.keys(others).map((settingName, i) => {
|
||||
{Object.keys(others).map((sName, i) => {
|
||||
const settingName = sName as keyof typeof others
|
||||
return <Setting key={settingName} providerName={providerName} settingName={settingName} />
|
||||
})}
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -15,8 +15,10 @@ export const mountFnGenerator = (Component: React.FC) => (rootElement: HTMLEleme
|
|||
return
|
||||
}
|
||||
|
||||
_registerServices(services)
|
||||
const disposables = _registerServices(services)
|
||||
|
||||
const root = ReactDOM.createRoot(rootElement)
|
||||
root.render(<Component />);
|
||||
|
||||
return disposables
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import { useState, useEffect } from 'react'
|
|||
import { VoidSidebarState, ReactServicesType } from '../../../registerSidebar.js'
|
||||
import { ThreadsState } from '../../../registerThreads.js'
|
||||
import { SettingsOfProvider } from '../../../../../../../platform/void/common/voidConfigTypes.js'
|
||||
import { RefreshModelState } from '../../../../../../../platform/void/common/refreshModelService.js'
|
||||
import { IDisposable } from '../../../../../../../base/common/lifecycle.js'
|
||||
|
||||
|
||||
// normally to do this you'd use a useEffect that calls .onDidChangeState(), but useEffect mounts too late and misses initial state changes
|
||||
|
|
@ -17,11 +19,13 @@ let services: ReactServicesType
|
|||
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()
|
||||
const threadsStateListeners: Set<(s: ThreadsState) => void> = new Set()
|
||||
const settingsOfProviderListeners: Set<(s: SettingsOfProvider) => void> = new Set()
|
||||
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!
|
||||
|
|
@ -30,30 +34,47 @@ let wasCalled = false
|
|||
|
||||
export const _registerServices = (services_: ReactServicesType) => {
|
||||
|
||||
const disposables: IDisposable[] = []
|
||||
|
||||
if (wasCalled) console.error(`⚠️ Void _registerServices was called again! It should only be called once.`)
|
||||
wasCalled = true
|
||||
|
||||
services = services_
|
||||
const { sidebarStateService, configStateService, threadsStateService, } = services
|
||||
const { sidebarStateService, configStateService, threadsStateService, refreshModelService } = services
|
||||
|
||||
sidebarState = sidebarStateService.state
|
||||
sidebarStateService.onDidChangeState(() => {
|
||||
sidebarState = sidebarStateService.state
|
||||
sidebarStateListeners.forEach(l => l(sidebarState))
|
||||
})
|
||||
|
||||
disposables.push(
|
||||
sidebarStateService.onDidChangeState(() => {
|
||||
sidebarState = sidebarStateService.state
|
||||
sidebarStateListeners.forEach(l => l(sidebarState))
|
||||
})
|
||||
)
|
||||
|
||||
threadsState = threadsStateService.state
|
||||
threadsStateService.onDidChangeCurrentThread(() => {
|
||||
threadsState = threadsStateService.state
|
||||
threadsStateListeners.forEach(l => l(threadsState))
|
||||
})
|
||||
disposables.push(
|
||||
threadsStateService.onDidChangeCurrentThread(() => {
|
||||
threadsState = threadsStateService.state
|
||||
threadsStateListeners.forEach(l => l(threadsState))
|
||||
})
|
||||
)
|
||||
|
||||
settingsOfProvider = configStateService.state.settingsOfProvider
|
||||
configStateService.onDidChangeState(() => {
|
||||
settingsOfProvider = configStateService.state.settingsOfProvider
|
||||
settingsOfProviderListeners.forEach(l => l(settingsOfProvider))
|
||||
})
|
||||
disposables.push(
|
||||
configStateService.onDidChangeState(() => {
|
||||
settingsOfProvider = configStateService.state.settingsOfProvider
|
||||
settingsOfProviderListeners.forEach(l => l(settingsOfProvider))
|
||||
})
|
||||
)
|
||||
|
||||
refreshModelState = refreshModelService.state
|
||||
disposables.push(
|
||||
refreshModelService.onDidChangeState(() => {
|
||||
refreshModelState = refreshModelService.state
|
||||
refreshModelStateListeners.forEach(l => l(refreshModelState))
|
||||
})
|
||||
)
|
||||
|
||||
return disposables
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -96,3 +117,14 @@ export const useThreadsState = () => {
|
|||
}, [ss])
|
||||
return s
|
||||
}
|
||||
|
||||
|
||||
export const useRefreshModelState = () => {
|
||||
const [s, ss] = useState(refreshModelState)
|
||||
useEffect(() => {
|
||||
ss(refreshModelState)
|
||||
refreshModelStateListeners.add(ss)
|
||||
return () => { refreshModelStateListeners.delete(ss) }
|
||||
}, [ss])
|
||||
return s
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import { Position } from '../../../../editor/common/core/position.js';
|
|||
import { InlineCompletion, InlineCompletionContext } from '../../../../editor/common/languages.js';
|
||||
import { CancellationToken } from '../../../../base/common/cancellation.js';
|
||||
import { Range } from '../../../../editor/common/core/range.js';
|
||||
import { ILLMMessageService } from '../../../../platform/void/browser/llmMessageService.js';
|
||||
import { ILLMMessageService } from '../../../../platform/void/common/llmMessageService.js';
|
||||
import { IEditorService } from '../../../services/editor/common/editorService.js';
|
||||
import { isCodeEditor } from '../../../../editor/browser/editorBrowser.js';
|
||||
import { EditorResourceAccessor } from '../../../common/editor.js';
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ import * as dom from '../../../../base/browser/dom.js';
|
|||
import { Widget } from '../../../../base/browser/ui/widget.js';
|
||||
import { URI } from '../../../../base/common/uri.js';
|
||||
import { LLMFeatureSelection, ServiceSendLLMMessageParams } from '../../../../platform/void/common/llmMessageTypes.js';
|
||||
import { ILLMMessageService } from '../../../../platform/void/browser/llmMessageService.js';
|
||||
import { ILLMMessageService } from '../../../../platform/void/common/llmMessageService.js';
|
||||
|
||||
|
||||
// gets converted to --vscode-void-greenBG, see void.css
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import { IViewPaneOptions, ViewPane } from '../../../browser/parts/views/viewPan
|
|||
|
||||
import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';
|
||||
import { createDecorator, IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
|
||||
import { Disposable } from '../../../../base/common/lifecycle.js';
|
||||
import { Disposable, IDisposable } from '../../../../base/common/lifecycle.js';
|
||||
import { Emitter, Event } from '../../../../base/common/event.js';
|
||||
import { IThreadHistoryService } from './registerThreads.js';
|
||||
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
|
||||
|
|
@ -42,10 +42,11 @@ import { IVoidConfigStateService } from '../../../../platform/void/common/voidCo
|
|||
import { IFileService } from '../../../../platform/files/common/files.js';
|
||||
import { IInlineDiffsService } from './registerInlineDiffs.js';
|
||||
import { IModelService } from '../../../../editor/common/services/model.js';
|
||||
import { ILLMMessageService } from '../../../../platform/void/browser/llmMessageService.js';
|
||||
import { ILLMMessageService } from '../../../../platform/void/common/llmMessageService.js';
|
||||
import { IClipboardService } from '../../../../platform/clipboard/common/clipboardService.js';
|
||||
import { IViewsService } from '../../../services/views/common/viewsService.js';
|
||||
import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';
|
||||
import { IRefreshModelService } from '../../../../platform/void/common/refreshModelService.js';
|
||||
|
||||
|
||||
// compare against search.contribution.ts and debug.contribution.ts, scm.contribution.ts (source control)
|
||||
|
|
@ -64,6 +65,7 @@ export type ReactServicesType = {
|
|||
inlineDiffService: IInlineDiffsService;
|
||||
llmMessageService: ILLMMessageService;
|
||||
clipboardService: IClipboardService;
|
||||
refreshModelService: IRefreshModelService;
|
||||
|
||||
themeService: IThemeService,
|
||||
hoverService: IHoverService,
|
||||
|
|
@ -113,10 +115,14 @@ class VoidSidebarViewPane extends ViewPane {
|
|||
clipboardService: accessor.get(IClipboardService),
|
||||
themeService: accessor.get(IThemeService),
|
||||
hoverService: accessor.get(IHoverService),
|
||||
refreshModelService: accessor.get(IRefreshModelService),
|
||||
contextViewService: accessor.get(IContextViewService),
|
||||
contextMenuService: accessor.get(IContextMenuService),
|
||||
}
|
||||
mountFn(parent, services);
|
||||
|
||||
// mount react
|
||||
const disposables: IDisposable[] | undefined = mountFn(parent, services);
|
||||
disposables?.forEach(d => this._register(d))
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import './browser/workbench.contribution.js';
|
|||
//#region --- Void
|
||||
// Void added this:
|
||||
import './contrib/void/browser/void.contribution.js';
|
||||
import '../platform/void/browser/void.contribution.js';
|
||||
import '../platform/void/common/void.contribution.js';
|
||||
//#endregion
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue