diff --git a/extensions/void/src/common/getRules.ts b/extensions/void/src/common/getRules.ts new file mode 100644 index 00000000..0a7ef6c4 --- /dev/null +++ b/extensions/void/src/common/getRules.ts @@ -0,0 +1,12 @@ +import { awaitVSCodeResponse, getVSCodeAPI } from '../sidebar/getVscodeApi'; + +export async function getRules() { + try { + getVSCodeAPI().postMessage({ type: 'getRules', rules: '' }) + const rules = await awaitVSCodeResponse('getRules') + return rules.rules + } catch (error) { + console.error('Error reading .voidrules file:', error); + throw error; + } +} diff --git a/extensions/void/src/common/sendLLMMessage.ts b/extensions/void/src/common/sendLLMMessage.ts index 479a61d3..dcab0eaf 100644 --- a/extensions/void/src/common/sendLLMMessage.ts +++ b/extensions/void/src/common/sendLLMMessage.ts @@ -3,6 +3,7 @@ import { createOpenAI, OpenAIProviderSettings } from '@ai-sdk/openai'; import { AnthropicProviderSettings, createAnthropic } from '@ai-sdk/anthropic'; import { AzureOpenAIProviderSettings, createAzure } from '@ai-sdk/azure'; import { createOllama, OllamaProviderSettings } from 'ollama-ai-provider'; +import { getRules } from './getRules'; export type ApiConfig = { /** @default 'anthropic' */ @@ -142,24 +143,29 @@ const sendGreptileMsg: SendLLMMessageFnTypeInternal = ({ messages, onText, onFin export const sendLLMMessage: SendLLMMessageFnTypeExternal = ({ messages, onText, onFinalMessage, apiConfig }) => { if (!apiConfig) return { abort: () => { } } const provider = apiConfig.provider - // TODO: create an @ai-sdk provider for greptile + // TODO: create an @ai-sdk provider for greptile, if (provider === 'greptile') return sendGreptileMsg({ messages, onText, onFinalMessage, apiConfig }) const model = getAiModel(apiConfig) + const abortController = new AbortController() const abortSignal = abortController.signal - streamText({ - model, - messages, - abortSignal, - }).then(async (result) => { - let fullText = '' - for await (const textPart of result.textStream) { - fullText += textPart - onText(textPart, fullText) - } - onFinalMessage(fullText) + + getRules().then(rules => { + streamText({ + model, + system: rules || '', + messages, + abortSignal, + }).then(async (result) => { + let fullText = '' + for await (const textPart of result.textStream) { + fullText += textPart + onText(textPart, fullText) + } + onFinalMessage(fullText) + }) }) return { abort: abortController.abort } @@ -167,20 +173,28 @@ export const sendLLMMessage: SendLLMMessageFnTypeExternal = ({ messages, onText, export const getAiModel = (apiConfig: ApiConfig) => { switch (apiConfig.provider) { - case 'openai': return createOpenAI({ - ...apiConfig.openai.providerSettings, - apiKey: apiConfig.openai.apiKey, - })(apiConfig.openai.model || 'gpt-4o') - case 'anthropic': return createAnthropic({ - ...apiConfig.anthropic.providerSettings, - apiKey: apiConfig.anthropic.apiKey, - })(apiConfig.anthropic.model || 'claude-3-5-sonnet-20240620') - case 'ollama': return createOllama(apiConfig.ollama.providerSettings)(apiConfig.ollama.model || 'llama3.1') - case 'azure': return createAzure({ - ...apiConfig.azure.providerSettings, - apiKey: apiConfig.azure.apiKey, - resourceName: apiConfig.azure.resourceName, - })(`${apiConfig.azure.deploymentId}`) + case 'openai': + return createOpenAI({ + ...apiConfig.openai.providerSettings, + apiKey: apiConfig.openai.apiKey, + })(apiConfig.openai.model || 'gpt-4o') + + case 'anthropic': + return createAnthropic({ + ...apiConfig.anthropic.providerSettings, + apiKey: apiConfig.anthropic.apiKey, + })(apiConfig.anthropic.model || 'claude-3-5-sonnet-20240620') + + case 'ollama': + return createOllama(apiConfig.ollama.providerSettings)(apiConfig.ollama.model || 'llama3.1') + + case 'azure': + return createAzure({ + ...apiConfig.azure.providerSettings, + apiKey: apiConfig.azure.apiKey, + resourceName: apiConfig.azure.resourceName, + })(`${apiConfig.azure.deploymentId}`) + default: throw new Error(`Error: provider was ${apiConfig.provider}, which is not recognized!`) } diff --git a/extensions/void/src/extension.ts b/extensions/void/src/extension.ts index 5d2ae6c0..fa2805e8 100644 --- a/extensions/void/src/extension.ts +++ b/extensions/void/src/extension.ts @@ -115,7 +115,22 @@ export function activate(context: vscode.ExtensionContext) { // Receive messages in the extension from the sidebar webview (messages are sent using `postMessage`) webview.onDidReceiveMessage(async (m: WebviewMessage) => { - if (m.type === 'requestFiles') { + if (m.type === 'getRules') { + const workspaceFolder = vscode.workspace.workspaceFolders?.[0]; + if (workspaceFolder) { + const rulesFilePath = vscode.Uri.joinPath(workspaceFolder.uri, '.voidrules'); + try { + const rulesContent = await readFileContentOfUri(rulesFilePath); + webview.postMessage({ type: 'getRules', rules: rulesContent } satisfies WebviewMessage); + } catch (error) { + console.error('Error reading .voidrules file:', error); + webview.postMessage({ type: 'getRules', rules: null } satisfies WebviewMessage); + } + } else { + webview.postMessage({ type: 'getRules', rules: null } satisfies WebviewMessage); + } + } + else if (m.type === 'requestFiles') { // get contents of all file paths const files = await Promise.all( diff --git a/extensions/void/src/shared_types.ts b/extensions/void/src/shared_types.ts index 4d7c0dc9..d443bbe6 100644 --- a/extensions/void/src/shared_types.ts +++ b/extensions/void/src/shared_types.ts @@ -27,6 +27,9 @@ type WebviewMessage = ( // editor -> sidebar | { type: 'apiConfig', apiConfig: ApiConfig } + // sidebar -> editor + | { type: 'getRules', rules: string | null } + ) type Command = WebviewMessage['type'] diff --git a/extensions/void/src/sidebar/Sidebar.tsx b/extensions/void/src/sidebar/Sidebar.tsx index 0107e228..86df6407 100644 --- a/extensions/void/src/sidebar/Sidebar.tsx +++ b/extensions/void/src/sidebar/Sidebar.tsx @@ -266,7 +266,7 @@ const Sidebar = () => { {!selection?.selectionStr ? null : (
-