From 23f1e8c6417e19879f50f6519fa465865bd3a116 Mon Sep 17 00:00:00 2001 From: Andrew Pareles Date: Wed, 16 Apr 2025 02:21:36 -0700 Subject: [PATCH] .voidinstructions file --- .../browser/convertToLLMMessageService.ts | 50 +++++++++++++++---- .../convertToLLMMessageWorkbenchContrib.ts | 37 ++++++++++++++ .../contrib/void/browser/void.contribution.ts | 1 + 3 files changed, 78 insertions(+), 10 deletions(-) create mode 100644 src/vs/workbench/contrib/void/browser/convertToLLMMessageWorkbenchContrib.ts diff --git a/src/vs/workbench/contrib/void/browser/convertToLLMMessageService.ts b/src/vs/workbench/contrib/void/browser/convertToLLMMessageService.ts index 053d25bd..19606415 100644 --- a/src/vs/workbench/contrib/void/browser/convertToLLMMessageService.ts +++ b/src/vs/workbench/contrib/void/browser/convertToLLMMessageService.ts @@ -13,6 +13,8 @@ import { IVoidSettingsService } from '../common/voidSettingsService.js'; import { ChatMode, FeatureName, ModelSelection } from '../common/voidSettingsTypes.js'; import { IDirectoryStrService } from './directoryStrService.js'; import { ITerminalToolService } from './terminalToolService.js'; +import { IVoidModelService } from '../common/voidModelService.js'; +import { URI } from '../../../../base/common/uri.js'; @@ -412,9 +414,9 @@ const prepareMessages = ({ export interface IConvertToLLMMessageService { readonly _serviceBrand: undefined; - prepareLLMSimpleMessages: (opts: { simpleMessages: SimpleLLMMessage[], systemMessage: string, modelSelection: ModelSelection | null, featureName: FeatureName }) => { messages: LLMChatMessage[], separateSystemMessage: string | undefined }; + prepareLLMSimpleMessages: (opts: { simpleMessages: SimpleLLMMessage[], systemMessage: string, modelSelection: ModelSelection | null, featureName: FeatureName }) => { messages: LLMChatMessage[], separateSystemMessage: string | undefined } prepareLLMChatMessages: (opts: { chatMessages: ChatMessage[], chatMode: ChatMode, modelSelection: ModelSelection | null }) => Promise<{ messages: LLMChatMessage[], separateSystemMessage: string | undefined }> - prepareFIMMessage(opts: { messages: LLMFIMMessage, aiInstructions: string, }): { prefix: string, suffix: string, stopTokens: string[] } + prepareFIMMessage(opts: { messages: LLMFIMMessage, }): { prefix: string, suffix: string, stopTokens: string[] } } @@ -431,10 +433,35 @@ class ConvertToLLMMessageService extends Disposable implements IConvertToLLMMess @IDirectoryStrService private readonly directoryStrService: IDirectoryStrService, @ITerminalToolService private readonly terminalToolService: ITerminalToolService, @IVoidSettingsService private readonly voidSettingsService: IVoidSettingsService, + @IVoidModelService private readonly voidModelService: IVoidModelService, ) { super() } + // Read .voidinstructions files from workspace folders + private _getVoidInstructionsFileContents(): string { + const workspaceFolders = this.workspaceContextService.getWorkspace().folders; + let voidInstructions = ''; + for (const folder of workspaceFolders) { + const uri = URI.joinPath(folder.uri, '.voidinstructions') + const { model } = this.voidModelService.getModel(uri) + if (!model) continue + voidInstructions += model.getValue() + '\n\n'; + } + return voidInstructions.trim(); + } + + // Get combined AI instructions from settings and .voidinstructions files + private _getCombinedAIInstructions(): string { + const globalAIInstructions = this.voidSettingsService.state.globalSettings.aiInstructions; + const voidInstructionsFileContent = this._getVoidInstructionsFileContents(); + + const ans: string[] = [] + if (globalAIInstructions) ans.push(globalAIInstructions) + if (voidInstructionsFileContent) ans.push(voidInstructionsFileContent) + return ans.join('\n\n') + } + // system message private _generateChatMessagesSystemMessage = async (chatMode: ChatMode, specialToolFormat: 'openai-style' | 'anthropic-style' | undefined) => { @@ -502,7 +529,9 @@ class ConvertToLLMMessageService extends Disposable implements IConvertToLLMMess } = getModelCapabilities(providerName, modelName) const modelSelectionOptions = this.voidSettingsService.state.optionsOfModelSelection[featureName][modelSelection.providerName]?.[modelSelection.modelName] - const aiInstructions = this.voidSettingsService.state.globalSettings.aiInstructions + + // Get combined AI instructions + const aiInstructions = this._getCombinedAIInstructions(); const isReasoningEnabled = getIsReasoningEnabledState(featureName, providerName, modelName, modelSelectionOptions) const maxOutputTokens = getMaxOutputTokens(providerName, modelName, { isReasoningEnabled }) @@ -518,7 +547,6 @@ class ConvertToLLMMessageService extends Disposable implements IConvertToLLMMess maxOutputTokens, }) return { messages, separateSystemMessage }; - } prepareLLMChatMessages: IConvertToLLMMessageService['prepareLLMChatMessages'] = async ({ chatMessages, chatMode, modelSelection }) => { if (modelSelection === null) return { messages: [], separateSystemMessage: undefined } @@ -531,7 +559,9 @@ class ConvertToLLMMessageService extends Disposable implements IConvertToLLMMess const systemMessage = await this._generateChatMessagesSystemMessage(chatMode, specialToolFormat) const modelSelectionOptions = this.voidSettingsService.state.optionsOfModelSelection['Chat'][modelSelection.providerName]?.[modelSelection.modelName] - const aiInstructions = this.voidSettingsService.state.globalSettings.aiInstructions + + // Get combined AI instructions + const aiInstructions = this._getCombinedAIInstructions(); const isReasoningEnabled = getIsReasoningEnabledState('Chat', providerName, modelName, modelSelectionOptions) const maxOutputTokens = getMaxOutputTokens(providerName, modelName, { isReasoningEnabled }) @@ -548,19 +578,20 @@ class ConvertToLLMMessageService extends Disposable implements IConvertToLLMMess maxOutputTokens, }) return { messages, separateSystemMessage }; - } // --- FIM --- - prepareFIMMessage: IConvertToLLMMessageService['prepareFIMMessage'] = ({ messages, aiInstructions }) => { + prepareFIMMessage: IConvertToLLMMessageService['prepareFIMMessage'] = ({ messages }) => { + // Get combined AI instructions with the provided aiInstructions as the base + const combinedInstructions = this._getCombinedAIInstructions(); let prefix = `\ -${!aiInstructions ? '' : `\ +${!combinedInstructions ? '' : `\ // Instructions: // Do not output an explanation. Try to avoid outputting comments. Only output the middle code. -${aiInstructions.split('\n').map(line => `//${line}`).join('\n')}`} +${combinedInstructions.split('\n').map(line => `//${line}`).join('\n')}`} ${messages.prefix}` @@ -573,7 +604,6 @@ ${messages.prefix}` } -// pick one and delete the other: registerSingleton(IConvertToLLMMessageService, ConvertToLLMMessageService, InstantiationType.Eager); diff --git a/src/vs/workbench/contrib/void/browser/convertToLLMMessageWorkbenchContrib.ts b/src/vs/workbench/contrib/void/browser/convertToLLMMessageWorkbenchContrib.ts new file mode 100644 index 00000000..9e65f9da --- /dev/null +++ b/src/vs/workbench/contrib/void/browser/convertToLLMMessageWorkbenchContrib.ts @@ -0,0 +1,37 @@ +/*-------------------------------------------------------------------------------------- + * Copyright 2025 Glass Devtools, Inc. All rights reserved. + * Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information. + *--------------------------------------------------------------------------------------*/ + +import { Disposable } from '../../../../base/common/lifecycle.js'; +import { URI } from '../../../../base/common/uri.js'; +import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.js'; +import { IWorkbenchContribution, registerWorkbenchContribution2, WorkbenchPhase } from '../../../common/contributions.js'; +import { IVoidModelService } from '../common/voidModelService.js'; + +class ConvertContribWorkbenchContribution extends Disposable implements IWorkbenchContribution { + static readonly ID = 'workbench.contrib.void.convertcontrib' + _serviceBrand: undefined; + + constructor( + @IVoidModelService private readonly voidModelService: IVoidModelService, + @IWorkspaceContextService private readonly workspaceContext: IWorkspaceContextService, + ) { + super() + + const initializeURI = (uri: URI) => { + this.workspaceContext.getWorkspace() + const voidInstrsURI = URI.joinPath(uri, '.voidinstructions') + this.voidModelService.initializeModel(voidInstrsURI) + } + + // call + this._register(this.workspaceContext.onDidChangeWorkspaceFolders((e) => { + [...e.changed, ...e.added].forEach(w => { initializeURI(w.uri) }) + })) + this.workspaceContext.getWorkspace().folders.forEach(w => { initializeURI(w.uri) }) + } +} + + +registerWorkbenchContribution2(ConvertContribWorkbenchContribution.ID, ConvertContribWorkbenchContribution, WorkbenchPhase.BlockRestore); diff --git a/src/vs/workbench/contrib/void/browser/void.contribution.ts b/src/vs/workbench/contrib/void/browser/void.contribution.ts index 30cdfc8b..cd7b6f60 100644 --- a/src/vs/workbench/contrib/void/browser/void.contribution.ts +++ b/src/vs/workbench/contrib/void/browser/void.contribution.ts @@ -32,6 +32,7 @@ import './media/void.css' // update (frontend part, also see platform/) import './voidUpdateActions.js' +import './convertToLLMMessageWorkbenchContrib.js' // tools import './toolsService.js'