llmMessageService now multiplexes between sendLLMMessage, ollama, etc

This commit is contained in:
Andrew Pareles 2024-12-12 19:30:43 -08:00
parent 94f4d2caaf
commit 1365400f21
8 changed files with 47 additions and 67 deletions

View file

@ -15,18 +15,18 @@ import { IVoidConfigStateService } from '../common/voidConfigService.js';
// import { INotificationService } from '../../notification/common/notification.js';
// BROWSER IMPLEMENTATION OF SENDLLMMESSAGE
export const ISendLLMMessageService = createDecorator<ISendLLMMessageService>('sendLLMMessageService');
// BROWSER IMPLEMENTATION
export const ILLMMessageService = createDecorator<ILLMMessageService>('llmMessageService');
// defines an interface that node/ creates and browser/ uses
export interface ISendLLMMessageService {
export interface ILLMMessageService {
readonly _serviceBrand: undefined;
sendLLMMessage: (params: ServiceSendLLMMessageParams) => string | null;
abort: (requestId: string) => void;
}
export class SendLLMMessageService extends Disposable implements ISendLLMMessageService {
export class LLMMessageService extends Disposable implements ILLMMessageService {
readonly _serviceBrand: undefined;
private readonly channel: IChannel // LLMMessageChannel
@ -53,30 +53,27 @@ export class SendLLMMessageService extends Disposable implements ISendLLMMessage
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
const onTextEvent: Event<EventLLMMessageOnTextParams> = this.channel.listen('onText')
const onFinalMessageEvent: Event<EventLLMMessageOnFinalMessageParams> = this.channel.listen('onFinalMessage')
const onErrorEvent: Event<EventLLMMessageOnErrorParams> = this.channel.listen('onError')
this._register(
onTextEvent(e => {
this.onTextHooks_llm[e.requestId]?.(e)
})
)
this._register(
onFinalMessageEvent(e => {
this.onFinalMessageHooks_llm[e.requestId]?.(e)
this._onRequestIdDone(e.requestId)
})
)
this._register(
onErrorEvent(e => {
console.log('Error in SendLLMMessageService:', JSON.stringify(e))
this.onErrorHooks_llm[e.requestId]?.(e)
this._onRequestIdDone(e.requestId)
})
)
// llm
this._register((this.channel.listen('onText_llm') satisfies Event<EventLLMMessageOnTextParams>)(e => {
this.onTextHooks_llm[e.requestId]?.(e)
}))
this._register((this.channel.listen('onFinalMessage_llm') satisfies Event<EventLLMMessageOnFinalMessageParams>)(e => {
this.onFinalMessageHooks_llm[e.requestId]?.(e)
this._onRequestIdDone(e.requestId)
}))
this._register((this.channel.listen('onError_llm') satisfies Event<EventLLMMessageOnErrorParams>)(e => {
console.log('Error in LLMMessageService:', JSON.stringify(e))
this.onErrorHooks_llm[e.requestId]?.(e)
this._onRequestIdDone(e.requestId)
}))
// ollama
this._register((this.channel.listen('onSuccess_ollama') satisfies Event<EventOllamaListOnSuccessParams>)(e => {
this.onSuccess_ollama[e.requestId]?.(e)
}))
this._register((this.channel.listen('onError_ollama') satisfies Event<EventOllamaListOnErrorParams>)(e => {
this.onError_ollama[e.requestId]?.(e)
}))
}
sendLLMMessage(params: ServiceSendLLMMessageParams) {
@ -145,5 +142,5 @@ export class SendLLMMessageService extends Disposable implements ISendLLMMessage
}
}
registerSingleton(ISendLLMMessageService, SendLLMMessageService, InstantiationType.Delayed);
registerSingleton(ILLMMessageService, LLMMessageService, InstantiationType.Delayed);

View file

@ -3,9 +3,6 @@
// metrics
import '../browser/metricsService.js'
// ollamaList
import '../browser/ollamaListService.js'
// --- common ---
// llmMessage
import '../browser/llmMessageService.js'

View file

@ -18,22 +18,15 @@ import { ollamaList } from './llmMessage/ollama.js';
export class LLMMessageChannel implements IServerChannel {
// sendLLMMessage
private readonly _onText_llm = new Emitter<EventLLMMessageOnTextParams>();
private readonly onText_llm = this._onText_llm.event;
private readonly _onFinalMessage_llm = new Emitter<EventLLMMessageOnFinalMessageParams>();
private readonly onFinalMessage_llm = this._onFinalMessage_llm.event;
private readonly _onError_llm = new Emitter<EventLLMMessageOnErrorParams>();
private readonly onError_llm = this._onError_llm.event;
// abort
private readonly _abortRefOfRequestId_llm: Record<string, AbortRef> = {}
// ollamaList
private readonly _onSuccess_ollama = new Emitter<EventOllamaListOnSuccessParams>();
private readonly onSuccess_ollama = this._onSuccess_ollama.event;
private readonly _onError_ollama = new Emitter<EventOllamaListOnErrorParams>();
private readonly onError_ollama = this._onError_ollama.event;
// stupidly, channels can't take in @IService
constructor(
@ -44,19 +37,19 @@ export class LLMMessageChannel implements IServerChannel {
// browser uses this to listen for changes
listen(_: unknown, event: string): Event<any> {
if (event === 'onText_llm') {
return this.onText_llm;
return this._onText_llm.event;
}
else if (event === 'onFinalMessage_llm') {
return this.onFinalMessage_llm;
return this._onFinalMessage_llm.event;
}
else if (event === 'onError_llm') {
return this.onError_llm;
return this._onError_llm.event;
}
else if (event === 'onSuccess_ollama') {
return this.onSuccess_ollama;
return this._onSuccess_ollama.event;
}
else if (event === 'onError_ollama') {
return this.onError_ollama;
return this._onError_ollama.event;
}
else {
throw new Error(`Event not found: ${event}`);
@ -65,7 +58,6 @@ export class LLMMessageChannel implements IServerChannel {
// browser uses this to call
async call(_: unknown, command: string, params: any): Promise<any> {
try {
if (command === 'sendLLMMessage') {
this._callSendLLMMessage(params)

View file

@ -18,7 +18,7 @@ import { URI } from '../../../../../../../base/common/uri.js';
import { EndOfLinePreference } from '../../../../../../../editor/common/model.js';
import { IDisposable } from '../../../../../../../base/common/lifecycle.js';
import { ErrorDisplay } from './ErrorDisplay.js';
import { LLMMessageServiceParams, OnError } from '../../../../../../../platform/void/common/llmMessageTypes.js';
import { OnError, ServiceSendLLMMessageParams } from '../../../../../../../platform/void/common/llmMessageTypes.js';
import { getCmdKey } from '../../../getCmdKey.js'
import { HistoryInputBox, InputBox } from '../../../../../../../base/browser/ui/inputbox/inputBox.js';
import { VoidInputBox } from './inputs.js';
@ -240,7 +240,7 @@ export const SidebarChat = () => {
const [latestError, setLatestError] = useState<Parameters<OnError>[0] | null>(null)
const sendLLMMessageService = useService('sendLLMMessageService')
const llmMessageService = useService('llmMessageService')
// state of current message
const [instructions, setInstructions] = useState('') // the user's instructions
@ -295,7 +295,7 @@ export const SidebarChat = () => {
inputBoxRef.current.blur();
}
const object: LLMMessageServiceParams = {
const object: ServiceSendLLMMessageParams = {
logging: { loggingName: 'Chat' },
messages: [...(currentThread?.messages ?? []).map(m => ({ role: m.role, content: m.content || '(null)' })),],
onText: ({ newText, fullText }) => setMessageStream(fullText),
@ -325,7 +325,7 @@ export const SidebarChat = () => {
}
const latestRequestId = sendLLMMessageService.sendLLMMessage(object)
const latestRequestId = llmMessageService.sendLLMMessage(object)
latestRequestIdRef.current = latestRequestId
threadsStateService.setStaging([]) // clear staging
@ -335,7 +335,7 @@ export const SidebarChat = () => {
const onAbort = () => {
// abort the LLM call
if (latestRequestIdRef.current)
sendLLMMessageService.abort(latestRequestIdRef.current)
llmMessageService.abort(latestRequestIdRef.current)
// if messageStream was not empty, add it to the history
const llmContent = messageStream ?? ''

View file

@ -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 { ISendLLMMessageService } from '../../../../platform/void/browser/llmMessageService.js';
import { ILLMMessageService } from '../../../../platform/void/browser/llmMessageService.js';
import { IEditorService } from '../../../services/editor/common/editorService.js';
import { isCodeEditor } from '../../../../editor/browser/editorBrowser.js';
import { EditorResourceAccessor } from '../../../common/editor.js';
@ -527,7 +527,7 @@ export class AutocompleteService extends Disposable implements IAutocompleteServ
MAX_CACHE_SIZE,
(autocompletion: Autocompletion) => {
if (autocompletion.requestId)
this._sendLLMMessageService.abort(autocompletion.requestId)
this._llmMessageService.abort(autocompletion.requestId)
}
)
}
@ -644,7 +644,7 @@ export class AutocompleteService extends Disposable implements IAutocompleteServ
// set parameters of `newAutocompletion` appropriately
newAutocompletion.llmPromise = new Promise((resolve, reject) => {
const requestId = this._sendLLMMessageService.sendLLMMessage({
const requestId = this._llmMessageService.sendLLMMessage({
logging: { loggingName: 'Autocomplete' },
messages: [],
onText: async ({ newText, fullText }) => {
@ -713,7 +713,7 @@ export class AutocompleteService extends Disposable implements IAutocompleteServ
constructor(
@ILanguageFeaturesService private _langFeatureService: ILanguageFeaturesService,
@ISendLLMMessageService private readonly _sendLLMMessageService: ISendLLMMessageService,
@ILLMMessageService private readonly _llmMessageService: ILLMMessageService,
@IEditorService private readonly _editorService: IEditorService,
@IModelService private readonly _modelService: IModelService,
) {

View file

@ -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 { ISendLLMMessageService } from '../../../../platform/void/browser/llmMessageService.js';
import { ILLMMessageService } from '../../../../platform/void/browser/llmMessageService.js';
// gets converted to --vscode-void-greenBG, see void.css
@ -149,7 +149,7 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService {
@IModelService private readonly _modelService: IModelService,
@IUndoRedoService private readonly _undoRedoService: IUndoRedoService, // undoRedo service is the history of pressing ctrl+z
@ILanguageService private readonly _langService: ILanguageService,
@ISendLLMMessageService private readonly _sendLLMMessageService: ISendLLMMessageService,
@ILLMMessageService private readonly _llmMessageService: ILLMMessageService,
) {
super();
@ -732,7 +732,7 @@ Please finish writing the new file by applying the diff to the original file. Re
console.error('Error rewriting file with diff', e);
// TODO indicate there was an error
if (streamRequestId)
this._sendLLMMessageService.abort(streamRequestId)
this._llmMessageService.abort(streamRequestId)
diffArea._sweepState = { isStreaming: false, line: null }
resolve();
@ -740,7 +740,7 @@ Please finish writing the new file by applying the diff to the original file. Re
...opts
}
streamRequestId = this._sendLLMMessageService.sendLLMMessage(object)
streamRequestId = this._llmMessageService.sendLLMMessage(object)
})
onFinishEdit()

View file

@ -42,7 +42,7 @@ 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 { ISendLLMMessageService } from '../../../../platform/void/browser/llmMessageService.js';
import { ILLMMessageService } from '../../../../platform/void/browser/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';
@ -62,7 +62,7 @@ export type ReactServicesType = {
fileService: IFileService;
modelService: IModelService;
inlineDiffService: IInlineDiffsService;
sendLLMMessageService: ISendLLMMessageService;
llmMessageService: ILLMMessageService;
clipboardService: IClipboardService;
themeService: IThemeService,
@ -109,7 +109,7 @@ class VoidSidebarViewPane extends ViewPane {
fileService: accessor.get(IFileService),
modelService: accessor.get(IModelService),
inlineDiffService: accessor.get(IInlineDiffsService),
sendLLMMessageService: accessor.get(ISendLLMMessageService),
llmMessageService: accessor.get(ILLMMessageService),
clipboardService: accessor.get(IClipboardService),
themeService: accessor.get(IThemeService),
hoverService: accessor.get(IHoverService),

View file

@ -31,12 +31,6 @@ import './electron-sandbox/parts/dialogs/dialog.contribution.js';
//#endregion
// //#region --- Void
// // Void added this (modeling off of import '.*clipboardservice.js'):
// import './services/void/electron-main/sendLLMMessage.js';
// //#endregion
//#region --- workbench services